xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp (revision 71a9dc39e4faf74eecdcb46f18ca21ee1c41dfe1)
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(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 LangOptions &LO) {
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(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 LangOptions &LO) {
77   return true;
78 }
79 
80 //===----------------------------------------------------------------------===//
81 // LiveVariablesDumper
82 //===----------------------------------------------------------------------===//
83 
84 namespace {
85 class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
86 public:
87   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
88                         BugReporter &BR) const {
89     if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
90       L->dumpBlockLiveness(mgr.getSourceManager());
91     }
92   }
93 };
94 }
95 
96 void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
97   mgr.registerChecker<LiveVariablesDumper>();
98 }
99 
100 bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) {
101   return true;
102 }
103 
104 //===----------------------------------------------------------------------===//
105 // LiveStatementsDumper
106 //===----------------------------------------------------------------------===//
107 
108 namespace {
109 class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
110 public:
111   void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
112                         BugReporter &BR) const {
113     if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
114       L->dumpStmtLiveness(Mgr.getSourceManager());
115   }
116 };
117 }
118 
119 void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
120   mgr.registerChecker<LiveStatementsDumper>();
121 }
122 
123 bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) {
124   return true;
125 }
126 
127 //===----------------------------------------------------------------------===//
128 // CFGViewer
129 //===----------------------------------------------------------------------===//
130 
131 namespace {
132 class CFGViewer : public Checker<check::ASTCodeBody> {
133 public:
134   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
135                         BugReporter &BR) const {
136     if (CFG *cfg = mgr.getCFG(D)) {
137       cfg->viewCFG(mgr.getLangOpts());
138     }
139   }
140 };
141 }
142 
143 void ento::registerCFGViewer(CheckerManager &mgr) {
144   mgr.registerChecker<CFGViewer>();
145 }
146 
147 bool ento::shouldRegisterCFGViewer(const LangOptions &LO) {
148   return true;
149 }
150 
151 //===----------------------------------------------------------------------===//
152 // CFGDumper
153 //===----------------------------------------------------------------------===//
154 
155 namespace {
156 class CFGDumper : public Checker<check::ASTCodeBody> {
157 public:
158   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
159                         BugReporter &BR) const {
160     PrintingPolicy Policy(mgr.getLangOpts());
161     Policy.TerseOutput = true;
162     Policy.PolishForDeclaration = true;
163     D->print(llvm::errs(), Policy);
164 
165     if (CFG *cfg = mgr.getCFG(D)) {
166       cfg->dump(mgr.getLangOpts(),
167                 llvm::sys::Process::StandardErrHasColors());
168     }
169   }
170 };
171 }
172 
173 void ento::registerCFGDumper(CheckerManager &mgr) {
174   mgr.registerChecker<CFGDumper>();
175 }
176 
177 bool ento::shouldRegisterCFGDumper(const LangOptions &LO) {
178   return true;
179 }
180 
181 //===----------------------------------------------------------------------===//
182 // CallGraphViewer
183 //===----------------------------------------------------------------------===//
184 
185 namespace {
186 class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
187 public:
188   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
189                     BugReporter &BR) const {
190     CallGraph CG;
191     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
192     CG.viewGraph();
193   }
194 };
195 }
196 
197 void ento::registerCallGraphViewer(CheckerManager &mgr) {
198   mgr.registerChecker<CallGraphViewer>();
199 }
200 
201 bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) {
202   return true;
203 }
204 
205 //===----------------------------------------------------------------------===//
206 // CallGraphDumper
207 //===----------------------------------------------------------------------===//
208 
209 namespace {
210 class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
211 public:
212   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
213                     BugReporter &BR) const {
214     CallGraph CG;
215     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
216     CG.dump();
217   }
218 };
219 }
220 
221 void ento::registerCallGraphDumper(CheckerManager &mgr) {
222   mgr.registerChecker<CallGraphDumper>();
223 }
224 
225 bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) {
226   return true;
227 }
228 
229 //===----------------------------------------------------------------------===//
230 // ConfigDumper
231 //===----------------------------------------------------------------------===//
232 
233 namespace {
234 class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
235   typedef AnalyzerOptions::ConfigTable Table;
236 
237   static int compareEntry(const Table::MapEntryTy *const *LHS,
238                           const Table::MapEntryTy *const *RHS) {
239     return (*LHS)->getKey().compare((*RHS)->getKey());
240   }
241 
242 public:
243   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
244                                  AnalysisManager& mgr,
245                                  BugReporter &BR) const {
246     const Table &Config = mgr.options.Config;
247 
248     SmallVector<const Table::MapEntryTy *, 32> Keys;
249     for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
250          ++I)
251       Keys.push_back(&*I);
252     llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
253 
254     llvm::errs() << "[config]\n";
255     for (unsigned I = 0, E = Keys.size(); I != E; ++I)
256       llvm::errs() << Keys[I]->getKey() << " = "
257                    << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
258                    << '\n';
259 
260     llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
261   }
262 };
263 }
264 
265 void ento::registerConfigDumper(CheckerManager &mgr) {
266   mgr.registerChecker<ConfigDumper>();
267 }
268 
269 bool ento::shouldRegisterConfigDumper(const LangOptions &LO) {
270   return true;
271 }
272 
273 //===----------------------------------------------------------------------===//
274 // ExplodedGraph Viewer
275 //===----------------------------------------------------------------------===//
276 
277 namespace {
278 class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
279 public:
280   ExplodedGraphViewer() {}
281   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
282     Eng.ViewGraph(0);
283   }
284 };
285 
286 }
287 
288 void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
289   mgr.registerChecker<ExplodedGraphViewer>();
290 }
291 
292 bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) {
293   return true;
294 }
295 
296 //===----------------------------------------------------------------------===//
297 // Emits a report for every Stmt that the analyzer visits.
298 //===----------------------------------------------------------------------===//
299 
300 namespace {
301 
302 class ReportStmts : public Checker<check::PreStmt<Stmt>> {
303   BuiltinBug BT_stmtLoc{this, "Statement"};
304 
305 public:
306   void checkPreStmt(const Stmt *S, CheckerContext &C) const {
307     ExplodedNode *Node = C.generateNonFatalErrorNode();
308     if (!Node)
309       return;
310 
311     auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node);
312 
313     C.emitReport(std::move(Report));
314   }
315 };
316 
317 } // end of anonymous namespace
318 
319 void ento::registerReportStmts(CheckerManager &mgr) {
320   mgr.registerChecker<ReportStmts>();
321 }
322 
323 bool ento::shouldRegisterReportStmts(const LangOptions &LO) {
324   return true;
325 }
326