]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Frontend / CheckerRegistry.cpp
1 //===- CheckerRegistry.cpp - Maintains all available checkers -------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
11 #include "clang/Basic/Diagnostic.h"
12 #include "clang/Basic/LLVM.h"
13 #include "clang/Frontend/FrontendDiagnostic.h"
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
16 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SetVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringRef.h"
21 #include "llvm/Support/DynamicLibrary.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <algorithm>
25
26 using namespace clang;
27 using namespace ento;
28 using llvm::sys::DynamicLibrary;
29
30 using RegisterCheckersFn = void (*)(CheckerRegistry &);
31
32 static bool isCompatibleAPIVersion(const char *versionString) {
33   // If the version string is null, it's not an analyzer plugin.
34   if (!versionString)
35     return false;
36
37   // For now, none of the static analyzer API is considered stable.
38   // Versions must match exactly.
39   return strcmp(versionString, CLANG_ANALYZER_API_VERSION_STRING) == 0;
40 }
41
42 CheckerRegistry::CheckerRegistry(ArrayRef<std::string> plugins,
43                                  DiagnosticsEngine &diags) : Diags(diags) {
44 #define GET_CHECKERS
45 #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI)                            \
46   addChecker(register##CLASS, FULLNAME, HELPTEXT, DOC_URI);
47 #include "clang/StaticAnalyzer/Checkers/Checkers.inc"
48 #undef CHECKER
49 #undef GET_CHECKERS
50
51   for (ArrayRef<std::string>::iterator i = plugins.begin(), e = plugins.end();
52        i != e; ++i) {
53     // Get access to the plugin.
54     std::string err;
55     DynamicLibrary lib = DynamicLibrary::getPermanentLibrary(i->c_str(), &err);
56     if (!lib.isValid()) {
57       diags.Report(diag::err_fe_unable_to_load_plugin) << *i << err;
58       continue;
59     }
60
61     // See if it's compatible with this build of clang.
62     const char *pluginAPIVersion =
63       (const char *) lib.getAddressOfSymbol("clang_analyzerAPIVersionString");
64     if (!isCompatibleAPIVersion(pluginAPIVersion)) {
65       Diags.Report(diag::warn_incompatible_analyzer_plugin_api)
66           << llvm::sys::path::filename(*i);
67       Diags.Report(diag::note_incompatible_analyzer_plugin_api)
68           << CLANG_ANALYZER_API_VERSION_STRING
69           << pluginAPIVersion;
70       continue;
71     }
72
73     // Register its checkers.
74     RegisterCheckersFn registerPluginCheckers =
75       (RegisterCheckersFn) (intptr_t) lib.getAddressOfSymbol(
76                                                       "clang_registerCheckers");
77     if (registerPluginCheckers)
78       registerPluginCheckers(*this);
79   }
80 }
81
82 static constexpr char PackageSeparator = '.';
83
84 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
85                           const CheckerRegistry::CheckerInfo &b) {
86   return a.FullName < b.FullName;
87 }
88
89 static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
90                         StringRef packageName) {
91   // Does the checker's full name have the package as a prefix?
92   if (!checker.FullName.startswith(packageName))
93     return false;
94
95   // Is the package actually just the name of a specific checker?
96   if (checker.FullName.size() == packageName.size())
97     return true;
98
99   // Is the checker in the package (or a subpackage)?
100   if (checker.FullName[packageName.size()] == PackageSeparator)
101     return true;
102
103   return false;
104 }
105
106 CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers(
107                                             const AnalyzerOptions &Opts) const {
108
109   assert(std::is_sorted(Checkers.begin(), Checkers.end(), checkerNameLT) &&
110          "In order to efficiently gather checkers, this function expects them "
111          "to be already sorted!");
112
113   CheckerInfoSet enabledCheckers;
114   const auto end = Checkers.cend();
115
116   for (const std::pair<std::string, bool> &opt : Opts.CheckersControlList) {
117     // Use a binary search to find the possible start of the package.
118     CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.first, "", "");
119     auto firstRelatedChecker =
120       std::lower_bound(Checkers.cbegin(), end, packageInfo, checkerNameLT);
121
122     if (firstRelatedChecker == end ||
123         !isInPackage(*firstRelatedChecker, opt.first)) {
124       Diags.Report(diag::err_unknown_analyzer_checker) << opt.first;
125       Diags.Report(diag::note_suggest_disabling_all_checkers);
126       return {};
127     }
128
129     // See how large the package is.
130     // If the package doesn't exist, assume the option refers to a single
131     // checker.
132     size_t size = 1;
133     llvm::StringMap<size_t>::const_iterator packageSize =
134       Packages.find(opt.first);
135     if (packageSize != Packages.end())
136       size = packageSize->getValue();
137
138     // Step through all the checkers in the package.
139     for (auto lastRelatedChecker = firstRelatedChecker+size;
140          firstRelatedChecker != lastRelatedChecker; ++firstRelatedChecker)
141       if (opt.second)
142         enabledCheckers.insert(&*firstRelatedChecker);
143       else
144         enabledCheckers.remove(&*firstRelatedChecker);
145   }
146
147   return enabledCheckers;
148 }
149
150 void CheckerRegistry::addChecker(InitializationFunction Fn, StringRef Name,
151                                  StringRef Desc, StringRef DocsUri) {
152   Checkers.emplace_back(Fn, Name, Desc, DocsUri);
153
154   // Record the presence of the checker in its packages.
155   StringRef packageName, leafName;
156   std::tie(packageName, leafName) = Name.rsplit(PackageSeparator);
157   while (!leafName.empty()) {
158     Packages[packageName] += 1;
159     std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
160   }
161 }
162
163 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
164                                         const AnalyzerOptions &Opts) const {
165   // Sort checkers for efficient collection.
166   llvm::sort(Checkers, checkerNameLT);
167
168   // Collect checkers enabled by the options.
169   CheckerInfoSet enabledCheckers = getEnabledCheckers(Opts);
170
171   // Initialize the CheckerManager with all enabled checkers.
172   for (const auto *i : enabledCheckers) {
173     checkerMgr.setCurrentCheckName(CheckName(i->FullName));
174     i->Initialize(checkerMgr);
175   }
176 }
177
178 void CheckerRegistry::validateCheckerOptions(
179                                             const AnalyzerOptions &opts) const {
180   for (const auto &config : opts.Config) {
181     size_t pos = config.getKey().find(':');
182     if (pos == StringRef::npos)
183       continue;
184
185     bool hasChecker = false;
186     StringRef checkerName = config.getKey().substr(0, pos);
187     for (const auto &checker : Checkers) {
188       if (checker.FullName.startswith(checkerName) &&
189           (checker.FullName.size() == pos || checker.FullName[pos] == '.')) {
190         hasChecker = true;
191         break;
192       }
193     }
194     if (!hasChecker)
195       Diags.Report(diag::err_unknown_analyzer_checker) << checkerName;
196   }
197 }
198
199 void CheckerRegistry::printHelp(raw_ostream &out,
200                                 size_t maxNameChars) const {
201   // FIXME: Alphabetical sort puts 'experimental' in the middle.
202   // Would it be better to name it '~experimental' or something else
203   // that's ASCIIbetically last?
204   llvm::sort(Checkers, checkerNameLT);
205
206   // FIXME: Print available packages.
207
208   out << "CHECKERS:\n";
209
210   // Find the maximum option length.
211   size_t optionFieldWidth = 0;
212   for (const auto &i : Checkers) {
213     // Limit the amount of padding we are willing to give up for alignment.
214     //   Package.Name     Description  [Hidden]
215     size_t nameLength = i.FullName.size();
216     if (nameLength <= maxNameChars)
217       optionFieldWidth = std::max(optionFieldWidth, nameLength);
218   }
219
220   const size_t initialPad = 2;
221   for (const auto &i : Checkers) {
222     out.indent(initialPad) << i.FullName;
223
224     int pad = optionFieldWidth - i.FullName.size();
225
226     // Break on long option names.
227     if (pad < 0) {
228       out << '\n';
229       pad = optionFieldWidth + initialPad;
230     }
231     out.indent(pad + 2) << i.Desc;
232
233     out << '\n';
234   }
235 }
236
237 void CheckerRegistry::printList(raw_ostream &out,
238                                 const AnalyzerOptions &opts) const {
239   // Sort checkers for efficient collection.
240   llvm::sort(Checkers, checkerNameLT);
241
242   // Collect checkers enabled by the options.
243   CheckerInfoSet enabledCheckers = getEnabledCheckers(opts);
244
245   for (const auto *i : enabledCheckers)
246     out << i->FullName << '\n';
247 }