/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 7 | BugReporter &BR) const { |
37 | 7 | if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { |
38 | 7 | CFGDomTree Dom; |
39 | 7 | Dom.buildDominatorTree(AC->getCFG()); |
40 | 7 | Dom.dump(); |
41 | 7 | } |
42 | 7 | } |
43 | | }; |
44 | | } |
45 | | |
46 | 2 | void ento::registerDominatorsTreeDumper(CheckerManager &mgr) { |
47 | 2 | mgr.registerChecker<DominatorsTreeDumper>(); |
48 | 2 | } |
49 | | |
50 | 2 | bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) { |
51 | 2 | return true; |
52 | 2 | } |
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 | 7 | BugReporter &BR) const { |
63 | 7 | if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { |
64 | 7 | CFGPostDomTree Dom; |
65 | 7 | Dom.buildDominatorTree(AC->getCFG()); |
66 | 7 | Dom.dump(); |
67 | 7 | } |
68 | 7 | } |
69 | | }; |
70 | | } |
71 | | |
72 | 2 | void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { |
73 | 2 | mgr.registerChecker<PostDominatorsTreeDumper>(); |
74 | 2 | } |
75 | | |
76 | 2 | bool ento::shouldRegisterPostDominatorsTreeDumper(const LangOptions &LO) { |
77 | 2 | return true; |
78 | 2 | } |
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 | 7 | BugReporter &BR) const { |
89 | 7 | if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { |
90 | 7 | ControlDependencyCalculator Dom(AC->getCFG()); |
91 | 7 | Dom.dump(); |
92 | 7 | } |
93 | 7 | } |
94 | | }; |
95 | | } |
96 | | |
97 | 2 | void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) { |
98 | 2 | mgr.registerChecker<ControlDependencyTreeDumper>(); |
99 | 2 | } |
100 | | |
101 | 2 | bool ento::shouldRegisterControlDependencyTreeDumper(const LangOptions &LO) { |
102 | 2 | return true; |
103 | 2 | } |
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 | 0 | BugReporter &BR) const { |
114 | 0 | if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) { |
115 | 0 | L->dumpBlockLiveness(mgr.getSourceManager()); |
116 | 0 | } |
117 | 0 | } |
118 | | }; |
119 | | } |
120 | | |
121 | 0 | void ento::registerLiveVariablesDumper(CheckerManager &mgr) { |
122 | 0 | mgr.registerChecker<LiveVariablesDumper>(); |
123 | 0 | } |
124 | | |
125 | 0 | bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { |
126 | 0 | return true; |
127 | 0 | } |
128 | | |
129 | | //===----------------------------------------------------------------------===// |
130 | | // LiveStatementsDumper |
131 | | //===----------------------------------------------------------------------===// |
132 | | |
133 | | namespace { |
134 | | class LiveStatementsDumper : public Checker<check::ASTCodeBody> { |
135 | | public: |
136 | | void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr, |
137 | 5 | BugReporter &BR) const { |
138 | 5 | if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D)) |
139 | 5 | L->dumpStmtLiveness(Mgr.getSourceManager()); |
140 | 5 | } |
141 | | }; |
142 | | } |
143 | | |
144 | 1 | void ento::registerLiveStatementsDumper(CheckerManager &mgr) { |
145 | 1 | mgr.registerChecker<LiveStatementsDumper>(); |
146 | 1 | } |
147 | | |
148 | 1 | bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { |
149 | 1 | return true; |
150 | 1 | } |
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 | 0 | BugReporter &BR) const { |
161 | 0 | if (CFG *cfg = mgr.getCFG(D)) { |
162 | 0 | cfg->viewCFG(mgr.getLangOpts()); |
163 | 0 | } |
164 | 0 | } |
165 | | }; |
166 | | } |
167 | | |
168 | 0 | void ento::registerCFGViewer(CheckerManager &mgr) { |
169 | 0 | mgr.registerChecker<CFGViewer>(); |
170 | 0 | } |
171 | | |
172 | 0 | bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { |
173 | 0 | return true; |
174 | 0 | } |
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 | 670 | BugReporter &BR) const { |
185 | 670 | PrintingPolicy Policy(mgr.getLangOpts()); |
186 | 670 | Policy.TerseOutput = true; |
187 | 670 | Policy.PolishForDeclaration = true; |
188 | 670 | D->print(llvm::errs(), Policy); |
189 | 670 | |
190 | 670 | if (CFG *cfg = mgr.getCFG(D)) { |
191 | 670 | cfg->dump(mgr.getLangOpts(), |
192 | 670 | llvm::sys::Process::StandardErrHasColors()); |
193 | 670 | } |
194 | 670 | } |
195 | | }; |
196 | | } |
197 | | |
198 | 33 | void ento::registerCFGDumper(CheckerManager &mgr) { |
199 | 33 | mgr.registerChecker<CFGDumper>(); |
200 | 33 | } |
201 | | |
202 | 33 | bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { |
203 | 33 | return true; |
204 | 33 | } |
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 | 0 | BugReporter &BR) const { |
215 | 0 | CallGraph CG; |
216 | 0 | CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); |
217 | 0 | CG.viewGraph(); |
218 | 0 | } |
219 | | }; |
220 | | } |
221 | | |
222 | 0 | void ento::registerCallGraphViewer(CheckerManager &mgr) { |
223 | 0 | mgr.registerChecker<CallGraphViewer>(); |
224 | 0 | } |
225 | | |
226 | 0 | bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { |
227 | 0 | return true; |
228 | 0 | } |
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 | 1 | BugReporter &BR) const { |
239 | 1 | CallGraph CG; |
240 | 1 | CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU)); |
241 | 1 | CG.dump(); |
242 | 1 | } |
243 | | }; |
244 | | } |
245 | | |
246 | 1 | void ento::registerCallGraphDumper(CheckerManager &mgr) { |
247 | 1 | mgr.registerChecker<CallGraphDumper>(); |
248 | 1 | } |
249 | | |
250 | 1 | bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { |
251 | 1 | return true; |
252 | 1 | } |
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 | 3.25k | const Table::MapEntryTy *const *RHS) { |
264 | 3.25k | return (*LHS)->getKey().compare((*RHS)->getKey()); |
265 | 3.25k | } |
266 | | |
267 | | public: |
268 | | void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, |
269 | | AnalysisManager& mgr, |
270 | 6 | BugReporter &BR) const { |
271 | 6 | const Table &Config = mgr.options.Config; |
272 | 6 | |
273 | 6 | SmallVector<const Table::MapEntryTy *, 32> Keys; |
274 | 537 | for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E; |
275 | 531 | ++I) |
276 | 531 | Keys.push_back(&*I); |
277 | 6 | llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry); |
278 | 6 | |
279 | 6 | llvm::errs() << "[config]\n"; |
280 | 537 | for (unsigned I = 0, E = Keys.size(); I != E; ++I531 ) |
281 | 531 | llvm::errs() << Keys[I]->getKey() << " = " |
282 | 531 | << (Keys[I]->second.empty() ? "\"\""12 : Keys[I]->second519 ) |
283 | 531 | << '\n'; |
284 | 6 | |
285 | 6 | llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; |
286 | 6 | } |
287 | | }; |
288 | | } |
289 | | |
290 | 6 | void ento::registerConfigDumper(CheckerManager &mgr) { |
291 | 6 | mgr.registerChecker<ConfigDumper>(); |
292 | 6 | } |
293 | | |
294 | 6 | bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { |
295 | 6 | return true; |
296 | 6 | } |
297 | | |
298 | | //===----------------------------------------------------------------------===// |
299 | | // ExplodedGraph Viewer |
300 | | //===----------------------------------------------------------------------===// |
301 | | |
302 | | namespace { |
303 | | class ExplodedGraphViewer : public Checker< check::EndAnalysis > { |
304 | | public: |
305 | 0 | ExplodedGraphViewer() {} |
306 | 0 | void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const { |
307 | 0 | Eng.ViewGraph(0); |
308 | 0 | } |
309 | | }; |
310 | | |
311 | | } |
312 | | |
313 | 0 | void ento::registerExplodedGraphViewer(CheckerManager &mgr) { |
314 | 0 | mgr.registerChecker<ExplodedGraphViewer>(); |
315 | 0 | } |
316 | | |
317 | 0 | bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { |
318 | 0 | return true; |
319 | 0 | } |
320 | | |
321 | | //===----------------------------------------------------------------------===// |
322 | | // Emits a report for every Stmt that the analyzer visits. |
323 | | //===----------------------------------------------------------------------===// |
324 | | |
325 | | namespace { |
326 | | |
327 | | class ReportStmts : public Checker<check::PreStmt<Stmt>> { |
328 | | BuiltinBug BT_stmtLoc{this, "Statement"}; |
329 | | |
330 | | public: |
331 | 6 | void checkPreStmt(const Stmt *S, CheckerContext &C) const { |
332 | 6 | ExplodedNode *Node = C.generateNonFatalErrorNode(); |
333 | 6 | if (!Node) |
334 | 0 | return; |
335 | 6 | |
336 | 6 | auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node); |
337 | 6 | |
338 | 6 | C.emitReport(std::move(Report)); |
339 | 6 | } |
340 | | }; |
341 | | |
342 | | } // end of anonymous namespace |
343 | | |
344 | 1 | void ento::registerReportStmts(CheckerManager &mgr) { |
345 | 1 | mgr.registerChecker<ReportStmts>(); |
346 | 1 | } |
347 | | |
348 | 1 | bool ento::shouldRegisterReportStmts(const LangOptions &LO) { |
349 | 1 | return true; |
350 | 1 | } |