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