CheckerRegistry.cpp revision 00bd44d5677783527d7517c1ffe45e4d75a0f56f
1//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
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/Core/CheckerRegistry.h"
11#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
12#include "llvm/ADT/SetVector.h"
13#include "llvm/ADT/STLExtras.h"
14
15using namespace clang;
16using namespace ento;
17
18static const char PackageSeparator = '.';
19typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
20
21
22static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
23                          const CheckerRegistry::CheckerInfo &b) {
24  return a.FullName < b.FullName;
25}
26
27static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
28                        StringRef packageName) {
29  // Does the checker's full name have the package as a prefix?
30  if (!checker.FullName.startswith(packageName))
31    return false;
32
33  // Is the package actually just the name of a specific checker?
34  if (checker.FullName.size() == packageName.size())
35    return true;
36
37  // Is the checker in the package (or a subpackage)?
38  if (checker.FullName[packageName.size()] == PackageSeparator)
39    return true;
40
41  return false;
42}
43
44static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
45                            const llvm::StringMap<size_t> &packageSizes,
46                            CheckerOptInfo &opt, CheckerInfoSet &collected) {
47  // Use a binary search to find the possible start of the package.
48  CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), "");
49  CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
50  CheckerRegistry::CheckerInfoList::const_iterator i =
51    std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
52
53  // If we didn't even find a possible package, give up.
54  if (i == e)
55    return;
56
57  // If what we found doesn't actually start the package, give up.
58  if (!isInPackage(*i, opt.getName()))
59    return;
60
61  // There is at least one checker in the package; claim the option.
62  opt.claim();
63
64  // See how large the package is.
65  // If the package doesn't exist, assume the option refers to a single checker.
66  size_t size = 1;
67  llvm::StringMap<size_t>::const_iterator packageSize =
68    packageSizes.find(opt.getName());
69  if (packageSize != packageSizes.end())
70    size = packageSize->getValue();
71
72  // Step through all the checkers in the package.
73  for (e = i+size; i != e; ++i) {
74    if (opt.isEnabled())
75      collected.insert(&*i);
76    else
77      collected.remove(&*i);
78  }
79}
80
81void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
82                                 StringRef desc) {
83  Checkers.push_back(CheckerInfo(fn, name, desc));
84
85  // Record the presence of the checker in its packages.
86  StringRef packageName, leafName;
87  llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator);
88  while (!leafName.empty()) {
89    Packages[packageName] += 1;
90    llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
91  }
92}
93
94void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
95                                  SmallVectorImpl<CheckerOptInfo> &opts) const {
96  // Sort checkers for efficient collection.
97  std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
98
99  // Collect checkers enabled by the options.
100  CheckerInfoSet enabledCheckers;
101  for (SmallVectorImpl<CheckerOptInfo>::iterator
102         i = opts.begin(), e = opts.end(); i != e; ++i) {
103    collectCheckers(Checkers, Packages, *i, enabledCheckers);
104  }
105
106  // Initialize the CheckerManager with all enabled checkers.
107  for (CheckerInfoSet::iterator
108         i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
109    (*i)->Initialize(checkerMgr);
110  }
111}
112
113void CheckerRegistry::printHelp(llvm::raw_ostream &out,
114                                size_t maxNameChars) const {
115  // FIXME: Alphabetical sort puts 'experimental' in the middle.
116  // Would it be better to name it '~experimental' or something else
117  // that's ASCIIbetically last?
118  std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
119
120  // FIXME: Print available packages.
121
122  out << "CHECKERS:\n";
123
124  // Find the maximum option length.
125  size_t optionFieldWidth = 0;
126  for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
127       i != e; ++i) {
128    // Limit the amount of padding we are willing to give up for alignment.
129    //   Package.Name     Description  [Hidden]
130    size_t nameLength = i->FullName.size();
131    if (nameLength <= maxNameChars)
132      optionFieldWidth = std::max(optionFieldWidth, nameLength);
133  }
134
135  const size_t initialPad = 2;
136  for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
137       i != e; ++i) {
138    out.indent(initialPad) << i->FullName;
139
140    int pad = optionFieldWidth - i->FullName.size();
141
142    // Break on long option names.
143    if (pad < 0) {
144      out << '\n';
145      pad = optionFieldWidth + initialPad;
146    }
147    out.indent(pad + 2) << i->Desc;
148
149    out << '\n';
150  }
151}
152