]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't display implementation checkers under -analyzer-checker-help, but...
authorKristof Umann <kristof.umann@ericsson.com>
Wed, 1 May 2019 19:56:47 +0000 (19:56 +0000)
committerKristof Umann <kristof.umann@ericsson.com>
Wed, 1 May 2019 19:56:47 +0000 (19:56 +0000)
During my work on analyzer dependencies, I created a great amount of new
checkers that emitted no diagnostics at all, and were purely modeling some
function or another.

However, the user shouldn't really disable/enable these by hand, hence this
patch, which hides these by default. I intentionally chose not to hide alpha
checkers, because they have a scary enough name, in my opinion, to cause no
surprise when they emit false positives or cause crashes.

The patch introduces the Hidden bit into the TableGen files (you may remember
it before I removed it in D53995), and checkers that are either marked as
hidden, or are in a package that is marked hidden won't be displayed under
-analyzer-checker-help. -analyzer-checker-help-hidden, a new flag meant for
developers only, displays the full list.

Differential Revision: https://reviews.llvm.org/D60925

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359720 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/Driver/CC1Options.td
include/clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h
include/clang/StaticAnalyzer/Checkers/CheckerBase.td
include/clang/StaticAnalyzer/Checkers/Checkers.td
include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
lib/Frontend/CompilerInvocation.cpp
lib/FrontendTool/ExecuteCompilerInvocation.cpp
lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
lib/StaticAnalyzer/Core/SarifDiagnostics.cpp
lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
test/Analysis/show-checker-list.c [new file with mode: 0644]
utils/TableGen/ClangSACheckersEmitter.cpp

