Browse Source

[analyzer] Don't display implementation checkers under -analyzer-checker-help, but do under the new flag -analyzer-checker-help-hidden

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
Kristof Umann 6 years ago
parent
commit
34d9084833

+ 5 - 1
include/clang/Driver/CC1Options.td

@@ -107,7 +107,7 @@ def analyzer_checker : Separate<["-"], "analyzer-checker">,
   ValuesCode<[{
   ValuesCode<[{
     const char *Values =
     const char *Values =
     #define GET_CHECKERS
     #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"
     #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
     #undef GET_CHECKERS
     #undef GET_CHECKERS
     #define GET_PACKAGES
     #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">,
 def analyzer_checker_help : Flag<["-"], "analyzer-checker-help">,
   HelpText<"Display the list of analyzer checkers that are available">;
   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">,
 def analyzer_config_help : Flag<["-"], "analyzer-config-help">,
   HelpText<"Display the list of -analyzer-config options">;
   HelpText<"Display the list of -analyzer-config options">;
 
 

+ 1 - 1
include/clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h

@@ -26,7 +26,7 @@ class CheckerManager;
 class CheckerRegistry;
 class CheckerRegistry;
 
 
 #define GET_CHECKERS
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   void register##CLASS(CheckerManager &mgr);                                   \
   void register##CLASS(CheckerManager &mgr);                                   \
   bool shouldRegister##CLASS(const LangOptions &LO);
   bool shouldRegister##CLASS(const LangOptions &LO);
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"

+ 6 - 0
include/clang/StaticAnalyzer/Checkers/CheckerBase.td

@@ -49,6 +49,7 @@ class Package<string name> {
   // This field is optional.
   // This field is optional.
   list<CmdLineOption> PackageOptions;
   list<CmdLineOption> PackageOptions;
   Package             ParentPackage;
   Package             ParentPackage;
+  bit                 Hidden = 0;
 }
 }
 
 
 /// Describes a 'super' package that holds another package inside it. This is
 /// Describes a 'super' package that holds another package inside it. This is
@@ -91,6 +92,7 @@ class Checker<string name = ""> {
   list<Checker>       Dependencies;
   list<Checker>       Dependencies;
   bits<2>             Documentation;
   bits<2>             Documentation;
   Package             ParentPackage;
   Package             ParentPackage;
+  bit                 Hidden = 0;
 }
 }
 
 
 /// Describes a list of checker options.
 /// Describes a list of checker options.
@@ -108,3 +110,7 @@ class CheckerOptions<list<CmdLineOption> opts> {
 class Dependencies<list<Checker> Deps = []> {
 class Dependencies<list<Checker> Deps = []> {
   list<Checker> Dependencies = 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; }

+ 30 - 17
include/clang/StaticAnalyzer/Checkers/Checkers.td

@@ -20,7 +20,7 @@ include "CheckerBase.td"
 def Alpha : Package<"alpha">;
 def Alpha : Package<"alpha">;
 
 
 def Core : Package<"core">;
 def Core : Package<"core">;
-def CoreBuiltin : Package<"builtin">, ParentPackage<Core>;
+def CoreBuiltin : Package<"builtin">, ParentPackage<Core>, Hidden;
 def CoreUninitialized  : Package<"uninitialized">, ParentPackage<Core>;
 def CoreUninitialized  : Package<"uninitialized">, ParentPackage<Core>;
 def CoreAlpha : Package<"core">, ParentPackage<Alpha>;
 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
 // The APIModeling package is for checkers that model APIs and don't perform
 // any diagnostics. These checkers are always turned on; this package is
 // any diagnostics. These checkers are always turned on; this package is
 // intended for API modeling that is not controlled by the target triple.
 // 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>;
 def CloneDetectionAlpha : Package<"clone">, ParentPackage<Alpha>;
 
 
@@ -141,7 +141,8 @@ def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">,
 
 
 def StackAddrEscapeBase : Checker<"StackAddrEscapeBase">,
 def StackAddrEscapeBase : Checker<"StackAddrEscapeBase">,
   HelpText<"Generate information about stack address escapes.">,
   HelpText<"Generate information about stack address escapes.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
 def StackAddrEscapeChecker : Checker<"StackAddressEscape">,
   HelpText<"Check that addresses to stack memory do not escape the function">,
   HelpText<"Check that addresses to stack memory do not escape the function">,
@@ -154,7 +155,8 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">,
 
 
 def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">,
 def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">,
   HelpText<"Assume that const string-like globals are non-null">,
   HelpText<"Assume that const string-like globals are non-null">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 } // end "core"
 } // end "core"
 
 
@@ -231,7 +233,8 @@ let ParentPackage = Nullability in {
 
 
 def NullabilityBase : Checker<"NullabilityBase">,
 def NullabilityBase : Checker<"NullabilityBase">,
   HelpText<"Stores information during the analysis about nullability.">,
   HelpText<"Stores information during the analysis about nullability.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">,
 def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">,
   HelpText<"Warns when a null pointer is passed to a pointer which has a "
   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 "
   HelpText<"The base of several CString related checkers. On it's own it emits "
            "no reports, but adds valuable information to the analysis when "
            "no reports, but adds valuable information to the analysis when "
            "enabled.">,
            "enabled.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def CStringNullArg : Checker<"NullArg">,
 def CStringNullArg : Checker<"NullArg">,
   HelpText<"Check for null pointers being passed as arguments to C string "
   HelpText<"Check for null pointers being passed as arguments to C string "
@@ -390,7 +394,8 @@ def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">,
                   "false">
                   "false">
   ]>,
   ]>,
   Dependencies<[CStringModeling]>,
   Dependencies<[CStringModeling]>,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def MallocChecker: Checker<"Malloc">,
 def MallocChecker: Checker<"Malloc">,
   HelpText<"Check for memory leaks, double free, and use-after-free problems. "
   HelpText<"Check for memory leaks, double free, and use-after-free problems. "
@@ -462,11 +467,13 @@ def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
 
 
 def CXXSelfAssignmentChecker : Checker<"SelfAssignment">,
 def CXXSelfAssignmentChecker : Checker<"SelfAssignment">,
   HelpText<"Checks C++ copy and move assignment operators for self assignment">,
   HelpText<"Checks C++ copy and move assignment operators for self assignment">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def SmartPtrModeling: Checker<"SmartPtr">,
 def SmartPtrModeling: Checker<"SmartPtr">,
   HelpText<"Model behavior of C++ smart pointers">,
   HelpText<"Model behavior of C++ smart pointers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def MoveChecker: Checker<"Move">,
 def MoveChecker: Checker<"Move">,
   HelpText<"Find use-after-move bugs in C++">,
   HelpText<"Find use-after-move bugs in C++">,
@@ -559,7 +566,8 @@ def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">,
 
 
 def IteratorModeling : Checker<"IteratorModeling">,
 def IteratorModeling : Checker<"IteratorModeling">,
   HelpText<"Models iterators of C++ containers">,
   HelpText<"Models iterators of C++ containers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def InvalidatedIteratorChecker : Checker<"InvalidatedIterator">,
 def InvalidatedIteratorChecker : Checker<"InvalidatedIterator">,
   HelpText<"Check for use of invalidated iterators">,
   HelpText<"Check for use of invalidated iterators">,
@@ -588,7 +596,8 @@ let ParentPackage = Valist in {
 
 
 def ValistBase : Checker<"ValistBase">,
 def ValistBase : Checker<"ValistBase">,
   HelpText<"Gathers information about va_lists.">,
   HelpText<"Gathers information about va_lists.">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def UninitializedChecker : Checker<"Uninitialized">,
 def UninitializedChecker : Checker<"Uninitialized">,
   HelpText<"Check for usages of uninitialized (or already released) va_lists.">,
   HelpText<"Check for usages of uninitialized (or already released) va_lists.">,
@@ -655,7 +664,8 @@ let ParentPackage = InsecureAPI in {
 
 
 def SecuritySyntaxChecker : Checker<"SecuritySyntaxChecker">,
 def SecuritySyntaxChecker : Checker<"SecuritySyntaxChecker">,
   HelpText<"Base of various security function related checkers">,
   HelpText<"Base of various security function related checkers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def bcmp : Checker<"bcmp">,
 def bcmp : Checker<"bcmp">,
   HelpText<"Warn on uses of the 'bcmp' function">,
   HelpText<"Warn on uses of the 'bcmp' function">,
@@ -787,7 +797,8 @@ let ParentPackage = Cocoa in {
 
 
 def RetainCountBase : Checker<"RetainCountBase">,
 def RetainCountBase : Checker<"RetainCountBase">,
   HelpText<"Common base of various retain count related checkers">,
   HelpText<"Common base of various retain count related checkers">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 } // end "osx.cocoa"
 } // end "osx.cocoa"
 
 
@@ -795,7 +806,8 @@ let ParentPackage = OSX in {
 
 
 def NSOrCFErrorDerefChecker : Checker<"NSOrCFErrorDerefChecker">,
 def NSOrCFErrorDerefChecker : Checker<"NSOrCFErrorDerefChecker">,
   HelpText<"Implementation checker for NSErrorChecker and CFErrorChecker">,
   HelpText<"Implementation checker for NSErrorChecker and CFErrorChecker">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def NumberObjectConversionChecker : Checker<"NumberObjectConversion">,
 def NumberObjectConversionChecker : Checker<"NumberObjectConversion">,
   HelpText<"Check for erroneous conversions of objects representing numbers "
   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 "
   HelpText<"Gathers information for annotation driven invalidation checking "
            "for classes that contains a method annotated with "
            "for classes that contains a method annotated with "
            "'objc_instance_variable_invalidator'">,
            "'objc_instance_variable_invalidator'">,
-  Documentation<NotDocumented>;
+  Documentation<NotDocumented>,
+  Hidden;
 
 
 def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
 def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
   HelpText<"Check that the invalidatable instance variables are invalidated in "
   HelpText<"Check that the invalidatable instance variables are invalidated in "

+ 1 - 0
include/clang/StaticAnalyzer/Core/AnalyzerOptions.h

@@ -197,6 +197,7 @@ public:
   unsigned DisableAllChecks : 1;
   unsigned DisableAllChecks : 1;
 
 
   unsigned ShowCheckerHelp : 1;
   unsigned ShowCheckerHelp : 1;
+  unsigned ShowCheckerHelpHidden : 1;
   unsigned ShowEnabledCheckerList : 1;
   unsigned ShowEnabledCheckerList : 1;
   unsigned ShowConfigOptionsList : 1;
   unsigned ShowConfigOptionsList : 1;
   unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;
   unsigned ShouldEmitErrorsOnInvalidConfigValue : 1;

+ 10 - 5
include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h

@@ -137,6 +137,7 @@ public:
     StringRef Desc;
     StringRef Desc;
     StringRef DocumentationUri;
     StringRef DocumentationUri;
     CmdLineOptionList CmdLineOptions;
     CmdLineOptionList CmdLineOptions;
+    bool IsHidden = false;
     StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
     StateFromCmdLine State = StateFromCmdLine::State_Unspecified;
 
 
     ConstCheckerInfoList Dependencies;
     ConstCheckerInfoList Dependencies;
@@ -150,9 +151,10 @@ public:
     }
     }
 
 
     CheckerInfo(InitializationFunction Fn, ShouldRegisterFunction sfn,
     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),
         : Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc),
