Skip to content

Commit 514c4e3

Browse files
committed
fixed #13087 - store unmatchedSuppression in AnalyzerInformation
1 parent a438097 commit 514c4e3

File tree

4 files changed

+77
-16
lines changed

4 files changed

+77
-16
lines changed

cli/cppcheckexecutor.cpp

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -299,9 +299,10 @@ int CppCheckExecutor::check_wrapper(const Settings& settings, Suppressions& supp
299299
* @param unmatched list of unmatched suppressions (from Settings::Suppressions::getUnmatched(Local|Global)Suppressions)
300300
* @return true is returned if errors are reported
301301
*/
302-
static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppression> &unmatched, ErrorLogger &errorLogger, const std::vector<std::string>& filters)
302+
static std::vector<::ErrorMessage> reportUnmatchedSuppressions(const std::list<SuppressionList::Suppression> &unmatched, const std::vector<std::string>& filters)
303303
{
304-
bool err = false;
304+
std::vector<::ErrorMessage> errors;
305+
305306
// Report unmatched suppressions
306307
for (const SuppressionList::Suppression &s : unmatched) {
307308
// check if this unmatched suppression is suppressed
@@ -329,10 +330,11 @@ static bool reportUnmatchedSuppressions(const std::list<SuppressionList::Suppres
329330
if (!s.fileName.empty()) {
330331
callStack.emplace_back(s.fileName, s.lineNumber, 0);
331332
}
332-
errorLogger.reportErr(::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal));
333-
err = true;
333+
auto errmsg = ::ErrorMessage(std::move(callStack), "", Severity::information, "Unmatched suppression: " + s.errorId, "unmatchedSuppression", Certainty::normal);
334+
errors.emplace_back(std::move(errmsg));
334335
}
335-
return err;
336+
337+
return errors;
336338
}
337339

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

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

363385
for (auto i = files.cbegin(); i != files.cend(); ++i) {
364-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), errorLogger, settings.unmatchedSuppressionFilters);
386+
const std::vector<ErrorMessage> errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), settings.unmatchedSuppressionFilters);
387+
err |= reportErrorsFn(i->spath(), 0, errors);
365388
}
366389

367390
for (auto i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) {
368-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), errorLogger, settings.unmatchedSuppressionFilters);
391+
const std::vector<ErrorMessage> errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), settings.unmatchedSuppressionFilters);
392+
err |= reportErrorsFn(i->file.spath(), i->fileIndex, errors);
369393
}
370394

371395
if (settings.inlineSuppressions) {
372-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), errorLogger, settings.unmatchedSuppressionFilters);
396+
const std::vector<ErrorMessage> errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), settings.unmatchedSuppressionFilters);
397+
for (const auto& errmsg : errors) {
398+
std::string sourcefile;
399+
if (!errmsg.callStack.empty())
400+
sourcefile = errmsg.callStack.cbegin()->getfile();
401+
err |= reportErrorsFn(sourcefile, 0, {errmsg});
402+
}
373403
}
374404

375-
err |= ::reportUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), errorLogger, settings.unmatchedSuppressionFilters);
405+
const std::vector<ErrorMessage> errors = ::reportUnmatchedSuppressions(supprlist.getUnmatchedGlobalSuppressions(), settings.unmatchedSuppressionFilters);
406+
for (const auto& errmsg : errors) {
407+
std::string sourcefile;
408+
if (!errmsg.callStack.empty())
409+
sourcefile = errmsg.callStack.cbegin()->getfile();
410+
err |= reportErrorsFn(sourcefile, 0, {errmsg});
411+
}
376412
return err;
377413
}
378414

@@ -425,9 +461,10 @@ int CppCheckExecutor::check_internal(const Settings& settings, Suppressions& sup
425461
#endif
426462
}
427463

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

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

lib/analyzerinfo.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::st
149149
{
150150
if (buildDir.empty() || sourcefile.empty())
151151
return true;
152-
close();
153152

154153
const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fileIndex);
155154

@@ -162,11 +161,16 @@ bool AnalyzerInformation::analyzeFile(const std::string &buildDir, const std::st
162161
if (mOutputStream.is_open()) {
163162
mOutputStream << "<?xml version=\"1.0\"?>\n";
164163
mOutputStream << "<analyzerinfo hash=\"" << hash << "\">\n";
165-
}
164+
} else {
165+
// TODO: report error
166+
// TODO: return false?
167+
}
166168

167169
return true;
168170
}
169171

172+
#include <iostream>
173+
170174
void AnalyzerInformation::reportErr(const ErrorMessage &msg)
171175
{
172176
if (mOutputStream.is_open())
@@ -240,3 +244,23 @@ void AnalyzerInformation::processFilesTxt(const std::string& buildDir, const std
240244
}
241245
}
242246

247+
void AnalyzerInformation::reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex)
248+
{
249+
if (buildDir.empty() || sourcefile.empty())
250+
return;
251+
252+
const std::string analyzerInfoFile = AnalyzerInformation::getAnalyzerInfoFile(buildDir,sourcefile,cfg,fileIndex);
253+
std::ifstream ifs(analyzerInfoFile);
254+
if (!ifs.is_open())
255+
return;
256+
257+
std::ostringstream iss;
258+
iss << ifs.rdbuf();
259+
ifs.close();
260+
261+
std::string content = iss.str();
262+
content = content.substr(0, content.find("</analyzerinfo>"));
263+
264+
mOutputStream.open(analyzerInfoFile, std::ios::trunc);
265+
mOutputStream << content;
266+
}

lib/analyzerinfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class CPPCHECKLIB AnalyzerInformation {
6666
void setFileInfo(const std::string &check, const std::string &fileInfo);
6767
static std::string getAnalyzerInfoFile(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex);
6868

69+
void reopen(const std::string &buildDir, const std::string &sourcefile, const std::string &cfg, int fileIndex);
70+
6971
static const char sep = ':';
7072

7173
class CPPCHECKLIB Info {

test/cli/other_test.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,12 +2353,12 @@ def test_inline_suppr_builddir(tmp_path):
23532353
__test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j1'])
23542354

23552355

2356-
# TODO: the suppressions are generated outside of the scope which captures the analysis information
2357-
@pytest.mark.xfail(strict=True)
23582356
def test_inline_suppr_builddir_cached(tmp_path):
23592357
build_dir = tmp_path / 'b1'
23602358
os.mkdir(build_dir)
23612359
__test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j1'])
2360+
with open(build_dir / 'test.a1' , 'r') as f:
2361+
print(f.readlines())
23622362
__test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j1'])
23632363

23642364

@@ -2368,8 +2368,6 @@ def test_inline_suppr_builddir_j(tmp_path):
23682368
__test_inline_suppr(tmp_path, ['--cppcheck-build-dir={}'.format(build_dir), '-j2'])
23692369

23702370

2371-
# TODO: the suppressions are generated outside of the scope which captures the analysis information
2372-
@pytest.mark.xfail(strict=True)
23732371
def test_inline_suppr_builddir_j_cached(tmp_path):
23742372
build_dir = tmp_path / 'b1'
23752373
os.mkdir(build_dir)

0 commit comments

Comments
 (0)