Charusso updated this revision to Diff 215159.
Charusso marked 4 inline comments as done.
Charusso added a comment.
- Rainbow Butterfly Unicorn Kitty <https://www.youtube.com/watch?v=U4VbR45xy0w>
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D66042/new/
https://reviews.llvm.org/D66042
Files:
clang-tools-extra/clang-tidy/ClangTidy.cpp
clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
clang/lib/Frontend/CompilerInvocation.cpp
clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
clang/lib/StaticAnalyzer/Core/BugReporter.cpp
clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
clang/test/Analysis/analyzer-config.c
clang/test/Analysis/silence-checkers-and-packages-core-all.cpp
clang/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp
clang/tools/scan-build/bin/scan-build
clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
Index: clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
===================================================================
--- clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
+++ clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp
@@ -46,7 +46,7 @@
std::unique_ptr<AnalysisASTConsumer> AnalysisConsumer =
CreateAnalysisConsumer(Compiler);
AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput));
- Compiler.getAnalyzerOpts()->CheckersControlList = {
+ Compiler.getAnalyzerOpts()->CheckersAndPackages = {
{"custom.CustomChecker", true}};
AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<CheckerT>("custom.CustomChecker", "Description", "");
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 => {},
+ SilenceCheckers => {},
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 are disabled/silenced.
+ # See whether it is a core checker to disable. That means we do not want
+ # to emit a report from that checker so we have to silence it.
+ if (index($Checker, "core") == 0) {
+ $Options{SilenceCheckers}{$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{SilenceCheckers}{$a} <=> $Options{SilenceCheckers}{$b} }
+ keys %{$Options{SilenceCheckers}}) {
+ # Push checkers in order they were silenced.
+ push @AnalysesToRun, "-analyzer-config silence-checker", $_;
+}
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/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=core -analyzer-config \
+// RUN: silence-checkers=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'
+}
+
+void test_disable_null_deref(int *p) {
+ if (p)
+ return;
+
+ int x = p[0];
+ // expected-warning@-1 {{Array access (from variable 'p') results in a null pointer dereference}}
+}
Index: clang/test/Analysis/silence-checkers-and-packages-core-all.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/silence-checkers-and-packages-core-all.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=core -analyzer-config \
+// RUN: silence-checkers=core \
+// RUN: -verify %s
+
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=core -analyzer-config \
+// RUN: silence-checkers="core.DivideZero;core.NullDereference" \
+// RUN: -verify %s
+
+// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: -analyzer-checker=core -analyzer-config \
+// RUN: silence-checkers=core.NullDeref \
+// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-CHECKER-ERROR
+
+// CHECK-CHECKER-ERROR: (frontend): no analyzer checkers or packages
+// CHECK-CHECKER-ERROR-SAME: are associated with 'core.NullDeref'
+
+// RUN: not %clang_analyze_cc1 -verify %s \
+// RUN: -analyzer-checker=core -analyzer-config \
+// RUN: silence-checkers=coreModeling \
+// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-PACKAGE-ERROR
+
+// CHECK-PACKAGE-ERROR: (frontend): no analyzer checkers or packages
+// CHECK-PACKAGE-ERROR-SAME: are associated with 'coreModeling'
+
+void test_disable_core_div_by_zero() {
+ (void)(1 / 0);
+ // expected-warning@-1 {{division by zero is undefined}}
+ // no-warning: 'Division by zero'
+}
+
+void test_disable_null_deref(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/analyzer-config.c
===================================================================
--- clang/test/Analysis/analyzer-config.c
+++ clang/test/Analysis/analyzer-config.c
@@ -82,6 +82,7 @@
// CHECK-NEXT: region-store-small-struct-limit = 2
// CHECK-NEXT: report-in-main-source-file = false
// CHECK-NEXT: serialize-stats = false
+// CHECK-NEXT: silence-checkers = ""
// CHECK-NEXT: stable-report-filename = false
// CHECK-NEXT: suppress-c++-stdlib = true
// CHECK-NEXT: suppress-inlined-defensive-checks = true
@@ -92,4 +93,4 @@
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 89
+// CHECK-NEXT: num-entries = 90
Index: clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -200,12 +200,12 @@
// Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
// command line.
- for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersControlList) {
+ for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
CheckerInfoListRange CheckerForCmdLineArg =
getMutableCheckersForCmdLineArg(Opt.first);
if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
- Diags.Report(diag::err_unknown_analyzer_checker) << Opt.first;
+ Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
Diags.Report(diag::note_suggest_disabling_all_checkers);
}
@@ -468,9 +468,10 @@
void CheckerRegistry::validateCheckerOptions() const {
for (const auto &Config : AnOpts.Config) {
- StringRef SuppliedChecker;
+ StringRef SuppliedCheckerOrPackage;
StringRef SuppliedOption;
- std::tie(SuppliedChecker, SuppliedOption) = Config.getKey().split(':');
+ std::tie(SuppliedCheckerOrPackage, SuppliedOption) =
+ Config.getKey().split(':');
if (SuppliedOption.empty())
continue;
@@ -483,21 +484,24 @@
// Since lower_bound would look for the first element *not less* than "cor",
// it would return with an iterator to the first checker in the core, so we
// we really have to use find here, which uses operator==.
- auto CheckerIt = llvm::find(Checkers, CheckerInfo(SuppliedChecker));
+ auto CheckerIt =
+ llvm::find(Checkers, CheckerInfo(SuppliedCheckerOrPackage));
if (CheckerIt != Checkers.end()) {
- isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedChecker,
+ isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage,
SuppliedOption, AnOpts, Diags);
continue;
}
- auto PackageIt = llvm::find(Packages, PackageInfo(SuppliedChecker));
+ auto PackageIt =
+ llvm::find(Packages, PackageInfo(SuppliedCheckerOrPackage));
if (PackageIt != Packages.end()) {
- isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedChecker,
+ isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage,
SuppliedOption, AnOpts, Diags);
continue;
}
- Diags.Report(diag::err_unknown_analyzer_checker) << SuppliedChecker;
+ Diags.Report(diag::err_unknown_analyzer_checker_or_package)
+ << SuppliedCheckerOrPackage;
}
}
Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -1917,12 +1917,20 @@
PathDiagnosticBuilder &PDB,
const ExplodedNode *ErrorNode,
const VisitorsDiagnosticsTy &VisitorsDiagnostics) {
+ BugReport *R = PDB.getBugReport();
+ AnalyzerOptions &Opts = PDB.getBugReporter().getAnalyzerOptions();
+ StringRef ErrorTag = ErrorNode->getLocation().getTag()->getTagDescription();
+
+ // See whether we need to silence the checker/package.
+ // FIXME: This will not work if the report was emitted with an incorrect tag.
+ for (const std::string &CheckerOrPackage : Opts.SilencedCheckersAndPackages) {
+ if (ErrorTag.startswith(CheckerOrPackage))
+ 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 +2694,12 @@
const ExplodedNode *ErrorNode = ErrorGraph.ErrorNode;
for (PathDiagnosticConsumer *PC : consumers) {
PathDiagnosticBuilder PDB(*this, R, ErrorGraph.BackMap, PC);
- std::unique_ptr<PathDiagnostic> PD = generatePathDiagnosticForConsumer(
- PC->getGenerationScheme(), PDB, ErrorNode, *ReportInfo.second);
- (*Out)[PC] = std::move(PD);
+ if (std::unique_ptr<PathDiagnostic> PD =
+ generatePathDiagnosticForConsumer(PC->getGenerationScheme(), PDB,
+ ErrorNode,
+ *ReportInfo.second)) {
+ (*Out)[PC] = std::move(PD);
+ }
}
}
Index: clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -30,25 +30,6 @@
using namespace ento;
using namespace llvm;
-std::vector<StringRef>
-AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
- static const StringRef StaticAnalyzerChecks[] = {
-#define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \
- FULLNAME,
-#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
-#undef CHECKER
-#undef GET_CHECKERS
- };
- std::vector<StringRef> Result;
- for (StringRef CheckName : StaticAnalyzerChecks) {
- if (!CheckName.startswith("debug.") &&
- (IncludeExperimental || !CheckName.startswith("alpha.")))
- Result.push_back(CheckName);
- }
- return Result;
-}
-
void AnalyzerOptions::printFormattedEntry(
llvm::raw_ostream &Out,
std::pair<StringRef, StringRef> EntryDescPair,
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -324,18 +324,18 @@
getLastArgIntValue(Args, OPT_analyzer_inline_max_stack_depth,
Opts.InlineMaxStackDepth, Diags);
- Opts.CheckersControlList.clear();
+ Opts.CheckersAndPackages.clear();
for (const Arg *A :
Args.filtered(OPT_analyzer_checker, OPT_analyzer_disable_checker)) {
A->claim();
- bool enable = (A->getOption().getID() == OPT_analyzer_checker);
+ bool IsEnabled = A->getOption().getID() == OPT_analyzer_checker;
// We can have a list of comma separated checker names, e.g:
// '-analyzer-checker=cocoa,unix'
- StringRef checkerList = A->getValue();
- SmallVector<StringRef, 4> checkers;
- checkerList.split(checkers, ",");
- for (auto checker : checkers)
- Opts.CheckersControlList.emplace_back(checker, enable);
+ StringRef CheckerAndPackageList = A->getValue();
+ SmallVector<StringRef, 16> CheckersAndPackages;
+ CheckerAndPackageList.split(CheckersAndPackages, ",");
+ for (const StringRef CheckerOrPackage : CheckersAndPackages)
+ Opts.CheckersAndPackages.emplace_back(CheckerOrPackage, IsEnabled);
}
// Go through the analyzer configuration options.
@@ -479,6 +479,29 @@
!llvm::sys::fs::is_directory(AnOpts.ModelPath))
Diags->Report(diag::err_analyzer_config_invalid_input) << "model-path"
<< "a filename";
+
+ if (!AnOpts.RawSilencedCheckersAndPackages.empty()) {
+ std::vector<StringRef> Checkers =
+ AnOpts.getRegisteredCheckers(/*IncludeExperimental=*/true);
+ std::vector<StringRef> Packages =
+ AnOpts.getRegisteredPackages(/*IncludeExperimental=*/true);
+
+ SmallVector<StringRef, 16> CheckersAndPackages;
+ AnOpts.RawSilencedCheckersAndPackages.split(CheckersAndPackages, ";");
+
+ for (const StringRef CheckerOrPackage : CheckersAndPackages) {
+ bool IsChecker = CheckerOrPackage.contains('.');
+ bool IsValidName =
+ IsChecker ? llvm::find(Checkers, CheckerOrPackage) != Checkers.end()
+ : llvm::find(Packages, CheckerOrPackage) != Packages.end();
+
+ if (!IsValidName)
+ Diags->Report(diag::err_unknown_analyzer_checker_or_package)
+ << CheckerOrPackage;
+
+ AnOpts.SilencedCheckersAndPackages.emplace_back(CheckerOrPackage);
+ }
+ }
}
static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) {
Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -164,7 +164,40 @@
using ConfigTable = llvm::StringMap<std::string>;
static std::vector<StringRef>
- getRegisteredCheckers(bool IncludeExperimental = false);
+ getRegisteredCheckers(bool IncludeExperimental = false) {
+ static const StringRef StaticAnalyzerChecks[] = {
+#define GET_CHECKERS
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) FULLNAME,
+#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+#undef CHECKER
+#undef GET_CHECKERS
+ };
+ std::vector<StringRef> Checkers;
+ for (StringRef CheckerName : StaticAnalyzerChecks) {
+ if (!CheckerName.startswith("debug.") &&
+ (IncludeExperimental || !CheckerName.startswith("alpha.")))
+ Checkers.push_back(CheckerName);
+ }
+ return Checkers;
+ }
+
+ static std::vector<StringRef>
+ getRegisteredPackages(bool IncludeExperimental = false) {
+ static const StringRef StaticAnalyzerPackages[] = {
+#define GET_PACKAGES
+#define PACKAGE(FULLNAME) FULLNAME,
+#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
+#undef PACKAGE
+#undef GET_PACKAGES
+ };
+ std::vector<StringRef> Packages;
+ for (StringRef PackageName : StaticAnalyzerPackages) {
+ if (PackageName != "debug" &&
+ (IncludeExperimental || PackageName != "alpha"))
+ Packages.push_back(PackageName);
+ }
+ return Packages;
+ }
/// Convenience function for printing options or checkers and their
/// description in a formatted manner. If \p MinLineWidth is set to 0, no line
@@ -188,9 +221,11 @@
std::pair<StringRef, StringRef> EntryDescPair,
size_t EntryWidth, size_t InitialPad, size_t MinLineWidth = 0);
+ /// Pairs of checker/package name and enable/disable.
+ std::vector<std::pair<std::string, bool>> CheckersAndPackages;
- /// Pair of checker name and enable/disable.
- std::vector<std::pair<std::string, bool>> CheckersControlList;
+ /// Vector of checker/package names which will not emit warnings.
+ std::vector<std::string> SilencedCheckersAndPackages;
/// A key-value table of use-specified configuration values.
// TODO: This shouldn't be public.
Index: clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
+++ clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def
@@ -380,12 +380,6 @@
"Value: \"constructors\", \"destructors\", \"methods\".",
"destructors")
-ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
- StringRef, IPAMode, "ipa",
- "Controls the mode of inter-procedural analysis. Value: \"none\", "
- "\"basic-inlining\", \"inlining\", \"dynamic\", \"dynamic-bifurcate\".",
- /* SHALLOW_VAL */ "inlining", /* DEEP_VAL */ "dynamic-bifurcate")
-
ANALYZER_OPTION(
StringRef, ExplorationStrategy, "exploration_strategy",
"Value: \"dfs\", \"bfs\", \"unexplored_first\", "
@@ -393,5 +387,17 @@
"\"bfs_block_dfs_contents\".",
"unexplored_first_queue")
+ANALYZER_OPTION(
+ StringRef, RawSilencedCheckersAndPackages, "silence-checkers",
+ "A semicolon separated list of checker and package names to silence. "
+ "Silenced checkers will not emit reports, but the modeling remain enabled.",
+ "")
+
+ANALYZER_OPTION_DEPENDS_ON_USER_MODE(
+ StringRef, IPAMode, "ipa",
+ "Controls the mode of inter-procedural analysis. Value: \"none\", "
+ "\"basic-inlining\", \"inlining\", \"dynamic\", \"dynamic-bifurcate\".",
+ /* SHALLOW_VAL */ "inlining", /* DEEP_VAL */ "dynamic-bifurcate")
+
#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE
#undef ANALYZER_OPTION
Index: clang/include/clang/Basic/DiagnosticCommonKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -300,7 +300,7 @@
"directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier| with 'source' dependence}2">;
// Static Analyzer Core
-def err_unknown_analyzer_checker : Error<
+def err_unknown_analyzer_checker_or_package : Error<
"no analyzer checkers or packages are associated with '%0'">;
def note_suggest_disabling_all_checkers : Note<
"use -analyzer-disable-all-checks to disable all static analyzer checkers">;
Index: clang-tools-extra/clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -334,8 +334,8 @@
typedef std::vector<std::pair<std::string, bool>> CheckersList;
-static CheckersList getCheckersControlList(ClangTidyContext &Context,
- bool IncludeExperimental) {
+static CheckersList getAnalyzerCheckersAndPackages(ClangTidyContext &Context,
+ bool IncludeExperimental) {
CheckersList List;
const auto &RegisteredCheckers =
@@ -419,9 +419,9 @@
#if CLANG_ENABLE_STATIC_ANALYZER
AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
- AnalyzerOptions->CheckersControlList =
- getCheckersControlList(Context, Context.canEnableAnalyzerAlphaCheckers());
- if (!AnalyzerOptions->CheckersControlList.empty()) {
+ AnalyzerOptions->CheckersAndPackages = getAnalyzerCheckersAndPackages(
+ Context, Context.canEnableAnalyzerAlphaCheckers());
+ if (!AnalyzerOptions->CheckersAndPackages.empty()) {
setStaticAnalyzerCheckerOpts(Context.getOptions(), AnalyzerOptions);
AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
@@ -447,7 +447,7 @@
}
#if CLANG_ENABLE_STATIC_ANALYZER
- for (const auto &AnalyzerCheck : getCheckersControlList(
+ for (const auto &AnalyzerCheck : getAnalyzerCheckersAndPackages(
Context, Context.canEnableAnalyzerAlphaCheckers()))
CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
#endif // CLANG_ENABLE_STATIC_ANALYZER
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits