blob: 461de3f68cbb0f7ce6abdc61b87b98d95f92a218 [file] [log] [blame]
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +00001//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===//
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// Defines the CheckerProvider for the checkers defined in
11// libclangStaticAnalyzerCheckers.
12//
13//===----------------------------------------------------------------------===//
14
15#include "ClangSACheckerProvider.h"
16#include "ClangSACheckers.h"
17#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000019#include "llvm/Support/raw_ostream.h"
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000020#include "llvm/ADT/DenseSet.h"
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000021#include "map"
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000022
23using namespace clang;
24using namespace ento;
25
26namespace {
27
28/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
29class ClangSACheckerProvider : public CheckerProvider {
30public:
31 virtual void registerCheckers(CheckerManager &checkerMgr,
32 CheckerOptInfo *checkOpts, unsigned numCheckOpts);
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000033 virtual void printHelp(llvm::raw_ostream &OS);
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000034};
35
36}
37
38CheckerProvider *ento::createClangSACheckerProvider() {
39 return new ClangSACheckerProvider();
40}
41
42namespace {
43
44struct StaticCheckerInfoRec {
45 const char *FullName;
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +000046 void (*RegFunc)(CheckerManager &mgr);
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000047 const char *HelpText;
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +000048 int GroupIndex;
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000049 bool Hidden;
50};
51
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +000052struct StaticPackageInfoRec {
53 const char *FullName;
54 int GroupIndex;
55 bool Hidden;
56};
57
58struct StaticGroupInfoRec {
59 const char *FullName;
60};
61
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000062} // end anonymous namespace.
63
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +000064static const StaticPackageInfoRec StaticPackageInfo[] = {
65#define GET_PACKAGES
66#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \
67 { FULLNAME, GROUPINDEX, HIDDEN },
68#include "Checkers.inc"
69 { 0, -1, 0 }
70#undef PACKAGE
71#undef GET_PACKAGES
72};
73
74static const unsigned NumPackages = sizeof(StaticPackageInfo)
75 / sizeof(StaticPackageInfoRec) - 1;
76
77static const StaticGroupInfoRec StaticGroupInfo[] = {
78#define GET_GROUPS
79#define GROUP(FULLNAME) \
80 { FULLNAME },
81#include "Checkers.inc"
82 { 0 }
83#undef GROUP
84#undef GET_GROUPS
85};
86
87static const unsigned NumGroups = sizeof(StaticGroupInfo)
88 / sizeof(StaticGroupInfoRec) - 1;
89
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000090static const StaticCheckerInfoRec StaticCheckerInfo[] = {
91#define GET_CHECKERS
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +000092#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
93 { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN },
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000094#include "Checkers.inc"
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +000095 { 0, 0, 0, -1, 0}
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000096#undef CHECKER
97#undef GET_CHECKERS
98};
99
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000100static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
101 / sizeof(StaticCheckerInfoRec) - 1;
102
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000103namespace {
104
105struct CheckNameOption {
106 const char *Name;
107 const short *Members;
108 const short *SubGroups;
Argyrios Kyrtzidis26c05b12011-02-15 07:42:38 +0000109 bool Hidden;
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000110};
111
112} // end anonymous namespace.
113
114#define GET_MEMBER_ARRAYS
115#include "Checkers.inc"
116#undef GET_MEMBER_ARRAYS
117
118// The table of check name options, sorted by name for fast binary lookup.
119static const CheckNameOption CheckNameTable[] = {
120#define GET_CHECKNAME_TABLE
121#include "Checkers.inc"
122#undef GET_CHECKNAME_TABLE
123};
124static const size_t
125 CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);
126
127static bool CheckNameOptionCompare(const CheckNameOption &LHS,
128 const CheckNameOption &RHS) {
129 return strcmp(LHS.Name, RHS.Name) < 0;
130}
131
132static void collectCheckers(const CheckNameOption *checkName,
133 bool enable,
134 llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
135 bool collectHidden) {
Argyrios Kyrtzidis26c05b12011-02-15 07:42:38 +0000136 if (checkName->Hidden && !collectHidden)
137 return;
138
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000139 if (const short *member = checkName->Members) {
140 if (enable) {
141 if (collectHidden || !StaticCheckerInfo[*member].Hidden)
142 checkers.insert(&StaticCheckerInfo[*member]);
143 } else {
144 for (; *member != -1; ++member)
145 checkers.erase(&StaticCheckerInfo[*member]);
146 }
147 }
148
149 // Enable/disable all subgroups along with this one.
150 if (const short *subGroups = checkName->SubGroups) {
Argyrios Kyrtzidis08099ad2011-02-24 21:42:52 +0000151 for (; *subGroups != -1; ++subGroups) {
152 const CheckNameOption *sub = &CheckNameTable[*subGroups];
153 collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
154 }
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000155 }
156}
157
158static void collectCheckers(CheckerOptInfo &opt,
159 llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
160 const char *optName = opt.getName();
Argyrios Kyrtzidis26c05b12011-02-15 07:42:38 +0000161 CheckNameOption key = { optName, 0, 0, false };
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000162 const CheckNameOption *found =
163 std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
164 CheckNameOptionCompare);
165 if (found == CheckNameTable + CheckNameTableSize ||
166 strcmp(found->Name, optName) != 0)
167 return; // Check name not found.
168
169 opt.claim();
170 collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
171}
172
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000173void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
174 CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
175 llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
176 for (unsigned i = 0; i != numCheckOpts; ++i)
177 collectCheckers(checkOpts[i], enabledCheckers);
178 for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
179 I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000180 (*I)->RegFunc(checkerMgr);
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000181 }
182}
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000183
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +0000184//===----------------------------------------------------------------------===//
185// Printing Help.
186//===----------------------------------------------------------------------===//
187
188static void printPackageOption(llvm::raw_ostream &OS) {
189 // Find the maximum option length.
190 unsigned OptionFieldWidth = 0;
191 for (unsigned i = 0; i != NumPackages; ++i) {
192 // Limit the amount of padding we are willing to give up for alignment.
193 unsigned Length = strlen(StaticPackageInfo[i].FullName);
194 if (Length <= 30)
195 OptionFieldWidth = std::max(OptionFieldWidth, Length);
196 }
197
198 const unsigned InitialPad = 2;
199 for (unsigned i = 0; i != NumPackages; ++i) {
200 const StaticPackageInfoRec &package = StaticPackageInfo[i];
201 const std::string &Option = package.FullName;
202 int Pad = OptionFieldWidth - int(Option.size());
203 OS.indent(InitialPad) << Option;
204
205 if (package.GroupIndex != -1 || package.Hidden) {
206 // Break on long option names.
207 if (Pad < 0) {
208 OS << "\n";
209 Pad = OptionFieldWidth + InitialPad;
210 }
211 OS.indent(Pad + 1) << "[";
212 if (package.GroupIndex != -1) {
213 OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName;
214 if (package.Hidden)
215 OS << ", ";
216 }
217 if (package.Hidden)
218 OS << "Hidden";
219 OS << "]";
220 }
221
222 OS << "\n";
223 }
224}
225
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000226typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
227
228static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
229 // Find the maximum option length.
230 unsigned OptionFieldWidth = 0;
231 for (SortedCheckers::iterator
232 I = checkers.begin(), E = checkers.end(); I != E; ++I) {
233 // Limit the amount of padding we are willing to give up for alignment.
234 unsigned Length = strlen(I->second->FullName);
235 if (Length <= 30)
236 OptionFieldWidth = std::max(OptionFieldWidth, Length);
237 }
238
239 const unsigned InitialPad = 2;
240 for (SortedCheckers::iterator
241 I = checkers.begin(), E = checkers.end(); I != E; ++I) {
242 const std::string &Option = I->first;
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +0000243 const StaticCheckerInfoRec &checker = *I->second;
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000244 int Pad = OptionFieldWidth - int(Option.size());
245 OS.indent(InitialPad) << Option;
246
247 // Break on long option names.
248 if (Pad < 0) {
249 OS << "\n";
250 Pad = OptionFieldWidth + InitialPad;
251 }
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +0000252 OS.indent(Pad + 1) << checker.HelpText;
253
254 if (checker.GroupIndex != -1 || checker.Hidden) {
255 OS << " [";
256 if (checker.GroupIndex != -1) {
257 OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName;
258 if (checker.Hidden)
259 OS << ", ";
260 }
261 if (checker.Hidden)
262 OS << "Hidden";
263 OS << "]";
264 }
265
266 OS << "\n";
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000267 }
268}
269
270void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
Argyrios Kyrtzidis9bc1afc2011-03-29 23:57:38 +0000271 OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n";
272
273 OS << "\nGROUPS:\n";
274 for (unsigned i = 0; i != NumGroups; ++i)
275 OS.indent(2) << StaticGroupInfo[i].FullName << "\n";
276
277 OS << "\nPACKAGES:\n";
278 printPackageOption(OS);
279
280 OS << "\nCHECKERS:\n";
281
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000282 // Sort checkers according to their full name.
283 SortedCheckers checkers;
284 for (unsigned i = 0; i != NumCheckers; ++i)
285 checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
286
287 printCheckerOption(OS, checkers);
288}