From eb1a2354d805e932fc261929406a2a191c3464df Mon Sep 17 00:00:00 2001 From: Kristof Umann Date: Thu, 23 May 2019 21:46:51 +0000 Subject: [PATCH] [analyzer] List checkers in 3 categories: released, alpha, developer Previously, the only way to display the list of available checkers was to invoke the analyzer with -analyzer-checker-help frontend flag. This however wasn't really great from a maintainer standpoint: users came across checkers meant strictly for development purposes that weren't to be tinkered with, or those that were still in development. This patch creates a clearer division in between these categories. From now on, we'll have 3 flags to display the list checkers. These lists are mutually exclusive and can be used in any combination (for example to display both stable and alpha checkers). -analyzer-checker-help: Displays the list for stable, production ready checkers. -analyzer-checker-help-alpha: Displays the list for in development checkers. Enabling is discouraged for non-development purposes. -analyzer-checker-help-developer: Modeling and debug checkers. Modeling checkers shouldn't be enabled/disabled by hand, and debug checkers shouldn't be touched by users. Differential Revision: https://reviews.llvm.org/D62093 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@361558 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/CC1Options.td | 11 +++- .../StaticAnalyzer/Checkers/CheckerBase.td | 4 +- .../StaticAnalyzer/Core/AnalyzerOptions.h | 16 ++--- lib/Frontend/CompilerInvocation.cpp | 4 +- .../ExecuteCompilerInvocation.cpp | 3 +- .../Frontend/CheckerRegistry.cpp | 31 +++++++-- test/Analysis/show-checker-list.c | 63 ++++++++++++++++--- 7 files changed, 107 insertions(+), 25 deletions(-) diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index f7da3746bd..7605b3fc13 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -130,9 +130,14 @@ 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_checker_help_alpha : Flag<["-"], "analyzer-checker-help-alpha">, + HelpText<"Display the list of in development analyzer checkers. These " + "are NOT considered safe, they are unstable and will emit incorrect " + "reports. Enable ONLY FOR DEVELOPMENT purposes">; + +def analyzer_checker_help_developer : Flag<["-"], "analyzer-checker-help-developer">, + HelpText<"Display the list of developer-only checkers such as modeling " + "and debug checkers">; def analyzer_config_help : Flag<["-"], "analyzer-config-help">, HelpText<"Display the list of -analyzer-config options">; diff --git a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td index c381d4b13e..3c7c6fe9b2 100644 --- a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td +++ b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td @@ -111,6 +111,6 @@ class Dependencies Deps = []> { list 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. +/// Marks a checker or a package hidden. Hidden entries are meant for developers +/// only, and aren't exposed to end users. class Hidden { bit Hidden = 1; } diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 6a54e157e8..1c45ffdff8 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -220,7 +220,8 @@ public: unsigned DisableAllChecks : 1; unsigned ShowCheckerHelp : 1; - unsigned ShowCheckerHelpHidden : 1; + unsigned ShowCheckerHelpAlpha : 1; + unsigned ShowCheckerHelpDeveloper : 1; unsigned ShowEnabledCheckerList : 1; unsigned ShowCheckerOptionList : 1; unsigned ShowConfigOptionsList : 1; @@ -285,12 +286,13 @@ public: AnalyzerOptions() : DisableAllChecks(false), ShowCheckerHelp(false), - ShowCheckerHelpHidden(false), ShowEnabledCheckerList(false), - ShowCheckerOptionList(false), ShowConfigOptionsList(false), - AnalyzeAll(false), AnalyzerDisplayProgress(false), - AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false), - TrimGraph(false), visualizeExplodedGraphWithGraphViz(false), - UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false) { + ShowCheckerHelpAlpha(false), ShowCheckerHelpDeveloper(false), + ShowEnabledCheckerList(false), ShowCheckerOptionList(false), + ShowConfigOptionsList(false), AnalyzeAll(false), + AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false), + eagerlyAssumeBinOpBifurcation(false), TrimGraph(false), + visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false), + PrintStats(false), NoRetryExhausted(false) { llvm::sort(AnalyzerConfigCmdFlags); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 877e70b661..34693af8f4 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -285,7 +285,9 @@ 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.ShowCheckerHelpAlpha = Args.hasArg(OPT_analyzer_checker_help_alpha); + Opts.ShowCheckerHelpDeveloper = + Args.hasArg(OPT_analyzer_checker_help_developer); Opts.ShowCheckerOptionList = Args.hasArg(OPT_analyzer_checker_option_help); Opts.ShowConfigOptionsList = Args.hasArg(OPT_analyzer_config_help); Opts.ShowEnabledCheckerList = Args.hasArg(OPT_analyzer_list_enabled_checkers); diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 27690be777..ea720c83c2 100644 --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -238,7 +238,8 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { AnalyzerOptions &AnOpts = *Clang->getAnalyzerOpts(); // Honor -analyzer-checker-help and -analyzer-checker-help-hidden. - if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpHidden) { + if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpAlpha || + AnOpts.ShowCheckerHelpDeveloper) { ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins, AnOpts, diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index d405933ca6..5f96389e59 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -514,13 +514,36 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, } const size_t InitialPad = 2; - for (const auto &Checker : Checkers) { - if (!AnOpts.ShowCheckerHelpHidden && Checker.IsHidden) - continue; - AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Checker.Desc}, + auto Print = [=](llvm::raw_ostream &Out, const CheckerInfo &Checker, + StringRef Description) { + AnalyzerOptions::printFormattedEntry(Out, {Checker.FullName, Description}, InitialPad, OptionFieldWidth); Out << '\n'; + }; + + for (const auto &Checker : Checkers) { + // The order of this if branches is significant, we wouldn't like to display + // developer checkers even in the alpha output. For example, + // alpha.cplusplus.IteratorModeling is a modeling checker, hence it's hidden + // by default, and users (even when the user is a developer of an alpha + // checker) shouldn't normally tinker with whether they should be enabled. + + if (Checker.IsHidden) { + if (AnOpts.ShowCheckerHelpDeveloper) + Print(Out, Checker, Checker.Desc); + continue; + } + + if (Checker.FullName.startswith("alpha")) { + if (AnOpts.ShowCheckerHelpAlpha) + Print(Out, Checker, + ("(Enable only for development!) " + Checker.Desc).str()); + continue; + } + + if (AnOpts.ShowCheckerHelp) + Print(Out, Checker, Checker.Desc); } } diff --git a/test/Analysis/show-checker-list.c b/test/Analysis/show-checker-list.c index 83ed6e4897..3d354c338b 100644 --- a/test/Analysis/show-checker-list.c +++ b/test/Analysis/show-checker-list.c @@ -1,11 +1,60 @@ // RUN: %clang_cc1 -analyzer-checker-help \ -// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-STABLE -// RUN: %clang_cc1 -analyzer-checker-help-hidden \ -// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-HIDDEN +// RUN: %clang_cc1 -analyzer-checker-help-alpha \ +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-ALPHA -// CHECK: core.DivideZero -// CHECK-HIDDEN: core.DivideZero +// RUN: %clang_cc1 -analyzer-checker-help-developer \ +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-DEVELOPER -// CHECK-NOT: unix.DynamicMemoryModeling -// CHECK-HIDDEN: unix.DynamicMemoryModeling +// RUN: %clang_cc1 -analyzer-checker-help-developer \ +// RUN: -analyzer-checker-help-alpha \ +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-DEVELOPER-ALPHA + +// RUN: %clang_cc1 -analyzer-checker-help \ +// RUN: -analyzer-checker-help-alpha \ +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-STABLE-ALPHA + +// RUN: %clang_cc1 -analyzer-checker-help \ +// RUN: -analyzer-checker-help-developer \ +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-STABLE-DEVELOPER + +// RUN: %clang_cc1 -analyzer-checker-help \ +// RUN: -analyzer-checker-help-alpha \ +// RUN: -analyzer-checker-help-developer \ +// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-STABLE-ALPHA-DEVELOPER + +// CHECK-STABLE-NOT: alpha.unix.Chroot +// CHECK-DEVELOPER-NOT: alpha.unix.Chroot +// CHECK-ALPHA: alpha.unix.Chroot + +// Note that alpha.cplusplus.IteratorModeling is not only an alpha, but also a +// hidden checker. In this case, we'd only like to see it in the developer list. +// CHECK-ALPHA-NOT: alpha.cplusplus.IteratorModeling +// CHECK-DEVELOPER: alpha.cplusplus.IteratorModeling + +// CHECK-STABLE: core.DivideZero +// CHECK-DEVELOPER-NOT: core.DivideZero +// CHECK-ALPHA-NOT: core.DivideZero + +// CHECK-STABLE-NOT: debug.ConfigDumper +// CHECK-DEVELOPER: debug.ConfigDumper +// CHECK-ALPHA-NOT: debug.ConfigDumper + + +// CHECK-STABLE-ALPHA: alpha.unix.Chroot +// CHECK-DEVELOPER-ALPHA: alpha.unix.Chroot +// CHECK-STABLE-DEVELOPER-NOT: alpha.unix.Chroot + +// CHECK-STABLE-ALPHA: core.DivideZero +// CHECK-DEVELOPER-ALPHA-NOT: core.DivideZero +// CHECK-STABLE-DEVELOPER: core.DivideZero + +// CHECK-STABLE-ALPHA-NOT: debug.ConfigDumper +// CHECK-DEVELOPER-ALPHA: debug.ConfigDumper +// CHECK-STABLE-DEVELOPER: debug.ConfigDumper + + +// CHECK-STABLE-ALPHA-DEVELOPER: alpha.unix.Chroot +// CHECK-STABLE-ALPHA-DEVELOPER: core.DivideZero +// CHECK-STABLE-ALPHA-DEVELOPER: debug.ConfigDumper -- 2.40.0