diff --git a/Makefile b/Makefile index 2a72e243844..b081aa304c7 100644 --- a/Makefile +++ b/Makefile @@ -743,7 +743,7 @@ test/testcondition.o: test/testcondition.cpp lib/addoninfo.h lib/check.h lib/che test/testconstructors.o: test/testconstructors.cpp lib/addoninfo.h lib/check.h lib/checkclass.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testconstructors.cpp -test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h +test/testcppcheck.o: test/testcppcheck.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/filesettings.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/tokenize.h lib/tokenlist.h lib/utils.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testcppcheck.cpp test/testerrorlogger.o: test/testerrorlogger.cpp externals/tinyxml2/tinyxml2.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/xml.h test/fixture.h test/helpers.h diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 79448429ede..4b891f33ea0 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -850,19 +850,24 @@ static simplecpp::TokenList createTokenList(const std::string& filename, std::ve return {filename, files, outputList}; } -static std::size_t calculateHash(const Preprocessor& preprocessor, const simplecpp::TokenList& tokens, const Settings& settings, const Suppressions& supprs) +std::size_t CppCheck::calculateHash(const Preprocessor& preprocessor, const simplecpp::TokenList& tokens) const { std::ostringstream toolinfo; - toolinfo << (settings.cppcheckCfgProductName.empty() ? CPPCHECK_VERSION_STRING : settings.cppcheckCfgProductName); - toolinfo << (settings.severity.isEnabled(Severity::warning) ? 'w' : ' '); - toolinfo << (settings.severity.isEnabled(Severity::style) ? 's' : ' '); - toolinfo << (settings.severity.isEnabled(Severity::performance) ? 'p' : ' '); - toolinfo << (settings.severity.isEnabled(Severity::portability) ? 'p' : ' '); - toolinfo << (settings.severity.isEnabled(Severity::information) ? 'i' : ' '); - toolinfo << settings.userDefines; - toolinfo << std::to_string(static_cast(settings.checkLevel)); + toolinfo << (mSettings.cppcheckCfgProductName.empty() ? CPPCHECK_VERSION_STRING : mSettings.cppcheckCfgProductName); + toolinfo << (mSettings.severity.isEnabled(Severity::warning) ? 'w' : ' '); + toolinfo << (mSettings.severity.isEnabled(Severity::style) ? 's' : ' '); + toolinfo << (mSettings.severity.isEnabled(Severity::performance) ? 'p' : ' '); + toolinfo << (mSettings.severity.isEnabled(Severity::portability) ? 'p' : ' '); + toolinfo << (mSettings.severity.isEnabled(Severity::information) ? 'i' : ' '); + toolinfo << mSettings.userDefines; + toolinfo << std::to_string(static_cast(mSettings.checkLevel)); + for (const auto &a : mSettings.addonInfos) { + toolinfo << a.name; + toolinfo << a.args; + } + toolinfo << mSettings.premiumArgs; // TODO: do we need to add more options? - supprs.nomsg.dump(toolinfo); + mSuppressions.nomsg.dump(toolinfo); return preprocessor.calculateHash(tokens, toolinfo.str()); } @@ -922,7 +927,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string simplecpp::TokenList tokens(*fileStream, files, file.spath()); if (analyzerInformation) { const Preprocessor preprocessor(mSettings, mErrorLogger, Standards::Language::C); - hash = calculateHash(preprocessor, tokens, mSettings, mSuppressions); + hash = calculateHash(preprocessor, tokens); } tokenlist.createTokens(std::move(tokens)); } @@ -931,7 +936,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string simplecpp::TokenList tokens(file.spath(), files); if (analyzerInformation) { const Preprocessor preprocessor(mSettings, mErrorLogger, file.lang()); - hash = calculateHash(preprocessor, tokens, mSettings, mSuppressions); + hash = calculateHash(preprocessor, tokens); } tokenlist.createTokens(std::move(tokens)); } @@ -1015,7 +1020,7 @@ unsigned int CppCheck::checkFile(const FileWithDetails& file, const std::string if (analyzerInformation) { // Calculate hash so it can be compared with old hash / future hashes - const std::size_t hash = calculateHash(preprocessor, tokens1, mSettings, mSuppressions); + const std::size_t hash = calculateHash(preprocessor, tokens1); std::list errors; if (!analyzerInformation->analyzeFile(mSettings.buildDir, file.spath(), cfgname, fileIndex, hash, errors)) { while (!errors.empty()) { diff --git a/lib/cppcheck.h b/lib/cppcheck.h index d7c326704a1..3a39b2db6d6 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -42,6 +42,7 @@ class AnalyzerInformation; class ErrorLogger; class Settings; struct Suppressions; +class Preprocessor; namespace simplecpp { class TokenList; } @@ -162,6 +163,15 @@ class CPPCHECKLIB CppCheck { /** @brief There has been an internal error => Report information message */ void internalError(const std::string &filename, const std::string &msg); + /** + * @brief Calculate hash used to detect when a file needs to be reanalyzed. + * + * @param preprocessor Preprocessor used to calculate the hash. + * @param tokens Token list from preprocessed file. + * @return hash + */ + std::size_t calculateHash(const Preprocessor &preprocessor, const simplecpp::TokenList &tokens) const; + /** * @brief Check a file using stream * @param file the file diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index a5b2b83e9f1..18562c17a19 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -23,6 +23,7 @@ #include "fixture.h" #include "helpers.h" #include "path.h" +#include "preprocessor.h" #include "settings.h" #include "suppressions.h" @@ -68,6 +69,7 @@ class TestCppcheck : public TestFixture { TEST_CASE(isPremiumCodingStandardId); TEST_CASE(getDumpFileContentsRawTokens); TEST_CASE(getDumpFileContentsLibrary); + TEST_CASE(premiumResultsCache); } void getErrorMessages() const { @@ -324,6 +326,40 @@ class TestCppcheck : public TestFixture { } } + void premiumResultsCache() const { + // Trac #13889 - cached misra results are shown after removing --premium=misra-c-2012 option + + Settings settings; + Suppressions supprs; + ErrorLogger2 errorLogger; + + std::vector files; + + std::istringstream istr("void f();\nint x;\n"); + const simplecpp::TokenList tokens(istr, files, "m1.c"); + + Preprocessor preprocessor(settings, errorLogger, Standards::Language::C); + ASSERT(preprocessor.loadFiles(tokens, files)); + + AddonInfo premiumaddon; + premiumaddon.name = "premiumaddon.json"; + premiumaddon.executable = "premiumaddon"; + + settings.cppcheckCfgProductName = "Cppcheck Premium 0.0.0"; + settings.addons.insert(premiumaddon.name); + settings.addonInfos.push_back(premiumaddon); + + settings.premiumArgs = "misra-c-2012"; + CppCheck check(settings, supprs, errorLogger, false, {}); + const size_t hash1 = check.calculateHash(preprocessor, tokens); + + settings.premiumArgs = ""; + const size_t hash2 = check.calculateHash(preprocessor, tokens); + + // cppcheck-suppress knownConditionTrueFalse + ASSERT(hash1 != hash2); + } + // TODO: test suppressions // TODO: test all with FS };