index 2825a927797ae793920c5ca3d9cddd21a105882c..d18c37eb36fafc6c9b83fabbac4b327760362fc5 100644 (file)
@@ -107,7 +107,7 @@ def analyzer_checker : Separate<["-"], "analyzer-checker">,
   ValuesCode<[{
     const char *Values =
     #define GET_CHECKERS
-    #define CHECKER(FULLNAME, CLASS, HT, DOC_URI)  FULLNAME ","
+    #define CHECKER(FULLNAME, CLASS, HT, DOC_URI, IS_HIDDEN)  FULLNAME ","
     #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
     #undef GET_CHECKERS
     #define GET_PACKAGES
@@ -130,6 +130,10 @@ def analyzer_disable_all_checks : Flag<["-"], "analyzer-disable-all-checks">,
 def analyzer_checker_help : Flag<["-"], "analyzer-checker-help">,
   HelpText<"Display the list of analyzer checkers that are available">;
 
+def analyzer_checker_help_hidden : Flag<["-"], "analyzer-checker-help-hidden">,
+  HelpText<"Display the list of analyzer checkers that are available, "
+           "including modeling checkers">;
+
 def analyzer_config_help : Flag<["-"], "analyzer-config-help">,
   HelpText<"Display the list of -analyzer-config options">;
 
index 51b300299f1b71cc5c16044dc88ddc6501b3a8f5..c7732333d9bafd445b3daff3cb3aec88d1b942c1 100644 (file)
@@ -26,7 +26,7 @@ class CheckerManager;
 class CheckerRegistry;
 
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   void register##CLASS(CheckerManager &mgr);                                   \
   bool shouldRegister##CLASS(const LangOptions &LO);
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
index 0b0f92ea59edc7ba9c98b2628e6b7ede7264f4ee..c381d4b13ecd4e37843431e604b13d2fa4727a16 100644 (file)
@@ -49,6 +49,7 @@ class Package<string name> {
   // This field is optional.
   list<CmdLineOption> PackageOptions;
   Package             ParentPackage;
+  bit                 Hidden = 0;
 }
 
 /// Describes a 'super' package that holds another package inside it. This is
@@ -91,6 +92,7 @@ class Checker<string name = ""> {
   list<Checker>       Dependencies;
   bits<2>             Documentation;
   Package             ParentPackage;
+  bit                 Hidden = 0;
 }
 
 /// Describes a list of checker options.
@@ -108,3 +110,7 @@ class CheckerOptions<list<CmdLineOption> opts> {
 class Dependencies<list<Checker> Deps = []> {
   list<Checker> Dependencies = Deps;
 }
+
+/// Marks a checker or a package hidden. Hidden entries won't be displayed in
+/// -analyzer-checker-help, which is desirable for alpha or modeling checkers.
+class Hidden { bit Hidden = 1; }
index 0b16a2a429239d45792ce66dd4b3adf2875b02c7..911edd8066cbc1be33e7e5d5444e761477eaa9d7 100644 (file)
@@ -20,7 +20,7 @@ include "CheckerBase.td"
 def Alpha : Package<"alpha">;
 
 def Core : Package<"core">;
-def CoreBuiltin : Package<"builtin">, ParentPackage<Core>;
+def CoreBuiltin : Package<"builtin">, ParentPackage<Core>, Hidden;
 def CoreUninitialized  : Package<"uninitialized">, ParentPackage<Core>;
 def CoreAlpha : Package<"core">, ParentPackage<Alpha>;
 
@@ -97,10 +97,10 @@ def LLVMAlpha : Package<"llvm">, ParentPackage<Alpha>;
 // The APIModeling package is for checkers that model APIs and don't perform
 // any diagnostics. These checkers are always turned on; this package is
 // intended for API modeling that is not controlled by the target triple.
-def APIModeling : Package<"apiModeling">;
-def GoogleAPIModeling : Package<"google">, ParentPackage<APIModeling>;
+def APIModeling : Package<"apiModeling">, Hidden;
+def GoogleAPIModeling : Package<"google">, ParentPackage<APIModeling>, Hidden;
 
-def Debug : Package<"debug">;
+def Debug : Package<"debug">, Hidden;
 
 def CloneDetectionAlpha : Package<"clone">, ParentPackage<Alpha>;
 
@@ -141,7 +141,8 @@ def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">,
 
 def StackAddrEscapeBase : Checker<"StackAddrEscapeBase">,
   HelpText<"Generate information about stack address escapes.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
   HelpText<"Check that addresses to stack memory do not escape the function">,
@@ -154,7 +155,8 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
 
 def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">,
   HelpText<"Assume that const string-like globals are non-null">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 } // end "core"
 
@@ -231,7 +233,8 @@ let ParentPackage = Nullability in {
 
 def NullabilityBase : Checker<"NullabilityBase">,
   HelpText<"Stores information during the analysis about nullability.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">,
   HelpText<"Warns when a null pointer is passed to a pointer which has a "
@@ -336,7 +339,8 @@ def CStringModeling : Checker<"CStringModeling">,
   HelpText<"The base of several CString related checkers. On it's own it emits "
            "no reports, but adds valuable information to the analysis when "
            "enabled.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def CStringNullArg : Checker<"NullArg">,
   HelpText<"Check for null pointers being passed as arguments to C string "
@@ -390,7 +394,8 @@ def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">,
                   "false">
   ]>,
   Dependencies<[CStringModeling]>,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def MallocChecker: Checker<"Malloc">,
   HelpText<"Check for memory leaks, double free, and use-after-free problems. "
@@ -462,11 +467,13 @@ def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
 
 def CXXSelfAssignmentChecker : Checker<"SelfAssignment">,
   HelpText<"Checks C++ copy and move assignment operators for self assignment">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def SmartPtrModeling: Checker<"SmartPtr">,
   HelpText<"Model behavior of C++ smart pointers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def MoveChecker: Checker<"Move">,
   HelpText<"Find use-after-move bugs in C++">,
@@ -559,7 +566,8 @@ def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">,
 
 def IteratorModeling : Checker<"IteratorModeling">,
   HelpText<"Models iterators of C++ containers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def InvalidatedIteratorChecker : Checker<"InvalidatedIterator">,
   HelpText<"Check for use of invalidated iterators">,
@@ -588,7 +596,8 @@ let ParentPackage = Valist in {
 
 def ValistBase : Checker<"ValistBase">,
   HelpText<"Gathers information about va_lists.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def UninitializedChecker : Checker<"Uninitialized">,
   HelpText<"Check for usages of uninitialized (or already released) va_lists.">,
@@ -655,7 +664,8 @@ let ParentPackage = InsecureAPI in {
 
 def SecuritySyntaxChecker : Checker<"SecuritySyntaxChecker">,
   HelpText<"Base of various security function related checkers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def bcmp : Checker<"bcmp">,
   HelpText<"Warn on uses of the 'bcmp' function">,
@@ -787,7 +797,8 @@ let ParentPackage = Cocoa in {
 
 def RetainCountBase : Checker<"RetainCountBase">,
   HelpText<"Common base of various retain count related checkers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 } // end "osx.cocoa"
 
@@ -795,7 +806,8 @@ let ParentPackage = OSX in {
 
 def NSOrCFErrorDerefChecker : Checker<"NSOrCFErrorDerefChecker">,
   HelpText<"Implementation checker for NSErrorChecker and CFErrorChecker">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def NumberObjectConversionChecker : Checker<"NumberObjectConversion">,
   HelpText<"Check for erroneous conversions of objects representing numbers "
@@ -962,7 +974,8 @@ def IvarInvalidationModeling : Checker<"IvarInvalidationModeling">,
   HelpText<"Gathers information for annotation driven invalidation checking "
            "for classes that contains a method annotated with "
            "'objc_instance_variable_invalidator'">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
   HelpText<"Check that the invalidatable instance variables are invalidated in "
index b8d92132f1969e0036dcc8165c5bc7f811e89004..63b7cd35ed329cc206948508ba8bbe8c35fd3ce4 100644 (file)
@@ -197,6 +197,7 @@ public:
   unsigned DisableAllChecks : 1;
 
   unsigned ShowCheckerHelp : 1;
+  unsigned ShowCheckerHelpHidden : 1;
   unsigned ShowEnabledCheckerList : 1;
   unsigned ShowConfigOptionsList : 1;
   unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
index 8550baa43e79af64a9f989c7cc71f84cac1476e8..c6cb8ac6319526159598fbc8df5d871d2497a231 100644 (file)
@@ -137,6 +137,7 @@ public:
     StringRef Desc;
     StringRef DocumentationUri;
     CmdLineOptionList CmdLineOptions;
+    bool IsHidden = false;
     StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
 
     ConstCheckerInfoList Dependencies;
@@ -150,9 +151,10 @@ public:
     }
 
     CheckerInfo(InitializationFunction Fn, ShouldRegisterFunction sfn,
-                StringRef Name, StringRef Desc, StringRef DocsUri)
+                StringRef Name, StringRef Desc, StringRef DocsUri,
+                bool IsHidden)
         : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc),
-          DocumentationUri(DocsUri) {}
+          DocumentationUri(DocsUri), IsHidden(IsHidden) {}
 
     // Used for lower_bound.
     explicit CheckerInfo(StringRef FullName) : FullName(FullName) {}
@@ -190,16 +192,19 @@ public:
   /// Adds a checker to the registry. Use this non-templated overload when your
   /// checker requires custom initialization.
   void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn,
-                  StringRef FullName, StringRef Desc, StringRef DocsUri);
+                  StringRef FullName, StringRef Desc, StringRef DocsUri,
+                  bool IsHidden);
 
   /// Adds a checker to the registry. Use this templated overload when your
   /// checker does not require any custom initialization.
   template <class T>
-  void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri) {
+  void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri,
+                  bool IsHidden = false) {
     // Avoid MSVC's Compiler Error C2276:
     // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx
     addChecker(&CheckerRegistry::initializeManager<T>,
-               &CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri);
+               &CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri,
+               IsHidden);
   }
 
   /// Makes the checker with the full name \p fullName depends on the checker
