• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- 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"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/ADT/DenseSet.h"
21 #include "map"
22 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 
28 /// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
29 class ClangSACheckerProvider : public CheckerProvider {
30 public:
31   virtual void registerCheckers(CheckerManager &checkerMgr,
32                               CheckerOptInfo *checkOpts, unsigned numCheckOpts);
33   virtual void printHelp(llvm::raw_ostream &OS);
34 };
35 
36 }
37 
createClangSACheckerProvider()38 CheckerProvider *ento::createClangSACheckerProvider() {
39   return new ClangSACheckerProvider();
40 }
41 
42 namespace {
43 
44 struct StaticCheckerInfoRec {
45   const char *FullName;
46   void (*RegFunc)(CheckerManager &mgr);
47   const char *HelpText;
48   int GroupIndex;
49   bool Hidden;
50 };
51 
52 struct StaticPackageInfoRec {
53   const char *FullName;
54   int GroupIndex;
55   bool Hidden;
56 };
57 
58 struct StaticGroupInfoRec {
59   const char *FullName;
60 };
61 
62 } // end anonymous namespace.
63 
64 static 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 
74 static const unsigned NumPackages =   sizeof(StaticPackageInfo)
75                                     / sizeof(StaticPackageInfoRec) - 1;
76 
77 static 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 
87 static const unsigned NumGroups =   sizeof(StaticGroupInfo)
88                                     / sizeof(StaticGroupInfoRec) - 1;
89 
90 static const StaticCheckerInfoRec StaticCheckerInfo[] = {
91 #define GET_CHECKERS
92 #define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN)    \
93   { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN },
94 #include "Checkers.inc"
95   { 0, 0, 0, -1, 0}
96 #undef CHECKER
97 #undef GET_CHECKERS
98 };
99 
100 static const unsigned NumCheckers =   sizeof(StaticCheckerInfo)
101                                     / sizeof(StaticCheckerInfoRec) - 1;
102 
103 namespace {
104 
105 struct CheckNameOption {
106   const char  *Name;
107   const short *Members;
108   const short *SubGroups;
109   bool Hidden;
110 };
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.
119 static const CheckNameOption CheckNameTable[] = {
120 #define GET_CHECKNAME_TABLE
121 #include "Checkers.inc"
122 #undef GET_CHECKNAME_TABLE
123 };
124 static const size_t
125         CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);
126 
CheckNameOptionCompare(const CheckNameOption & LHS,const CheckNameOption & RHS)127 static bool CheckNameOptionCompare(const CheckNameOption &LHS,
128                                    const CheckNameOption &RHS) {
129   return strcmp(LHS.Name, RHS.Name) < 0;
130 }
131 
collectCheckers(const CheckNameOption * checkName,bool enable,llvm::DenseSet<const StaticCheckerInfoRec * > & checkers,bool collectHidden)132 static void collectCheckers(const CheckNameOption *checkName,
133                             bool enable,
134                          llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
135                             bool collectHidden) {
136   if (checkName->Hidden && !collectHidden)
137     return;
138 
139   if (const short *member = checkName->Members) {
140     if (enable) {
141       for (; *member != -1; ++member)
142         if (collectHidden || !StaticCheckerInfo[*member].Hidden)
143           checkers.insert(&StaticCheckerInfo[*member]);
144     } else {
145       for (; *member != -1; ++member)
146         checkers.erase(&StaticCheckerInfo[*member]);
147     }
148   }
149 
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);
155     }
156   }
157 }
158 
collectCheckers(CheckerOptInfo & opt,llvm::DenseSet<const StaticCheckerInfoRec * > & checkers)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.
169 
170   opt.claim();
171   collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
172 }
173 
registerCheckers(CheckerManager & checkerMgr,CheckerOptInfo * checkOpts,unsigned numCheckOpts)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);
182   }
183 }
184 
185 //===----------------------------------------------------------------------===//
186 // Printing Help.
187 //===----------------------------------------------------------------------===//
188 
printPackageOption(llvm::raw_ostream & OS)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);
195     if (Length <= 30)
196       OptionFieldWidth = std::max(OptionFieldWidth, Length);
197   }
198 
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;
205 
206     if (package.GroupIndex != -1 || package.Hidden) {
207       // Break on long option names.
208       if (Pad < 0) {
209         OS << "\n";
210         Pad = OptionFieldWidth + InitialPad;
211       }
212       OS.indent(Pad + 1) << "[";
213       if (package.GroupIndex != -1) {
214         OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName;
215         if (package.Hidden)
216           OS << ", ";
217       }
218       if (package.Hidden)
219         OS << "Hidden";
220       OS << "]";
221     }
222 
223     OS << "\n";
224   }
225 }
226 
227 typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
228 
printCheckerOption(llvm::raw_ostream & OS,SortedCheckers & checkers)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);
236     if (Length <= 30)
237       OptionFieldWidth = std::max(OptionFieldWidth, Length);
238   }
239 
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;
247 
248     // Break on long option names.
249     if (Pad < 0) {
250       OS << "\n";
251       Pad = OptionFieldWidth + InitialPad;
252     }
253     OS.indent(Pad + 1) << checker.HelpText;
254 
255     if (checker.GroupIndex != -1 || checker.Hidden) {
256       OS << "  [";
257       if (checker.GroupIndex != -1) {
258         OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName;
259         if (checker.Hidden)
260           OS << ", ";
261       }
262       if (checker.Hidden)
263         OS << "Hidden";
264       OS << "]";
265     }
266 
267     OS << "\n";
268   }
269 }
270 
printHelp(llvm::raw_ostream & OS)271 void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
272   OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n";
273 
274   OS << "\nGROUPS:\n";
275   for (unsigned i = 0; i != NumGroups; ++i)
276     OS.indent(2) << StaticGroupInfo[i].FullName << "\n";
277 
278   OS << "\nPACKAGES:\n";
279   printPackageOption(OS);
280 
281   OS << "\nCHECKERS:\n";
282 
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];
287 
288   printCheckerOption(OS, checkers);
289 }
290