diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp | 144 |
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(); |