xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp (revision 76a21502fdc12366cdda4fe92b2dbdfe7661064a)
1 //==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines checkers that display debugging information.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15 #include "clang/Analysis/Analyses/Dominators.h"
16 #include "clang/Analysis/Analyses/LiveVariables.h"
17 #include "clang/Analysis/CallGraph.h"
18 #include "clang/StaticAnalyzer/Core/Checker.h"
19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
24 #include "llvm/Support/Process.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 //===----------------------------------------------------------------------===//
30 // DominatorsTreeDumper
31 //===----------------------------------------------------------------------===//
32 
33 namespace {
34 class DominatorsTreeDumper : public Checker<check::ASTCodeBody> {
35 public:
36   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
37                         BugReporter &BR) const {
38     if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
39       DominatorTree dom;
40       dom.buildDominatorTree(*AC);
41       dom.dump();
42     }
43   }
44 };
45 }
46 
47 void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
48   mgr.registerChecker<DominatorsTreeDumper>();
49 }
50 
51 //===----------------------------------------------------------------------===//
52 // LiveVariablesDumper
53 //===----------------------------------------------------------------------===//
54 
55 namespace {
56 class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
57 public:
58   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
59                         BugReporter &BR) const {
60     if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
61       L->dumpBlockLiveness(mgr.getSourceManager());
62     }
63   }
64 };
65 }
66 
67 void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
68   mgr.registerChecker<LiveVariablesDumper>();
69 }
70 
71 //===----------------------------------------------------------------------===//
72 // CFGViewer
73 //===----------------------------------------------------------------------===//
74 
75 namespace {
76 class CFGViewer : public Checker<check::ASTCodeBody> {
77 public:
78   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
79                         BugReporter &BR) const {
80     if (CFG *cfg = mgr.getCFG(D)) {
81       cfg->viewCFG(mgr.getLangOpts());
82     }
83   }
84 };
85 }
86 
87 void ento::registerCFGViewer(CheckerManager &mgr) {
88   mgr.registerChecker<CFGViewer>();
89 }
90 
91 //===----------------------------------------------------------------------===//
92 // CFGDumper
93 //===----------------------------------------------------------------------===//
94 
95 namespace {
96 class CFGDumper : public Checker<check::ASTCodeBody> {
97 public:
98   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
99                         BugReporter &BR) const {
100     PrintingPolicy Policy(mgr.getLangOpts());
101     Policy.TerseOutput = true;
102     Policy.PolishForDeclaration = true;
103     D->print(llvm::errs(), Policy);
104 
105     if (CFG *cfg = mgr.getCFG(D)) {
106       cfg->dump(mgr.getLangOpts(),
107                 llvm::sys::Process::StandardErrHasColors());
108     }
109   }
110 };
111 }
112 
113 void ento::registerCFGDumper(CheckerManager &mgr) {
114   mgr.registerChecker<CFGDumper>();
115 }
116 
117 //===----------------------------------------------------------------------===//
118 // CallGraphViewer
119 //===----------------------------------------------------------------------===//
120 
121 namespace {
122 class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
123 public:
124   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
125                     BugReporter &BR) const {
126     CallGraph CG;
127     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
128     CG.viewGraph();
129   }
130 };
131 }
132 
133 void ento::registerCallGraphViewer(CheckerManager &mgr) {
134   mgr.registerChecker<CallGraphViewer>();
135 }
136 
137 //===----------------------------------------------------------------------===//
138 // CallGraphDumper
139 //===----------------------------------------------------------------------===//
140 
141 namespace {
142 class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
143 public:
144   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
145                     BugReporter &BR) const {
146     CallGraph CG;
147     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
148     CG.dump();
149   }
150 };
151 }
152 
153 void ento::registerCallGraphDumper(CheckerManager &mgr) {
154   mgr.registerChecker<CallGraphDumper>();
155 }
156 
157 
158 //===----------------------------------------------------------------------===//
159 // ConfigDumper
160 //===----------------------------------------------------------------------===//
161 
162 namespace {
163 class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
164   typedef AnalyzerOptions::ConfigTable Table;
165 
166   static int compareEntry(const Table::MapEntryTy *const *LHS,
167                           const Table::MapEntryTy *const *RHS) {
168     return (*LHS)->getKey().compare((*RHS)->getKey());
169   }
170 
171 public:
172   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
173                                  AnalysisManager& mgr,
174                                  BugReporter &BR) const {
175     const Table &Config = mgr.options.Config;
176 
177     SmallVector<const Table::MapEntryTy *, 32> Keys;
178     for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
179          ++I)
180       Keys.push_back(&*I);
181     llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
182 
183     llvm::errs() << "[config]\n";
184     for (unsigned I = 0, E = Keys.size(); I != E; ++I)
185       llvm::errs() << Keys[I]->getKey() << " = "
186                    << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
187                    << '\n';
188 
189     llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
190   }
191 };
192 }
193 
194 void ento::registerConfigDumper(CheckerManager &mgr) {
195   mgr.registerChecker<ConfigDumper>();
196 }
197 
198 //===----------------------------------------------------------------------===//
199 // ExplodedGraph Viewer
200 //===----------------------------------------------------------------------===//
201 
202 namespace {
203 class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
204 public:
205   ExplodedGraphViewer() {}
206   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
207     Eng.ViewGraph(0);
208   }
209 };
210 
211 }
212 
213 void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
214   mgr.registerChecker<ExplodedGraphViewer>();
215 }
216 
217