index cc7d5b62a84c3d37ed705667e6467b6c50c3cab7..12846b18c075db892c2838d4540a6b7376276475 100644 (file)
@@ -285,6 +285,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
   }
 
   Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
+  Opts.ShowCheckerHelpHidden = Args.hasArg(OPT_analyzer_checker_help_hidden);
   Opts.ShowConfigOptionsList = Args.hasArg(OPT_analyzer_config_help);
   Opts.ShowEnabledCheckerList = Args.hasArg(OPT_analyzer_list_enabled_checkers);
   Opts.ShouldEmitErrorsOnInvalidConfigValue =
index c226838786f092726eae4a6ef2fb07a87c21cc65..f77a865efa70a91c64cece2f976c40371a0833b3 100644 (file)
@@ -234,28 +234,30 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
   }
 
 #if CLANG_ENABLE_STATIC_ANALYZER
-  // Honor -analyzer-checker-help.
-  // This should happen AFTER plugins have been loaded!
-  if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
+  // These should happen AFTER plugins have been loaded!
+
+  AnalyzerOptions &AnOpts = *Clang->getAnalyzerOpts();
+  // Honor -analyzer-checker-help and -analyzer-checker-help-hidden.
+  if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpHidden) {
     ento::printCheckerHelp(llvm::outs(),
                            Clang->getFrontendOpts().Plugins,
-                           *Clang->getAnalyzerOpts(),
+                           AnOpts,
                            Clang->getDiagnostics(),
                            Clang->getLangOpts());
     return true;
   }
 
   // Honor -analyzer-list-enabled-checkers.
