1 //===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Defines the CheckerProvider for the checkers defined in
11 // libclangStaticAnalyzerCheckers.
13 //===----------------------------------------------------------------------===//
15 #include "ClangSACheckerProvider.h"
16 #include "ClangSACheckers.h"
17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18 #include "clang/StaticAnalyzer/Core/CheckerProvider.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/ADT/DenseSet.h"
23 using namespace clang;
28 /// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
29 class ClangSACheckerProvider : public CheckerProvider {
31 virtual void registerCheckers(CheckerManager &checkerMgr,
32 CheckerOptInfo *checkOpts, unsigned numCheckOpts);
33 virtual void printHelp(llvm::raw_ostream &OS);
38 CheckerProvider *ento::createClangSACheckerProvider() {
39 return new ClangSACheckerProvider();
44 struct StaticCheckerInfoRec {
46 void (*RegFunc)(CheckerManager &mgr);
52 struct StaticPackageInfoRec {
58 struct StaticGroupInfoRec {
62 } // end anonymous namespace.
64 static const StaticPackageInfoRec StaticPackageInfo[] = {
66 #define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \
67 { FULLNAME, GROUPINDEX, HIDDEN },
68 #include "Checkers.inc"
74 static const unsigned NumPackages = sizeof(StaticPackageInfo)
75 / sizeof(StaticPackageInfoRec) - 1;
77 static const StaticGroupInfoRec StaticGroupInfo[] = {
79 #define GROUP(FULLNAME) \
81 #include "Checkers.inc"
87 static const unsigned NumGroups = sizeof(StaticGroupInfo)
88 / sizeof(StaticGroupInfoRec) - 1;
90 static const StaticCheckerInfoRec StaticCheckerInfo[] = {
92 #define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
93 { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN },
94 #include "Checkers.inc"
100 static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
101 / sizeof(StaticCheckerInfoRec) - 1;
105 struct CheckNameOption {
107 const short *Members;
108 const short *SubGroups;
112 } // end anonymous namespace.
114 #define GET_MEMBER_ARRAYS
115 #include "Checkers.inc"
116 #undef GET_MEMBER_ARRAYS
118 // The table of check name options, sorted by name for fast binary lookup.
119 static const CheckNameOption CheckNameTable[] = {
120 #define GET_CHECKNAME_TABLE
121 #include "Checkers.inc"
122 #undef GET_CHECKNAME_TABLE
125 CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);
127 static bool CheckNameOptionCompare(const CheckNameOption &LHS,
128 const CheckNameOption &RHS) {
129 return strcmp(LHS.Name, RHS.Name) < 0;
132 static void collectCheckers(const CheckNameOption *checkName,
134 llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
135 bool collectHidden) {
136 if (checkName->Hidden && !collectHidden)
139 if (const short *member = checkName->Members) {
141 for (; *member != -1; ++member)
142 if (collectHidden || !StaticCheckerInfo[*member].Hidden)
143 checkers.insert(&StaticCheckerInfo[*member]);
145 for (; *member != -1; ++member)
146 checkers.erase(&StaticCheckerInfo[*member]);
150 // Enable/disable all subgroups along with this one.
151 if (const short *subGroups = checkName->SubGroups) {
152 for (; *subGroups != -1; ++subGroups) {
153 const CheckNameOption *sub = &CheckNameTable[*subGroups];
154 collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
159 static void collectCheckers(CheckerOptInfo &opt,
160 llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
161 const char *optName = opt.getName();
162 CheckNameOption key = { optName, 0, 0, false };
163 const CheckNameOption *found =
164 std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
165 CheckNameOptionCompare);
166 if (found == CheckNameTable + CheckNameTableSize ||
167 strcmp(found->Name, optName) != 0)
168 return; // Check name not found.
171 collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
174 void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
175 CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
176 llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
177 for (unsigned i = 0; i != numCheckOpts; ++i)
178 collectCheckers(checkOpts[i], enabledCheckers);
179 for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
180 I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
181 (*I)->RegFunc(checkerMgr);
185 //===----------------------------------------------------------------------===//
187 //===----------------------------------------------------------------------===//
189 static void printPackageOption(llvm::raw_ostream &OS) {
190 // Find the maximum option length.
191 unsigned OptionFieldWidth = 0;
192 for (unsigned i = 0; i != NumPackages; ++i) {
193 // Limit the amount of padding we are willing to give up for alignment.
194 unsigned Length = strlen(StaticPackageInfo[i].FullName);
196 OptionFieldWidth = std::max(OptionFieldWidth, Length);
199 const unsigned InitialPad = 2;
200 for (unsigned i = 0; i != NumPackages; ++i) {
201 const StaticPackageInfoRec &package = StaticPackageInfo[i];
202 const std::string &Option = package.FullName;
203 int Pad = OptionFieldWidth - int(Option.size());
204 OS.indent(InitialPad) << Option;
206 if (package.GroupIndex != -1 || package.Hidden) {
207 // Break on long option names.
210 Pad = OptionFieldWidth + InitialPad;
212 OS.indent(Pad + 1) << "[";
213 if (package.GroupIndex != -1) {
214 OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName;
227 typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
229 static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
230 // Find the maximum option length.
231 unsigned OptionFieldWidth = 0;
232 for (SortedCheckers::iterator
233 I = checkers.begin(), E = checkers.end(); I != E; ++I) {
234 // Limit the amount of padding we are willing to give up for alignment.
235 unsigned Length = strlen(I->second->FullName);
237 OptionFieldWidth = std::max(OptionFieldWidth, Length);
240 const unsigned InitialPad = 2;
241 for (SortedCheckers::iterator
242 I = checkers.begin(), E = checkers.end(); I != E; ++I) {
243 const std::string &Option = I->first;
244 const StaticCheckerInfoRec &checker = *I->second;
245 int Pad = OptionFieldWidth - int(Option.size());
246 OS.indent(InitialPad) << Option;
248 // Break on long option names.
251 Pad = OptionFieldWidth + InitialPad;
253 OS.indent(Pad + 1) << checker.HelpText;
255 if (checker.GroupIndex != -1 || checker.Hidden) {
257 if (checker.GroupIndex != -1) {
258 OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName;
271 void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
272 OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n";
275 for (unsigned i = 0; i != NumGroups; ++i)
276 OS.indent(2) << StaticGroupInfo[i].FullName << "\n";
278 OS << "\nPACKAGES:\n";
279 printPackageOption(OS);
281 OS << "\nCHECKERS:\n";
283 // Sort checkers according to their full name.
284 SortedCheckers checkers;
285 for (unsigned i = 0; i != NumCheckers; ++i)
286 checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
288 printCheckerOption(OS, checkers);