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