-  if (Clang->getAnalyzerOpts()->ShowEnabledCheckerList) {
+  if (AnOpts.ShowEnabledCheckerList) {
     ento::printEnabledCheckerList(llvm::outs(),
                                   Clang->getFrontendOpts().Plugins,
-                                  *Clang->getAnalyzerOpts(),
+                                  AnOpts,
                                   Clang->getDiagnostics(),
                                   Clang->getLangOpts());
   }
 
   // Honor -analyzer-config-help.
-  if (Clang->getAnalyzerOpts()->ShowConfigOptionsList) {
+  if (AnOpts.ShowConfigOptionsList) {
     ento::printAnalyzerConfigList(llvm::outs());
     return true;
   }
index ee670fb45a7766a419a757da83d92a2cecf132b2..893c72190e1983ffee4b3f1f1f0f655fd02bd3c6 100644 (file)
@@ -33,7 +33,7 @@ std::vector<StringRef>
 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
   static const StringRef StaticAnalyzerChecks[] = {
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   FULLNAME,
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
index 226d5a942b3f0e0d1519f6420748fce62142c5bd..a8f529b7d353f3daf30efe19e9be4194d8dfe312 100644 (file)
@@ -256,7 +256,7 @@ static json::Object createResult(const PathDiagnostic &Diag, json::Array &Files,
 static StringRef getRuleDescription(StringRef CheckName) {
   return llvm::StringSwitch<StringRef>(CheckName)
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   .Case(FULLNAME, HELPTEXT)
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
@@ -267,7 +267,7 @@ static StringRef getRuleDescription(StringRef CheckName) {
 static StringRef getRuleHelpURIStr(StringRef CheckName) {
   return llvm::StringSwitch<StringRef>(CheckName)
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   .Case(FULLNAME, DOC_URI)
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
index f1ee454f632816697af97a34708300ffae757928..4267d8a2cdcdca47073cb4280dde35722e5f1ecd 100644 (file)
@@ -115,9 +115,9 @@ CheckerRegistry::CheckerRegistry(
 
   // Register builtin checkers.
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT,       \
-             DOC_URI);
+             DOC_URI, IS_HIDDEN);
 
 #define GET_PACKAGES
 #define PACKAGE(FULLNAME) addPackage(FULLNAME);
@@ -350,8 +350,9 @@ void CheckerRegistry::addPackageOption(StringRef OptionType,
 
 void CheckerRegistry::addChecker(InitializationFunction Rfn,
                                  ShouldRegisterFunction Sfn, StringRef Name,
-                                 StringRef Desc, StringRef DocsUri) {
-  Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri);
+                                 StringRef Desc, StringRef DocsUri,
+                                 bool IsHidden) {
+  Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
 
   // Record the presence of the checker in its packages.
   StringRef PackageName, LeafName;
@@ -421,6 +422,9 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
 
   const size_t InitialPad = 2;
   for (const auto &Checker : Checkers) {
+    if (!AnOpts.ShowCheckerHelpHidden && Checker.IsHidden)
+      continue;
+
     Out.indent(InitialPad) << Checker.FullName;
 
     int Pad = OptionFieldWidth - Checker.FullName.size();
diff --git a/test/Analysis/show-checker-list.c b/test/Analysis/show-checker-list.c
new file mode 100644 (file)
index 0000000..83ed6e4
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -analyzer-checker-help \
+// RUN:   2>&1 | FileCheck %s -check-prefix=CHECK
+
+// RUN: %clang_cc1 -analyzer-checker-help-hidden \
+// RUN:   2>&1 | FileCheck %s -check-prefix=CHECK-HIDDEN
+
+// CHECK: core.DivideZero
+// CHECK-HIDDEN: core.DivideZero
+
+// CHECK-NOT: unix.DynamicMemoryModeling
+// CHECK-HIDDEN: unix.DynamicMemoryModeling
index 03c3b3b9fb9600e4dc65336d54d3a80eb321e0d6..428a5c81276b89e3e72e50cc2ce008145aad62e1 100644 (file)
@@ -110,6 +110,16 @@ static std::string getCheckerOptionType(const Record &R) {
   return "";
 }
 
+static bool isHidden(const Record *R) {
+  if (R->getValueAsBit("Hidden"))
+    return true;
+  // Not declared as hidden, check the parent package if it is hidden.
+  if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
+    return isHidden(DI->getDef());
+
+  return false;
+}
+
 static void printChecker(llvm::raw_ostream &OS, const Record &R) {
     OS << "CHECKER(" << "\"";
     OS.write_escaped(getCheckerFullName(&R)) << "\", ";
@@ -118,7 +128,14 @@ static void printChecker(llvm::raw_ostream &OS, const Record &R) {
     OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
     OS << "\"";
     OS.write_escaped(getCheckerDocs(R));
-    OS << "\"";
+    OS << "\", ";
+
+    if (!isHidden(&R))
+      OS << "false";
+    else
+      OS << "true";
+
+    OS << ")\n";
 }
 
 namespace clang {
@@ -206,7 +223,6 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
         "\n";
   for (const Record *checker : checkers) {
     printChecker(OS, *checker);
-    OS << ")\n";
   }
   OS << "\n"
         "#endif // GET_CHECKERS\n"