xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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 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(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(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(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(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(llvm::errs(), Policy);
189 
190     if (CFG *cfg = mgr.getCFG(D)) {
191       cfg->dump(mgr.getLangOpts(),
192                 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)->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(&Entry);
276     llvm::array_pod_sort(Keys.begin(), Keys.end(), 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(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>(BT_stmtLoc, "Statement", Node);
335 
336     C.emitReport(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