1*67e74705SXin Li //===--- CheckerRegistration.cpp - Registration for the Analyzer Checkers -===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // Defines the registration function for the analyzer checkers.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li
14*67e74705SXin Li #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
15*67e74705SXin Li #include "clang/Basic/Diagnostic.h"
16*67e74705SXin Li #include "clang/Frontend/FrontendDiagnostic.h"
17*67e74705SXin Li #include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
18*67e74705SXin Li #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
19*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
23*67e74705SXin Li #include "llvm/ADT/SmallVector.h"
24*67e74705SXin Li #include "llvm/Support/DynamicLibrary.h"
25*67e74705SXin Li #include "llvm/Support/Path.h"
26*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
27*67e74705SXin Li #include <memory>
28*67e74705SXin Li
29*67e74705SXin Li using namespace clang;
30*67e74705SXin Li using namespace ento;
31*67e74705SXin Li using llvm::sys::DynamicLibrary;
32*67e74705SXin Li
33*67e74705SXin Li namespace {
34*67e74705SXin Li class ClangCheckerRegistry : public CheckerRegistry {
35*67e74705SXin Li typedef void (*RegisterCheckersFn)(CheckerRegistry &);
36*67e74705SXin Li
37*67e74705SXin Li static bool isCompatibleAPIVersion(const char *versionString);
38*67e74705SXin Li static void warnIncompatible(DiagnosticsEngine *diags, StringRef pluginPath,
39*67e74705SXin Li const char *pluginAPIVersion);
40*67e74705SXin Li
41*67e74705SXin Li public:
42*67e74705SXin Li ClangCheckerRegistry(ArrayRef<std::string> plugins,
43*67e74705SXin Li DiagnosticsEngine *diags = nullptr);
44*67e74705SXin Li };
45*67e74705SXin Li
46*67e74705SXin Li } // end anonymous namespace
47*67e74705SXin Li
ClangCheckerRegistry(ArrayRef<std::string> plugins,DiagnosticsEngine * diags)48*67e74705SXin Li ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,
49*67e74705SXin Li DiagnosticsEngine *diags) {
50*67e74705SXin Li registerBuiltinCheckers(*this);
51*67e74705SXin Li
52*67e74705SXin Li for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
53*67e74705SXin Li i != e; ++i) {
54*67e74705SXin Li // Get access to the plugin.
55*67e74705SXin Li std::string err;
56*67e74705SXin Li DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str(), &err);
57*67e74705SXin Li if (!lib.isValid()) {
58*67e74705SXin Li diags->Report(diag::err_fe_unable_to_load_plugin) << *i << err;
59*67e74705SXin Li continue;
60*67e74705SXin Li }
61*67e74705SXin Li
62*67e74705SXin Li // See if it's compatible with this build of clang.
63*67e74705SXin Li const char *pluginAPIVersion =
64*67e74705SXin Li (const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString");
65*67e74705SXin Li if (!isCompatibleAPIVersion(pluginAPIVersion)) {
66*67e74705SXin Li warnIncompatible(diags, *i, pluginAPIVersion);
67*67e74705SXin Li continue;
68*67e74705SXin Li }
69*67e74705SXin Li
70*67e74705SXin Li // Register its checkers.
71*67e74705SXin Li RegisterCheckersFn registerPluginCheckers =
72*67e74705SXin Li (RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol(
73*67e74705SXin Li "clang_registerCheckers");
74*67e74705SXin Li if (registerPluginCheckers)
75*67e74705SXin Li registerPluginCheckers(*this);
76*67e74705SXin Li }
77*67e74705SXin Li }
78*67e74705SXin Li
isCompatibleAPIVersion(const char * versionString)79*67e74705SXin Li bool ClangCheckerRegistry::isCompatibleAPIVersion(const char *versionString) {
80*67e74705SXin Li // If the version string is null, it's not an analyzer plugin.
81*67e74705SXin Li if (!versionString)
82*67e74705SXin Li return false;
83*67e74705SXin Li
84*67e74705SXin Li // For now, none of the static analyzer API is considered stable.
85*67e74705SXin Li // Versions must match exactly.
86*67e74705SXin Li return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
87*67e74705SXin Li }
88*67e74705SXin Li
warnIncompatible(DiagnosticsEngine * diags,StringRef pluginPath,const char * pluginAPIVersion)89*67e74705SXin Li void ClangCheckerRegistry::warnIncompatible(DiagnosticsEngine *diags,
90*67e74705SXin Li StringRef pluginPath,
91*67e74705SXin Li const char *pluginAPIVersion) {
92*67e74705SXin Li if (!diags)
93*67e74705SXin Li return;
94*67e74705SXin Li if (!pluginAPIVersion)
95*67e74705SXin Li return;
96*67e74705SXin Li
97*67e74705SXin Li diags->Report(diag::warn_incompatible_analyzer_plugin_api)
98*67e74705SXin Li << llvm::sys::path::filename(pluginPath);
99*67e74705SXin Li diags->Report(diag::note_incompatible_analyzer_plugin_api)
100*67e74705SXin Li << CLANG_ANALYZER_API_VERSION_STRING
101*67e74705SXin Li << pluginAPIVersion;
102*67e74705SXin Li }
103*67e74705SXin Li
104*67e74705SXin Li std::unique_ptr<CheckerManager>
createCheckerManager(AnalyzerOptions & opts,const LangOptions & langOpts,ArrayRef<std::string> plugins,DiagnosticsEngine & diags)105*67e74705SXin Li ento::createCheckerManager(AnalyzerOptions &opts, const LangOptions &langOpts,
106*67e74705SXin Li ArrayRef<std::string> plugins,
107*67e74705SXin Li DiagnosticsEngine &diags) {
108*67e74705SXin Li std::unique_ptr<CheckerManager> checkerMgr(
109*67e74705SXin Li new CheckerManager(langOpts, &opts));
110*67e74705SXin Li
111*67e74705SXin Li SmallVector<CheckerOptInfo, 8> checkerOpts;
112*67e74705SXin Li for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
113*67e74705SXin Li const std::pair<std::string, bool> &opt = opts.CheckersControlList[i];
114*67e74705SXin Li checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second));
115*67e74705SXin Li }
116*67e74705SXin Li
117*67e74705SXin Li ClangCheckerRegistry allCheckers(plugins, &diags);
118*67e74705SXin Li allCheckers.initializeManager(*checkerMgr, checkerOpts);
119*67e74705SXin Li allCheckers.validateCheckerOptions(opts, diags);
120*67e74705SXin Li checkerMgr->finishedCheckerRegistration();
121*67e74705SXin Li
122*67e74705SXin Li for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
123*67e74705SXin Li if (checkerOpts[i].isUnclaimed()) {
124*67e74705SXin Li diags.Report(diag::err_unknown_analyzer_checker)
125*67e74705SXin Li << checkerOpts[i].getName();
126*67e74705SXin Li diags.Report(diag::note_suggest_disabling_all_checkers);
127*67e74705SXin Li }
128*67e74705SXin Li
129*67e74705SXin Li }
130*67e74705SXin Li
131*67e74705SXin Li return checkerMgr;
132*67e74705SXin Li }
133*67e74705SXin Li
printCheckerHelp(raw_ostream & out,ArrayRef<std::string> plugins)134*67e74705SXin Li void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
135*67e74705SXin Li out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n";
136*67e74705SXin Li out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
137*67e74705SXin Li
138*67e74705SXin Li ClangCheckerRegistry(plugins).printHelp(out);
139*67e74705SXin Li }
140