Skip to content

Commit a35bbf0

Browse files
committed
fixed #13087 - store unmatchedSuppression in AnalyzerInformation
1 parent 64abf20 commit a35bbf0

4 files changed

Lines changed: 73 additions & 17 deletions

File tree

cli/cppcheckexecutor.cpp

Lines changed: 51 additions & 13 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
@@ -330,10 +332,11 @@ static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppres
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+
auto errmsg = ::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, unmatchedSuppressionId, Certainty::normal);
336+
errors.emplace_back(std::move(errmsg));
335337
}
336-
return err;
338+
339+
return errors;
337340
}
338341

339342
bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, const SuppressionList& suppressions, const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, ErrorLogger& errorLogger) {
@@ -359,21 +362,55 @@ bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, con
359362
supprlist.addSuppression(std::move(s));
360363
}
361364

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

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

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

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

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

@@ -426,9 +463,10 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup
426463
#endif
427464
}
428465

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

431-
if (settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) {
469+
if ((settings.severity.isEnabled(Severity::information) || settings.checkConfiguration) && !supprs.nomsg.getSuppressions().empty()) {
432470
const bool err = reportUnmatchedSuppressions(settings, supprs.nomsg, mFiles, mFileSettings, stdLogger);
433471
if (err && returnValue == 0)
434472
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 = content.substr(0, 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)