aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorKirstóf Umann <dkszelethus@gmail.com>2020-06-18 21:40:43 +0200
committerKirstóf Umann <dkszelethus@gmail.com>2020-07-04 12:31:51 +0200
commitb6cbe6cb0399d4671e5384dcc326af56bc6bd122 (patch)
treeb1de591e1e48eed82b4e47b652599506d001a579 /clang/lib
parent4f2e7f6fb1f212a84d1647920963b66b21175a24 (diff)
downloadllvm-b6cbe6cb0399d4671e5384dcc326af56bc6bd122.zip
llvm-b6cbe6cb0399d4671e5384dcc326af56bc6bd122.tar.gz
llvm-b6cbe6cb0399d4671e5384dcc326af56bc6bd122.tar.bz2
[analyzer][NFC] Move the data structures from CheckerRegistry to the Core library
If you were around the analyzer for a while now, you must've seen a lot of patches that awkwardly puts code from one library to the other: * D75360 moves the constructors of CheckerManager, which lies in the Core library, to the Frontend library. Most the patch itself was a struggle along the library lines. * D78126 had to be reverted because dependency information would be utilized in the Core library, but the actual data lied in the frontend. D78126#inline-751477 touches on this issue as well. This stems from the often mentioned problem: the Frontend library depends on Core and Checkers, Checkers depends on Core. The checker registry functions (`registerMallocChecker`, etc) lie in the Checkers library in order to keep each checker its own module. What this implies is that checker registration cannot take place in the Core, but the Core might still want to use the data that results from it (which checker/package is enabled, dependencies, etc). D54436 was the patch that initiated this. Back in the days when CheckerRegistry was super dumb and buggy, it implemented a non-documented solution to this problem by keeping the data in the Core, and leaving the logic in the Frontend. At the time when the patch landed, the merger to the Frontend made sense, because the data hadn't been utilized anywhere, and the whole workaround without any documentation made little sense to me. So, lets put the data back where it belongs, in the Core library. This patch introduces `CheckerRegistryData`, and turns `CheckerRegistry` into a short lived wrapper around this data that implements the logic of checker registration. The data is tied to CheckerManager because it is required to parse it. Side note: I can't help but cringe at the fact how ridiculously awkward the library lines are. I feel like I'm thinking too much inside the box, but I guess this is just the price of keeping the checkers so modularized. Differential Revision: https://reviews.llvm.org/D82585
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/StaticAnalyzer/Core/CMakeLists.txt1
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp233
-rw-r--r--clang/lib/StaticAnalyzer/Core/Environment.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp382
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp15
6 files changed, 323 insertions, 328 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
index 192185b..f2329ae 100644
--- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt
@@ -16,6 +16,7 @@ add_clang_library(clangStaticAnalyzerCore
CheckerContext.cpp
CheckerHelpers.cpp
CheckerManager.cpp
+ CheckerRegistryData.cpp
CommonBugCategories.cpp
ConstraintManager.cpp
CoreEngine.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
new file mode 100644
index 0000000..7d5bfb2
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
@@ -0,0 +1,233 @@
+//===- CheckerRegistry.h - Maintains all available checkers -----*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/CheckerRegistryData.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "llvm/ADT/Twine.h"
+#include <map>
+
+using namespace clang;
+using namespace ento;
+
+//===----------------------------------------------------------------------===//
+// Methods of CmdLineOption, PackageInfo and CheckerInfo.
+//===----------------------------------------------------------------------===//
+
+LLVM_DUMP_METHOD void
+CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
+ // The description can be just checked in Checkers.inc, the point here is to
+ // debug whether we succeeded in parsing it.
+ Out << OptionName << " (" << OptionType << ", "
+ << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
+ << DefaultValStr;
+}
+
+static StringRef toString(StateFromCmdLine Kind) {
+ switch (Kind) {
+ case StateFromCmdLine::State_Disabled:
+ return "Disabled";
+ case StateFromCmdLine::State_Enabled:
+ return "Enabled";
+ case StateFromCmdLine::State_Unspecified:
+ return "Unspecified";
+ }
+ llvm_unreachable("Unhandled StateFromCmdLine enum");
+}
+
+LLVM_DUMP_METHOD void CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
+ // The description can be just checked in Checkers.inc, the point here is to
+ // debug whether we succeeded in parsing it. Same with documentation uri.
+ Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
+ << ")\n";
+ Out << " Options:\n";
+ for (const CmdLineOption &Option : CmdLineOptions) {
+ Out << " ";
+ Option.dumpToStream(Out);
+ Out << '\n';
+ }
+ Out << " Dependencies:\n";
+ for (const CheckerInfo *Dependency : Dependencies) {
+ Out << " " << Dependency->FullName << '\n';
+ }
+ Out << " Weak dependencies:\n";
+ for (const CheckerInfo *Dependency : WeakDependencies) {
+ Out << " " << Dependency->FullName << '\n';
+ }
+}
+
+LLVM_DUMP_METHOD void PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
+ Out << FullName << "\n";
+ Out << " Options:\n";
+ for (const CmdLineOption &Option : CmdLineOptions) {
+ Out << " ";
+ Option.dumpToStream(Out);
+ Out << '\n';
+ }
+}
+
+static constexpr char PackageSeparator = '.';
+
+static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
+ // Does the checker's full name have the package as a prefix?
+ if (!Checker.FullName.startswith(PackageName))
+ return false;
+
+ // Is the package actually just the name of a specific checker?
+ if (Checker.FullName.size() == PackageName.size())
+ return true;
+
+ // Is the checker in the package (or a subpackage)?
+ if (Checker.FullName[PackageName.size()] == PackageSeparator)
+ return true;
+
+ return false;
+}
+
+CheckerInfoListRange
+CheckerRegistryData::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
+ auto It = checker_registry::binaryFind(Checkers, CmdLineArg);
+
+ if (!isInPackage(*It, CmdLineArg))
+ return {Checkers.end(), Checkers.end()};
+
+ // See how large the package is.
+ // If the package doesn't exist, assume the option refers to a single
+ // checker.
+ size_t Size = 1;
+ llvm::StringMap<size_t>::const_iterator PackageSize =
+ PackageSizes.find(CmdLineArg);
+
+ if (PackageSize != PackageSizes.end())
+ Size = PackageSize->getValue();
+
+ return {It, It + Size};
+}
+//===----------------------------------------------------------------------===//
+// Printing functions.
+//===----------------------------------------------------------------------===//
+
+void CheckerRegistryData::printCheckerWithDescList(
+ const AnalyzerOptions &AnOpts, raw_ostream &Out,
+ size_t MaxNameChars) const {
+ // FIXME: Print available packages.
+
+ Out << "CHECKERS:\n";
+
+ // Find the maximum option length.
+ size_t OptionFieldWidth = 0;
+ for (const auto &Checker : Checkers) {
+ // Limit the amount of padding we are willing to give up for alignment.
+ // Package.Name Description [Hidden]
+ size_t NameLength = Checker.FullName.size();
+ if (NameLength <= MaxNameChars)
+ OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
+ }
+
+ const size_t InitialPad = 2;
+
+ 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);
+ }
+}
+
+void CheckerRegistryData::printEnabledCheckerList(raw_ostream &Out) const {
+ for (const auto *i : EnabledCheckers)
+ Out << i->FullName << '\n';
+}
+
+void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
+ raw_ostream &Out) const {
+ Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
+ Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
+ Out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
+ "OPTION2=VALUE, ...\n\n";
+ Out << "OPTIONS:\n\n";
+
+ // It's usually ill-advised to use multimap, but clang will terminate after
+ // this function.
+ std::multimap<StringRef, const CmdLineOption &> OptionMap;
+
+ for (const CheckerInfo &Checker : Checkers) {
+ for (const CmdLineOption &Option : Checker.CmdLineOptions) {
+ OptionMap.insert({Checker.FullName, Option});
+ }
+ }
+
+ for (const PackageInfo &Package : Packages) {
+ for (const CmdLineOption &Option : Package.CmdLineOptions) {
+ OptionMap.insert({Package.FullName, Option});
+ }
+ }
+
+ auto Print = [](llvm::raw_ostream &Out, StringRef FullOption,
+ StringRef Desc) {
+ AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
+ /*InitialPad*/ 2,
+ /*EntryWidth*/ 50,
+ /*MinLineWidth*/ 90);
+ Out << "\n\n";
+ };
+ for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
+ OptionMap) {
+ const CmdLineOption &Option = Entry.second;
+ std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
+
+ std::string Desc =
+ ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
+ (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
+ .str();
+
+ // The list of these if branches is significant, we wouldn't like to
+ // display hidden alpha checker options for
+ // -analyzer-checker-option-help-alpha.
+
+ if (Option.IsHidden) {
+ if (AnOpts.ShowCheckerOptionDeveloperList)
+ Print(Out, FullOption, Desc);
+ continue;
+ }
+
+ if (Option.DevelopmentStatus == "alpha" ||
+ Entry.first.startswith("alpha")) {
+ if (AnOpts.ShowCheckerOptionAlphaList)
+ Print(Out, FullOption,
+ llvm::Twine("(Enable only for development!) " + Desc).str());
+ continue;
+ }
+
+ if (AnOpts.ShowCheckerOptionList)
+ Print(Out, FullOption, Desc);
+ }
+}
diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp
index 1ccf4c6..9e6d79b 100644
--- a/clang/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp
@@ -183,12 +183,18 @@ EnvironmentManager::removeDeadBindings(Environment Env,
F.getTreeFactory());
// Iterate over the block-expr bindings.
- for (Environment::iterator I = Env.begin(), E = Env.end();
- I != E; ++I) {
+ for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) {
const EnvironmentEntry &BlkExpr = I.getKey();
const SVal &X = I.getData();
- if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
+ const bool IsBlkExprLive =
+ SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext());
+
+ assert((isa<Expr>(BlkExpr.getStmt()) || !IsBlkExprLive) &&
+ "Only Exprs can be live, LivenessAnalysis argues about the liveness "
+ "of *values*!");
+
+ if (IsBlkExprLive) {
// Copy the binding to the new map.
EBMapRef = EBMapRef.add(BlkExpr, X);
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
index d589e69..eb6014a 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
@@ -33,7 +33,8 @@ void ento::printCheckerHelp(raw_ostream &out, CompilerInstance &CI) {
*CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
CI.getFrontendOpts().Plugins);
- CheckerMgr->getCheckerRegistry().printCheckerWithDescList(out);
+ CheckerMgr->getCheckerRegistryData().printCheckerWithDescList(
+ *CI.getAnalyzerOpts(), out);
}
void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) {
@@ -43,7 +44,7 @@ void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) {
*CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
CI.getFrontendOpts().Plugins);
- CheckerMgr->getCheckerRegistry().printEnabledCheckerList(out);
+ CheckerMgr->getCheckerRegistryData().printEnabledCheckerList(out);
}
void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) {
@@ -52,7 +53,8 @@ void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) {
*CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
CI.getFrontendOpts().Plugins);
- CheckerMgr->getCheckerRegistry().printCheckerOptionList(out);
+ CheckerMgr->getCheckerRegistryData().printCheckerOptionList(
+ *CI.getAnalyzerOpts(), out);
}
void ento::printAnalyzerConfigList(raw_ostream &out) {
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index e690ed8..a688205 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -25,14 +25,13 @@
using namespace clang;
using namespace ento;
+using namespace checker_registry;
using llvm::sys::DynamicLibrary;
//===----------------------------------------------------------------------===//
// Utilities.
//===----------------------------------------------------------------------===//
-using RegisterCheckersFn = void (*)(CheckerRegistry &);
-
static bool isCompatibleAPIVersion(const char *VersionString) {
// If the version string is null, its not an analyzer plugin.
if (!VersionString)
@@ -43,140 +42,17 @@ static bool isCompatibleAPIVersion(const char *VersionString) {
return strcmp(VersionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
}
-namespace {
-template <class T> struct FullNameLT {
- bool operator()(const T &Lhs, const T &Rhs) {
- return Lhs.FullName < Rhs.FullName;
- }
-};
-
-using PackageNameLT = FullNameLT<CheckerRegistry::PackageInfo>;
-using CheckerNameLT = FullNameLT<CheckerRegistry::CheckerInfo>;
-} // end of anonymous namespace
-
-template <class CheckerOrPackageInfoList>
-static std::conditional_t<std::is_const<CheckerOrPackageInfoList>::value,
- typename CheckerOrPackageInfoList::const_iterator,
- typename CheckerOrPackageInfoList::iterator>
-binaryFind(CheckerOrPackageInfoList &Collection, StringRef FullName) {
-
- using CheckerOrPackage = typename CheckerOrPackageInfoList::value_type;
- using CheckerOrPackageFullNameLT = FullNameLT<CheckerOrPackage>;
-
- assert(llvm::is_sorted(Collection, CheckerOrPackageFullNameLT{}) &&
- "In order to efficiently gather checkers/packages, this function "
- "expects them to be already sorted!");
-
- return llvm::lower_bound(Collection, CheckerOrPackage(FullName),
- CheckerOrPackageFullNameLT{});
-}
-
static constexpr char PackageSeparator = '.';
-static bool isInPackage(const CheckerRegistry::CheckerInfo &Checker,
- StringRef PackageName) {
- // Does the checker's full name have the package as a prefix?
- if (!Checker.FullName.startswith(PackageName))
- return false;
-
- // Is the package actually just the name of a specific checker?
- if (Checker.FullName.size() == PackageName.size())
- return true;
-
- // Is the checker in the package (or a subpackage)?
- if (Checker.FullName[PackageName.size()] == PackageSeparator)
- return true;
-
- return false;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods of CmdLineOption, PackageInfo and CheckerInfo.
-//===----------------------------------------------------------------------===//
-
-LLVM_DUMP_METHOD void
-CheckerRegistry::CmdLineOption::dumpToStream(llvm::raw_ostream &Out) const {
- // The description can be just checked in Checkers.inc, the point here is to
- // debug whether we succeeded in parsing it.
- Out << OptionName << " (" << OptionType << ", "
- << (IsHidden ? "hidden, " : "") << DevelopmentStatus << ") default: \""
- << DefaultValStr;
-}
-
-static StringRef toString(CheckerRegistry::StateFromCmdLine Kind) {
- switch (Kind) {
- case CheckerRegistry::StateFromCmdLine::State_Disabled:
- return "Disabled";
- case CheckerRegistry::StateFromCmdLine::State_Enabled:
- return "Enabled";
- case CheckerRegistry::StateFromCmdLine::State_Unspecified:
- return "Unspecified";
- }
- llvm_unreachable("Unhandled CheckerRegistry::StateFromCmdLine enum");
-}
-
-LLVM_DUMP_METHOD void
-CheckerRegistry::CheckerInfo::dumpToStream(llvm::raw_ostream &Out) const {
- // The description can be just checked in Checkers.inc, the point here is to
- // debug whether we succeeded in parsing it. Same with documentation uri.
- Out << FullName << " (" << toString(State) << (IsHidden ? ", hidden" : "")
- << ")\n";
- Out << " Options:\n";
- for (const CmdLineOption &Option : CmdLineOptions) {
- Out << " ";
- Option.dumpToStream(Out);
- Out << '\n';
- }
- Out << " Dependencies:\n";
- for (const CheckerInfo *Dependency : Dependencies) {
- Out << " " << Dependency->FullName << '\n';
- }
- Out << " Weak dependencies:\n";
- for (const CheckerInfo *Dependency : WeakDependencies) {
- Out << " " << Dependency->FullName << '\n';
- }
-}
-
-LLVM_DUMP_METHOD void
-CheckerRegistry::PackageInfo::dumpToStream(llvm::raw_ostream &Out) const {
- Out << FullName << "\n";
- Out << " Options:\n";
- for (const CmdLineOption &Option : CmdLineOptions) {
- Out << " ";
- Option.dumpToStream(Out);
- Out << '\n';
- }
-}
-
//===----------------------------------------------------------------------===//
// Methods of CheckerRegistry.
//===----------------------------------------------------------------------===//
-CheckerRegistry::CheckerInfoListRange
-CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
- auto It = binaryFind(Checkers, CmdLineArg);
-
- if (!isInPackage(*It, CmdLineArg))
- return {Checkers.end(), Checkers.end()};
-
- // See how large the package is.
- // If the package doesn't exist, assume the option refers to a single
- // checker.
- size_t Size = 1;
- llvm::StringMap<size_t>::const_iterator PackageSize =
- PackageSizes.find(CmdLineArg);
-
- if (PackageSize != PackageSizes.end())
- Size = PackageSize->getValue();
-
- return {It, It + Size};
-}
-
CheckerRegistry::CheckerRegistry(
- ArrayRef<std::string> Plugins, DiagnosticsEngine &Diags,
- AnalyzerOptions &AnOpts,
+ CheckerRegistryData &Data, ArrayRef<std::string> Plugins,
+ DiagnosticsEngine &Diags, AnalyzerOptions &AnOpts,
ArrayRef<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns)
- : Diags(Diags), AnOpts(AnOpts) {
+ : Data(Data), Diags(Diags), AnOpts(AnOpts) {
// Register builtin checkers.
#define GET_CHECKERS
@@ -216,9 +92,10 @@ CheckerRegistry::CheckerRegistry(
continue;
}
+ using RegisterPluginCheckerFn = void (*)(CheckerRegistry &);
// Register its checkers.
- RegisterCheckersFn RegisterPluginCheckers =
- reinterpret_cast<RegisterCheckersFn>(
+ RegisterPluginCheckerFn RegisterPluginCheckers =
+ reinterpret_cast<RegisterPluginCheckerFn>(
Lib.getAddressOfSymbol("clang_registerCheckers"));
if (RegisterPluginCheckers)
RegisterPluginCheckers(*this);
@@ -235,8 +112,8 @@ CheckerRegistry::CheckerRegistry(
// FIXME: Alphabetical sort puts 'experimental' in the middle.
// Would it be better to name it '~experimental' or something else
// that's ASCIIbetically last?
- llvm::sort(Packages, PackageNameLT{});
- llvm::sort(Checkers, CheckerNameLT{});
+ llvm::sort(Data.Packages, checker_registry::PackageNameLT{});
+ llvm::sort(Data.Checkers, checker_registry::CheckerNameLT{});
#define GET_CHECKER_DEPENDENCIES
@@ -274,8 +151,8 @@ CheckerRegistry::CheckerRegistry(
resolveDependencies<false>();
#ifndef NDEBUG
- for (auto &DepPair : Dependencies) {
- for (auto &WeakDepPair : WeakDependencies) {
+ for (auto &DepPair : Data.Dependencies) {
+ for (auto &WeakDepPair : Data.WeakDependencies) {
// Some assertions to enforce that strong dependencies are relations in
// between purely modeling checkers, and weak dependencies are about
// diagnostics.
@@ -295,7 +172,7 @@ CheckerRegistry::CheckerRegistry(
// command line.
for (const std::pair<std::string, bool> &Opt : AnOpts.CheckersAndPackages) {
CheckerInfoListRange CheckerForCmdLineArg =
- getMutableCheckersForCmdLineArg(Opt.first);
+ Data.getMutableCheckersForCmdLineArg(Opt.first);
if (CheckerForCmdLineArg.begin() == CheckerForCmdLineArg.end()) {
Diags.Report(diag::err_unknown_analyzer_checker_or_package) << Opt.first;
@@ -315,19 +192,16 @@ CheckerRegistry::CheckerRegistry(
//===----------------------------------------------------------------------===//
template <typename IsEnabledFn>
-static bool
-collectStrongDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
- const CheckerManager &Mgr,
- CheckerRegistry::CheckerInfoSet &Ret,
- IsEnabledFn IsEnabled);
+static bool collectStrongDependencies(const ConstCheckerInfoList &Deps,
+ const CheckerManager &Mgr,
+ CheckerInfoSet &Ret,
+ IsEnabledFn IsEnabled);
-/// Collects weak dependencies in \p enabledCheckers.
+/// Collects weak dependencies in \p enabledData.Checkers.
template <typename IsEnabledFn>
-static void
-collectWeakDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
- const CheckerManager &Mgr,
- CheckerRegistry::CheckerInfoSet &Ret,
- IsEnabledFn IsEnabled);
+static void collectWeakDependencies(const ConstCheckerInfoList &Deps,
+ const CheckerManager &Mgr,
+ CheckerInfoSet &Ret, IsEnabledFn IsEnabled);
void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) {
// First, we calculate the list of enabled checkers as specified by the
@@ -338,7 +212,7 @@ void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) {
auto IsEnabledFromCmdLine = [&](const CheckerInfo *Checker) {
return !Checker->isDisabled(Mgr);
};
- for (const CheckerInfo &Checker : Checkers) {
+ for (const CheckerInfo &Checker : Data.Checkers) {
if (!Checker.isEnabled(Mgr))
continue;
@@ -362,7 +236,7 @@ void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) {
auto IsEnabled = [&](const CheckerInfo *Checker) {
return llvm::is_contained(Tmp, Checker);
};
- for (const CheckerInfo &Checker : Checkers) {
+ for (const CheckerInfo &Checker : Data.Checkers) {
if (!Checker.isEnabled(Mgr))
continue;
@@ -378,19 +252,18 @@ void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) {
}
// Note that set_union also preserves the order of insertion.
- EnabledCheckers.set_union(Deps);
- EnabledCheckers.insert(&Checker);
+ Data.EnabledCheckers.set_union(Deps);
+ Data.EnabledCheckers.insert(&Checker);
}
}
template <typename IsEnabledFn>
-static bool
-collectStrongDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
- const CheckerManager &Mgr,
- CheckerRegistry::CheckerInfoSet &Ret,
- IsEnabledFn IsEnabled) {
+static bool collectStrongDependencies(const ConstCheckerInfoList &Deps,
+ const CheckerManager &Mgr,
+ CheckerInfoSet &Ret,
+ IsEnabledFn IsEnabled) {
- for (const CheckerRegistry::CheckerInfo *Dependency : Deps) {
+ for (const CheckerInfo *Dependency : Deps) {
if (!IsEnabled(Dependency))
return false;
@@ -405,13 +278,12 @@ collectStrongDependencies(const CheckerRegistry::ConstCheckerInfoList &Deps,
}
template <typename IsEnabledFn>
-static void
-collectWeakDependencies(const CheckerRegistry::ConstCheckerInfoList &WeakDeps,
- const CheckerManager &Mgr,
- CheckerRegistry::CheckerInfoSet &Ret,
- IsEnabledFn IsEnabled) {
+static void collectWeakDependencies(const ConstCheckerInfoList &WeakDeps,
+ const CheckerManager &Mgr,
+ CheckerInfoSet &Ret,
+ IsEnabledFn IsEnabled) {
- for (const CheckerRegistry::CheckerInfo *Dependency : WeakDeps) {
+ for (const CheckerInfo *Dependency : WeakDeps) {
// Don't enable this checker if strong dependencies are unsatisfied, but
// assume that weak dependencies are transitive.
collectWeakDependencies(Dependency->WeakDependencies, Mgr, Ret, IsEnabled);
@@ -425,15 +297,16 @@ collectWeakDependencies(const CheckerRegistry::ConstCheckerInfoList &WeakDeps,
template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
for (const std::pair<StringRef, StringRef> &Entry :
- (IsWeak ? WeakDependencies : Dependencies)) {
+ (IsWeak ? Data.WeakDependencies : Data.Dependencies)) {
- auto CheckerIt = binaryFind(Checkers, Entry.first);
- assert(CheckerIt != Checkers.end() && CheckerIt->FullName == Entry.first &&
+ auto CheckerIt = binaryFind(Data.Checkers, Entry.first);
+ assert(CheckerIt != Data.Checkers.end() &&
+ CheckerIt->FullName == Entry.first &&
"Failed to find the checker while attempting to set up its "
"dependencies!");
- auto DependencyIt = binaryFind(Checkers, Entry.second);
- assert(DependencyIt != Checkers.end() &&
+ auto DependencyIt = binaryFind(Data.Checkers, Entry.second);
+ assert(DependencyIt != Data.Checkers.end() &&
DependencyIt->FullName == Entry.second &&
"Failed to find the dependency of a checker!");
@@ -445,12 +318,12 @@ template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
}
void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) {
- Dependencies.emplace_back(FullName, Dependency);
+ Data.Dependencies.emplace_back(FullName, Dependency);
}
void CheckerRegistry::addWeakDependency(StringRef FullName,
StringRef Dependency) {
- WeakDependencies.emplace_back(FullName, Dependency);
+ Data.WeakDependencies.emplace_back(FullName, Dependency);
}
//===----------------------------------------------------------------------===//
@@ -459,8 +332,7 @@ void CheckerRegistry::addWeakDependency(StringRef FullName,
/// Insert the checker/package option to AnalyzerOptions' config table, and
/// validate it, if the user supplied it on the command line.
-static void insertAndValidate(StringRef FullName,
- const CheckerRegistry::CmdLineOption &Option,
+static void insertAndValidate(StringRef FullName, const CmdLineOption &Option,
AnalyzerOptions &AnOpts,
DiagnosticsEngine &Diags) {
@@ -509,10 +381,10 @@ static void insertAndValidate(StringRef FullName,
}
template <class T>
-static void
-insertOptionToCollection(StringRef FullName, T &Collection,
- const CheckerRegistry::CmdLineOption &Option,
- AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
+static void insertOptionToCollection(StringRef FullName, T &Collection,
+ const CmdLineOption &Option,
+ AnalyzerOptions &AnOpts,
+ DiagnosticsEngine &Diags) {
auto It = binaryFind(Collection, FullName);
assert(It != Collection.end() &&
"Failed to find the checker while attempting to add a command line "
@@ -525,20 +397,20 @@ insertOptionToCollection(StringRef FullName, T &Collection,
void CheckerRegistry::resolveCheckerAndPackageOptions() {
for (const std::pair<StringRef, CmdLineOption> &CheckerOptEntry :
- CheckerOptions) {
- insertOptionToCollection(CheckerOptEntry.first, Checkers,
+ Data.CheckerOptions) {
+ insertOptionToCollection(CheckerOptEntry.first, Data.Checkers,
CheckerOptEntry.second, AnOpts, Diags);
}
for (const std::pair<StringRef, CmdLineOption> &PackageOptEntry :
- PackageOptions) {
- insertOptionToCollection(PackageOptEntry.first, Packages,
+ Data.PackageOptions) {
+ insertOptionToCollection(PackageOptEntry.first, Data.Packages,
PackageOptEntry.second, AnOpts, Diags);
}
}
void CheckerRegistry::addPackage(StringRef FullName) {
- Packages.emplace_back(PackageInfo(FullName));
+ Data.Packages.emplace_back(PackageInfo(FullName));
}
void CheckerRegistry::addPackageOption(StringRef OptionType,
@@ -548,22 +420,22 @@ void CheckerRegistry::addPackageOption(StringRef OptionType,
StringRef Description,
StringRef DevelopmentStatus,
bool IsHidden) {
- PackageOptions.emplace_back(
+ Data.PackageOptions.emplace_back(
PackageFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
Description, DevelopmentStatus, IsHidden});
}
-void CheckerRegistry::addChecker(InitializationFunction Rfn,
+void CheckerRegistry::addChecker(RegisterCheckerFn Rfn,
ShouldRegisterFunction Sfn, StringRef Name,
StringRef Desc, StringRef DocsUri,
bool IsHidden) {
- Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
+ Data.Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri, IsHidden);
// Record the presence of the checker in its packages.
StringRef PackageName, LeafName;
std::tie(PackageName, LeafName) = Name.rsplit(PackageSeparator);
while (!LeafName.empty()) {
- PackageSizes[PackageName] += 1;
+ Data.PackageSizes[PackageName] += 1;
std::tie(PackageName, LeafName) = PackageName.rsplit(PackageSeparator);
}
}
@@ -575,29 +447,28 @@ void CheckerRegistry::addCheckerOption(StringRef OptionType,
StringRef Description,
StringRef DevelopmentStatus,
bool IsHidden) {
- CheckerOptions.emplace_back(
+ Data.CheckerOptions.emplace_back(
CheckerFullName, CmdLineOption{OptionType, OptionName, DefaultValStr,
Description, DevelopmentStatus, IsHidden});
}
void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const {
// Initialize the CheckerManager with all enabled checkers.
- for (const auto *Checker : EnabledCheckers) {
+ for (const auto *Checker : Data.EnabledCheckers) {
CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName));
Checker->Initialize(CheckerMgr);
}
}
-static void
-isOptionContainedIn(const CheckerRegistry::CmdLineOptionList &OptionList,
- StringRef SuppliedChecker, StringRef SuppliedOption,
- const AnalyzerOptions &AnOpts, DiagnosticsEngine &Diags) {
+static void isOptionContainedIn(const CmdLineOptionList &OptionList,
+ StringRef SuppliedChecker,
+ StringRef SuppliedOption,
+ const AnalyzerOptions &AnOpts,
+ DiagnosticsEngine &Diags) {
if (!AnOpts.ShouldEmitErrorsOnInvalidConfigValue)
return;
- using CmdLineOption = CheckerRegistry::CmdLineOption;
-
auto SameOptName = [SuppliedOption](const CmdLineOption &Opt) {
return Opt.OptionName == SuppliedOption;
};
@@ -631,16 +502,16 @@ void CheckerRegistry::validateCheckerOptions() const {
// it would return with an iterator to the first checker in the core, so we
// we really have to use find here, which uses operator==.
auto CheckerIt =
- llvm::find(Checkers, CheckerInfo(SuppliedCheckerOrPackage));
- if (CheckerIt != Checkers.end()) {
+ llvm::find(Data.Checkers, CheckerInfo(SuppliedCheckerOrPackage));
+ if (CheckerIt != Data.Checkers.end()) {
isOptionContainedIn(CheckerIt->CmdLineOptions, SuppliedCheckerOrPackage,
SuppliedOption, AnOpts, Diags);
continue;
}
const auto *PackageIt =
- llvm::find(Packages, PackageInfo(SuppliedCheckerOrPackage));
- if (PackageIt != Packages.end()) {
+ llvm::find(Data.Packages, PackageInfo(SuppliedCheckerOrPackage));
+ if (PackageIt != Data.Packages.end()) {
isOptionContainedIn(PackageIt->CmdLineOptions, SuppliedCheckerOrPackage,
SuppliedOption, AnOpts, Diags);
continue;
@@ -651,122 +522,3 @@ void CheckerRegistry::validateCheckerOptions() const {
}
}
-//===----------------------------------------------------------------------===//
-// Printing functions.
-//===----------------------------------------------------------------------===//
-
-void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out,
- size_t MaxNameChars) const {
- // FIXME: Print available packages.
-
- Out << "CHECKERS:\n";
-
- // Find the maximum option length.
- size_t OptionFieldWidth = 0;
- for (const auto &Checker : Checkers) {
- // Limit the amount of padding we are willing to give up for alignment.
- // Package.Name Description [Hidden]
- size_t NameLength = Checker.FullName.size();
- if (NameLength <= MaxNameChars)
- OptionFieldWidth = std::max(OptionFieldWidth, NameLength);
- }
-
- const size_t InitialPad = 2;
-
- 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);
- }
-}
-
-void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const {
- for (const auto *i : EnabledCheckers)
- Out << i->FullName << '\n';
-}
-
-void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const {
- Out << "OVERVIEW: Clang Static Analyzer Checker and Package Option List\n\n";
- Out << "USAGE: -analyzer-config <OPTION1=VALUE,OPTION2=VALUE,...>\n\n";
- Out << " -analyzer-config OPTION1=VALUE, -analyzer-config "
- "OPTION2=VALUE, ...\n\n";
- Out << "OPTIONS:\n\n";
-
- std::multimap<StringRef, const CmdLineOption &> OptionMap;
-
- for (const CheckerInfo &Checker : Checkers) {
- for (const CmdLineOption &Option : Checker.CmdLineOptions) {
- OptionMap.insert({Checker.FullName, Option});
- }
- }
-
- for (const PackageInfo &Package : Packages) {
- for (const CmdLineOption &Option : Package.CmdLineOptions) {
- OptionMap.insert({Package.FullName, Option});
- }
- }
-
- auto Print = [] (llvm::raw_ostream &Out, StringRef FullOption, StringRef Desc) {
- AnalyzerOptions::printFormattedEntry(Out, {FullOption, Desc},
- /*InitialPad*/ 2,
- /*EntryWidth*/ 50,
- /*MinLineWidth*/ 90);
- Out << "\n\n";
- };
- for (const std::pair<const StringRef, const CmdLineOption &> &Entry :
- OptionMap) {
- const CmdLineOption &Option = Entry.second;
- std::string FullOption = (Entry.first + ":" + Option.OptionName).str();
-
- std::string Desc =
- ("(" + Option.OptionType + ") " + Option.Description + " (default: " +
- (Option.DefaultValStr.empty() ? "\"\"" : Option.DefaultValStr) + ")")
- .str();
-
- // The list of these if branches is significant, we wouldn't like to
- // display hidden alpha checker options for
- // -analyzer-checker-option-help-alpha.
-
- if (Option.IsHidden) {
- if (AnOpts.ShowCheckerOptionDeveloperList)
- Print(Out, FullOption, Desc);
- continue;
- }
-
- if (Option.DevelopmentStatus == "alpha" ||
- Entry.first.startswith("alpha")) {
- if (AnOpts.ShowCheckerOptionAlphaList)
- Print(Out, FullOption,
- llvm::Twine("(Enable only for development!) " + Desc).str());
- continue;
- }
-
- if (AnOpts.ShowCheckerOptionList)
- Print(Out, FullOption, Desc);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp
index 140f807..21a6078 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp
@@ -23,11 +23,11 @@ CheckerManager::CheckerManager(
ArrayRef<std::function<void(CheckerRegistry &)>> checkerRegistrationFns)
: Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions),
PP(&PP), Diags(Context.getDiagnostics()),
- Registry(
- std::make_unique<CheckerRegistry>(plugins, Context.getDiagnostics(),
- AOptions, checkerRegistrationFns)) {
- Registry->initializeRegistry(*this);
- Registry->initializeManager(*this);
+ RegistryData(std::make_unique<CheckerRegistryData>()) {
+ CheckerRegistry Registry(*RegistryData, plugins, Context.getDiagnostics(),
+ AOptions, checkerRegistrationFns);
+ Registry.initializeRegistry(*this);
+ Registry.initializeManager(*this);
finishedCheckerRegistration();
}
@@ -36,8 +36,9 @@ CheckerManager::CheckerManager(AnalyzerOptions &AOptions,
DiagnosticsEngine &Diags,
ArrayRef<std::string> plugins)
: LangOpts(LangOpts), AOptions(AOptions), Diags(Diags),
- Registry(std::make_unique<CheckerRegistry>(plugins, Diags, AOptions)) {
- Registry->initializeRegistry(*this);
+ RegistryData(std::make_unique<CheckerRegistryData>()) {
+ CheckerRegistry Registry(*RegistryData, plugins, Diags, AOptions, {});
+ Registry.initializeRegistry(*this);
}
CheckerManager::~CheckerManager() {