1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
14 | #include "clang/Analysis/Analyses/Dominators.h" |
15 | #include "clang/Analysis/Analyses/LiveVariables.h" |
16 | #include "clang/Analysis/CallGraph.h" |
17 | #include "clang/StaticAnalyzer/Core/Checker.h" |
18 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
19 | #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" |
20 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
21 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" |
22 | #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" |
23 | #include "llvm/Support/Process.h" |
24 | |
25 | using namespace clang; |
26 | using namespace ento; |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | namespace { |
33 | class DominatorsTreeDumper : public Checker<check::ASTCodeBody> { |
34 | public: |
35 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
36 | BugReporter &BR) const { |
37 | if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { |
38 | DominatorTree dom; |
39 | dom.buildDominatorTree(*AC); |
40 | dom.dump(); |
41 | } |
42 | } |
43 | }; |
44 | } |
45 | |
46 | void ento::registerDominatorsTreeDumper(CheckerManager &mgr) { |
47 | mgr.registerChecker<DominatorsTreeDumper>(); |
48 | } |
49 | |
50 | bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) { |
51 | return true; |
52 | } |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | namespace { |
59 | class LiveVariablesDumper : public Checker<check::ASTCodeBody> { |
60 | public: |
61 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
62 | BugReporter &BR) const { |
63 | if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { |
64 | L->dumpBlockLiveness(mgr.getSourceManager()); |
65 | } |
66 | } |
67 | }; |
68 | } |
69 | |
70 | void ento::registerLiveVariablesDumper(CheckerManager &mgr) { |
71 | mgr.registerChecker<LiveVariablesDumper>(); |
72 | } |
73 | |
74 | bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { |
75 | return true; |
76 | } |
77 | |
78 | |
79 | |
80 | |
81 | |
82 | namespace { |
83 | class LiveStatementsDumper : public Checker<check::ASTCodeBody> { |
84 | public: |
85 | void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, |
86 | BugReporter &BR) const { |
87 | if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) |
88 | L->dumpStmtLiveness(Mgr.getSourceManager()); |
89 | } |
90 | }; |
91 | } |
92 | |
93 | void ento::registerLiveStatementsDumper(CheckerManager &mgr) { |
94 | mgr.registerChecker<LiveStatementsDumper>(); |
95 | } |
96 | |
97 | bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { |
98 | return true; |
99 | } |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | namespace { |
106 | class CFGViewer : public Checker<check::ASTCodeBody> { |
107 | public: |
108 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
109 | BugReporter &BR) const { |
110 | if (CFG *cfg = mgr.getCFG(D)) { |
111 | cfg->viewCFG(mgr.getLangOpts()); |
112 | } |
113 | } |
114 | }; |
115 | } |
116 | |
117 | void ento::registerCFGViewer(CheckerManager &mgr) { |
118 | mgr.registerChecker<CFGViewer>(); |
119 | } |
120 | |
121 | bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { |
122 | return true; |
123 | } |
124 | |
125 | |
126 | |
127 | |
128 | |
129 | namespace { |
130 | class CFGDumper : public Checker<check::ASTCodeBody> { |
131 | public: |
132 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
133 | BugReporter &BR) const { |
134 | PrintingPolicy Policy(mgr.getLangOpts()); |
135 | Policy.TerseOutput = true; |
136 | Policy.PolishForDeclaration = true; |
137 | D->print(llvm::errs(), Policy); |
138 | |
139 | if (CFG *cfg = mgr.getCFG(D)) { |
140 | cfg->dump(mgr.getLangOpts(), |
141 | llvm::sys::Process::StandardErrHasColors()); |
142 | } |
143 | } |
144 | }; |
145 | } |
146 | |
147 | void ento::registerCFGDumper(CheckerManager &mgr) { |
148 | mgr.registerChecker<CFGDumper>(); |
149 | } |
150 | |
151 | bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { |
152 | return true; |
153 | } |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | namespace { |
160 | class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { |
161 | public: |
162 | void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, |
163 | BugReporter &BR) const { |
164 | CallGraph CG; |
165 | CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); |
166 | CG.viewGraph(); |
167 | } |
168 | }; |
169 | } |
170 | |
171 | void ento::registerCallGraphViewer(CheckerManager &mgr) { |
172 | mgr.registerChecker<CallGraphViewer>(); |
173 | } |
174 | |
175 | bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { |
176 | return true; |
177 | } |
178 | |
179 | |
180 | |
181 | |
182 | |
183 | namespace { |
184 | class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { |
185 | public: |
186 | void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, |
187 | BugReporter &BR) const { |
188 | CallGraph CG; |
189 | CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); |
190 | CG.dump(); |
191 | } |
192 | }; |
193 | } |
194 | |
195 | void ento::registerCallGraphDumper(CheckerManager &mgr) { |
196 | mgr.registerChecker<CallGraphDumper>(); |
197 | } |
198 | |
199 | bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { |
200 | return true; |
201 | } |
202 | |
203 | |
204 | |
205 | |
206 | |
207 | namespace { |
208 | class ConfigDumper : public Checker< check::EndOfTranslationUnit > { |
209 | typedef AnalyzerOptions::ConfigTable Table; |
210 | |
211 | static int compareEntry(const Table::MapEntryTy *const *LHS, |
212 | const Table::MapEntryTy *const *RHS) { |
213 | return (*LHS)->getKey().compare((*RHS)->getKey()); |
214 | } |
215 | |
216 | public: |
217 | void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, |
218 | AnalysisManager& mgr, |
219 | BugReporter &BR) const { |
220 | const Table &Config = mgr.options.Config; |
221 | |
222 | SmallVector<const Table::MapEntryTy *, 32> Keys; |
223 | for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; |
224 | ++I) |
225 | Keys.push_back(&*I); |
226 | llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); |
227 | |
228 | llvm::errs() << "[config]\n"; |
229 | for (unsigned I = 0, E = Keys.size(); I != E; ++I) |
230 | llvm::errs() << Keys[I]->getKey() << " = " |
231 | << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second) |
232 | << '\n'; |
233 | |
234 | llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; |
235 | } |
236 | }; |
237 | } |
238 | |
239 | void ento::registerConfigDumper(CheckerManager &mgr) { |
240 | mgr.registerChecker<ConfigDumper>(); |
241 | } |
242 | |
243 | bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { |
244 | return true; |
245 | } |
246 | |
247 | |
248 | |
249 | |
250 | |
251 | namespace { |
252 | class ExplodedGraphViewer : public Checker< check::EndAnalysis > { |
253 | public: |
254 | ExplodedGraphViewer() {} |
255 | void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { |
256 | Eng.ViewGraph(0); |
257 | } |
258 | }; |
259 | |
260 | } |
261 | |
262 | void ento::registerExplodedGraphViewer(CheckerManager &mgr) { |
263 | mgr.registerChecker<ExplodedGraphViewer>(); |
264 | } |
265 | |
266 | bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { |
267 | return true; |
268 | } |
269 | |
270 | |
271 | |
272 | |
273 | |
274 | namespace { |
275 | |
276 | class ReportStmts : public Checker<check::PreStmt<Stmt>> { |
277 | BuiltinBug BT_stmtLoc{this, "Statement"}; |
278 | |
279 | public: |
280 | void checkPreStmt(const Stmt *S, CheckerContext &C) const { |
281 | ExplodedNode *Node = C.generateNonFatalErrorNode(); |
282 | if (!Node) |
283 | return; |
284 | |
285 | auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node); |
286 | |
287 | C.emitReport(std::move(Report)); |
288 | } |
289 | }; |
290 | |
291 | } |
292 | |
293 | void ento::registerReportStmts(CheckerManager &mgr) { |
294 | mgr.registerChecker<ReportStmts>(); |
295 | } |
296 | |
297 | bool ento::shouldRegisterReportStmts(const LangOptions &LO) { |
298 | return true; |
299 | } |
300 | |