Skip to content

Commit f04dccd

Browse files
authored
fixed #13087 - store unmatchedSuppression in AnalyzerInformation (#8173)
1 parent 11c3958 commit f04dccd

File tree

4 files changed

+73
-18
lines changed

4 files changed

+73
-18
lines changed

cli/cppcheckexecutor.cpp

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -295,13 +295,15 @@ int CppCheckExecutor::check_wrapper(const Settings& settings, Suppressions& supp
295295
}
296296

297297
/**
298-
* Report unmatched suppressions
299-
* @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions)
300-
* @return true is returned if errors are reported
298+
* Get list of unmatchedSuppression errors
299+
* @param unmatched list of unmatched suppressions
300+
* @param filters a list of (globbed) IDs to filter out
301+
* @return vector of unmatchedSuppression errors
301302
*/
302-
static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppression> &unmatched, ErrorLogger &errorLogger, const std::vector<std::string>& filters)
303+
static std::vector<ErrorMessage> getUnmatchedSuppressions(const std::list<SuppressionList::Suppression> &unmatched, const std::vector<std::string>& filters)
303304
{
304-
bool err = false;
305+
std::vector<ErrorMessage> errors;
306+
305307
// Report unmatched suppressions
306308
for (const SuppressionList::Suppression &s : unmatched) {
307309
// check if this unmatched suppression is suppressed
@@ -325,15 +327,15 @@ static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppres
325327
if (skip)
326328
continue;
327329

328-
std::list<::ErrorMessage::FileLocation> callStack;
330+
std::list<ErrorMessage::FileLocation> callStack;
329331
if (!s.fileName.empty()) {
330332
callStack.emplace_back(s.fileName, s.lineNumber, 0);
331333
}
332334
const std::string unmatchedSuppressionId = s.isPolyspace ? "unmatchedPolyspaceSuppression" : "unmatchedSuppression";
333-
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, Certainty::normal));
334-
err = true;
335+
errors.emplace_back(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, Certainty::normal);
335336
}
336-
return err;
337+
338+
return errors;
337339
}
338340

339341
bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, const SuppressionList& suppressions, const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, ErrorLogger& errorLogger) {
@@ -359,21 +361,55 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con
359361
supprlist.addSuppression(std::move(s));
360362
}
361363

364+
const auto reportErrorsFn = [&](const std::string& sourcefile, std::size_t fsFileId, const std::vector<ErrorMessage>& errors) -> bool {
365+
if (errors.empty())
366+
return false;
367+
368+
// TODO: what if sourcefile is empty?
369+
370+
AnalyzerInformation analyzerInfo;
371+
// FIXME: this is a horrible hack
372+
// we need to "re-open" the file so we can add the unmatchedSuppression findings.
373+
// we cannot keep it open conditionally because the whole program analysis reads the XML.
374+
// re-ordering the code is also not an option because the unmatched suppression reporting needs to be run after all other checks.
375+
analyzerInfo.reopen(settings.buildDir, sourcefile, /*cfgname*/ "", fsFileId);
376+
377+
for (const auto& errmsg : errors) {
378+
analyzerInfo.reportErr(errmsg);
379+
errorLogger.reportErr(errmsg);
380+
}
381+
return true;
382+
};
383+
362384
bool err = false;
363385

364386
for (auto i = files.cbegin(); i != files.cend(); ++i) {
365-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), errorLogger, settings.unmatchedSuppressionFilters);
387+
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), settings.unmatchedSuppressionFilters);
388+
err |= reportErrorsFn(i->spath(), i->fsFileId(), errors);
366389
}
367390

368391
for (auto i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) {
369-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), errorLogger, settings.unmatchedSuppressionFilters);
392+
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), settings.unmatchedSuppressionFilters);
393+
err |= reportErrorsFn(i->file.spath(), i->file.fsFileId(), errors);
370394
}
371395

372396
if (settings.inlineSuppressions) {
373-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), errorLogger, settings.unmatchedSuppressionFilters);
397+
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), settings.unmatchedSuppressionFilters);
398+
for (const auto& errmsg : errors) {
399+
std::string sourcefile;
400+
if (!errmsg.callStack.empty())
401+
sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path?
402+
err |= reportErrorsFn(sourcefile, 0, {errmsg});
403+
}
374404
}
375405

376-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), errorLogger, settings.unmatchedSuppressionFilters);
406+
const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), settings.unmatchedSuppressionFilters);
407+
for (const auto& errmsg : errors) {
408+
std::string sourcefile;
409+
if (!errmsg.callStack.empty())
410+
sourcefile = errmsg.callStack.cbegin()->getfile(false); // TODO: simplify path?
411+
err |= reportErrorsFn(sourcefile, 0, {errmsg});
412+
}
377413
return err;
378414
}
379415

@@ -426,9 +462,10 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup
426462
#endif
427463
}
428464

465+
// TODO: is this run again instead of using previously cached results?
429466
returnValue |= cppcheck.analyseWholeProgram(settings.buildDir, mFiles, mFileSettings, stdLogger.getCtuInfo());
430467

431-
if (settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) {
468+
if ((settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) && !supprs.nomsg.getSuppressions().empty()) {
432469
const bool err = reportUnmatchedSuppressions(settings, supprs.nomsg, mFiles, mFileSettings, stdLogger);
433470
if (err && returnValue == 0)
434471
returnValue = settings.exitCode;

lib/analyzerinfo.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,3 +292,23 @@ std::string AnalyzerInformation::processFilesTxt(const std::string& buildDir, co
292292
return "";
293293
}
294294

295+
void AnalyzerInformation::reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId)
296+
{
297+
if (buildDir.empty() || sourcefile.empty())
298+
return;
299+
300+
const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fsFileId);
301+
std::ifstream ifs(analyzerInfoFile);
302+
if (!ifs.is_open())
303+
return;
304+
305+
std::ostringstream iss;
306+
iss << ifs.rdbuf();
307+
ifs.close();
308+
309+
std::string content = iss.str();
310+
content.resize(content.find("</analyzerinfo>"));
311+
312+
mOutputStream.open(analyzerInfoFile, std::ios::trunc);
313+
mOutputStream << content;
314+
}

lib/analyzerinfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ class CPPCHECKLIB AnalyzerInformation {
6969
void setFileInfo(const std::string &check, const std::string &fileInfo);
7070
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);
7171

72+
void reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, std::size_t fsFileId);
73+
7274
static const char sep = ':';
7375

7476
class CPPCHECKLIB Info {

test/cli/other_test.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,8 +2373,6 @@ def test_inline_suppr_builddir(tmp_path):
23732373
__test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j1'])
23742374

23752375

2376-
# TODO: the suppressions are generated outside of the scope which captures the analysis information
2377-
@pytest.mark.xfail(strict=True)
23782376
def test_inline_suppr_builddir_cached(tmp_path):
23792377
build_dir = tmp_path / 'b1'
23802378
os.mkdir(build_dir)
@@ -2388,8 +2386,6 @@ def test_inline_suppr_builddir_j(tmp_path):
23882386
__test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j2'])
23892387

23902388

2391-
# TODO: the suppressions are generated outside of the scope which captures the analysis information
2392-
@pytest.mark.xfail(strict=True)
23932389
def test_inline_suppr_builddir_j_cached(tmp_path):
23942390
build_dir = tmp_path / 'b1'
23952391
os.mkdir(build_dir)

0 commit comments

Comments
 (0)