summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp144
1 files changed, 77 insertions, 67 deletions
diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index d7cd4072a8d..08633ce740e 100644
--- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -38,12 +38,66 @@ static bool isCompatibleAPIVersion(const char *versionString) {
return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
}
+static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
+ const CheckerRegistry::CheckerInfo &b) {
+ return a.FullName < b.FullName;
+}
+
+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;
+}
+
+CheckerRegistry::CheckerInfoListRange
+CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) {
+
+ assert(std::is_sorted(Checkers.begin(), Checkers.end(), checkerNameLT) &&
+ "In order to efficiently gather checkers, this function expects them "
+ "to be already sorted!");
+
+ // Use a binary search to find the possible start of the package.
+ CheckerRegistry::CheckerInfo
+ packageInfo(nullptr, nullptr, CmdLineArg, "", "");
+ auto it = std::lower_bound(Checkers.begin(), Checkers.end(),
+ packageInfo, checkerNameLT);
+
+ 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 =
+ Packages.find(CmdLineArg);
+
+ if (packageSize != Packages.end())
+ size = packageSize->getValue();
+
+ return { it, it + size };
+}
+
CheckerRegistry::CheckerRegistry(ArrayRef<std::string> plugins,
DiagnosticsEngine &diags,
AnalyzerOptions &AnOpts,
const LangOptions &LangOpts)
: Diags(diags), AnOpts(AnOpts), LangOpts(LangOpts) {
+ // Register builtin checkers.
#define GET_CHECKERS
#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI) \
addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
@@ -52,6 +106,7 @@ CheckerRegistry::CheckerRegistry(ArrayRef<std::string> plugins,
#undef CHECKER
#undef GET_CHECKERS
+ // Register checkers from plugins.
for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
i != e; ++i) {
// Get access to the plugin.
@@ -81,73 +136,38 @@ CheckerRegistry::CheckerRegistry(ArrayRef<std::string> plugins,
if (registerPluginCheckers)
registerPluginCheckers(*this);
}
-}
-
-static constexpr char PackageSeparator = '.';
-
-static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
- const CheckerRegistry::CheckerInfo &b) {
- return a.FullName < b.FullName;
-}
-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;
+ // Sort checkers for efficient collection.
+ // 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(Checkers, checkerNameLT);
- // Is the package actually just the name of a specific checker?
- if (checker.FullName.size() == packageName.size())
- return true;
+ // Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
+ // command line.
+ for (const std::pair<std::string, bool> &opt : AnOpts.CheckersControlList) {
+ CheckerInfoListRange checkersForCmdLineArg =
+ getMutableCheckersForCmdLineArg(opt.first);
- // Is the checker in the package (or a subpackage)?
- if (checker.FullName[packageName.size()] == PackageSeparator)
- return true;
+ if (checkersForCmdLineArg.begin() == checkersForCmdLineArg.end()) {
+ Diags.Report(diag::err_unknown_analyzer_checker) << opt.first;
+ Diags.Report(diag::note_suggest_disabling_all_checkers);
+ }
- return false;
+ for (CheckerInfo &checker : checkersForCmdLineArg) {
+ checker.State = opt.second ? StateFromCmdLine::State_Enabled :
+ StateFromCmdLine::State_Disabled;
+ }
+ }
}
CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
- assert(std::is_sorted(Checkers.begin(), Checkers.end(), checkerNameLT) &&
- "In order to efficiently gather checkers, this function expects them "
- "to be already sorted!");
-
CheckerInfoSet enabledCheckers;
- const auto end = Checkers.cend();
- for (const std::pair<std::string, bool> &opt : AnOpts.CheckersControlList) {
- // Use a binary search to find the possible start of the package.
- CheckerRegistry::CheckerInfo
- packageInfo(nullptr, nullptr, opt.first, "", "");
- auto firstRelatedChecker =
- std::lower_bound(Checkers.cbegin(), end, packageInfo, checkerNameLT);
-
- if (firstRelatedChecker == end ||
- !isInPackage(*firstRelatedChecker, opt.first)) {
- Diags.Report(diag::err_unknown_analyzer_checker) << opt.first;
- Diags.Report(diag::note_suggest_disabling_all_checkers);
- return {};
- }
-
- // 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 =
- Packages.find(opt.first);
- if (packageSize != Packages.end())
- size = packageSize->getValue();
-
- // Step through all the checkers in the package.
- for (auto lastRelatedChecker = firstRelatedChecker+size;
- firstRelatedChecker != lastRelatedChecker; ++firstRelatedChecker)
- if (opt.second) {
- if (firstRelatedChecker->ShouldRegister(LangOpts))
- enabledCheckers.insert(&*firstRelatedChecker);
- } else {
- enabledCheckers.remove(&*firstRelatedChecker);
- }
+ for (const CheckerInfo &checker : Checkers) {
+ if (checker.isEnabled(LangOpts))
+ enabledCheckers.insert(&checker);
}
return enabledCheckers;
@@ -168,8 +188,6 @@ void CheckerRegistry::addChecker(InitializationFunction Rfn,
}
void CheckerRegistry::initializeManager(CheckerManager &checkerMgr) const {
- // Sort checkers for efficient collection.
- llvm::sort(Checkers, checkerNameLT);
// Collect checkers enabled by the options.
CheckerInfoSet enabledCheckers = getEnabledCheckers();
@@ -203,11 +221,6 @@ void CheckerRegistry::validateCheckerOptions() const {
void CheckerRegistry::printHelp(raw_ostream &out,
size_t maxNameChars) const {
- // 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(Checkers, checkerNameLT);
-
// FIXME: Print available packages.
out << "CHECKERS:\n";
@@ -240,9 +253,6 @@ void CheckerRegistry::printHelp(raw_ostream &out,
}
void CheckerRegistry::printList(raw_ostream &out) const {
- // Sort checkers for efficient collection.
- llvm::sort(Checkers, checkerNameLT);
-
// Collect checkers enabled by the options.
CheckerInfoSet enabledCheckers = getEnabledCheckers();
OpenPOWER on IntegriCloud