-          DocumentationUri(DocsUri) {}
+          DocumentationUri(DocsUri), IsHidden(IsHidden) {}
 
 
     // Used for lower_bound.
     // Used for lower_bound.
     explicit CheckerInfo(StringRef FullName) : FullName(FullName) {}
     explicit CheckerInfo(StringRef FullName) : FullName(FullName) {}
@@ -190,16 +192,19 @@ public:
   /// Adds a checker to the registry. Use this non-templated overload when your
   /// Adds a checker to the registry. Use this non-templated overload when your
   /// checker requires custom initialization.
   /// checker requires custom initialization.
   void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn,
   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
   /// Adds a checker to the registry. Use this templated overload when your
   /// checker does not require any custom initialization.
   /// checker does not require any custom initialization.
   template <class T>
   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:
     // Avoid MSVC's Compiler Error C2276:
     // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx
     // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx
     addChecker(&CheckerRegistry::initializeManager<T>,
     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
   /// Makes the checker with the full name \p fullName depends on the checker

+ 1 - 0
lib/Frontend/CompilerInvocation.cpp

@@ -285,6 +285,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
   }
   }
 
 
   Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help);
   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.ShowConfigOptionsList = Args.hasArg(OPT_analyzer_config_help);
   Opts.ShowEnabledCheckerList = Args.hasArg(OPT_analyzer_list_enabled_checkers);
   Opts.ShowEnabledCheckerList = Args.hasArg(OPT_analyzer_list_enabled_checkers);
   Opts.ShouldEmitErrorsOnInvalidConfigValue =
   Opts.ShouldEmitErrorsOnInvalidConfigValue =

