Index: clang-tools-extra/clang-tidy/ClangTidy.cpp =================================================================== --- clang-tools-extra/clang-tidy/ClangTidy.cpp +++ clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -419,9 +419,9 @@ #if CLANG_ENABLE_STATIC_ANALYZER AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts(); - AnalyzerOptions->CheckersControlList = + AnalyzerOptions->CheckerAnalysisVector = getCheckersControlList(Context, Context.canEnableAnalyzerAlphaCheckers()); - if (!AnalyzerOptions->CheckersControlList.empty()) { + if (!AnalyzerOptions->CheckerAnalysisVector.empty()) { setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions); AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel; AnalyzerOptions->AnalysisDiagOpt = PD_NONE; Index: clang/include/clang/Driver/CC1Options.td =================================================================== --- clang/include/clang/Driver/CC1Options.td +++ clang/include/clang/Driver/CC1Options.td @@ -124,6 +124,11 @@ def analyzer_disable_checker_EQ : Joined<["-"], "analyzer-disable-checker=">, Alias; +def analyzer_disable_warning : Separate<["-"], "analyzer-disable-warning">, + HelpText<"Choose analyzer checkers of the warnings to disable">; +def analyzer_disable_warning_EQ : Joined<["-"], "analyzer-disable-warning=">, + Alias; + def analyzer_disable_all_checks : Flag<["-"], "analyzer-disable-all-checks">, HelpText<"Disable all static analyzer checks">; Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -189,8 +189,11 @@ size_t EntryWidth, size_t InitialPad, size_t MinLineWidth = 0); - /// Pair of checker name and enable/disable. - std::vector> CheckersControlList; + /// Pair of checker name and enable/disable to do analysis. + std::vector> CheckerAnalysisVector; + + /// Vector of checker names to do not emit warnings. + std::vector CheckerWarningVector; /// A key-value table of use-specified configuration values. // TODO: This shouldn't be public. Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -324,7 +324,7 @@ getLastArgIntValue(Args, OPT_analyzer_inline_max_stack_depth, Opts.InlineMaxStackDepth, Diags); - Opts.CheckersControlList.clear(); + Opts.CheckerAnalysisVector.clear(); for (const Arg *A : Args.filtered(OPT_analyzer_checker, OPT_analyzer_disable_checker)) { A->claim(); @@ -332,10 +332,22 @@ // We can have a list of comma separated checker names, e.g: // '-analyzer-checker=cocoa,unix' StringRef checkerList = A->getValue(); - SmallVector checkers; + SmallVector checkers; checkerList.split(checkers, ","); for (auto checker : checkers) - Opts.CheckersControlList.emplace_back(checker, enable); + Opts.CheckerAnalysisVector.emplace_back(checker, enable); + } + + Opts.CheckerWarningVector.clear(); + for (const Arg *A : Args.filtered(OPT_analyzer_disable_warning)) { + A->claim(); + // We can have a list of comma separated checker names, e.g: + // '-analyzer-checker=cocoa,unix' + StringRef checkerList = A->getValue(); + SmallVector checkers; + checkerList.split(checkers, ","); + for (auto checker : checkers) + Opts.CheckerWarningVector.emplace_back(checker); } // Go through the analyzer configuration options. Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -1917,12 +1917,19 @@ PathDiagnosticBuilder &PDB, const ExplodedNode *ErrorNode, const VisitorsDiagnosticsTy &VisitorsDiagnostics) { + BugReport *R = PDB.getBugReport(); + AnalyzerOptions &Opts = PDB.getBugReporter().getAnalyzerOptions(); + StringRef ErrorTag = ErrorNode->getLocation().getTag()->getTagDescription(); + + // The 'CheckerName' could be 'core' so that 'contains()' is appropriate. + for (const std::string &CheckerName : Opts.CheckerWarningVector) { + if (ErrorTag.contains(CheckerName)) + return nullptr; + } bool GenerateDiagnostics = (ActiveScheme != PathDiagnosticConsumer::None); bool AddPathEdges = (ActiveScheme == PathDiagnosticConsumer::Extensive); SourceManager &SM = PDB.getSourceManager(); - BugReport *R = PDB.getBugReport(); - AnalyzerOptions &Opts = PDB.getBugReporter().getAnalyzerOptions(); StackDiagVector CallStack; InterestingExprs IE; LocationContextMap LCM; @@ -2686,9 +2693,12 @@ const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode; for (PathDiagnosticConsumer *PC : consumers) { PathDiagnosticBuilder PDB(*this, R, ErrorGraph.BackMap, PC); - std::unique_ptr PD = generatePathDiagnosticForConsumer( - PC->getGenerationScheme(), PDB, ErrorNode, *ReportInfo.second); - (*Out)[PC] = std::move(PD); + if (std::unique_ptr PD = + generatePathDiagnosticForConsumer(PC->getGenerationScheme(), PDB, + ErrorNode, + *ReportInfo.second)) { + (*Out)[PC] = std::move(PD); + } } } Index: clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp =================================================================== --- clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -200,7 +200,7 @@ // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the // command line. - for (const std::pair &Opt : AnOpts.CheckersControlList) { + for (const std::pair &Opt : AnOpts.CheckerAnalysisVector) { CheckerInfoListRange CheckerForCmdLineArg = getMutableCheckersForCmdLineArg(Opt.first); Index: clang/test/Analysis/turn-off-warnings-core-all.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/turn-off-warnings-core-all.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-disable-warning=core \ +// RUN: -verify %s + +// expected-no-diagnostics + +void test_disable_core_all(int *p) { + if (p) + return; + + int x = p[0]; + // no-warning: Array access (from variable 'p') results in a null pointer dereference +} Index: clang/test/Analysis/turn-off-warnings-core-div-by-zero.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/turn-off-warnings-core-div-by-zero.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_analyze_cc1 \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-disable-warning core.DivideZero \ +// RUN: -verify %s + +void test_disable_core_div_by_zero() { + (void)(1 / 0); + // expected-warning@-1 {{division by zero is undefined}} + // no-warning: 'Division by zero' +} Index: clang/tools/scan-build/bin/scan-build =================================================================== --- clang/tools/scan-build/bin/scan-build +++ clang/tools/scan-build/bin/scan-build @@ -57,6 +57,7 @@ KeepEmpty => 0, # Don't remove output directory even with 0 results. EnableCheckers => {}, DisableCheckers => {}, + DisableWarnings => {}, Excludes => [], UseCC => undef, # C compiler to use for compilation. UseCXX => undef, # C++ compiler to use for compilation. @@ -1742,9 +1743,15 @@ if ($arg eq "-disable-checker") { shift @$Args; my $Checker = shift @$Args; - # Store $NumArgs to preserve the order the checkers were disabled. - $Options{DisableCheckers}{$Checker} = $NumArgs; - delete $Options{EnableCheckers}{$Checker}; + # Store $NumArgs to preserve the order the checkers/warnings are disabled. + # See whether it is a core checker to disable. That means we do not want + # to emit a report from the checker so we have to disable the warning. + if (index($Checker, "core") != -1) { + $Options{DisableWarnings}{$Checker} = $NumArgs; + } else { + $Options{DisableCheckers}{$Checker} = $NumArgs; + delete $Options{EnableCheckers}{$Checker}; + } next; } @@ -1882,6 +1889,11 @@ # Push checkers in order they were disabled. push @AnalysesToRun, "-analyzer-disable-checker", $_; } +foreach (sort { $Options{DisableWarnings}{$a} <=> $Options{DisableWarnings}{$b} } + keys %{$Options{DisableWarnings}}) { + # Push checkers' warnings in order they were disabled. + push @AnalysesToRun, "-analyzer-disable-warning", $_; +} if ($Options{AnalyzeHeaders}) { push @AnalysesToRun, "-analyzer-opt-analyze-headers"; } if ($Options{AnalyzerStats}) { push @AnalysesToRun, '-analyzer-checker=debug.Stats'; } if ($Options{MaxLoop} > 0) { push @AnalysesToRun, "-analyzer-max-loop $Options{MaxLoop}"; } Index: clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp =================================================================== --- clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp +++ clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp @@ -46,7 +46,7 @@ std::unique_ptr AnalysisConsumer = CreateAnalysisConsumer(Compiler); AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput)); - Compiler.getAnalyzerOpts()->CheckersControlList = { + Compiler.getAnalyzerOpts()->CheckerAnalysisVector = { {"custom.CustomChecker", true}}; AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) { Registry.addChecker("custom.CustomChecker", "Description", "");