clang  8.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"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/SetVector.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include <algorithm>
22 #include <cstddef>
23 #include <tuple>
24 
25 using namespace clang;
26 using namespace ento;
27 
28 static const char PackageSeparator = '.';
29 
30 using CheckerInfoSet = llvm::SetVector<const CheckerRegistry::CheckerInfo *>;
31 
32 namespace {
33 /// Represents a request to include or exclude a checker or package from a
34 /// specific analysis run.
35 ///
36 /// \sa CheckerRegistry::initializeManager
37 class CheckerOptInfo {
38  StringRef Name;
39  bool Enable;
40  bool Claimed;
41 
42 public:
43  CheckerOptInfo(StringRef name, bool enable)
44  : Name(name), Enable(enable), Claimed(false) { }
45 
46  StringRef getName() const { return Name; }
47  bool isEnabled() const { return Enable; }
48  bool isDisabled() const { return !isEnabled(); }
49 
50  bool isClaimed() const { return Claimed; }
51  bool isUnclaimed() const { return !isClaimed(); }
52  void claim() { Claimed = true; }
53 };
54 
55 } // end of anonymous namespace
56 
60  for (unsigned i = 0, e = opts.CheckersControlList.size(); i != e; ++i) {
61  const std::pair<std::string, bool> &opt = opts.CheckersControlList[i];
62  checkerOpts.push_back(CheckerOptInfo(opt.first, opt.second));
63  }
64  return checkerOpts;
65 }
66 
67 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
68  const CheckerRegistry::CheckerInfo &b) {
69  return a.FullName < b.FullName;
70 }
71 
72 static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
73  StringRef packageName) {
74  // Does the checker's full name have the package as a prefix?
75  if (!checker.FullName.startswith(packageName))
76  return false;
77 
78  // Is the package actually just the name of a specific checker?
79  if (checker.FullName.size() == packageName.size())
80  return true;
81 
82  // Is the checker in the package (or a subpackage)?
83  if (checker.FullName[packageName.size()] == PackageSeparator)
84  return true;
85 
86  return false;
87 }
88 
89 /// Collects the checkers for the supplied \p opt option into \p collected.
91  const llvm::StringMap<size_t> &packageSizes,
92  CheckerOptInfo &opt, CheckerInfoSet &collected) {
93  // Use a binary search to find the possible start of the package.
94  CheckerRegistry::CheckerInfo packageInfo(nullptr, opt.getName(), "");
95  auto end = checkers.cend();
96  auto i = std::lower_bound(checkers.cbegin(), end, packageInfo, checkerNameLT);
97 
98  // If we didn't even find a possible package, give up.
99  if (i == end)
100  return;
101 
102  // If what we found doesn't actually start the package, give up.
103  if (!isInPackage(*i, opt.getName()))
104  return;
105 
106  // There is at least one checker in the package; claim the option.
107  opt.claim();
108 
109  // See how large the package is.
110  // If the package doesn't exist, assume the option refers to a single checker.
111  size_t size = 1;
112  llvm::StringMap<size_t>::const_iterator packageSize =
113  packageSizes.find(opt.getName());
114  if (packageSize != packageSizes.end())
115  size = packageSize->getValue();
116 
117  // Step through all the checkers in the package.
118  for (auto checkEnd = i+size; i != checkEnd; ++i)
119  if (opt.isEnabled())
120  collected.insert(&*i);
121  else
122  collected.remove(&*i);
123 }
124 
125 void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
126  StringRef desc) {
127  Checkers.push_back(CheckerInfo(fn, name, desc));
128 
129  // Record the presence of the checker in its packages.
130  StringRef packageName, leafName;
131  std::tie(packageName, leafName) = name.rsplit(PackageSeparator);
132  while (!leafName.empty()) {
133  Packages[packageName] += 1;
134  std::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
135  }
136 }
137 
138 void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
139  const AnalyzerOptions &Opts,
140  DiagnosticsEngine &diags) const {
141  // Sort checkers for efficient collection.
142  llvm::sort(Checkers, checkerNameLT);
143 
145  // Collect checkers enabled by the options.
146  CheckerInfoSet enabledCheckers;
147  for (auto &i : checkerOpts)
148  collectCheckers(Checkers, Packages, i, enabledCheckers);
149 
150  // Initialize the CheckerManager with all enabled checkers.
151  for (const auto *i :enabledCheckers) {
152  checkerMgr.setCurrentCheckName(CheckName(i->FullName));
153  i->Initialize(checkerMgr);
154  }
155 
156  for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) {
157  if (checkerOpts[i].isUnclaimed()) {
158  diags.Report(diag::err_unknown_analyzer_checker)
159  << checkerOpts[i].getName();
160  diags.Report(diag::note_suggest_disabling_all_checkers);
161  }
162 
163  }
164 }
165 
167  DiagnosticsEngine &diags) const {
168  for (const auto &config : opts.Config) {
169  size_t pos = config.getKey().find(':');
170  if (pos == StringRef::npos)
171  continue;
172 
173  bool hasChecker = false;
174  StringRef checkerName = config.getKey().substr(0, pos);
175  for (const auto &checker : Checkers) {
176  if (checker.FullName.startswith(checkerName) &&
177  (checker.FullName.size() == pos || checker.FullName[pos] == '.')) {
178  hasChecker = true;
179  break;
180  }
181  }
182  if (!hasChecker)
183  diags.Report(diag::err_unknown_analyzer_checker) << checkerName;
184  }
185 }
186 
187 void CheckerRegistry::printHelp(raw_ostream &out,
188  size_t maxNameChars) const {
189  // FIXME: Alphabetical sort puts 'experimental' in the middle.
190  // Would it be better to name it '~experimental' or something else
191  // that's ASCIIbetically last?
192  llvm::sort(Checkers, checkerNameLT);
193 
194  // FIXME: Print available packages.
195 
196  out << "CHECKERS:\n";
197 
198  // Find the maximum option length.
199  size_t optionFieldWidth = 0;
200  for (const auto &i : Checkers) {
201  // Limit the amount of padding we are willing to give up for alignment.
202  // Package.Name Description [Hidden]
203  size_t nameLength = i.FullName.size();
204  if (nameLength <= maxNameChars)
205  optionFieldWidth = std::max(optionFieldWidth, nameLength);
206  }
207 
208  const size_t initialPad = 2;
209  for (const auto &i : Checkers) {
210  out.indent(initialPad) << i.FullName;
211 
212  int pad = optionFieldWidth - i.FullName.size();
213 
214  // Break on long option names.
215  if (pad < 0) {
216  out << '\n';
217  pad = optionFieldWidth + initialPad;
218  }
219  out.indent(pad + 2) << i.Desc;
220 
221  out << '\n';
222  }
223 }
224 
225 void CheckerRegistry::printList(raw_ostream &out,
226  const AnalyzerOptions &opts) const {
227  llvm::sort(Checkers, checkerNameLT);
228 
230  // Collect checkers enabled by the options.
231  CheckerInfoSet enabledCheckers;
232  for (auto &i : checkerOpts)
233  collectCheckers(Checkers, Packages, i, enabledCheckers);
234 
235  for (const auto *i : enabledCheckers)
236  out << i->FullName << '\n';
237 }
void validateCheckerOptions(const AnalyzerOptions &opts, DiagnosticsEngine &diags) const
Check if every option corresponds to a specific checker or package.
static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers, const llvm::StringMap< size_t > &packageSizes, CheckerOptInfo &opt, CheckerInfoSet &collected)
Collects the checkers for the supplied opt option into collected.
void printList(raw_ostream &out, const AnalyzerOptions &opts) const
static const char PackageSeparator
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1292
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
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.
static SmallVector< CheckerOptInfo, 8 > getCheckerOptList(const AnalyzerOptions &opts)
void addChecker(InitializationFunction fn, StringRef fullName, StringRef desc)
Adds a checker to the registry.
ConfigTable Config
A key-value table of use-specified configuration values.
static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag)
Dataflow Directional Tag Classes.
static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a, const CheckerRegistry::CheckerInfo &b)
std::vector< CheckerInfo > CheckerInfoList
llvm::SetVector< const CheckerRegistry::CheckerInfo * > CheckerInfoSet
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)