diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -14,6 +14,7 @@ #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" @@ -121,14 +122,36 @@ }; class CheckerManager { - ASTContext &Context; + ASTContext *Context; const LangOptions LangOpts; AnalyzerOptions &AOptions; CheckerNameRef CurrentCheckerName; + DiagnosticsEngine &Diags; + std::unique_ptr Registry; public: + // These constructors are defined in the Frontend library, because + // CheckerRegistry, a crucial component of the initialization is in there. + // CheckerRegistry cannot be moved to the Core library, because the checker + // registration functions are defined in the Checkers library, and the library + // dependencies look like this: Core -> Checkers -> Frontend. + + CheckerManager( + ASTContext &Context, AnalyzerOptions &AOptions, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns); + + /// 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); ~CheckerManager(); @@ -141,7 +164,12 @@ 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 --- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -55,7 +55,7 @@ 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 --- /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 --- 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 --- 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 @@ 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 @@ 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 @@ 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 @@ /// 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 @@ 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 @@ 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 @@ 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 --- a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -51,22 +51,7 @@ 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 --- 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 @@ // 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 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -64,10 +64,9 @@ 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; } //===----------------------------------------------------------------------===// @@ -903,8 +902,3 @@ Checkers.push_back(Info.CheckFn); return Checkers; } - -CheckerManager::~CheckerManager() { - for (const auto &CheckerDtor : CheckerDtors) - CheckerDtor(); -} diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp --- 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 "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" @@ -209,8 +208,8 @@ 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 rename from clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp rename to clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp --- 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 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -6,14 +6,16 @@ add_clang_library(clangStaticAnalyzerFrontend AnalysisConsumer.cpp - CheckerRegistration.cpp + AnalyzerHelpFlags.cpp CheckerRegistry.cpp + CreateCheckerManager.cpp FrontendActions.cpp ModelConsumer.cpp ModelInjector.cpp LINK_LIBS clangAST + clangASTMatchers clangAnalysis clangBasic clangCrossTU diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -109,9 +109,9 @@ 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 @@ 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 @@ : 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 @@ 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 @@ 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 @@ CheckerIt->Dependencies.emplace_back(&*DependencyIt); } - - Dependencies.clear(); } void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { @@ -378,14 +381,12 @@ 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::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 @@ } } +//===----------------------------------------------------------------------===// +// Printing functions. +//===----------------------------------------------------------------------===// + void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, size_t MaxNameChars) const { // FIXME: Print available packages. @@ -556,9 +558,6 @@ } 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'; } diff --git a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp @@ -0,0 +1,52 @@ +//===- CheckerManager.h - Static Analyzer Checker Manager -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Manager. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include + +namespace clang { +namespace ento { + +CheckerManager::CheckerManager( + ASTContext &Context, AnalyzerOptions &AOptions, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns) + : Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions), + Diags(Context.getDiagnostics()), + Registry( + std::make_unique(plugins, Context.getDiagnostics(), + AOptions, checkerRegistrationFns)) { + Registry->initializeRegistry(*this); + Registry->initializeManager(*this); + finishedCheckerRegistration(); +} + +/// 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::CheckerManager(AnalyzerOptions &AOptions, + const LangOptions &LangOpts, + DiagnosticsEngine &Diags, + ArrayRef plugins) + : LangOpts(LangOpts), AOptions(AOptions), Diags(Diags), + Registry(std::make_unique(plugins, Diags, AOptions)) { + Registry->initializeRegistry(*this); +} + +CheckerManager::~CheckerManager() { + for (const auto &CheckerDtor : CheckerDtors) + CheckerDtor(); +} + +} // namespace ento +} // namespace clang