diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 4f74bccbd5e..aec0e0f5d46 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -299,9 +299,10 @@ int CppCheckExecutor::check_wrapper(const Settings& settings, Suppressions& supp * @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions) * @return true is returned if errors are reported */ -static bool reportUnmatchedSuppressions(const std::list &unmatched, ErrorLogger &errorLogger, const std::vector& filters) +static std::vector<::ErrorMessage> reportUnmatchedSuppressions(const std::list &unmatched, const std::vector& filters) { - bool err = false; + std::vector<::ErrorMessage> errors; + // Report unmatched suppressions for (const SuppressionList::Suppression &s : unmatched) { // check if this unmatched suppression is suppressed @@ -330,10 +331,11 @@ static bool reportUnmatchedSuppressions(const std::list &files, const std::list& fileSettings, ErrorLogger& errorLogger) { @@ -359,21 +361,55 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con supprlist.addSuppression(std::move(s)); } + const auto reportErrorsFn = [&](const std::string& sourcefile, std::size_t fsFileId, const std::vector<::ErrorMessage>& errors) -> bool { + if (errors.empty()) + return false; + + // TODO: what if sourcefile is empty? + + AnalyzerInformation analyzerInfo; + // FIXME: this is a horrible hack + // we need to "re-open" the file so we can add the unmatchedSuppression findings. + // we cannot keep it open conditionally because the whole program analysis read the XML. + // re-ordering is also not an option because the unmatched suppression reporting needs to be run after all other checks. + analyzerInfo.reopen(settings.buildDir, sourcefile, /*cfgname*/ "", fsFileId); + + for (const auto& errmsg : errors) { + analyzerInfo.reportErr(errmsg); + errorLogger.reportErr(errmsg); + } + return true; + }; + bool err = false; for (auto i = files.cbegin(); i != files.cend(); ++i) { - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), settings.unmatchedSuppressionFilters); + err |= reportErrorsFn(i->spath(), 0, errors); } for (auto i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) { - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), settings.unmatchedSuppressionFilters); + err |= reportErrorsFn(i->file.spath(), i->file.fsFileId(), errors); } if (settings.inlineSuppressions) { - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), settings.unmatchedSuppressionFilters); + for (const auto& errmsg : errors) { + std::string sourcefile; + if (!errmsg.callStack.empty()) + sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path? + err |= reportErrorsFn(sourcefile, 0, {errmsg}); + } } - err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), errorLogger, settings.unmatchedSuppressionFilters); + const std::vector errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), settings.unmatchedSuppressionFilters); + for (const auto& errmsg : errors) { + std::string sourcefile; + if (!errmsg.callStack.empty()) + sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path? + err |= reportErrorsFn(sourcefile, 0, {errmsg}); + } return err; } @@ -426,9 +462,10 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup #endif } + // TODO: is this run again instead of using previously cached results? returnValue |= cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings, stdLogger.getCtuInfo()); - if (settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) { + if ((settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) && !supprs.nomsg.getSuppressions().empty()) { const bool err = reportUnmatchedSuppressions(settings, supprs.nomsg, mFiles, mFileSettings, stdLogger); if (err && returnValue == 0) returnValue = settings.exitCode; diff --git a/lib/analyzerinfo.cpp b/lib/analyzerinfo.cpp index d484f7d50a9..ebb359352c1 100644 --- a/lib/analyzerinfo.cpp +++ b/lib/analyzerinfo.cpp @@ -302,3 +302,23 @@ std::string AnalyzerInformation::processFilesTxt(const std::string& buildDir, co return ""; } +void AnalyzerInformation::reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex) +{ + if (buildDir.empty() || sourcefile.empty()) + return; + + const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fileIndex); + std::ifstream ifs(analyzerInfoFile); + if (!ifs.is_open()) + return; + + std::ostringstream iss; + iss << ifs.rdbuf(); + ifs.close(); + + std::string content = iss.str(); + content.resize(content.find("")); + + mOutputStream.open(analyzerInfoFile, std::ios::trunc); + mOutputStream << content; +} diff --git a/lib/analyzerinfo.h b/lib/analyzerinfo.h index 5435be62560..08f136548ee 100644 --- a/lib/analyzerinfo.h +++ b/lib/analyzerinfo.h @@ -69,6 +69,8 @@ class CPPCHECKLIB AnalyzerInformation { void setFileInfo(const std::string &check, const std::string &fileInfo); static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId); + void reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex); + static const char sep = ':'; class CPPCHECKLIB Info { diff --git a/test/cli/other_test.py b/test/cli/other_test.py index b8433bceef3..c41b0130cc5 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -2315,8 +2315,6 @@ def test_inline_suppr_builddir(tmp_path): __test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j1']) -# TODO: the suppressions are generated outside of the scope which captures the analysis information -@pytest.mark.xfail(strict=True) def test_inline_suppr_builddir_cached(tmp_path): build_dir = tmp_path / 'b1' os.mkdir(build_dir) @@ -2330,8 +2328,6 @@ def test_inline_suppr_builddir_j(tmp_path): __test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j2']) -# TODO: the suppressions are generated outside of the scope which captures the analysis information -@pytest.mark.xfail(strict=True) def test_inline_suppr_builddir_j_cached(tmp_path): build_dir = tmp_path / 'b1' os.mkdir(build_dir)