From 57b8a407493c34c3680e7e1e4cb82e097f43744a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Krist=C3=B3f=20Umann?= Date: Fri, 28 Feb 2020 15:07:50 +0100 Subject: [PATCH] [analyzer][NFC] Tie CheckerRegistry to CheckerManager, allow CheckerManager to be constructed for non-analysis purposes Its been a while since my CheckerRegistry related patches landed, allow me to refresh your memory: During compilation, TblGen turns clang/include/clang/StaticAnalyzer/Checkers/Checkers.td into (build directory)/tools/clang/include/clang/StaticAnalyzer/Checkers/Checkers.inc. This is a file that contains the full name of the checkers, their options, etc. The class that is responsible for parsing this file is CheckerRegistry. The job of this class is to establish what checkers are available for the analyzer (even from plugins and statically linked but non-tblgen generated files!), and calculate which ones should be turned on according to the analyzer's invocation. CheckerManager is the class that is responsible for the construction and storage of checkers. This process works by first creating a CheckerRegistry object, and passing itself to CheckerRegistry::initializeManager(CheckerManager&), which will call the checker registry functions (for example registerMallocChecker) on it. The big problem here is that these two classes lie in two different libraries, so their interaction is pretty awkward. This used to be far worse, but I refactored much of it, which made things better but nowhere near perfect. --- This patch changes how the above mentioned two classes interact. CheckerRegistry is mainly used by CheckerManager, and they are so intertwined, it makes a lot of sense to turn in into a field, instead of a one-time local variable. This has additional benefits: much of the information that CheckerRegistry conveniently holds is no longer thrown away right after the analyzer's initialization, and opens the possibility to pass CheckerManager in the shouldRegister* function rather then LangOptions (D75271). There are a few problems with this. CheckerManager isn't the only user, when we honor help flags like -analyzer-checker-help, we only have access to a CompilerInstance class, that is before the point of parsing the AST. CheckerManager makes little sense without ASTContext, so I made some changes and added new constructors to make it constructible for the use of help flags. Differential Revision: https://reviews.llvm.org/D75360 --- .../clang/StaticAnalyzer/Core/CheckerManager.h | 42 ++++++++- .../StaticAnalyzer/Frontend/AnalysisConsumer.h | 2 +- .../StaticAnalyzer/Frontend/AnalyzerHelpFlags.h | 30 ++++++ .../StaticAnalyzer/Frontend/CheckerRegistration.h | 38 -------- .../StaticAnalyzer/Frontend/CheckerRegistry.h | 38 +++++--- .../StaticAnalyzer/Frontend/FrontendActions.h | 17 +--- .../lib/FrontendTool/ExecuteCompilerInvocation.cpp | 20 +--- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp | 7 +- .../StaticAnalyzer/Frontend/AnalysisConsumer.cpp | 5 +- ...eckerRegistration.cpp => AnalyzerHelpFlags.cpp} | 60 +++++------- clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt | 2 +- .../StaticAnalyzer/Frontend/CheckerRegistry.cpp | 101 ++++++++++----------- 12 files changed, 176 insertions(+), 186 deletions(-) create mode 100644 clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h delete mode 100644 clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h rename clang/lib/StaticAnalyzer/Frontend/{CheckerRegistration.cpp => AnalyzerHelpFlags.cpp} (69%) diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 4454d76..6faf0f2 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -14,9 +14,11 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H #include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" @@ -40,7 +42,6 @@ class BugReporter; class CallEvent; class CheckerBase; class CheckerContext; -class CheckerRegistry; class ExplodedGraph; class ExplodedNode; class ExplodedNodeSet; @@ -121,14 +122,42 @@ enum class ObjCMessageVisitKind { }; class CheckerManager { - ASTContext &Context; + ASTContext *Context; const LangOptions LangOpts; AnalyzerOptions &AOptions; CheckerNameRef CurrentCheckerName; + DiagnosticsEngine &Diags; + CheckerRegistry Registry; public: + CheckerManager( + ASTContext &Context, AnalyzerOptions &AOptions, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns) + : Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions), + Diags(Context.getDiagnostics()), + Registry(plugins, Context.getDiagnostics(), AOptions, + checkerRegistrationFns) { + Registry.initializeRegistry(*this); + Registry.initializeManager(*this); + finishedCheckerRegistration(); + } + + /// Constructs a CheckerManager that ignores all non TblGen-generated + /// checkers. Useful for unit testing, unless the checker infrastructure + /// itself is tested. CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions) - : Context(Context), LangOpts(Context.getLangOpts()), AOptions(AOptions) {} + : CheckerManager(Context, AOptions, {}, {}) {} + + /// Constructs a CheckerManager without requiring an AST. No checker + /// registration will take place. Only useful for retrieving the + /// CheckerRegistry and print for help flags where the AST is unavalaible. + CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts, + DiagnosticsEngine &Diags, ArrayRef plugins) + : LangOpts(LangOpts), AOptions(AOptions), Diags(Diags), + Registry(plugins, Diags, AOptions) { + Registry.initializeRegistry(*this); + } ~CheckerManager(); @@ -141,7 +170,12 @@ public: const LangOptions &getLangOpts() const { return LangOpts; } AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } - ASTContext &getASTContext() const { return Context; } + const CheckerRegistry &getCheckerRegistry() const { return Registry; } + DiagnosticsEngine &getDiagnostics() const { return Diags; } + ASTContext &getASTContext() const { + assert(Context); + return *Context; + } /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h index 2d24e6a..bcc29a6 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -55,7 +55,7 @@ public: std::unique_ptr CreateAnalysisConsumer(CompilerInstance &CI); -} // end GR namespace +} // namespace ento } // end clang namespace diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h new file mode 100644 index 0000000..a30c241 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h @@ -0,0 +1,30 @@ +//===-- AnalyzerHelpFlags.h - Query functions for --help flags --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace clang { + +class CompilerInstance; + +namespace ento { + +void printCheckerHelp(llvm::raw_ostream &OS, CompilerInstance &CI); +void printEnabledCheckerList(llvm::raw_ostream &OS, CompilerInstance &CI); +void printAnalyzerConfigList(llvm::raw_ostream &OS); +void printCheckerConfigList(llvm::raw_ostream &OS, CompilerInstance &CI); + +} // namespace ento +} // namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h deleted file mode 100644 index 52a5344..0000000 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ /dev/null @@ -1,38 +0,0 @@ -//===-- CheckerRegistration.h - Checker Registration Function ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H -#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H - -#include "clang/AST/ASTContext.h" -#include "clang/Basic/LLVM.h" -#include -#include -#include - -namespace clang { - class AnalyzerOptions; - class LangOptions; - class DiagnosticsEngine; - -namespace ento { - class CheckerManager; - class CheckerRegistry; - - std::unique_ptr createCheckerManager( - ASTContext &context, - AnalyzerOptions &opts, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns, - DiagnosticsEngine &diags); - -} // end ento namespace - -} // end namespace clang - -#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index 8830542..dde2409 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -10,7 +10,6 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H #include "clang/Basic/LLVM.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -74,6 +73,8 @@ class LangOptions; namespace ento { +class CheckerManager; + /// Manages a set of available checkers for running a static analysis. /// The checkers are organized into packages by full name, where including /// a package will recursively include all subpackages and checkers within it. @@ -83,10 +84,15 @@ namespace ento { class CheckerRegistry { public: CheckerRegistry(ArrayRef plugins, DiagnosticsEngine &diags, - AnalyzerOptions &AnOpts, const LangOptions &LangOpts, + AnalyzerOptions &AnOpts, ArrayRef> checkerRegistrationFns = {}); + /// Collects all enabled checkers in the field EnabledCheckers. It preserves + /// the order of insertion, as dependencies have to be enabled before the + /// checkers that depend on them. + void initializeRegistry(const CheckerManager &Mgr); + /// Initialization functions perform any necessary setup for a checker. /// They should include a call to CheckerManager::registerChecker. using InitializationFunction = void (*)(CheckerManager &); @@ -205,14 +211,20 @@ public: using PackageInfoList = llvm::SmallVector; - template static void addToCheckerMgr(CheckerManager &mgr) { - mgr.registerChecker(); +private: + /// Default initialization function for checkers -- since CheckerManager + /// includes this header, we need to make it a template parameter, and since + /// the checker must be a template parameter as well, we can't put this in the + /// cpp file. + template static void initializeManager(MGR &mgr) { + mgr.template registerChecker(); } - static bool returnTrue(const LangOptions &LO) { + template static bool returnTrue(const LangOptions &) { return true; } +public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, @@ -221,13 +233,16 @@ public: /// Adds a checker to the registry. Use this templated overload when your /// checker does not require any custom initialization. + /// This function isn't really needed and probably causes more headaches than + /// the tiny convenience that it provides, but external plugins might use it, + /// and there isn't a strong incentive to remove it. template 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::addToCheckerMgr, - &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden); + addChecker(&initializeManager, &returnTrue, FullName, + Desc, DocsUri, IsHidden); } /// Makes the checker with the full name \p fullName depends on the checker @@ -263,7 +278,7 @@ public: void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, - bool IsHidden = false); + bool IsHidden = false); // FIXME: This *really* should be added to the frontend flag descriptions. /// Initializes a CheckerManager by calling the initialization functions for @@ -283,11 +298,6 @@ public: void printCheckerOptionList(raw_ostream &Out) const; private: - /// Collect all enabled checkers. The returned container preserves the order - /// of insertion, as dependencies have to be enabled before the checkers that - /// depend on them. - CheckerInfoSet getEnabledCheckers() const; - /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to. /// For example, it'll return the checkers for the core package, if /// \p CmdLineArg is "core". @@ -314,7 +324,7 @@ private: DiagnosticsEngine &Diags; AnalyzerOptions &AnOpts; - const LangOptions &LangOpts; + CheckerInfoSet EnabledCheckers; }; } // namespace ento diff --git a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index 878b65a..6b6a395 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -51,22 +51,7 @@ private: llvm::StringMap &Bodies; }; -void printCheckerHelp(raw_ostream &OS, - ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); -void printEnabledCheckerList(raw_ostream &OS, ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); -void printAnalyzerConfigList(raw_ostream &OS); -void printCheckerConfigList(raw_ostream &OS, ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); - -} // end GR namespace +} // namespace ento } // end namespace clang diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 70735ab..ab7a1e3 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -23,6 +23,7 @@ #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" @@ -243,35 +244,24 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { // 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.ShowCheckerHelpAlpha || AnOpts.ShowCheckerHelpDeveloper) { - ento::printCheckerHelp(llvm::outs(), - Clang->getFrontendOpts().Plugins, - AnOpts, - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printCheckerHelp(llvm::outs(), *Clang); return true; } // Honor -analyzer-checker-option-help. if (AnOpts.ShowCheckerOptionList || AnOpts.ShowCheckerOptionAlphaList || AnOpts.ShowCheckerOptionDeveloperList) { - ento::printCheckerConfigList(llvm::outs(), - Clang->getFrontendOpts().Plugins, - *Clang->getAnalyzerOpts(), - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printCheckerConfigList(llvm::outs(), *Clang); return true; } // Honor -analyzer-list-enabled-checkers. if (AnOpts.ShowEnabledCheckerList) { - ento::printEnabledCheckerList(llvm::outs(), - Clang->getFrontendOpts().Plugins, - AnOpts, - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printEnabledCheckerList(llvm::outs(), *Clang); return true; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index ce5e4a4..081a310 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -64,10 +64,9 @@ void CheckerManager::reportInvalidCheckerOptionValue( const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const { - Context.getDiagnostics() - .Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() - << ExpectedValueDesc; + getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) + << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() + << ExpectedValueDesc; } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index a908aed..1ef6c47 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -33,7 +33,6 @@ #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" @@ -348,8 +347,8 @@ public: void Initialize(ASTContext &Context) override { Ctx = &Context; - checkerMgr = createCheckerManager( - *Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.getDiagnostics()); + checkerMgr = std::make_unique(*Ctx, *Opts, Plugins, + CheckerRegistrationFns); Mgr = std::make_unique(*Ctx, PP, PathConsumers, CreateStoreMgr, CreateConstraintMgr, diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp similarity index 69% rename from clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp rename to clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp index f4f06e3..d589e69 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" +#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -24,53 +25,34 @@ using namespace clang; using namespace ento; -std::unique_ptr ento::createCheckerManager( - ASTContext &context, - AnalyzerOptions &opts, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns, - DiagnosticsEngine &diags) { - auto checkerMgr = std::make_unique(context, opts); - - CheckerRegistry allCheckers(plugins, diags, opts, context.getLangOpts(), - checkerRegistrationFns); - - allCheckers.initializeManager(*checkerMgr); - allCheckers.validateCheckerOptions(); - checkerMgr->finishedCheckerRegistration(); - - return checkerMgr; -} - -void ento::printCheckerHelp(raw_ostream &out, ArrayRef plugins, - AnalyzerOptions &anopts, - DiagnosticsEngine &diags, - const LangOptions &langOpts) { +void ento::printCheckerHelp(raw_ostream &out, CompilerInstance &CI) { out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n"; out << "USAGE: -analyzer-checker \n\n"; - CheckerRegistry(plugins, diags, anopts, langOpts) - .printCheckerWithDescList(out); + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printCheckerWithDescList(out); } -void ento::printEnabledCheckerList(raw_ostream &out, - ArrayRef plugins, - AnalyzerOptions &anopts, - DiagnosticsEngine &diags, - const LangOptions &langOpts) { +void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) { out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n"; - CheckerRegistry(plugins, diags, anopts, langOpts) - .printEnabledCheckerList(out); + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printEnabledCheckerList(out); } -void ento::printCheckerConfigList(raw_ostream &OS, - ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts) { - CheckerRegistry(plugins, diags, opts, LangOpts) - .printCheckerOptionList(OS); +void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) { + + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printCheckerOptionList(out); } void ento::printAnalyzerConfigList(raw_ostream &out) { diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 6f1151a..055878a 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -6,7 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangStaticAnalyzerFrontend AnalysisConsumer.cpp - CheckerRegistration.cpp + AnalyzerHelpFlags.cpp CheckerRegistry.cpp FrontendActions.cpp ModelConsumer.cpp diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index 4af2044..db09ca4e 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -109,9 +109,9 @@ CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) { CheckerRegistry::CheckerRegistry( ArrayRef Plugins, DiagnosticsEngine &Diags, - AnalyzerOptions &AnOpts, const LangOptions &LangOpts, + AnalyzerOptions &AnOpts, ArrayRef> CheckerRegistrationFns) - : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) { + : Diags(Diags), AnOpts(AnOpts) { // Register builtin checkers. #define GET_CHECKERS @@ -179,12 +179,16 @@ CheckerRegistry::CheckerRegistry( addDependency(FULLNAME, DEPENDENCY); #define GET_CHECKER_OPTIONS -#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ - addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); +#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ + DEVELOPMENT_STATUS, IS_HIDDEN) \ + addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ + DEVELOPMENT_STATUS, IS_HIDDEN); #define GET_PACKAGE_OPTIONS -#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ - addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); +#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ + DEVELOPMENT_STATUS, IS_HIDDEN) \ + addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ + DEVELOPMENT_STATUS, IS_HIDDEN); #include "clang/StaticAnalyzer/Checkers/Checkers.inc" #undef CHECKER_DEPENDENCY @@ -213,24 +217,53 @@ CheckerRegistry::CheckerRegistry( : StateFromCmdLine::State_Disabled; } } + validateCheckerOptions(); +} + +/// Collects dependenies in \p enabledCheckers. Return None on failure. +LLVM_NODISCARD +static llvm::Optional +collectDependencies(const CheckerRegistry::CheckerInfo &checker, + const CheckerManager &Mgr); + +void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { + for (const CheckerInfo &Checker : Checkers) { + if (!Checker.isEnabled(Mgr.getLangOpts())) + continue; + + // Recursively enable its dependencies. + llvm::Optional Deps = collectDependencies(Checker, Mgr); + + if (!Deps) { + // If we failed to enable any of the dependencies, don't enable this + // checker. + continue; + } + + // Note that set_union also preserves the order of insertion. + EnabledCheckers.set_union(*Deps); + + // Enable the checker. + EnabledCheckers.insert(&Checker); + } } /// Collects dependencies in \p ret, returns false on failure. static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const LangOptions &LO, + const CheckerManager &Mgr, CheckerRegistry::CheckerInfoSet &Ret); /// Collects dependenies in \p enabledCheckers. Return None on failure. LLVM_NODISCARD static llvm::Optional collectDependencies(const CheckerRegistry::CheckerInfo &checker, - const LangOptions &LO) { + const CheckerManager &Mgr) { CheckerRegistry::CheckerInfoSet Ret; // Add dependencies to the enabled checkers only if all of them can be // enabled. - if (!collectDependenciesImpl(checker.Dependencies, LO, Ret)) + if (!collectDependenciesImpl(checker.Dependencies, Mgr, Ret)) return None; return Ret; @@ -238,16 +271,16 @@ collectDependencies(const CheckerRegistry::CheckerInfo &checker, static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const LangOptions &LO, + const CheckerManager &Mgr, CheckerRegistry::CheckerInfoSet &Ret) { for (const CheckerRegistry::CheckerInfo *Dependency : Deps) { - if (Dependency->isDisabled(LO)) + if (Dependency->isDisabled(Mgr.getLangOpts())) return false; // Collect dependencies recursively. - if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret)) + if (!collectDependenciesImpl(Dependency->Dependencies, Mgr, Ret)) return false; Ret.insert(Dependency); @@ -256,34 +289,6 @@ collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, return true; } -CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const { - - CheckerInfoSet EnabledCheckers; - - for (const CheckerInfo &Checker : Checkers) { - if (!Checker.isEnabled(LangOpts)) - continue; - - // Recursively enable its dependencies. - llvm::Optional Deps = - collectDependencies(Checker, LangOpts); - - if (!Deps) { - // If we failed to enable any of the dependencies, don't enable this - // checker. - continue; - } - - // Note that set_union also preserves the order of insertion. - EnabledCheckers.set_union(*Deps); - - // Enable the checker. - EnabledCheckers.insert(&Checker); - } - - return EnabledCheckers; -} - void CheckerRegistry::resolveDependencies() { for (const std::pair &Entry : Dependencies) { auto CheckerIt = binaryFind(Checkers, Entry.first); @@ -298,8 +303,6 @@ void CheckerRegistry::resolveDependencies() { CheckerIt->Dependencies.emplace_back(&*DependencyIt); } - - Dependencies.clear(); } void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { @@ -378,14 +381,12 @@ void CheckerRegistry::resolveCheckerAndPackageOptions() { insertOptionToCollection(CheckerOptEntry.first, Checkers, CheckerOptEntry.second, AnOpts, Diags); } - CheckerOptions.clear(); for (const std::pair &PackageOptEntry : PackageOptions) { insertOptionToCollection(PackageOptEntry.first, Packages, PackageOptEntry.second, AnOpts, Diags); } - PackageOptions.clear(); } void CheckerRegistry::addPackage(StringRef FullName) { @@ -432,11 +433,8 @@ void CheckerRegistry::addCheckerOption(StringRef OptionType, } void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { - // Collect checkers enabled by the options. - CheckerInfoSet enabledCheckers = getEnabledCheckers(); - // Initialize the CheckerManager with all enabled checkers. - for (const auto *Checker : enabledCheckers) { + for (const auto *Checker : EnabledCheckers) { CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); Checker->Initialize(CheckerMgr); } @@ -505,6 +503,10 @@ void CheckerRegistry::validateCheckerOptions() const { } } +//===----------------------------------------------------------------------===// +// Printing functions. +//===----------------------------------------------------------------------===// + void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, size_t MaxNameChars) const { // FIXME: Print available packages. @@ -556,9 +558,6 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, } void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const { - // Collect checkers enabled by the options. - CheckerInfoSet EnabledCheckers = getEnabledCheckers(); - for (const auto *i : EnabledCheckers) Out << i->FullName << '\n'; } -- 2.7.4