clang  9.0.0svn
CheckerRegistry.cpp
Go to the documentation of this file.
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 
11 #include "clang/Basic/Diagnostic.h"
12 #include "clang/Basic/LLVM.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 
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)
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 
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 
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 }
llvm::SetVector< const CheckerRegistry::CheckerInfo * > CheckerInfoSet
void printList(raw_ostream &out, const AnalyzerOptions &opts) const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1295
#define CLANG_ANALYZER_API_VERSION_STRING
static bool isCompatibleAPIVersion(const char *versionString)
CheckerRegistry(ArrayRef< std::string > plugins, DiagnosticsEngine &diags)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:149
Defines the Diagnostic-related interfaces.
std::vector< std::pair< std::string, bool > > CheckersControlList
Pair of checker name and enable/disable.
__INTPTR_TYPE__ intptr_t
A signed integer type with the property that any valid pointer to void can be converted to this type...
Definition: opencl-c.h:83
void(*)(CheckerRegistry &) RegisterCheckersFn
void validateCheckerOptions(const AnalyzerOptions &opts) const
Check if every option corresponds to a specific checker or package.
void addChecker(InitializationFunction Fn, StringRef FullName, StringRef Desc, StringRef DocsUri)
Adds a checker to the registry.
ConfigTable Config
A key-value table of use-specified configuration values.
Dataflow Directional Tag Classes.
void(*)(CheckerManager &) InitializationFunction
Initialization functions perform any necessary setup for a checker.
static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, const CheckerRegistry::CheckerInfo &b)
Stores options for the analyzer from the command line.
void printHelp(raw_ostream &out, size_t maxNameChars=30) const
Prints the name and description of all checkers in this registry.
__DEVICE__ int max(int __a, int __b)
static bool isInPackage(const CheckerRegistry::CheckerInfo &checker, StringRef packageName)
static constexpr char PackageSeparator