blob: 5c0c9504db03843a05763dd30fcd7621369a3171 [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 Kyrtzidis43dee222011-02-14 18:13:31 +000048 bool Hidden;
49};
50
51} // end anonymous namespace.
52
53static const StaticCheckerInfoRec StaticCheckerInfo[] = {
54#define GET_CHECKERS
55#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN) \
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000056 { FULLNAME, register##CLASS, HELPTEXT, HIDDEN },
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000057#include "Checkers.inc"
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000058 { 0, 0, 0, 0}
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000059#undef CHECKER
60#undef GET_CHECKERS
61};
62
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +000063static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
64 / sizeof(StaticCheckerInfoRec) - 1;
65
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000066namespace {
67
68struct CheckNameOption {
69 const char *Name;
70 const short *Members;
71 const short *SubGroups;
Argyrios Kyrtzidis26c05b12011-02-15 07:42:38 +000072 bool Hidden;
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +000073};
74
75} // end anonymous namespace.
76
77#define GET_MEMBER_ARRAYS
78#include "Checkers.inc"
79#undef GET_MEMBER_ARRAYS
80
81// The table of check name options, sorted by name for fast binary lookup.
82static const CheckNameOption CheckNameTable[] = {
83#define GET_CHECKNAME_TABLE
84#include "Checkers.inc"
85#undef GET_CHECKNAME_TABLE
86};
87static const size_t
88 CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);
89
90static bool CheckNameOptionCompare(const CheckNameOption &LHS,
91 const CheckNameOption &RHS) {
92 return strcmp(LHS.Name, RHS.Name) < 0;
93}
94
95static void collectCheckers(const CheckNameOption *checkName,
96 bool enable,
97 llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
98 bool collectHidden) {
Argyrios Kyrtzidis26c05b12011-02-15 07:42:38 +000099 if (checkName->Hidden && !collectHidden)
100 return;
101
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000102 if (const short *member = checkName->Members) {
103 if (enable) {
104 if (collectHidden || !StaticCheckerInfo[*member].Hidden)
105 checkers.insert(&StaticCheckerInfo[*member]);
106 } else {
107 for (; *member != -1; ++member)
108 checkers.erase(&StaticCheckerInfo[*member]);
109 }
110 }
111
112 // Enable/disable all subgroups along with this one.
113 if (const short *subGroups = checkName->SubGroups) {
Argyrios Kyrtzidis08099ad2011-02-24 21:42:52 +0000114 for (; *subGroups != -1; ++subGroups) {
115 const CheckNameOption *sub = &CheckNameTable[*subGroups];
116 collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
117 }
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000118 }
119}
120
121static void collectCheckers(CheckerOptInfo &opt,
122 llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
123 const char *optName = opt.getName();
Argyrios Kyrtzidis26c05b12011-02-15 07:42:38 +0000124 CheckNameOption key = { optName, 0, 0, false };
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000125 const CheckNameOption *found =
126 std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
127 CheckNameOptionCompare);
128 if (found == CheckNameTable + CheckNameTableSize ||
129 strcmp(found->Name, optName) != 0)
130 return; // Check name not found.
131
132 opt.claim();
133 collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
134}
135
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000136void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
137 CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
138 llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
139 for (unsigned i = 0; i != numCheckOpts; ++i)
140 collectCheckers(checkOpts[i], enabledCheckers);
141 for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
142 I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
Argyrios Kyrtzidis695fb502011-02-17 21:39:17 +0000143 (*I)->RegFunc(checkerMgr);
Argyrios Kyrtzidis43dee222011-02-14 18:13:31 +0000144 }
145}
Argyrios Kyrtzidis116f3642011-02-25 00:09:51 +0000146
147typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
148
149static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) {
150 // Find the maximum option length.
151 unsigned OptionFieldWidth = 0;
152 for (SortedCheckers::iterator
153 I = checkers.begin(), E = checkers.end(); I != E; ++I) {
154 // Limit the amount of padding we are willing to give up for alignment.
155 unsigned Length = strlen(I->second->FullName);
156 if (Length <= 30)
157 OptionFieldWidth = std::max(OptionFieldWidth, Length);
158 }
159
160 const unsigned InitialPad = 2;
161 for (SortedCheckers::iterator
162 I = checkers.begin(), E = checkers.end(); I != E; ++I) {
163 const std::string &Option = I->first;
164 int Pad = OptionFieldWidth - int(Option.size());
165 OS.indent(InitialPad) << Option;
166
167 // Break on long option names.
168 if (Pad < 0) {
169 OS << "\n";
170 Pad = OptionFieldWidth + InitialPad;
171 }
172 OS.indent(Pad + 1) << I->second->HelpText << '\n';
173 }
174}
175
176void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) {
177 // Sort checkers according to their full name.
178 SortedCheckers checkers;
179 for (unsigned i = 0; i != NumCheckers; ++i)
180 checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
181
182 printCheckerOption(OS, checkers);
183}