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
14 using namespace clang;
15 using namespace ento;
16
17 static const char PackageSeparator = '.';
18 typedef llvm::SetVector<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
19
20
checkerNameLT(const CheckerRegistry::CheckerInfo & a,const CheckerRegistry::CheckerInfo & b)21 static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
22 const CheckerRegistry::CheckerInfo &b) {
23 return a.FullName < b.FullName;
24 }
25
isInPackage(const CheckerRegistry::CheckerInfo & checker,StringRef packageName)26 static 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
collectCheckers(const CheckerRegistry::CheckerInfoList & checkers,const llvm::StringMap<size_t> & packageSizes,CheckerOptInfo & opt,CheckerInfoSet & collected)43 static 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
addChecker(InitializationFunction fn,StringRef name,StringRef desc)80 void 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
initializeManager(CheckerManager & checkerMgr,SmallVectorImpl<CheckerOptInfo> & opts) const93 void 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
printHelp(llvm::raw_ostream & out,size_t maxNameChars) const112 void 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