2018-04-04 05:31:50 +08:00
|
|
|
//===- CheckerRegistry.cpp - Maintains all available checkers -------------===//
|
2011-08-17 05:24:21 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2011-08-17 05:24:21 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
[analyzer][NFC] Move CheckerRegistry from the Core directory to Frontend
ClangCheckerRegistry is a very non-obvious, poorly documented, weird concept.
It derives from CheckerRegistry, and is placed in lib/StaticAnalyzer/Frontend,
whereas it's base is located in lib/StaticAnalyzer/Core. It was, from what I can
imagine, used to circumvent the problem that the registry functions of the
checkers are located in the clangStaticAnalyzerCheckers library, but that
library depends on clangStaticAnalyzerCore. However, clangStaticAnalyzerFrontend
depends on both of those libraries.
One can make the observation however, that CheckerRegistry has no place in Core,
it isn't used there at all! The only place where it is used is Frontend, which
is where it ultimately belongs.
This move implies that since
include/clang/StaticAnalyzer/Checkers/ClangCheckers.h only contained a single function:
class CheckerRegistry;
void registerBuiltinCheckers(CheckerRegistry ®istry);
it had to re purposed, as CheckerRegistry is no longer available to
clangStaticAnalyzerCheckers. It was renamed to BuiltinCheckerRegistration.h,
which actually describes it a lot better -- it does not contain the registration
functions for checkers, but only those generated by the tblgen files.
Differential Revision: https://reviews.llvm.org/D54436
llvm-svn: 349275
2018-12-16 00:23:51 +08:00
|
|
|
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
|
2015-07-10 05:43:45 +08:00
|
|
|
#include "clang/Basic/Diagnostic.h"
|
2018-04-04 05:31:50 +08:00
|
|
|
#include "clang/Basic/LLVM.h"
|
2018-12-16 02:11:49 +08:00
|
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
|
|
|
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
|
2018-04-04 05:31:50 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
2015-07-10 05:43:45 +08:00
|
|
|
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
2018-04-04 05:31:50 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2011-12-15 09:36:04 +08:00
|
|
|
#include "llvm/ADT/SetVector.h"
|
2018-04-04 05:31:50 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
2018-12-16 02:11:49 +08:00
|
|
|
#include "llvm/Support/DynamicLibrary.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2012-12-02 01:12:56 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2018-04-04 05:31:50 +08:00
|
|
|
#include <algorithm>
|
2011-08-17 05:24:21 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
using namespace ento;
|
2018-12-16 02:11:49 +08:00
|
|
|
using llvm::sys::DynamicLibrary;
|
|
|
|
|
|
|
|
using RegisterCheckersFn = void (*)(CheckerRegistry &);
|
|
|
|
|
|
|
|
static bool isCompatibleAPIVersion(const char *versionString) {
|
|
|
|
// If the version string is null, it's not an analyzer plugin.
|
|
|
|
if (!versionString)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// For now, none of the static analyzer API is considered stable.
|
|
|
|
// Versions must match exactly.
|
|
|
|
return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
|
|
|
|
}
|
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
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 };
|
|
|
|
}
|
|
|
|
|
2019-01-27 01:27:40 +08:00
|
|
|
CheckerRegistry::CheckerRegistry(
|
|
|
|
ArrayRef<std::string> plugins, DiagnosticsEngine &diags,
|
|
|
|
AnalyzerOptions &AnOpts, const LangOptions &LangOpts,
|
|
|
|
ArrayRef<std::function<void(CheckerRegistry &)>>
|
|
|
|
checkerRegistrationFns)
|
2019-01-26 23:59:21 +08:00
|
|
|
: Diags(diags), AnOpts(AnOpts), LangOpts(LangOpts) {
|
2019-01-26 22:23:08 +08:00
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
// Register builtin checkers.
|
2018-12-16 02:11:49 +08:00
|
|
|
#define GET_CHECKERS
|
2018-12-21 04:20:20 +08:00
|
|
|
#define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI) \
|
2019-01-26 22:23:08 +08:00
|
|
|
addChecker(register##CLASS, shouldRegister##CLASS, FULLNAME, HELPTEXT, \
|
|
|
|
DOC_URI);
|
2018-12-16 02:11:49 +08:00
|
|
|
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
|
|
|
|
#undef CHECKER
|
|
|
|
#undef GET_CHECKERS
|
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
// Register checkers from plugins.
|
2018-12-16 02:11:49 +08:00
|
|
|
for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
|
|
|
|
i != e; ++i) {
|
|
|
|
// Get access to the plugin.
|
|
|
|
std::string err;
|
|
|
|
DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str(), &err);
|
|
|
|
if (!lib.isValid()) {
|
|
|
|
diags.Report(diag::err_fe_unable_to_load_plugin) << *i << err;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if it's compatible with this build of clang.
|
|
|
|
const char *pluginAPIVersion =
|
|
|
|
(const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString");
|
|
|
|
if (!isCompatibleAPIVersion(pluginAPIVersion)) {
|
|
|
|
Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
|
|
|
|
<< llvm::sys::path::filename(*i);
|
|
|
|
Diags.Report(diag::note_incompatible_analyzer_plugin_api)
|
|
|
|
<< CLANG_ANALYZER_API_VERSION_STRING
|
|
|
|
<< pluginAPIVersion;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register its checkers.
|
|
|
|
RegisterCheckersFn registerPluginCheckers =
|
|
|
|
(RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol(
|
|
|
|
"clang_registerCheckers");
|
|
|
|
if (registerPluginCheckers)
|
|
|
|
registerPluginCheckers(*this);
|
|
|
|
}
|
2011-08-17 05:24:21 +08:00
|
|
|
|
2019-01-27 01:27:40 +08:00
|
|
|
// Register statically linked checkers, that aren't generated from the tblgen
|
|
|
|
// file, but rather passed their registry function as a parameter in
|
|
|
|
// checkerRegistrationFns.
|
|
|
|
|
|
|
|
for (const auto &Fn : checkerRegistrationFns)
|
|
|
|
Fn(*this);
|
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
// 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);
|
2011-08-17 05:24:21 +08:00
|
|
|
|
[analyzer] Reimplement dependencies between checkers
Unfortunately, up until now, the fact that certain checkers depended on one
another was known, but how these actually unfolded was hidden deep within the
implementation. For example, many checkers (like RetainCount, Malloc or CString)
modelled a certain functionality, and exposed certain reportable bug types to
the user. For example, while MallocChecker models many many different types of
memory handling, the actual "unix.MallocChecker" checker the user was exposed to
was merely and option to this modeling part.
Other than this being an ugly mess, this issue made resolving the checker naming
issue almost impossible. (The checker naming issue being that if a checker
registered more than one checker within its registry function, both checker
object recieved the same name) Also, if the user explicitly disabled a checker
that was a dependency of another that _was_ explicitly enabled, it implicitly,
without "telling" the user, reenabled it.
Clearly, changing this to a well structured, declarative form, where the
handling of dependencies are done on a higher level is very much preferred.
This patch, among the detailed things later, makes checkers declare their
dependencies within the TableGen file Checkers.td, and exposes the same
functionality to plugins and statically linked non-generated checkers through
CheckerRegistry::addDependency. CheckerRegistry now resolves these dependencies,
makes sure that checkers are added to CheckerManager in the correct order,
and makes sure that if a dependency is disabled, so will be every checker that
depends on it.
In detail:
* Add a new field to the Checker class in CheckerBase.td called Dependencies,
which is a list of Checkers.
* Move unix checkers before cplusplus, as there is no forward declaration in
tblgen :/
* Add the following new checkers:
- StackAddrEscapeBase
- StackAddrEscapeBase
- CStringModeling
- DynamicMemoryModeling (base of the MallocChecker family)
- IteratorModeling (base of the IteratorChecker family)
- ValistBase
- SecuritySyntaxChecker (base of bcmp, bcopy, etc...)
- NSOrCFErrorDerefChecker (base of NSErrorChecker and CFErrorChecker)
- IvarInvalidationModeling (base of IvarInvalidation checker family)
- RetainCountBase (base of RetainCount and OSObjectRetainCount)
* Clear up and registry functions in MallocChecker, happily remove old FIXMEs.
* Add a new addDependency function to CheckerRegistry.
* Neatly format RUN lines in files I looked at while debugging.
Big thanks to Artem Degrachev for all the guidance through this project!
Differential Revision: https://reviews.llvm.org/D54438
llvm-svn: 352287
2019-01-27 04:06:54 +08:00
|
|
|
#define GET_CHECKER_DEPENDENCIES
|
|
|
|
|
|
|
|
#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
|
|
|
|
addDependency(FULLNAME, DEPENDENCY);
|
|
|
|
|
|
|
|
#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
|
|
|
|
#undef CHECKER_DEPENDENCY
|
|
|
|
#undef GET_CHECKER_DEPENDENCIES
|
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
// 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);
|
2011-08-17 05:24:21 +08:00
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
if (checkersForCmdLineArg.begin() == checkersForCmdLineArg.end()) {
|
|
|
|
Diags.Report(diag::err_unknown_analyzer_checker) << opt.first;
|
|
|
|
Diags.Report(diag::note_suggest_disabling_all_checkers);
|
|
|
|
}
|
2011-08-17 05:24:21 +08:00
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
for (CheckerInfo &checker : checkersForCmdLineArg) {
|
|
|
|
checker.State = opt.second ? StateFromCmdLine::State_Enabled :
|
|
|
|
StateFromCmdLine::State_Disabled;
|
|
|
|
}
|
|
|
|
}
|
2011-08-17 05:24:21 +08:00
|
|
|
}
|
|
|
|
|
[analyzer] Reimplement dependencies between checkers
Unfortunately, up until now, the fact that certain checkers depended on one
another was known, but how these actually unfolded was hidden deep within the
implementation. For example, many checkers (like RetainCount, Malloc or CString)
modelled a certain functionality, and exposed certain reportable bug types to
the user. For example, while MallocChecker models many many different types of
memory handling, the actual "unix.MallocChecker" checker the user was exposed to
was merely and option to this modeling part.
Other than this being an ugly mess, this issue made resolving the checker naming
issue almost impossible. (The checker naming issue being that if a checker
registered more than one checker within its registry function, both checker
object recieved the same name) Also, if the user explicitly disabled a checker
that was a dependency of another that _was_ explicitly enabled, it implicitly,
without "telling" the user, reenabled it.
Clearly, changing this to a well structured, declarative form, where the
handling of dependencies are done on a higher level is very much preferred.
This patch, among the detailed things later, makes checkers declare their
dependencies within the TableGen file Checkers.td, and exposes the same
functionality to plugins and statically linked non-generated checkers through
CheckerRegistry::addDependency. CheckerRegistry now resolves these dependencies,
makes sure that checkers are added to CheckerManager in the correct order,
and makes sure that if a dependency is disabled, so will be every checker that
depends on it.
In detail:
* Add a new field to the Checker class in CheckerBase.td called Dependencies,
which is a list of Checkers.
* Move unix checkers before cplusplus, as there is no forward declaration in
tblgen :/
* Add the following new checkers:
- StackAddrEscapeBase
- StackAddrEscapeBase
- CStringModeling
- DynamicMemoryModeling (base of the MallocChecker family)
- IteratorModeling (base of the IteratorChecker family)
- ValistBase
- SecuritySyntaxChecker (base of bcmp, bcopy, etc...)
- NSOrCFErrorDerefChecker (base of NSErrorChecker and CFErrorChecker)
- IvarInvalidationModeling (base of IvarInvalidation checker family)
- RetainCountBase (base of RetainCount and OSObjectRetainCount)
* Clear up and registry functions in MallocChecker, happily remove old FIXMEs.
* Add a new addDependency function to CheckerRegistry.
* Neatly format RUN lines in files I looked at while debugging.
Big thanks to Artem Degrachev for all the guidance through this project!
Differential Revision: https://reviews.llvm.org/D54438
llvm-svn: 352287
2019-01-27 04:06:54 +08:00
|
|
|
/// Collects dependencies in \p ret, returns false on failure.
|
|
|
|
static bool collectDependenciesImpl(
|
|
|
|
const CheckerRegistry::ConstCheckerInfoList &deps,
|
|
|
|
const LangOptions &LO,
|
|
|
|
CheckerRegistry::CheckerInfoSet &ret);
|
|
|
|
|
|
|
|
/// Collects dependenies in \p enabledCheckers. Return None on failure.
|
|
|
|
LLVM_NODISCARD
|
|
|
|
static llvm::Optional<CheckerRegistry::CheckerInfoSet> collectDependencies(
|
|
|
|
const CheckerRegistry::CheckerInfo &checker, const LangOptions &LO) {
|
|
|
|
|
|
|
|
CheckerRegistry::CheckerInfoSet ret;
|
|
|
|
// Add dependencies to the enabled checkers only if all of them can be
|
|
|
|
// enabled.
|
|
|
|
if (!collectDependenciesImpl(checker.Dependencies, LO, ret))
|
|
|
|
return None;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool collectDependenciesImpl(
|
|
|
|
const CheckerRegistry::ConstCheckerInfoList &deps,
|
|
|
|
const LangOptions &LO,
|
|
|
|
CheckerRegistry::CheckerInfoSet &ret) {
|
|
|
|
|
|
|
|
for (const CheckerRegistry::CheckerInfo *dependency : deps) {
|
|
|
|
|
|
|
|
if (dependency->isDisabled(LO))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Collect dependencies recursively.
|
|
|
|
if (!collectDependenciesImpl(dependency->Dependencies, LO, ret))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ret.insert(dependency);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-26 23:59:21 +08:00
|
|
|
CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {
|
2018-12-15 23:44:05 +08:00
|
|
|
|
|
|
|
CheckerInfoSet enabledCheckers;
|
|
|
|
|
2019-01-27 00:35:33 +08:00
|
|
|
for (const CheckerInfo &checker : Checkers) {
|
[analyzer] Reimplement dependencies between checkers
Unfortunately, up until now, the fact that certain checkers depended on one
another was known, but how these actually unfolded was hidden deep within the
implementation. For example, many checkers (like RetainCount, Malloc or CString)
modelled a certain functionality, and exposed certain reportable bug types to
the user. For example, while MallocChecker models many many different types of
memory handling, the actual "unix.MallocChecker" checker the user was exposed to
was merely and option to this modeling part.
Other than this being an ugly mess, this issue made resolving the checker naming
issue almost impossible. (The checker naming issue being that if a checker
registered more than one checker within its registry function, both checker
object recieved the same name) Also, if the user explicitly disabled a checker
that was a dependency of another that _was_ explicitly enabled, it implicitly,
without "telling" the user, reenabled it.
Clearly, changing this to a well structured, declarative form, where the
handling of dependencies are done on a higher level is very much preferred.
This patch, among the detailed things later, makes checkers declare their
dependencies within the TableGen file Checkers.td, and exposes the same
functionality to plugins and statically linked non-generated checkers through
CheckerRegistry::addDependency. CheckerRegistry now resolves these dependencies,
makes sure that checkers are added to CheckerManager in the correct order,
and makes sure that if a dependency is disabled, so will be every checker that
depends on it.
In detail:
* Add a new field to the Checker class in CheckerBase.td called Dependencies,
which is a list of Checkers.
* Move unix checkers before cplusplus, as there is no forward declaration in
tblgen :/
* Add the following new checkers:
- StackAddrEscapeBase
- StackAddrEscapeBase
- CStringModeling
- DynamicMemoryModeling (base of the MallocChecker family)
- IteratorModeling (base of the IteratorChecker family)
- ValistBase
- SecuritySyntaxChecker (base of bcmp, bcopy, etc...)
- NSOrCFErrorDerefChecker (base of NSErrorChecker and CFErrorChecker)
- IvarInvalidationModeling (base of IvarInvalidation checker family)
- RetainCountBase (base of RetainCount and OSObjectRetainCount)
* Clear up and registry functions in MallocChecker, happily remove old FIXMEs.
* Add a new addDependency function to CheckerRegistry.
* Neatly format RUN lines in files I looked at while debugging.
Big thanks to Artem Degrachev for all the guidance through this project!
Differential Revision: https://reviews.llvm.org/D54438
llvm-svn: 352287
2019-01-27 04:06:54 +08:00
|
|
|
if (!checker.isEnabled(LangOpts))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Recursively enable it's dependencies.
|
|
|
|
llvm::Optional<CheckerInfoSet> 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);
|
2018-12-15 23:44:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return enabledCheckers;
|
2011-08-17 05:24:21 +08:00
|
|
|
}
|
|
|
|
|
2019-01-26 22:23:08 +08:00
|
|
|
void CheckerRegistry::addChecker(InitializationFunction Rfn,
|
|
|
|
ShouldRegisterFunction Sfn, StringRef Name,
|
2018-12-21 04:20:20 +08:00
|
|
|
StringRef Desc, StringRef DocsUri) {
|
2019-01-26 22:23:08 +08:00
|
|
|
Checkers.emplace_back(Rfn, Sfn, Name, Desc, DocsUri);
|
2011-08-17 05:24:21 +08:00
|
|
|
|
|
|
|
// Record the presence of the checker in its packages.
|
|
|
|
StringRef packageName, leafName;
|
2018-12-21 04:20:20 +08:00
|
|
|
std::tie(packageName, leafName) = Name.rsplit(PackageSeparator);
|
2011-08-17 05:24:21 +08:00
|
|
|
while (!leafName.empty()) {
|
|
|
|
Packages[packageName] += 1;
|
2014-03-02 21:01:17 +08:00
|
|
|
std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
|
2011-08-17 05:24:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-26 23:59:21 +08:00
|
|
|
void CheckerRegistry::initializeManager(CheckerManager &checkerMgr) const {
|
2011-08-17 05:24:21 +08:00
|
|
|
// Collect checkers enabled by the options.
|
2019-01-26 23:59:21 +08:00
|
|
|
CheckerInfoSet enabledCheckers = getEnabledCheckers();
|
2011-08-17 05:24:21 +08:00
|
|
|
|
|
|
|
// Initialize the CheckerManager with all enabled checkers.
|
2018-12-15 23:44:05 +08:00
|
|
|
for (const auto *i : enabledCheckers) {
|
2018-04-04 05:31:50 +08:00
|
|
|
checkerMgr.setCurrentCheckName(CheckName(i->FullName));
|
|
|
|
i->Initialize(checkerMgr);
|
2011-08-17 05:24:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-26 23:59:21 +08:00
|
|
|
void CheckerRegistry::validateCheckerOptions() const {
|
|
|
|
for (const auto &config : AnOpts.Config) {
|
2015-07-10 05:43:45 +08:00
|
|
|
size_t pos = config.getKey().find(':');
|
|
|
|
if (pos == StringRef::npos)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool hasChecker = false;
|
|
|
|
StringRef checkerName = config.getKey().substr(0, pos);
|
2018-04-04 05:31:50 +08:00
|
|
|
for (const auto &checker : Checkers) {
|
2015-07-10 05:43:45 +08:00
|
|
|
if (checker.FullName.startswith(checkerName) &&
|
|
|
|
(checker.FullName.size() == pos || checker.FullName[pos] == '.')) {
|
|
|
|
hasChecker = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-04-04 05:31:50 +08:00
|
|
|
if (!hasChecker)
|
2018-12-16 02:11:49 +08:00
|
|
|
Diags.Report(diag::err_unknown_analyzer_checker) << checkerName;
|
2015-07-10 05:43:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-13 03:30:44 +08:00
|
|
|
void CheckerRegistry::printHelp(raw_ostream &out,
|
2011-08-17 05:24:21 +08:00
|
|
|
size_t maxNameChars) const {
|
|
|
|
// FIXME: Print available packages.
|
|
|
|
|
|
|
|
out << "CHECKERS:\n";
|
|
|
|
|
|
|
|
// Find the maximum option length.
|
|
|
|
size_t optionFieldWidth = 0;
|
2018-04-04 05:31:50 +08:00
|
|
|
for (const auto &i : Checkers) {
|
2011-08-17 05:24:21 +08:00
|
|
|
// Limit the amount of padding we are willing to give up for alignment.
|
|
|
|
// Package.Name Description [Hidden]
|
2018-04-04 05:31:50 +08:00
|
|
|
size_t nameLength = i.FullName.size();
|
2011-08-17 05:24:21 +08:00
|
|
|
if (nameLength <= maxNameChars)
|
|
|
|
optionFieldWidth = std::max(optionFieldWidth, nameLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
const size_t initialPad = 2;
|
2018-04-04 05:31:50 +08:00
|
|
|
for (const auto &i : Checkers) {
|
|
|
|
out.indent(initialPad) << i.FullName;
|
2011-08-17 05:24:21 +08:00
|
|
|
|
2018-04-04 05:31:50 +08:00
|
|
|
int pad = optionFieldWidth - i.FullName.size();
|
2011-08-17 05:24:21 +08:00
|
|
|
|
|
|
|
// Break on long option names.
|
|
|
|
if (pad < 0) {
|
|
|
|
out << '\n';
|
|
|
|
pad = optionFieldWidth + initialPad;
|
|
|
|
}
|
2018-04-04 05:31:50 +08:00
|
|
|
out.indent(pad + 2) << i.Desc;
|
2011-08-17 05:24:21 +08:00
|
|
|
|
|
|
|
out << '\n';
|
|
|
|
}
|
|
|
|
}
|
2016-08-08 21:41:04 +08:00
|
|
|
|
2019-01-26 23:59:21 +08:00
|
|
|
void CheckerRegistry::printList(raw_ostream &out) const {
|
2016-08-08 21:41:04 +08:00
|
|
|
// Collect checkers enabled by the options.
|
2019-01-26 23:59:21 +08:00
|
|
|
CheckerInfoSet enabledCheckers = getEnabledCheckers();
|
2016-08-08 21:41:04 +08:00
|
|
|
|
2018-04-04 05:31:50 +08:00
|
|
|
for (const auto *i : enabledCheckers)
|
|
|
|
out << i->FullName << '\n';
|
2016-08-08 21:41:04 +08:00
|
|
|
}
|