Revert "Clang import; This experimental feature didn't "take off" much. After a lot of work we are still far fram the goal. I remove it now but don't rule out completely that it could ever be added again."
This reverts commit 207361b174
.
This commit is contained in:
parent
59ef06819a
commit
d2d2124238
|
@ -121,6 +121,7 @@ jobs:
|
||||||
copy .\bin\cppcheck.exe .\cppcheck.exe || exit /b !errorlevel!
|
copy .\bin\cppcheck.exe .\cppcheck.exe || exit /b !errorlevel!
|
||||||
copy .\bin\cppcheck-core.dll .\cppcheck-core.dll || exit /b !errorlevel!
|
copy .\bin\cppcheck-core.dll .\cppcheck-core.dll || exit /b !errorlevel!
|
||||||
cd test/cli || exit /b !errorlevel!
|
cd test/cli || exit /b !errorlevel!
|
||||||
|
python -m pytest --suppress-no-test-exit-code test-clang-import.py || exit /b !errorlevel!
|
||||||
python -m pytest test-helloworld.py || exit /b !errorlevel!
|
python -m pytest test-helloworld.py || exit /b !errorlevel!
|
||||||
python -m pytest test-inline-suppress.py || exit /b !errorlevel!
|
python -m pytest test-inline-suppress.py || exit /b !errorlevel!
|
||||||
python -m pytest test-more-projects.py || exit /b !errorlevel!
|
python -m pytest test-more-projects.py || exit /b !errorlevel!
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -185,6 +185,7 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \
|
||||||
$(libcppdir)/checkunusedfunctions.o \
|
$(libcppdir)/checkunusedfunctions.o \
|
||||||
$(libcppdir)/checkunusedvar.o \
|
$(libcppdir)/checkunusedvar.o \
|
||||||
$(libcppdir)/checkvaarg.o \
|
$(libcppdir)/checkvaarg.o \
|
||||||
|
$(libcppdir)/clangimport.o \
|
||||||
$(libcppdir)/cppcheck.o \
|
$(libcppdir)/cppcheck.o \
|
||||||
$(libcppdir)/ctu.o \
|
$(libcppdir)/ctu.o \
|
||||||
$(libcppdir)/errorlogger.o \
|
$(libcppdir)/errorlogger.o \
|
||||||
|
@ -232,6 +233,7 @@ TESTOBJ = test/options.o \
|
||||||
test/testbufferoverrun.o \
|
test/testbufferoverrun.o \
|
||||||
test/testbughuntingchecks.o \
|
test/testbughuntingchecks.o \
|
||||||
test/testcharvar.o \
|
test/testcharvar.o \
|
||||||
|
test/testclangimport.o \
|
||||||
test/testclass.o \
|
test/testclass.o \
|
||||||
test/testcmdlineparser.o \
|
test/testcmdlineparser.o \
|
||||||
test/testcondition.o \
|
test/testcondition.o \
|
||||||
|
@ -491,7 +493,10 @@ $(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp externals/simplecpp/simple
|
||||||
$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/astutils.h lib/check.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
|
$(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/astutils.h lib/check.h lib/checkvaarg.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checkvaarg.o $(libcppdir)/checkvaarg.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checkvaarg.o $(libcppdir)/checkvaarg.cpp
|
||||||
|
|
||||||
$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/astutils.h lib/check.h lib/checkunusedfunctions.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h
|
$(libcppdir)/clangimport.o: lib/clangimport.cpp lib/astutils.h lib/clangimport.h lib/config.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
|
||||||
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/clangimport.o $(libcppdir)/clangimport.cpp
|
||||||
|
|
||||||
|
$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/analyzerinfo.h lib/astutils.h lib/check.h lib/checkunusedfunctions.h lib/clangimport.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/cppcheck.o $(libcppdir)/cppcheck.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/cppcheck.o $(libcppdir)/cppcheck.cpp
|
||||||
|
|
||||||
$(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
|
$(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h
|
||||||
|
@ -617,6 +622,9 @@ test/testbughuntingchecks.o: test/testbughuntingchecks.cpp lib/astutils.h lib/co
|
||||||
test/testcharvar.o: test/testcharvar.cpp lib/astutils.h lib/check.h lib/checkother.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
|
test/testcharvar.o: test/testcharvar.cpp lib/astutils.h lib/check.h lib/checkother.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testcharvar.o test/testcharvar.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testcharvar.o test/testcharvar.cpp
|
||||||
|
|
||||||
|
test/testclangimport.o: test/testclangimport.cpp lib/astutils.h lib/clangimport.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
|
||||||
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testclangimport.o test/testclangimport.cpp
|
||||||
|
|
||||||
test/testclass.o: test/testclass.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
|
test/testclass.o: test/testclass.cpp externals/tinyxml2/tinyxml2.h lib/astutils.h lib/check.h lib/checkclass.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testclass.o test/testclass.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testclass.o test/testclass.cpp
|
||||||
|
|
||||||
|
|
|
@ -235,7 +235,10 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (std::strncmp(argv[i], "--clang", 7) == 0) {
|
else if (std::strncmp(argv[i], "--clang", 7) == 0) {
|
||||||
printMessage("Cppcheck: Clang import has been removed");
|
mSettings->clang = true;
|
||||||
|
if (std::strncmp(argv[i], "--clang=", 8) == 0) {
|
||||||
|
mSettings->clangExecutable = argv[i] + 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) {
|
else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) {
|
||||||
|
@ -989,11 +992,18 @@ void CmdLineParser::printHelp()
|
||||||
" * faster analysis; Cppcheck will reuse the results if\n"
|
" * faster analysis; Cppcheck will reuse the results if\n"
|
||||||
" the hash for a file is unchanged.\n"
|
" the hash for a file is unchanged.\n"
|
||||||
" * some useful debug information, i.e. commands used to\n"
|
" * some useful debug information, i.e. commands used to\n"
|
||||||
" execute clang-tidy/addons.\n"
|
" execute clang/clang-tidy/addons.\n"
|
||||||
" --check-config Check cppcheck configuration. The normal code\n"
|
" --check-config Check cppcheck configuration. The normal code\n"
|
||||||
" analysis is disabled by this flag.\n"
|
" analysis is disabled by this flag.\n"
|
||||||
" --check-library Show information messages when library files have\n"
|
" --check-library Show information messages when library files have\n"
|
||||||
" incomplete info.\n"
|
" incomplete info.\n"
|
||||||
|
" --clang=<path> Experimental: Use Clang parser instead of the builtin Cppcheck\n"
|
||||||
|
" parser. Takes the executable as optional parameter and\n"
|
||||||
|
" defaults to `clang`. Cppcheck will run the given Clang\n"
|
||||||
|
" executable, import the Clang AST and convert it into\n"
|
||||||
|
" Cppcheck data. After that the normal Cppcheck analysis is\n"
|
||||||
|
" used. You must have the executable in PATH if no path is\n"
|
||||||
|
" given.\n"
|
||||||
" --config-exclude=<dir>\n"
|
" --config-exclude=<dir>\n"
|
||||||
" Path (prefix) to be excluded from configuration\n"
|
" Path (prefix) to be excluded from configuration\n"
|
||||||
" checking. Preprocessor configurations defined in\n"
|
" checking. Preprocessor configurations defined in\n"
|
||||||
|
|
|
@ -873,6 +873,7 @@ Settings MainWindow::getCppcheckSettings()
|
||||||
result.userDefines += define.toStdString();
|
result.userDefines += define.toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.clang = mProjectFile->clangParser;
|
||||||
result.bugHunting = mProjectFile->bugHunting;
|
result.bugHunting = mProjectFile->bugHunting;
|
||||||
result.bugHuntingReport = " ";
|
result.bugHuntingReport = " ";
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ ProjectFile::ProjectFile(const QString &filename, QObject *parent) :
|
||||||
void ProjectFile::clear()
|
void ProjectFile::clear()
|
||||||
{
|
{
|
||||||
const Settings settings;
|
const Settings settings;
|
||||||
|
clangParser = false;
|
||||||
bugHunting = false;
|
bugHunting = false;
|
||||||
mRootPath.clear();
|
mRootPath.clear();
|
||||||
mBuildDir.clear();
|
mBuildDir.clear();
|
||||||
|
@ -61,7 +62,7 @@ void ProjectFile::clear()
|
||||||
mPlatform.clear();
|
mPlatform.clear();
|
||||||
mSuppressions.clear();
|
mSuppressions.clear();
|
||||||
mAddons.clear();
|
mAddons.clear();
|
||||||
mClangTidy = false;
|
mClangAnalyzer = mClangTidy = false;
|
||||||
mAnalyzeAllVsConfigs = false;
|
mAnalyzeAllVsConfigs = false;
|
||||||
mCheckHeaders = true;
|
mCheckHeaders = true;
|
||||||
mCheckUnusedTemplates = true;
|
mCheckUnusedTemplates = true;
|
||||||
|
@ -117,6 +118,9 @@ bool ProjectFile::read(const QString &filename)
|
||||||
if (xmlReader.name() == CppcheckXml::AnalyzeAllVsConfigsElementName)
|
if (xmlReader.name() == CppcheckXml::AnalyzeAllVsConfigsElementName)
|
||||||
mAnalyzeAllVsConfigs = readBool(xmlReader);
|
mAnalyzeAllVsConfigs = readBool(xmlReader);
|
||||||
|
|
||||||
|
if (xmlReader.name() == CppcheckXml::Parser)
|
||||||
|
clangParser = true;
|
||||||
|
|
||||||
if (xmlReader.name() == CppcheckXml::BugHunting)
|
if (xmlReader.name() == CppcheckXml::BugHunting)
|
||||||
bugHunting = true;
|
bugHunting = true;
|
||||||
|
|
||||||
|
@ -182,6 +186,7 @@ bool ProjectFile::read(const QString &filename)
|
||||||
if (xmlReader.name() == CppcheckXml::ToolsElementName) {
|
if (xmlReader.name() == CppcheckXml::ToolsElementName) {
|
||||||
QStringList tools;
|
QStringList tools;
|
||||||
readStringList(tools, xmlReader, CppcheckXml::ToolElementName);
|
readStringList(tools, xmlReader, CppcheckXml::ToolElementName);
|
||||||
|
mClangAnalyzer = tools.contains(CLANG_ANALYZER);
|
||||||
mClangTidy = tools.contains(CLANG_TIDY);
|
mClangTidy = tools.contains(CLANG_TIDY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,6 +875,12 @@ bool ProjectFile::write(const QString &filename)
|
||||||
xmlWriter.writeCharacters(mAnalyzeAllVsConfigs ? "true" : "false");
|
xmlWriter.writeCharacters(mAnalyzeAllVsConfigs ? "true" : "false");
|
||||||
xmlWriter.writeEndElement();
|
xmlWriter.writeEndElement();
|
||||||
|
|
||||||
|
if (clangParser) {
|
||||||
|
xmlWriter.writeStartElement(CppcheckXml::Parser);
|
||||||
|
xmlWriter.writeCharacters("clang");
|
||||||
|
xmlWriter.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
if (bugHunting) {
|
if (bugHunting) {
|
||||||
xmlWriter.writeStartElement(CppcheckXml::BugHunting);
|
xmlWriter.writeStartElement(CppcheckXml::BugHunting);
|
||||||
xmlWriter.writeEndElement();
|
xmlWriter.writeEndElement();
|
||||||
|
@ -1005,6 +1016,8 @@ bool ProjectFile::write(const QString &filename)
|
||||||
CppcheckXml::AddonElementName);
|
CppcheckXml::AddonElementName);
|
||||||
|
|
||||||
QStringList tools;
|
QStringList tools;
|
||||||
|
if (mClangAnalyzer)
|
||||||
|
tools << CLANG_ANALYZER;
|
||||||
if (mClangTidy)
|
if (mClangTidy)
|
||||||
tools << CLANG_TIDY;
|
tools << CLANG_TIDY;
|
||||||
writeStringList(xmlWriter,
|
writeStringList(xmlWriter,
|
||||||
|
@ -1064,6 +1077,8 @@ QStringList ProjectFile::fromNativeSeparators(const QStringList &paths)
|
||||||
QStringList ProjectFile::getAddonsAndTools() const
|
QStringList ProjectFile::getAddonsAndTools() const
|
||||||
{
|
{
|
||||||
QStringList ret(mAddons);
|
QStringList ret(mAddons);
|
||||||
|
if (mClangAnalyzer)
|
||||||
|
ret << CLANG_ANALYZER;
|
||||||
if (mClangTidy)
|
if (mClangTidy)
|
||||||
ret << CLANG_TIDY;
|
ret << CLANG_TIDY;
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -192,6 +192,14 @@ public:
|
||||||
*/
|
*/
|
||||||
QStringList getAddonsAndTools() const;
|
QStringList getAddonsAndTools() const;
|
||||||
|
|
||||||
|
bool getClangAnalyzer() const {
|
||||||
|
return false; //mClangAnalyzer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setClangAnalyzer(bool c) {
|
||||||
|
mClangAnalyzer = c;
|
||||||
|
}
|
||||||
|
|
||||||
bool getClangTidy() const {
|
bool getClangTidy() const {
|
||||||
return mClangTidy;
|
return mClangTidy;
|
||||||
}
|
}
|
||||||
|
@ -380,6 +388,9 @@ public:
|
||||||
mCheckUnknownFunctionReturn = s;
|
mCheckUnknownFunctionReturn = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Use Clang parser */
|
||||||
|
bool clangParser;
|
||||||
|
|
||||||
/** Bug hunting */
|
/** Bug hunting */
|
||||||
bool bugHunting;
|
bool bugHunting;
|
||||||
protected:
|
protected:
|
||||||
|
@ -572,6 +583,9 @@ private:
|
||||||
*/
|
*/
|
||||||
QStringList mAddons;
|
QStringList mAddons;
|
||||||
|
|
||||||
|
/** @brief Execute clang analyzer? */
|
||||||
|
bool mClangAnalyzer;
|
||||||
|
|
||||||
/** @brief Execute clang-tidy? */
|
/** @brief Execute clang-tidy? */
|
||||||
bool mClangTidy;
|
bool mClangTidy;
|
||||||
|
|
||||||
|
|
|
@ -270,6 +270,10 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
|
||||||
mUI.mCheckUnusedTemplates->setChecked(projectFile->getCheckUnusedTemplates());
|
mUI.mCheckUnusedTemplates->setChecked(projectFile->getCheckUnusedTemplates());
|
||||||
mUI.mMaxCtuDepth->setValue(projectFile->getMaxCtuDepth());
|
mUI.mMaxCtuDepth->setValue(projectFile->getMaxCtuDepth());
|
||||||
mUI.mMaxTemplateRecursion->setValue(projectFile->getMaxTemplateRecursion());
|
mUI.mMaxTemplateRecursion->setValue(projectFile->getMaxTemplateRecursion());
|
||||||
|
if (projectFile->clangParser)
|
||||||
|
mUI.mBtnClangParser->setChecked(true);
|
||||||
|
else
|
||||||
|
mUI.mBtnCppcheckParser->setChecked(true);
|
||||||
mUI.mBtnSafeClasses->setChecked(projectFile->safeChecks.classes);
|
mUI.mBtnSafeClasses->setChecked(projectFile->safeChecks.classes);
|
||||||
mUI.mBtnBugHunting->setChecked(projectFile->bugHunting);
|
mUI.mBtnBugHunting->setChecked(projectFile->bugHunting);
|
||||||
setExcludedPaths(projectFile->getExcludedPaths());
|
setExcludedPaths(projectFile->getExcludedPaths());
|
||||||
|
@ -337,6 +341,7 @@ void ProjectFileDialog::loadFromProjectFile(const ProjectFile *projectFile)
|
||||||
mUI.mAddonMisra->setText(mUI.mAddonMisra->text() + ' ' + tr("(no rule texts file)"));
|
mUI.mAddonMisra->setText(mUI.mAddonMisra->text() + ' ' + tr("(no rule texts file)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mUI.mToolClangAnalyzer->setChecked(projectFile->getClangAnalyzer());
|
||||||
mUI.mToolClangTidy->setChecked(projectFile->getClangTidy());
|
mUI.mToolClangTidy->setChecked(projectFile->getClangTidy());
|
||||||
if (CheckThread::clangTidyCmd().isEmpty()) {
|
if (CheckThread::clangTidyCmd().isEmpty()) {
|
||||||
mUI.mToolClangTidy->setText(tr("Clang-tidy (not found)"));
|
mUI.mToolClangTidy->setText(tr("Clang-tidy (not found)"));
|
||||||
|
@ -363,6 +368,7 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const
|
||||||
projectFile->setCheckPaths(getCheckPaths());
|
projectFile->setCheckPaths(getCheckPaths());
|
||||||
projectFile->setExcludedPaths(getExcludedPaths());
|
projectFile->setExcludedPaths(getExcludedPaths());
|
||||||
projectFile->setLibraries(getLibraries());
|
projectFile->setLibraries(getLibraries());
|
||||||
|
projectFile->clangParser = mUI.mBtnClangParser->isChecked();
|
||||||
projectFile->safeChecks.classes = mUI.mBtnSafeClasses->isChecked();
|
projectFile->safeChecks.classes = mUI.mBtnSafeClasses->isChecked();
|
||||||
projectFile->bugHunting = mUI.mBtnBugHunting->isChecked();
|
projectFile->bugHunting = mUI.mBtnBugHunting->isChecked();
|
||||||
if (mUI.mComboBoxPlatform->currentText().endsWith(".xml"))
|
if (mUI.mComboBoxPlatform->currentText().endsWith(".xml"))
|
||||||
|
@ -402,6 +408,7 @@ void ProjectFileDialog::saveToProjectFile(ProjectFile *projectFile) const
|
||||||
if (mUI.mAddonMisra->isChecked())
|
if (mUI.mAddonMisra->isChecked())
|
||||||
list << "misra";
|
list << "misra";
|
||||||
projectFile->setAddons(list);
|
projectFile->setAddons(list);
|
||||||
|
projectFile->setClangAnalyzer(mUI.mToolClangAnalyzer->isChecked());
|
||||||
projectFile->setClangTidy(mUI.mToolClangTidy->isChecked());
|
projectFile->setClangTidy(mUI.mToolClangTidy->isChecked());
|
||||||
projectFile->setTags(mUI.mEditTags->text().split(";", QString::SkipEmptyParts));
|
projectFile->setTags(mUI.mEditTags->text().split(";", QString::SkipEmptyParts));
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,6 +426,32 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_10">
|
||||||
|
<property name="title">
|
||||||
|
<string>Parser</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="mBtnCppcheckParser">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cppcheck (built in)</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="mBtnClangParser">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clang (experimental)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_11">
|
<widget class="QGroupBox" name="groupBox_11">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
|
|
@ -69,6 +69,10 @@ void StatsDialog::setProject(const ProjectFile* projectFile)
|
||||||
QChartView *chartView;
|
QChartView *chartView;
|
||||||
chartView = createChart(statsFile, "cppcheck");
|
chartView = createChart(statsFile, "cppcheck");
|
||||||
mUI.mTabHistory->layout()->addWidget(chartView);
|
mUI.mTabHistory->layout()->addWidget(chartView);
|
||||||
|
if (projectFile->getClangAnalyzer()) {
|
||||||
|
chartView = createChart(statsFile, CLANG_ANALYZER);
|
||||||
|
mUI.mTabHistory->layout()->addWidget(chartView);
|
||||||
|
}
|
||||||
if (projectFile->getClangTidy()) {
|
if (projectFile->getClangTidy()) {
|
||||||
chartView = createChart(statsFile, CLANG_TIDY);
|
chartView = createChart(statsFile, CLANG_TIDY);
|
||||||
mUI.mTabHistory->layout()->addWidget(chartView);
|
mUI.mTabHistory->layout()->addWidget(chartView);
|
||||||
|
|
|
@ -211,7 +211,7 @@ static void divByZero(const Token *tok, const ExprEngine::Value &value, ExprEngi
|
||||||
if (tok->astParent()->astOperand2() == tok && value.isEqual(dataBase, 0)) {
|
if (tok->astParent()->astOperand2() == tok && value.isEqual(dataBase, 0)) {
|
||||||
const char * const id = (tok->valueType() && tok->valueType()->isFloat()) ? "bughuntingDivByZeroFloat" : "bughuntingDivByZero";
|
const char * const id = (tok->valueType() && tok->valueType()->isFloat()) ? "bughuntingDivByZeroFloat" : "bughuntingDivByZero";
|
||||||
const bool bailout = (value.type == ExprEngine::ValueType::BailoutValue);
|
const bool bailout = (value.type == ExprEngine::ValueType::BailoutValue);
|
||||||
dataBase->reportError(tok->astParent(),
|
dataBase->reportError(dataBase->settings->clang ? tok : tok->astParent(),
|
||||||
Severity::SeverityType::error,
|
Severity::SeverityType::error,
|
||||||
id,
|
id,
|
||||||
"There is division, cannot determine that there can't be a division by zero.",
|
"There is division, cannot determine that there can't be a division by zero.",
|
||||||
|
|
|
@ -188,6 +188,9 @@ void CheckLeakAutoVar::doubleFreeError(const Token *tok, const Token *prevFreeTo
|
||||||
|
|
||||||
void CheckLeakAutoVar::check()
|
void CheckLeakAutoVar::check()
|
||||||
{
|
{
|
||||||
|
if (mSettings->clang)
|
||||||
|
return;
|
||||||
|
|
||||||
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
|
|
||||||
// Local variables that are known to be non-zero.
|
// Local variables that are known to be non-zero.
|
||||||
|
|
|
@ -758,6 +758,9 @@ void CheckMemoryLeakInClass::publicAllocationError(const Token *tok, const std::
|
||||||
|
|
||||||
void CheckMemoryLeakStructMember::check()
|
void CheckMemoryLeakStructMember::check()
|
||||||
{
|
{
|
||||||
|
if (mSettings->clang)
|
||||||
|
return;
|
||||||
|
|
||||||
const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
|
const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
for (const Variable* var : symbolDatabase->variableList()) {
|
for (const Variable* var : symbolDatabase->variableList()) {
|
||||||
if (!var || !var->isLocal() || var->isStatic() || var->isReference())
|
if (!var || !var->isLocal() || var->isStatic() || var->isReference())
|
||||||
|
|
|
@ -884,6 +884,9 @@ void CheckOther::unreachableCodeError(const Token *tok, bool inconclusive)
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void CheckOther::checkVariableScope()
|
void CheckOther::checkVariableScope()
|
||||||
{
|
{
|
||||||
|
if (mSettings->clang)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!mSettings->severity.isEnabled(Severity::style))
|
if (!mSettings->severity.isEnabled(Severity::style))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,9 @@ public:
|
||||||
|
|
||||||
/** @brief Run checks against the normal token list */
|
/** @brief Run checks against the normal token list */
|
||||||
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
|
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
|
||||||
|
if (settings->clang)
|
||||||
|
return;
|
||||||
|
|
||||||
CheckUninitVar checkUninitVar(tokenizer, settings, errorLogger);
|
CheckUninitVar checkUninitVar(tokenizer, settings, errorLogger);
|
||||||
checkUninitVar.check();
|
checkUninitVar.check();
|
||||||
checkUninitVar.valueFlowUninit();
|
checkUninitVar.valueFlowUninit();
|
||||||
|
|
|
@ -1145,6 +1145,9 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
if (!mSettings->severity.isEnabled(Severity::style))
|
if (!mSettings->severity.isEnabled(Severity::style))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (mSettings->clang)
|
||||||
|
return;
|
||||||
|
|
||||||
// Parse all executing scopes..
|
// Parse all executing scopes..
|
||||||
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,8 @@ void CheckVaarg::referenceAs_va_start_error(const Token *tok, const std::string&
|
||||||
|
|
||||||
void CheckVaarg::va_list_usage()
|
void CheckVaarg::va_list_usage()
|
||||||
{
|
{
|
||||||
|
if (mSettings->clang)
|
||||||
|
return;
|
||||||
const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
|
const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
for (const Variable* var : symbolDatabase->variableList()) {
|
for (const Variable* var : symbolDatabase->variableList()) {
|
||||||
if (!var || var->isPointer() || var->isReference() || var->isArray() || !var->scope() || var->typeStartToken()->str() != "va_list")
|
if (!var || var->isPointer() || var->isReference() || var->isArray() || !var->scope() || var->typeStartToken()->str() != "va_list")
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Cppcheck - A tool for static C/C++ code analysis
|
||||||
|
* Copyright (C) 2007-2020 Cppcheck team.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifndef clangimportH
|
||||||
|
#define clangimportH
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <istream>
|
||||||
|
|
||||||
|
class Tokenizer;
|
||||||
|
|
||||||
|
namespace clangimport {
|
||||||
|
void parseClangAstDump(Tokenizer *tokenizer, std::istream &f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
158
lib/cppcheck.cpp
158
lib/cppcheck.cpp
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "checkunusedfunctions.h"
|
#include "checkunusedfunctions.h"
|
||||||
|
#include "clangimport.h"
|
||||||
#include "ctu.h"
|
#include "ctu.h"
|
||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "mathlib.h"
|
#include "mathlib.h"
|
||||||
|
@ -319,8 +320,154 @@ const char * CppCheck::extraVersion()
|
||||||
return ExtraVersion;
|
return ExtraVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool reportClangErrors(std::istream &is, std::function<void(const ErrorMessage&)> reportErr)
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(is, line)) {
|
||||||
|
if (line.empty() || line[0] == ' ' || line[0] == '`' || line[0] == '-')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string::size_type pos3 = line.find(": error: ");
|
||||||
|
if (pos3 == std::string::npos)
|
||||||
|
pos3 = line.find(": fatal error:");
|
||||||
|
if (pos3 == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// file:line:column: error: ....
|
||||||
|
const std::string::size_type pos2 = line.rfind(":", pos3 - 1);
|
||||||
|
const std::string::size_type pos1 = line.rfind(":", pos2 - 1);
|
||||||
|
|
||||||
|
if (pos1 >= pos2 || pos2 >= pos3)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const std::string filename = line.substr(0, pos1);
|
||||||
|
const std::string linenr = line.substr(pos1+1, pos2-pos1-1);
|
||||||
|
const std::string colnr = line.substr(pos2+1, pos3-pos2-1);
|
||||||
|
const std::string msg = line.substr(line.find(":", pos3+1) + 2);
|
||||||
|
|
||||||
|
std::list<ErrorMessage::FileLocation> locationList;
|
||||||
|
ErrorMessage::FileLocation loc;
|
||||||
|
loc.setfile(Path::toNativeSeparators(filename));
|
||||||
|
loc.line = std::atoi(linenr.c_str());
|
||||||
|
loc.column = std::atoi(colnr.c_str());
|
||||||
|
locationList.push_back(loc);
|
||||||
|
ErrorMessage errmsg(locationList,
|
||||||
|
loc.getfile(),
|
||||||
|
Severity::error,
|
||||||
|
msg,
|
||||||
|
"syntaxError",
|
||||||
|
Certainty::normal);
|
||||||
|
reportErr(errmsg);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int CppCheck::check(const std::string &path)
|
unsigned int CppCheck::check(const std::string &path)
|
||||||
{
|
{
|
||||||
|
if (mSettings.clang) {
|
||||||
|
if (!mSettings.quiet)
|
||||||
|
mErrorLogger.reportOut(std::string("Checking ") + path + "...");
|
||||||
|
|
||||||
|
const std::string lang = Path::isCPP(path) ? "-x c++" : "-x c";
|
||||||
|
const std::string analyzerInfo = mSettings.buildDir.empty() ? std::string() : AnalyzerInformation::getAnalyzerInfoFile(mSettings.buildDir, path, "");
|
||||||
|
const std::string clangcmd = analyzerInfo + ".clang-cmd";
|
||||||
|
const std::string clangStderr = analyzerInfo + ".clang-stderr";
|
||||||
|
const std::string clangAst = analyzerInfo + ".clang-ast";
|
||||||
|
std::string exe = mSettings.clangExecutable;
|
||||||
|
#ifdef _WIN32
|
||||||
|
// append .exe if it is not a path
|
||||||
|
if (Path::fromNativeSeparators(mSettings.clangExecutable).find('/') == std::string::npos) {
|
||||||
|
exe += ".exe";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string flags(lang + " ");
|
||||||
|
if (Path::isCPP(path) && !mSettings.standards.stdValue.empty())
|
||||||
|
flags += "-std=" + mSettings.standards.stdValue + " ";
|
||||||
|
|
||||||
|
for (const std::string &i: mSettings.includePaths)
|
||||||
|
flags += "-I" + i + " ";
|
||||||
|
|
||||||
|
flags += getDefinesFlags(mSettings.userDefines);
|
||||||
|
|
||||||
|
const std::string args2 = "-fsyntax-only -Xclang -ast-dump -fno-color-diagnostics " + flags + path;
|
||||||
|
const std::string redirect2 = analyzerInfo.empty() ? std::string("2>&1") : ("2> " + clangStderr);
|
||||||
|
if (!mSettings.buildDir.empty()) {
|
||||||
|
std::ofstream fout(clangcmd);
|
||||||
|
fout << exe << " " << args2 << " " << redirect2 << std::endl;
|
||||||
|
} else if (mSettings.verbose && !mSettings.quiet) {
|
||||||
|
mErrorLogger.reportOut(exe + " " + args2);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string output2;
|
||||||
|
if (!mExecuteCommand(exe,split(args2),redirect2,&output2) || output2.find("TranslationUnitDecl") == std::string::npos) {
|
||||||
|
std::cerr << "Failed to execute '" << exe << " " << args2 << " " << redirect2 << "'" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure there are not syntax errors...
|
||||||
|
if (!mSettings.buildDir.empty()) {
|
||||||
|
std::ifstream fin(clangStderr);
|
||||||
|
auto reportError = [this](const ErrorMessage& errorMessage) {
|
||||||
|
reportErr(errorMessage);
|
||||||
|
};
|
||||||
|
if (reportClangErrors(fin, reportError))
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
std::istringstream istr(output2);
|
||||||
|
auto reportError = [this](const ErrorMessage& errorMessage) {
|
||||||
|
reportErr(errorMessage);
|
||||||
|
};
|
||||||
|
if (reportClangErrors(istr, reportError))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mSettings.buildDir.empty()) {
|
||||||
|
std::ofstream fout(clangAst);
|
||||||
|
fout << output2 << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::istringstream ast(output2);
|
||||||
|
Tokenizer tokenizer(&mSettings, this);
|
||||||
|
tokenizer.list.appendFileIfNew(path);
|
||||||
|
clangimport::parseClangAstDump(&tokenizer, ast);
|
||||||
|
ValueFlow::setValues(&tokenizer.list, const_cast<SymbolDatabase *>(tokenizer.getSymbolDatabase()), this, &mSettings);
|
||||||
|
if (mSettings.debugnormal)
|
||||||
|
tokenizer.printDebugOutput(1);
|
||||||
|
checkNormalTokens(tokenizer);
|
||||||
|
|
||||||
|
// create dumpfile
|
||||||
|
std::ofstream fdump;
|
||||||
|
std::string dumpFile;
|
||||||
|
createDumpFile(mSettings, path, tokenizer.list.getFiles(), nullptr, fdump, dumpFile);
|
||||||
|
if (fdump.is_open()) {
|
||||||
|
fdump << "<dump cfg=\"\">" << std::endl;
|
||||||
|
fdump << " <standards>" << std::endl;
|
||||||
|
fdump << " <c version=\"" << mSettings.standards.getC() << "\"/>" << std::endl;
|
||||||
|
fdump << " <cpp version=\"" << mSettings.standards.getCPP() << "\"/>" << std::endl;
|
||||||
|
fdump << " </standards>" << std::endl;
|
||||||
|
tokenizer.dump(fdump);
|
||||||
|
fdump << "</dump>" << std::endl;
|
||||||
|
fdump << "</dumps>" << std::endl;
|
||||||
|
fdump.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// run addons
|
||||||
|
executeAddons(dumpFile);
|
||||||
|
|
||||||
|
} catch (const InternalError &e) {
|
||||||
|
internalError(path, e.errorMessage);
|
||||||
|
mExitCode = 1; // e.g. reflect a syntax error
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
internalError(path, e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return mExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
std::ifstream fin(path);
|
std::ifstream fin(path);
|
||||||
return checkFile(Path::simplifyPath(path), emptyString, fin);
|
return checkFile(Path::simplifyPath(path), emptyString, fin);
|
||||||
}
|
}
|
||||||
|
@ -337,6 +484,9 @@ unsigned int CppCheck::check(const ImportProject::FileSettings &fs)
|
||||||
temp.mSettings = mSettings;
|
temp.mSettings = mSettings;
|
||||||
if (!temp.mSettings.userDefines.empty())
|
if (!temp.mSettings.userDefines.empty())
|
||||||
temp.mSettings.userDefines += ';';
|
temp.mSettings.userDefines += ';';
|
||||||
|
if (mSettings.clang)
|
||||||
|
temp.mSettings.userDefines += fs.defines;
|
||||||
|
else
|
||||||
temp.mSettings.userDefines += fs.cppcheckDefines();
|
temp.mSettings.userDefines += fs.cppcheckDefines();
|
||||||
temp.mSettings.includePaths = fs.includePaths;
|
temp.mSettings.includePaths = fs.includePaths;
|
||||||
temp.mSettings.userUndefs.insert(fs.undefs.cbegin(), fs.undefs.cend());
|
temp.mSettings.userUndefs.insert(fs.undefs.cbegin(), fs.undefs.cend());
|
||||||
|
@ -346,6 +496,10 @@ unsigned int CppCheck::check(const ImportProject::FileSettings &fs)
|
||||||
temp.mSettings.standards.setC(fs.standard);
|
temp.mSettings.standards.setC(fs.standard);
|
||||||
if (fs.platformType != Settings::Unspecified)
|
if (fs.platformType != Settings::Unspecified)
|
||||||
temp.mSettings.platform(fs.platformType);
|
temp.mSettings.platform(fs.platformType);
|
||||||
|
if (mSettings.clang) {
|
||||||
|
temp.mSettings.includePaths.insert(temp.mSettings.includePaths.end(), fs.systemIncludePaths.cbegin(), fs.systemIncludePaths.cend());
|
||||||
|
return temp.check(Path::simplifyPath(fs.filename));
|
||||||
|
}
|
||||||
std::ifstream fin(fs.filename);
|
std::ifstream fin(fs.filename);
|
||||||
unsigned int returnValue = temp.checkFile(Path::simplifyPath(fs.filename), fs.cfg, fin);
|
unsigned int returnValue = temp.checkFile(Path::simplifyPath(fs.filename), fs.cfg, fin);
|
||||||
mSettings.nomsg.addSuppressions(temp.mSettings.nomsg.getSuppressions());
|
mSettings.nomsg.addSuppressions(temp.mSettings.nomsg.getSuppressions());
|
||||||
|
@ -800,6 +954,10 @@ void CppCheck::checkNormalTokens(const Tokenizer &tokenizer)
|
||||||
check->runChecks(&tokenizer, &mSettings, this);
|
check->runChecks(&tokenizer, &mSettings, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mSettings.clang)
|
||||||
|
// TODO: Use CTU for Clang analysis
|
||||||
|
return;
|
||||||
|
|
||||||
// Analyse the tokens..
|
// Analyse the tokens..
|
||||||
|
|
||||||
CTU::FileInfo *fi1 = CTU::getFileInfo(&tokenizer);
|
CTU::FileInfo *fi1 = CTU::getFileInfo(&tokenizer);
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
<ClCompile Include="checkunusedfunctions.cpp" />
|
<ClCompile Include="checkunusedfunctions.cpp" />
|
||||||
<ClCompile Include="checkunusedvar.cpp" />
|
<ClCompile Include="checkunusedvar.cpp" />
|
||||||
<ClCompile Include="checkvaarg.cpp" />
|
<ClCompile Include="checkvaarg.cpp" />
|
||||||
|
<ClCompile Include="clangimport.cpp" />
|
||||||
<ClCompile Include="cppcheck.cpp" />
|
<ClCompile Include="cppcheck.cpp" />
|
||||||
<ClCompile Include="ctu.cpp" />
|
<ClCompile Include="ctu.cpp" />
|
||||||
<ClCompile Include="errorlogger.cpp" />
|
<ClCompile Include="errorlogger.cpp" />
|
||||||
|
@ -135,6 +136,7 @@
|
||||||
<ClInclude Include="checkunusedfunctions.h" />
|
<ClInclude Include="checkunusedfunctions.h" />
|
||||||
<ClInclude Include="checkunusedvar.h" />
|
<ClInclude Include="checkunusedvar.h" />
|
||||||
<ClInclude Include="checkvaarg.h" />
|
<ClInclude Include="checkvaarg.h" />
|
||||||
|
<ClInclude Include="clangimport.h" />
|
||||||
<ClInclude Include="config.h" />
|
<ClInclude Include="config.h" />
|
||||||
<ClInclude Include="cppcheck.h" />
|
<ClInclude Include="cppcheck.h" />
|
||||||
<ClInclude Include="ctu.h" />
|
<ClInclude Include="ctu.h" />
|
||||||
|
|
|
@ -1143,6 +1143,8 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
guiProject.platform = node->GetText();
|
guiProject.platform = node->GetText();
|
||||||
else if (strcmp(node->Name(), CppcheckXml::AnalyzeAllVsConfigsElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::AnalyzeAllVsConfigsElementName) == 0)
|
||||||
guiProject.analyzeAllVsConfigs = node->GetText();
|
guiProject.analyzeAllVsConfigs = node->GetText();
|
||||||
|
else if (strcmp(node->Name(), CppcheckXml::Parser) == 0)
|
||||||
|
temp.clang = true;
|
||||||
else if (strcmp(node->Name(), CppcheckXml::AddonsElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::AddonsElementName) == 0)
|
||||||
temp.addons = readXmlStringList(node, "", CppcheckXml::AddonElementName, nullptr);
|
temp.addons = readXmlStringList(node, "", CppcheckXml::AddonElementName, nullptr);
|
||||||
else if (strcmp(node->Name(), CppcheckXml::TagsElementName) == 0)
|
else if (strcmp(node->Name(), CppcheckXml::TagsElementName) == 0)
|
||||||
|
@ -1188,6 +1190,7 @@ bool ImportProject::importCppcheckGuiProject(std::istream &istr, Settings *setti
|
||||||
settings->userDefines = temp.userDefines;
|
settings->userDefines = temp.userDefines;
|
||||||
settings->userUndefs = temp.userUndefs;
|
settings->userUndefs = temp.userUndefs;
|
||||||
settings->addons = temp.addons;
|
settings->addons = temp.addons;
|
||||||
|
settings->clang = temp.clang;
|
||||||
settings->clangTidy = temp.clangTidy;
|
settings->clangTidy = temp.clangTidy;
|
||||||
|
|
||||||
for (const std::string &p : paths)
|
for (const std::string &p : paths)
|
||||||
|
|
|
@ -125,6 +125,7 @@ namespace CppcheckXml {
|
||||||
const char BuildDirElementName[] = "builddir";
|
const char BuildDirElementName[] = "builddir";
|
||||||
const char ImportProjectElementName[] = "importproject";
|
const char ImportProjectElementName[] = "importproject";
|
||||||
const char AnalyzeAllVsConfigsElementName[] = "analyze-all-vs-configs";
|
const char AnalyzeAllVsConfigsElementName[] = "analyze-all-vs-configs";
|
||||||
|
const char Parser[] = "parser";
|
||||||
const char BugHunting[] = "bug-hunting";
|
const char BugHunting[] = "bug-hunting";
|
||||||
const char IncludeDirElementName[] = "includedir";
|
const char IncludeDirElementName[] = "includedir";
|
||||||
const char DirElementName[] = "dir";
|
const char DirElementName[] = "dir";
|
||||||
|
|
|
@ -32,6 +32,7 @@ HEADERS += $${PWD}/analyzerinfo.h \
|
||||||
$${PWD}/checkunusedfunctions.h \
|
$${PWD}/checkunusedfunctions.h \
|
||||||
$${PWD}/checkunusedvar.h \
|
$${PWD}/checkunusedvar.h \
|
||||||
$${PWD}/checkvaarg.h \
|
$${PWD}/checkvaarg.h \
|
||||||
|
$${PWD}/clangimport.h \
|
||||||
$${PWD}/cppcheck.h \
|
$${PWD}/cppcheck.h \
|
||||||
$${PWD}/ctu.h \
|
$${PWD}/ctu.h \
|
||||||
$${PWD}/errorlogger.h \
|
$${PWD}/errorlogger.h \
|
||||||
|
@ -89,6 +90,7 @@ SOURCES += $${PWD}/analyzerinfo.cpp \
|
||||||
$${PWD}/checkunusedfunctions.cpp \
|
$${PWD}/checkunusedfunctions.cpp \
|
||||||
$${PWD}/checkunusedvar.cpp \
|
$${PWD}/checkunusedvar.cpp \
|
||||||
$${PWD}/checkvaarg.cpp \
|
$${PWD}/checkvaarg.cpp \
|
||||||
|
$${PWD}/clangimport.cpp \
|
||||||
$${PWD}/cppcheck.cpp \
|
$${PWD}/cppcheck.cpp \
|
||||||
$${PWD}/ctu.cpp \
|
$${PWD}/ctu.cpp \
|
||||||
$${PWD}/errorlogger.cpp \
|
$${PWD}/errorlogger.cpp \
|
||||||
|
|
|
@ -36,6 +36,8 @@ Settings::Settings()
|
||||||
checkHeaders(true),
|
checkHeaders(true),
|
||||||
checkLibrary(false),
|
checkLibrary(false),
|
||||||
checkUnusedTemplates(true),
|
checkUnusedTemplates(true),
|
||||||
|
clang(false),
|
||||||
|
clangExecutable("clang"),
|
||||||
clangTidy(false),
|
clangTidy(false),
|
||||||
daca(false),
|
daca(false),
|
||||||
debugBugHunting(false),
|
debugBugHunting(false),
|
||||||
|
|
|
@ -140,6 +140,12 @@ public:
|
||||||
/** Check unused/uninstantiated templates */
|
/** Check unused/uninstantiated templates */
|
||||||
bool checkUnusedTemplates;
|
bool checkUnusedTemplates;
|
||||||
|
|
||||||
|
/** Use Clang */
|
||||||
|
bool clang;
|
||||||
|
|
||||||
|
/** Custom Clang executable */
|
||||||
|
std::string clangExecutable;
|
||||||
|
|
||||||
/** Use clang-tidy */
|
/** Use clang-tidy */
|
||||||
bool clangTidy;
|
bool clangTidy;
|
||||||
|
|
||||||
|
|
|
@ -1823,6 +1823,69 @@ void SymbolDatabase::validate() const
|
||||||
//validateVariables();
|
//validateVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymbolDatabase::clangSetVariables(const std::vector<const Variable *> &variableList)
|
||||||
|
{
|
||||||
|
mVariableList = variableList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable::Variable(const Token *name_, const std::string &clangType, const Token *typeStart,
|
||||||
|
const Token *typeEnd, nonneg int index_, AccessControl access_,
|
||||||
|
const Type *type_, const Scope *scope_)
|
||||||
|
: mNameToken(name_),
|
||||||
|
mTypeStartToken(typeStart),
|
||||||
|
mTypeEndToken(typeEnd),
|
||||||
|
mIndex(index_),
|
||||||
|
mAccess(access_),
|
||||||
|
mFlags(0),
|
||||||
|
mType(type_),
|
||||||
|
mScope(scope_),
|
||||||
|
mValueType(nullptr)
|
||||||
|
{
|
||||||
|
if (!mTypeStartToken && mTypeEndToken) {
|
||||||
|
mTypeStartToken = mTypeEndToken;
|
||||||
|
while (Token::Match(mTypeStartToken->previous(), "%type%|*|&"))
|
||||||
|
mTypeStartToken = mTypeStartToken->previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Token::Match(mTypeStartToken, "const|struct|static")) {
|
||||||
|
if (mTypeStartToken->str() == "static")
|
||||||
|
setFlag(fIsStatic, true);
|
||||||
|
mTypeStartToken = mTypeStartToken->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::simpleMatch(mTypeEndToken, "&"))
|
||||||
|
setFlag(fIsReference, true);
|
||||||
|
else if (Token::simpleMatch(mTypeEndToken, "&&")) {
|
||||||
|
setFlag(fIsReference, true);
|
||||||
|
setFlag(fIsRValueRef, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string::size_type pos = clangType.find("[");
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
setFlag(fIsArray, true);
|
||||||
|
do {
|
||||||
|
const std::string::size_type pos1 = pos+1;
|
||||||
|
pos = clangType.find("]", pos1);
|
||||||
|
Dimension dim;
|
||||||
|
dim.tok = nullptr;
|
||||||
|
dim.known = pos > pos1;
|
||||||
|
if (pos > pos1)
|
||||||
|
dim.num = MathLib::toLongNumber(clangType.substr(pos1, pos-pos1));
|
||||||
|
else
|
||||||
|
dim.num = 0;
|
||||||
|
mDimensions.push_back(dim);
|
||||||
|
++pos;
|
||||||
|
} while (pos < clangType.size() && clangType[pos] == '[');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is there initialization in variable declaration
|
||||||
|
const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
|
||||||
|
while (initTok && initTok->str() == "[")
|
||||||
|
initTok = initTok->link()->next();
|
||||||
|
if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
|
||||||
|
setFlag(fIsInit, true);
|
||||||
|
}
|
||||||
|
|
||||||
Variable::Variable(const Variable &var, const Scope *scope)
|
Variable::Variable(const Variable &var, const Scope *scope)
|
||||||
: mValueType(nullptr)
|
: mValueType(nullptr)
|
||||||
{
|
{
|
||||||
|
@ -2170,6 +2233,39 @@ Function::Function(const Tokenizer *mTokenizer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Function::Function(const Token *tokenDef, const std::string &clangType)
|
||||||
|
: tokenDef(tokenDef),
|
||||||
|
argDef(nullptr),
|
||||||
|
token(nullptr),
|
||||||
|
arg(nullptr),
|
||||||
|
retDef(nullptr),
|
||||||
|
retType(nullptr),
|
||||||
|
functionScope(nullptr),
|
||||||
|
nestedIn(nullptr),
|
||||||
|
initArgCount(0),
|
||||||
|
type(eFunction),
|
||||||
|
access(AccessControl::Public),
|
||||||
|
noexceptArg(nullptr),
|
||||||
|
throwArg(nullptr),
|
||||||
|
templateDef(nullptr),
|
||||||
|
functionPointerUsage(nullptr),
|
||||||
|
mFlags(0)
|
||||||
|
{
|
||||||
|
// operator function
|
||||||
|
if (::isOperator(tokenDef)) {
|
||||||
|
isOperator(true);
|
||||||
|
|
||||||
|
// 'operator =' is special
|
||||||
|
if (tokenDef->str() == "operator=")
|
||||||
|
type = Function::eOperatorEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFlags(tokenDef, tokenDef->scope());
|
||||||
|
|
||||||
|
if (endsWith(clangType, " const", 6))
|
||||||
|
isConst(true);
|
||||||
|
}
|
||||||
|
|
||||||
const Token *Function::setFlags(const Token *tok1, const Scope *scope)
|
const Token *Function::setFlags(const Token *tok1, const Scope *scope)
|
||||||
{
|
{
|
||||||
// look for end of previous statement
|
// look for end of previous statement
|
||||||
|
@ -5951,7 +6047,30 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
|
||||||
parsedecl(type->type()->typeStart, valuetype, defaultSignedness, settings);
|
parsedecl(type->type()->typeStart, valuetype, defaultSignedness, settings);
|
||||||
else if (type->str() == "const")
|
else if (type->str() == "const")
|
||||||
valuetype->constness |= (1 << (valuetype->pointer - pointer0));
|
valuetype->constness |= (1 << (valuetype->pointer - pointer0));
|
||||||
else if (const Library::Container *container = settings->library.detectContainer(type)) {
|
else if (settings->clang && type->str().size() > 2 && type->str().find("::") < type->str().find("<")) {
|
||||||
|
TokenList typeTokens(settings);
|
||||||
|
std::string::size_type pos1 = 0;
|
||||||
|
do {
|
||||||
|
std::string::size_type pos2 = type->str().find("::", pos1);
|
||||||
|
if (pos2 == std::string::npos) {
|
||||||
|
typeTokens.addtoken(type->str().substr(pos1), 0, 0, 0, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
typeTokens.addtoken(type->str().substr(pos1, pos2 - pos1), 0, 0, 0, false);
|
||||||
|
typeTokens.addtoken("::", 0, 0, 0, false);
|
||||||
|
pos1 = pos2 + 2;
|
||||||
|
} while (pos1 < type->str().size());
|
||||||
|
const Library::Container *container = settings->library.detectContainer(typeTokens.front());
|
||||||
|
if (container) {
|
||||||
|
valuetype->type = ValueType::Type::CONTAINER;
|
||||||
|
valuetype->container = container;
|
||||||
|
} else {
|
||||||
|
const Scope *scope = type->scope();
|
||||||
|
valuetype->typeScope = scope->check->findScope(typeTokens.front(), scope);
|
||||||
|
if (valuetype->typeScope)
|
||||||
|
valuetype->type = (scope->type == Scope::ScopeType::eClass) ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
|
||||||
|
}
|
||||||
|
} else if (const Library::Container *container = settings->library.detectContainer(type)) {
|
||||||
valuetype->type = ValueType::Type::CONTAINER;
|
valuetype->type = ValueType::Type::CONTAINER;
|
||||||
valuetype->container = container;
|
valuetype->container = container;
|
||||||
while (Token::Match(type, "%name%|::|<")) {
|
while (Token::Match(type, "%name%|::|<")) {
|
||||||
|
|
|
@ -237,6 +237,10 @@ public:
|
||||||
evaluate(settings);
|
evaluate(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Variable(const Token *name_, const std::string &clangType, const Token *typeStart,
|
||||||
|
const Token *typeEnd, nonneg int index_, AccessControl access_,
|
||||||
|
const Type *type_, const Scope *scope_);
|
||||||
|
|
||||||
Variable(const Variable &var, const Scope *scope);
|
Variable(const Variable &var, const Scope *scope);
|
||||||
|
|
||||||
Variable(const Variable &var);
|
Variable(const Variable &var);
|
||||||
|
@ -742,6 +746,7 @@ public:
|
||||||
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction, eLambda };
|
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction, eLambda };
|
||||||
|
|
||||||
Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef);
|
Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef);
|
||||||
|
Function(const Token *tokenDef, const std::string &clangType);
|
||||||
|
|
||||||
const std::string &name() const {
|
const std::string &name() const {
|
||||||
return tokenDef->str();
|
return tokenDef->str();
|
||||||
|
@ -1379,6 +1384,7 @@ public:
|
||||||
/** Set array dimensions when valueflow analysis is completed */
|
/** Set array dimensions when valueflow analysis is completed */
|
||||||
void setArrayDimensionsUsingValueFlow();
|
void setArrayDimensionsUsingValueFlow();
|
||||||
|
|
||||||
|
void clangSetVariables(const std::vector<const Variable *> &variableList);
|
||||||
void createSymbolDatabaseExprIds();
|
void createSymbolDatabaseExprIds();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -169,6 +169,11 @@ int TokenList::appendFileIfNew(const std::string &fileName)
|
||||||
return mFiles.size() - 1;
|
return mFiles.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TokenList::clangSetOrigFiles()
|
||||||
|
{
|
||||||
|
mOrigFiles = mFiles;
|
||||||
|
}
|
||||||
|
|
||||||
void TokenList::deleteTokens(Token *tok)
|
void TokenList::deleteTokens(Token *tok)
|
||||||
{
|
{
|
||||||
while (tok) {
|
while (tok) {
|
||||||
|
|
|
@ -186,6 +186,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void simplifyStdType();
|
void simplifyStdType();
|
||||||
|
|
||||||
|
void clangSetOrigFiles();
|
||||||
|
|
||||||
bool isKeyword(const std::string &str) const;
|
bool isKeyword(const std::string &str) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -132,6 +132,18 @@ directory individually. The following command ignores both the src/b and src/c d
|
||||||
|
|
||||||
cppcheck -isrc/b -isrc/c
|
cppcheck -isrc/b -isrc/c
|
||||||
|
|
||||||
|
### Clang parser (experimental)
|
||||||
|
|
||||||
|
By default Cppcheck uses an internal C/C++ parser. However there is an experimental option to use the Clang parser instead.
|
||||||
|
|
||||||
|
Install `clang`. Then use Cppcheck option `--clang`.
|
||||||
|
|
||||||
|
Technically, Cppcheck will execute `clang` with its `-ast-dump` option. The Clang output is then imported and converted into
|
||||||
|
the normal Cppcheck format. And then normal Cppcheck analysis is performed on that.
|
||||||
|
|
||||||
|
You can also pass a custom Clang executable to the option by using for example `--clang=clang-10`. You can also pass it
|
||||||
|
with a path. On Windows it will append the `.exe` extension unless you use a path.
|
||||||
|
|
||||||
## Severities
|
## Severities
|
||||||
|
|
||||||
The possible severities for messages are:
|
The possible severities for messages are:
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
|
||||||
|
# python -m pytest test-clang-import.py
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import pytest
|
||||||
|
from testutils import cppcheck
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.call(['clang', '--version'])
|
||||||
|
except OSError:
|
||||||
|
pytest.skip("'clang' does not exist", allow_module_level=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_debug_section(title, stdout):
|
||||||
|
s = re.sub(r'0x[0-9a-fA-F]+', '0x12345678', stdout)
|
||||||
|
s = re.sub(r'nestedIn: Struct', 'nestedIn: Class', s)
|
||||||
|
s = re.sub(r'classDef: struct', 'classDef: class', s)
|
||||||
|
s = re.sub(r'isInline: [a-z]+', 'isInline: ---', s)
|
||||||
|
s = re.sub(r'needInitialization: .*', 'needInitialization: ---', s)
|
||||||
|
s = re.sub(r'functionOf: .*', 'functionOf: ---', s)
|
||||||
|
s = re.sub(r'0x12345678 Struct', '0x12345678 Class', s)
|
||||||
|
|
||||||
|
if title == '##AST':
|
||||||
|
# TODO set types
|
||||||
|
s = re.sub(r"return '[a-zA-Z0-9: *]+'", "return", s)
|
||||||
|
|
||||||
|
pos1 = s.find(title)
|
||||||
|
assert pos1 > 0, 'title not found'
|
||||||
|
pos1 = s.find('\n', pos1) + 1
|
||||||
|
assert pos1 > 0
|
||||||
|
pos2 = s.find("\n##", pos1)
|
||||||
|
if pos2 < 0:
|
||||||
|
return s[pos1:]
|
||||||
|
return s[pos1:pos2-1]
|
||||||
|
|
||||||
|
|
||||||
|
def check_symbol_database(code):
|
||||||
|
testfile = 'test.cpp'
|
||||||
|
with open(testfile, 'w+t') as f:
|
||||||
|
f.write(code)
|
||||||
|
ret1, stdout1, _ = cppcheck(['--clang', '--debug', '-v', testfile])
|
||||||
|
ret2, stdout2, _ = cppcheck(['--debug', '-v', testfile])
|
||||||
|
os.remove(testfile)
|
||||||
|
assert 0 == ret1, stdout1
|
||||||
|
assert 0 == ret2, stdout2
|
||||||
|
assert get_debug_section('### Symbol database', stdout1) == get_debug_section('### Symbol database', stdout2)
|
||||||
|
|
||||||
|
|
||||||
|
def check_ast(code):
|
||||||
|
testfile = 'test.cpp'
|
||||||
|
with open(testfile, 'w+t') as f:
|
||||||
|
f.write(code)
|
||||||
|
ret1, stdout1, _ = cppcheck(['--clang', '--debug', '-v', testfile])
|
||||||
|
ret2, stdout2, _ = cppcheck(['--debug', '-v', testfile])
|
||||||
|
os.remove(testfile)
|
||||||
|
assert 0 == ret1, stdout1
|
||||||
|
assert 0 == ret2, stdout1
|
||||||
|
assert get_debug_section('##AST', stdout1) == get_debug_section('##AST', stdout2)
|
||||||
|
|
||||||
|
|
||||||
|
def todo_check_ast(code):
|
||||||
|
testfile = 'test.cpp'
|
||||||
|
with open(testfile, 'w+t') as f:
|
||||||
|
f.write(code)
|
||||||
|
ret1, stdout1, _ = cppcheck(['--clang', '--debug', '-v', testfile])
|
||||||
|
ret2, stdout2, _ = cppcheck(['--debug', '-v', testfile])
|
||||||
|
os.remove(testfile)
|
||||||
|
assert 0 == ret1, stdout1
|
||||||
|
assert 0 == ret2, stdout2
|
||||||
|
assert get_debug_section('##AST', stdout1) != get_debug_section('##AST', stdout2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def test_symbol_database_1():
|
||||||
|
check_symbol_database('int main(){return 0;}')
|
||||||
|
|
||||||
|
def test_symbol_database_2():
|
||||||
|
check_symbol_database('struct Foo { void f(); }; void Foo::f() {}')
|
||||||
|
|
||||||
|
def test_symbol_database_3():
|
||||||
|
check_symbol_database('struct Fred { int a; }; int b; void f(int c, int d) { int e; }')
|
||||||
|
|
||||||
|
def test_symbol_database_4():
|
||||||
|
check_symbol_database('void f(const int x) {}')
|
||||||
|
|
||||||
|
def test_symbol_database_5():
|
||||||
|
check_symbol_database('void f(int);')
|
||||||
|
|
||||||
|
def test_symbol_database_6():
|
||||||
|
check_symbol_database('inline static int foo(int x) { return x; }')
|
||||||
|
|
||||||
|
def test_symbol_database_7():
|
||||||
|
check_symbol_database('struct S {int x;}; void f(struct S *s) {}')
|
||||||
|
|
||||||
|
def test_symbol_database_class_access_1():
|
||||||
|
check_symbol_database('class Fred { void foo ( ) {} } ;')
|
||||||
|
|
||||||
|
def test_symbol_database_class_access_2():
|
||||||
|
check_symbol_database('class Fred { protected: void foo ( ) {} } ;')
|
||||||
|
|
||||||
|
def test_symbol_database_class_access_3():
|
||||||
|
check_symbol_database('class Fred { public: void foo ( ) {} } ;')
|
||||||
|
|
||||||
|
def test_symbol_database_operator():
|
||||||
|
check_symbol_database('struct Fred { void operator=(int x); };')
|
||||||
|
|
||||||
|
def test_symbol_database_struct_1():
|
||||||
|
check_symbol_database('struct S {};')
|
||||||
|
|
||||||
|
def test_ast_calculations():
|
||||||
|
check_ast('int x = 5; int y = (x + 4) * 2;')
|
||||||
|
check_ast('long long dostuff(int x) { return x ? 3 : 5; }')
|
||||||
|
|
||||||
|
def test_ast_control_flow():
|
||||||
|
check_ast('void foo(int x) { if (x > 5){} }')
|
||||||
|
check_ast('int dostuff() { for (int x = 0; x < 10; x++); }')
|
||||||
|
check_ast('void foo(int x) { switch (x) {case 1: break; } }')
|
||||||
|
check_ast('void foo(int a, int b, int c) { foo(a,b,c); }')
|
||||||
|
|
||||||
|
def test_ast():
|
||||||
|
check_ast('struct S { int x; }; S* foo() { return new S(); }')
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue