1 | //==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file defines checkers that display debugging information. |
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 | // DominatorsTreeDumper |
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 | CFGDomTree Dom; |
39 | Dom.buildDominatorTree(cfg: AC->getCFG()); |
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 CheckerManager &mgr) { |
51 | return true; |
52 | } |
53 | |
54 | //===----------------------------------------------------------------------===// |
55 | // PostDominatorsTreeDumper |
56 | //===----------------------------------------------------------------------===// |
57 | |
58 | namespace { |
59 | class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> { |
60 | public: |
61 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
62 | BugReporter &BR) const { |
63 | if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { |
64 | CFGPostDomTree Dom; |
65 | Dom.buildDominatorTree(cfg: AC->getCFG()); |
66 | Dom.dump(); |
67 | } |
68 | } |
69 | }; |
70 | } |
71 | |
72 | void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { |
73 | mgr.registerChecker<PostDominatorsTreeDumper>(); |
74 | } |
75 | |
76 | bool ento::shouldRegisterPostDominatorsTreeDumper(const CheckerManager &mgr) { |
77 | return true; |
78 | } |
79 | |
80 | //===----------------------------------------------------------------------===// |
81 | // ControlDependencyTreeDumper |
82 | //===----------------------------------------------------------------------===// |
83 | |
84 | namespace { |
85 | class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> { |
86 | public: |
87 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
88 | BugReporter &BR) const { |
89 | if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { |
90 | ControlDependencyCalculator Dom(AC->getCFG()); |
91 | Dom.dump(); |
92 | } |
93 | } |
94 | }; |
95 | } |
96 | |
97 | void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) { |
98 | mgr.registerChecker<ControlDependencyTreeDumper>(); |
99 | } |
100 | |
101 | bool ento::shouldRegisterControlDependencyTreeDumper(const CheckerManager &mgr) { |
102 | return true; |
103 | } |
104 | |
105 | //===----------------------------------------------------------------------===// |
106 | // LiveVariablesDumper |
107 | //===----------------------------------------------------------------------===// |
108 | |
109 | namespace { |
110 | class LiveVariablesDumper : public Checker<check::ASTCodeBody> { |
111 | public: |
112 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
113 | BugReporter &BR) const { |
114 | if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { |
115 | L->dumpBlockLiveness(M: mgr.getSourceManager()); |
116 | } |
117 | } |
118 | }; |
119 | } |
120 | |
121 | void ento::registerLiveVariablesDumper(CheckerManager &mgr) { |
122 | mgr.registerChecker<LiveVariablesDumper>(); |
123 | } |
124 | |
125 | bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) { |
126 | return true; |
127 | } |
128 | |
129 | //===----------------------------------------------------------------------===// |
130 | // LiveStatementsDumper |
131 | //===----------------------------------------------------------------------===// |
132 | |
133 | namespace { |
134 | class LiveExpressionsDumper : public Checker<check::ASTCodeBody> { |
135 | public: |
136 | void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, |
137 | BugReporter &BR) const { |
138 | if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) |
139 | L->dumpExprLiveness(M: Mgr.getSourceManager()); |
140 | } |
141 | }; |
142 | } |
143 | |
144 | void ento::registerLiveExpressionsDumper(CheckerManager &mgr) { |
145 | mgr.registerChecker<LiveExpressionsDumper>(); |
146 | } |
147 | |
148 | bool ento::shouldRegisterLiveExpressionsDumper(const CheckerManager &mgr) { |
149 | return true; |
150 | } |
151 | |
152 | //===----------------------------------------------------------------------===// |
153 | // CFGViewer |
154 | //===----------------------------------------------------------------------===// |
155 | |
156 | namespace { |
157 | class CFGViewer : public Checker<check::ASTCodeBody> { |
158 | public: |
159 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
160 | BugReporter &BR) const { |
161 | if (CFG *cfg = mgr.getCFG(D)) { |
162 | cfg->viewCFG(LO: mgr.getLangOpts()); |
163 | } |
164 | } |
165 | }; |
166 | } |
167 | |
168 | void ento::registerCFGViewer(CheckerManager &mgr) { |
169 | mgr.registerChecker<CFGViewer>(); |
170 | } |
171 | |
172 | bool ento::shouldRegisterCFGViewer(const CheckerManager &mgr) { |
173 | return true; |
174 | } |
175 | |
176 | //===----------------------------------------------------------------------===// |
177 | // CFGDumper |
178 | //===----------------------------------------------------------------------===// |
179 | |
180 | namespace { |
181 | class CFGDumper : public Checker<check::ASTCodeBody> { |
182 | public: |
183 | void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, |
184 | BugReporter &BR) const { |
185 | PrintingPolicy Policy(mgr.getLangOpts()); |
186 | Policy.TerseOutput = true; |
187 | Policy.PolishForDeclaration = true; |
188 | D->print(Out&: llvm::errs(), Policy); |
189 | |
190 | if (CFG *cfg = mgr.getCFG(D)) { |
191 | cfg->dump(LO: mgr.getLangOpts(), |
192 | ShowColors: llvm::sys::Process::StandardErrHasColors()); |
193 | } |
194 | } |
195 | }; |
196 | } |
197 | |
198 | void ento::registerCFGDumper(CheckerManager &mgr) { |
199 | mgr.registerChecker<CFGDumper>(); |
200 | } |
201 | |
202 | bool ento::shouldRegisterCFGDumper(const CheckerManager &mgr) { |
203 | return true; |
204 | } |
205 | |
206 | //===----------------------------------------------------------------------===// |
207 | // CallGraphViewer |
208 | //===----------------------------------------------------------------------===// |
209 | |
210 | namespace { |
211 | class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > { |
212 | public: |
213 | void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, |
214 | BugReporter &BR) const { |
215 | CallGraph CG; |
216 | CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); |
217 | CG.viewGraph(); |
218 | } |
219 | }; |
220 | } |
221 | |
222 | void ento::registerCallGraphViewer(CheckerManager &mgr) { |
223 | mgr.registerChecker<CallGraphViewer>(); |
224 | } |
225 | |
226 | bool ento::shouldRegisterCallGraphViewer(const CheckerManager &mgr) { |
227 | return true; |
228 | } |
229 | |
230 | //===----------------------------------------------------------------------===// |
231 | // CallGraphDumper |
232 | //===----------------------------------------------------------------------===// |
233 | |
234 | namespace { |
235 | class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > { |
236 | public: |
237 | void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr, |
238 | BugReporter &BR) const { |
239 | CallGraph CG; |
240 | CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); |
241 | CG.dump(); |
242 | } |
243 | }; |
244 | } |
245 | |
246 | void ento::registerCallGraphDumper(CheckerManager &mgr) { |
247 | mgr.registerChecker<CallGraphDumper>(); |
248 | } |
249 | |
250 | bool ento::shouldRegisterCallGraphDumper(const CheckerManager &mgr) { |
251 | return true; |
252 | } |
253 | |
254 | //===----------------------------------------------------------------------===// |
255 | // ConfigDumper |
256 | //===----------------------------------------------------------------------===// |
257 | |
258 | namespace { |
259 | class ConfigDumper : public Checker< check::EndOfTranslationUnit > { |
260 | typedef AnalyzerOptions::ConfigTable Table; |
261 | |
262 | static int compareEntry(const Table::MapEntryTy *const *LHS, |
263 | const Table::MapEntryTy *const *RHS) { |
264 | return (*LHS)->getKey().compare(RHS: (*RHS)->getKey()); |
265 | } |
266 | |
267 | public: |
268 | void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, |
269 | AnalysisManager& mgr, |
270 | BugReporter &BR) const { |
271 | const Table &Config = mgr.options.Config; |
272 | |
273 | SmallVector<const Table::MapEntryTy *, 32> Keys; |
274 | for (const auto &Entry : Config) |
275 | Keys.push_back(Elt: &Entry); |
276 | llvm::array_pod_sort(Start: Keys.begin(), End: Keys.end(), Compare: compareEntry); |
277 | |
278 | llvm::errs() << "[config]\n" ; |
279 | for (unsigned I = 0, E = Keys.size(); I != E; ++I) |
280 | llvm::errs() << Keys[I]->getKey() << " = " |
281 | << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second) |
282 | << '\n'; |
283 | } |
284 | }; |
285 | } |
286 | |
287 | void ento::registerConfigDumper(CheckerManager &mgr) { |
288 | mgr.registerChecker<ConfigDumper>(); |
289 | } |
290 | |
291 | bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) { |
292 | return true; |
293 | } |
294 | |
295 | //===----------------------------------------------------------------------===// |
296 | // ExplodedGraph Viewer |
297 | //===----------------------------------------------------------------------===// |
298 | |
299 | namespace { |
300 | class ExplodedGraphViewer : public Checker< check::EndAnalysis > { |
301 | public: |
302 | ExplodedGraphViewer() {} |
303 | void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { |
304 | Eng.ViewGraph(trim: false); |
305 | } |
306 | }; |
307 | |
308 | } |
309 | |
310 | void ento::registerExplodedGraphViewer(CheckerManager &mgr) { |
311 | mgr.registerChecker<ExplodedGraphViewer>(); |
312 | } |
313 | |
314 | bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) { |
315 | return true; |
316 | } |
317 | |
318 | //===----------------------------------------------------------------------===// |
319 | // Emits a report for every Stmt that the analyzer visits. |
320 | //===----------------------------------------------------------------------===// |
321 | |
322 | namespace { |
323 | |
324 | class ReportStmts : public Checker<check::PreStmt<Stmt>> { |
325 | BugType BT_stmtLoc{this, "Statement" }; |
326 | |
327 | public: |
328 | void checkPreStmt(const Stmt *S, CheckerContext &C) const { |
329 | ExplodedNode *Node = C.generateNonFatalErrorNode(); |
330 | if (!Node) |
331 | return; |
332 | |
333 | auto Report = |
334 | std::make_unique<PathSensitiveBugReport>(args: BT_stmtLoc, args: "Statement" , args&: Node); |
335 | |
336 | C.emitReport(R: std::move(Report)); |
337 | } |
338 | }; |
339 | |
340 | } // end of anonymous namespace |
341 | |
342 | void ento::registerReportStmts(CheckerManager &mgr) { |
343 | mgr.registerChecker<ReportStmts>(); |
344 | } |
345 | |
346 | bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) { |
347 | return true; |
348 | } |
349 | |