+ 9 - 7
lib/FrontendTool/ExecuteCompilerInvocation.cpp

@@ -234,28 +234,30 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
   }
   }
 
 
 #if CLANG_ENABLE_STATIC_ANALYZER
 #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(),
     ento::printCheckerHelp(llvm::outs(),
                            Clang->getFrontendOpts().Plugins,
                            Clang->getFrontendOpts().Plugins,
-                           *Clang->getAnalyzerOpts(),
+                           AnOpts,
                            Clang->getDiagnostics(),
                            Clang->getDiagnostics(),
                            Clang->getLangOpts());
                            Clang->getLangOpts());
     return true;
     return true;
   }
   }
 
 
   // Honor -analyzer-list-enabled-checkers.
   // Honor -analyzer-list-enabled-checkers.
-  if (Clang->getAnalyzerOpts()->ShowEnabledCheckerList) {
+  if (AnOpts.ShowEnabledCheckerList) {
     ento::printEnabledCheckerList(llvm::outs(),
     ento::printEnabledCheckerList(llvm::outs(),
                                   Clang->getFrontendOpts().Plugins,
                                   Clang->getFrontendOpts().Plugins,
-                                  *Clang->getAnalyzerOpts(),
+                                  AnOpts,
                                   Clang->getDiagnostics(),
                                   Clang->getDiagnostics(),
                                   Clang->getLangOpts());
                                   Clang->getLangOpts());
   }
   }
 
 
   // Honor -analyzer-config-help.
   // Honor -analyzer-config-help.
