| 340 | } |
| 341 | |
| 342 | bool CppCheckExecutor::reportUnmatchedSuppressions(const Settings &settings, const SuppressionList& suppressions, const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, ErrorLogger& errorLogger) { |
| 343 | // the two inputs may only be used exclusively |
| 344 | assert(!(!files.empty() && !fileSettings.empty())); |
| 345 | |
| 346 | // bail out if there is a suppression of unmatchedSuppression which matches any file |
| 347 | auto suppr = suppressions.getSuppressions(); |
| 348 | if (std::any_of(suppr.cbegin(), suppr.cend(), [](const SuppressionList::Suppression& s) { |
| 349 | // TODO: handle unmatchedPolyspaceSuppression? |
| 350 | return s.errorId == "unmatchedSuppression" && (s.fileName.empty() || s.fileName == "*") && s.lineNumber == SuppressionList::Suppression::NO_LINE; |
| 351 | })) |
| 352 | return false; |
| 353 | |
| 354 | SuppressionList supprlist; |
| 355 | |
| 356 | const bool doUnusedFunctionOnly = Settings::unusedFunctionOnly(); |
| 357 | // ignore all other suppressions if we use the unusedFunction hack |
| 358 | for (auto&& s : suppr) |
| 359 | { |
| 360 | // TODO: checkersReport should not be reported - see #13387 |
| 361 | if (doUnusedFunctionOnly && s.errorId != "unusedFunction" && s.errorId != "checkersReport") |
| 362 | continue; |
| 363 | supprlist.addSuppression(std::move(s)); |
| 364 | } |
| 365 | |
| 366 | const auto reportErrorsFn = [&](const std::string& sourcefile, std::size_t fsFileId, const std::vector<ErrorMessage>& errors) -> bool { |
| 367 | if (errors.empty()) |
| 368 | return false; |
| 369 | |
| 370 | // TODO: what if sourcefile is empty? |
| 371 | |
| 372 | AnalyzerInformation analyzerInfo; |
| 373 | // FIXME: this is a horrible hack |
| 374 | // we need to "re-open" the file so we can add the unmatchedSuppression findings. |
| 375 | // we cannot keep it open conditionally because the whole program analysis reads the XML. |
| 376 | // re-ordering the code is also not an option because the unmatched suppression reporting needs to be run after all other checks. |
| 377 | analyzerInfo.reopen(settings.buildDir, sourcefile, /*cfgname*/ "", fsFileId); |
| 378 | |
| 379 | for (const auto& errmsg : errors) { |
| 380 | analyzerInfo.reportErr(errmsg); |
| 381 | errorLogger.reportErr(errmsg); |
| 382 | } |
| 383 | return true; |
| 384 | }; |
| 385 | |
| 386 | bool err = false; |
| 387 | |
| 388 | for (auto i = files.cbegin(); i != files.cend(); ++i) { |
| 389 | const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(*i), settings.unmatchedSuppressionFilters); |
| 390 | err |= reportErrorsFn(i->spath(), i->fsFileId(), errors); |
| 391 | } |
| 392 | |
| 393 | for (auto i = fileSettings.cbegin(); i != fileSettings.cend(); ++i) { |
| 394 | const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedLocalSuppressions(i->file), settings.unmatchedSuppressionFilters); |
| 395 | err |= reportErrorsFn(i->file.spath(), i->file.fsFileId(), errors); |
| 396 | } |
| 397 | |
| 398 | if (settings.inlineSuppressions) { |
| 399 | const std::vector<ErrorMessage> errors = getUnmatchedSuppressions(supprlist.getUnmatchedInlineSuppressions(), settings.unmatchedSuppressionFilters); |
nothing calls this directly
no test coverage detected