-  if (Clang->getAnalyzerOpts()->ShowConfigOptionsList) {
+  if (AnOpts.ShowConfigOptionsList) {
     ento::printAnalyzerConfigList(llvm::outs());
     ento::printAnalyzerConfigList(llvm::outs());
     return true;
     return true;
   }
   }

+ 1 - 1
lib/StaticAnalyzer/Core/AnalyzerOptions.cpp

@@ -33,7 +33,7 @@ std::vector<StringRef>
 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
 AnalyzerOptions::getRegisteredCheckers(bool IncludeExperimental /* = false */) {
   static const StringRef StaticAnalyzerChecks[] = {
   static const StringRef StaticAnalyzerChecks[] = {
 #define GET_CHECKERS
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   FULLNAME,
   FULLNAME,
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
 #undef CHECKER

+ 2 - 2
lib/StaticAnalyzer/Core/SarifDiagnostics.cpp

@@ -256,7 +256,7 @@ static json::Object createResult(const PathDiagnostic &Diag, json::Array &Files,
 static StringRef getRuleDescription(StringRef CheckName) {
 static StringRef getRuleDescription(StringRef CheckName) {
   return llvm::StringSwitch<StringRef>(CheckName)
   return llvm::StringSwitch<StringRef>(CheckName)
 #define GET_CHECKERS
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   .Case(FULLNAME, HELPTEXT)
   .Case(FULLNAME, HELPTEXT)
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
 #undef CHECKER
@@ -267,7 +267,7 @@ static StringRef getRuleDescription(StringRef CheckName) {
 static StringRef getRuleHelpURIStr(StringRef CheckName) {
 static StringRef getRuleHelpURIStr(StringRef CheckName) {
   return llvm::StringSwitch<StringRef>(CheckName)
   return llvm::StringSwitch<StringRef>(CheckName)
 #define GET_CHECKERS
 #define GET_CHECKERS
-#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
+#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN)                 \
   .Case(FULLNAME, DOC_URI)
   .Case(FULLNAME, DOC_URI)
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
 #undef CHECKER
 #undef CHECKER

+ 8 - 4
lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp

@@ -115,9 +115,9 @@ CheckerRegistry::CheckerRegistry(
 
 
   // Register builtin checkers.
   // Register builtin checkers.
 #define GET_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,       \
   addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT,       \
-             DOC_URI);
+             DOC_URI, IS_HIDDEN);
 
 
 #define GET_PACKAGES
 #define GET_PACKAGES
 #define PACKAGE(FULLNAME) addPackage(FULLNAME);
 #define PACKAGE(FULLNAME) addPackage(FULLNAME);
@@ -350,8 +350,9 @@ void CheckerRegistry::addPackageOption(StringRef OptionType,
 
 
 void CheckerRegistry::addChecker(InitializationFunction Rfn,
 void CheckerRegistry::addChecker(InitializationFunction Rfn,
                                  ShouldRegisterFunction Sfn, StringRef Name,
                                  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.
   // Record the presence of the checker in its packages.
   StringRef PackageName, LeafName;
   StringRef PackageName, LeafName;
@@ -421,6 +422,9 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
 
 
   const size_t InitialPad = 2;
   const size_t InitialPad = 2;
   for (const auto &Checker : Checkers) {
   for (const auto &Checker : Checkers) {
+    if (!AnOpts.ShowCheckerHelpHidden && Checker.IsHidden)
+      continue;
+
     Out.indent(InitialPad) << Checker.FullName;
     Out.indent(InitialPad) << Checker.FullName;
 
 
     int Pad = OptionFieldWidth - Checker.FullName.size();
     int Pad = OptionFieldWidth - Checker.FullName.size();

+ 11 - 0
test/Analysis/show-checker-list.c

@@ -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

+ 18 - 2
utils/TableGen/ClangSACheckersEmitter.cpp

@@ -110,6 +110,16 @@ static std::string getCheckerOptionType(const Record &R) {
   return "";
   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) {
 static void printChecker(llvm::raw_ostream &OS, const Record &R) {
     OS << "CHECKER(" << "\"";
     OS << "CHECKER(" << "\"";
     OS.write_escaped(getCheckerFullName(&R)) << "\", ";
     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.write_escaped(getStringValue(R, "HelpText")) << "\", ";
     OS << "\"";
     OS << "\"";
     OS.write_escaped(getCheckerDocs(R));
     OS.write_escaped(getCheckerDocs(R));
-    OS << "\"";
+    OS << "\", ";
+
+    if (!isHidden(&R))
+      OS << "false";
+    else
+      OS << "true";
+
+    OS << ")\n";
 }
 }
 
 
 namespace clang {
 namespace clang {
@@ -206,7 +223,6 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
         "\n";
         "\n";
   for (const Record *checker : checkers) {
   for (const Record *checker : checkers) {
     printChecker(OS, *checker);
     printChecker(OS, *checker);
-    OS << ")\n";
   }
   }
   OS << "\n"
   OS << "\n"
         "#endif // GET_CHECKERS\n"
         "#endif // GET_CHECKERS\n"