Clang Project

clang_source_code/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
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
25using namespace clang;
26using namespace ento;
27
28//===----------------------------------------------------------------------===//
29// DominatorsTreeDumper
30//===----------------------------------------------------------------------===//
31
32namespace {
33class DominatorsTreeDumper : public Checker<check::ASTCodeBody> {
34public:
35  void checkASTCodeBody(const Decl *DAnalysisManagermgr,
36                        BugReporter &BRconst {
37    if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
38      DominatorTree dom;
39      dom.buildDominatorTree(*AC);
40      dom.dump();
41    }
42  }
43};
44}
45
46void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
47  mgr.registerChecker<DominatorsTreeDumper>();
48}
49
50bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) {
51  return true;
52}
53
54//===----------------------------------------------------------------------===//
55// LiveVariablesDumper
56//===----------------------------------------------------------------------===//
57
58namespace {
59class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
60public:
61  void checkASTCodeBody(const Decl *DAnalysisManagermgr,
62                        BugReporter &BRconst {
63    if (LiveVariablesL = mgr.getAnalysis<LiveVariables>(D)) {
64      L->dumpBlockLiveness(mgr.getSourceManager());
65    }
66  }
67};
68}
69
70void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
71  mgr.registerChecker<LiveVariablesDumper>();
72}
73
74bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) {
75  return true;
76}
77
78//===----------------------------------------------------------------------===//
79// LiveStatementsDumper
80//===----------------------------------------------------------------------===//
81
82namespace {
83class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
84public:
85  void checkASTCodeBody(const Decl *DAnalysisManagerMgr,
86                        BugReporter &BRconst {
87    if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
88      L->dumpStmtLiveness(Mgr.getSourceManager());
89  }
90};
91}
92
93void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
94  mgr.registerChecker<LiveStatementsDumper>();
95}
96
97bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) {
98  return true;
99}
100
101//===----------------------------------------------------------------------===//
102// CFGViewer
103//===----------------------------------------------------------------------===//
104
105namespace {
106class CFGViewer : public Checker<check::ASTCodeBody> {
107public:
108  void checkASTCodeBody(const Decl *DAnalysisManagermgr,
109                        BugReporter &BRconst {
110    if (CFG *cfg = mgr.getCFG(D)) {
111      cfg->viewCFG(mgr.getLangOpts());
112    }
113  }
114};
115}
116
117void ento::registerCFGViewer(CheckerManager &mgr) {
118  mgr.registerChecker<CFGViewer>();
119}
120
121bool ento::shouldRegisterCFGViewer(const LangOptions &LO) {
122  return true;
123}
124
125//===----------------------------------------------------------------------===//
126// CFGDumper
127//===----------------------------------------------------------------------===//
128
129namespace {
130class CFGDumper : public Checker<check::ASTCodeBody> {
131public:
132  void checkASTCodeBody(const Decl *DAnalysisManagermgr,
133                        BugReporter &BRconst {
134    PrintingPolicy Policy(mgr.getLangOpts());
135    Policy.TerseOutput = true;
136    Policy.PolishForDeclaration = true;
137    D->print(llvm::errs(), Policy);
138
139    if (CFG *cfg = mgr.getCFG(D)) {
140      cfg->dump(mgr.getLangOpts(),
141                llvm::sys::Process::StandardErrHasColors());
142    }
143  }
144};
145}
146
147void ento::registerCFGDumper(CheckerManager &mgr) {
148  mgr.registerChecker<CFGDumper>();
149}
150
151bool ento::shouldRegisterCFGDumper(const LangOptions &LO) {
152  return true;
153}
154
155//===----------------------------------------------------------------------===//
156// CallGraphViewer
157//===----------------------------------------------------------------------===//
158
159namespace {
160class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
161public:
162  void checkASTDecl(const TranslationUnitDecl *TUAnalysisManagermgr,
163                    BugReporter &BRconst {
164    CallGraph CG;
165    CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
166    CG.viewGraph();
167  }
168};
169}
170
171void ento::registerCallGraphViewer(CheckerManager &mgr) {
172  mgr.registerChecker<CallGraphViewer>();
173}
174
175bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) {
176  return true;
177}
178
179//===----------------------------------------------------------------------===//
180// CallGraphDumper
181//===----------------------------------------------------------------------===//
182
183namespace {
184class CallGraphDumper : public Checkercheck::ASTDecl<TranslationUnitDecl> > {
185public:
186  void checkASTDecl(const TranslationUnitDecl *TUAnalysisManagermgr,
187                    BugReporter &BRconst {
188    CallGraph CG;
189    CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
190    CG.dump();
191  }
192};
193}
194
195void ento::registerCallGraphDumper(CheckerManager &mgr) {
196  mgr.registerChecker<CallGraphDumper>();
197}
198
199bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) {
200  return true;
201}
202
203//===----------------------------------------------------------------------===//
204// ConfigDumper
205//===----------------------------------------------------------------------===//
206
207namespace {
208class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
209  typedef AnalyzerOptions::ConfigTable Table;
210
211  static int compareEntry(const Table::MapEntryTy *const *LHS,
212                          const Table::MapEntryTy *const *RHS) {
213    return (*LHS)->getKey().compare((*RHS)->getKey());
214  }
215
216public:
217  void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
218                                 AnalysisManagermgr,
219                                 BugReporter &BRconst {
220    const Table &Config = mgr.options.Config;
221
222    SmallVector<const Table::MapEntryTy *, 32Keys;
223    for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
224         ++I)
225      Keys.push_back(&*I);
226    llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
227
228    llvm::errs() << "[config]\n";
229    for (unsigned I = 0, E = Keys.size(); I != E; ++I)
230      llvm::errs() << Keys[I]->getKey() << " = "
231                   << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
232                   << '\n';
233
234    llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
235  }
236};
237}
238
239void ento::registerConfigDumper(CheckerManager &mgr) {
240  mgr.registerChecker<ConfigDumper>();
241}
242
243bool ento::shouldRegisterConfigDumper(const LangOptions &LO) {
244  return true;
245}
246
247//===----------------------------------------------------------------------===//
248// ExplodedGraph Viewer
249//===----------------------------------------------------------------------===//
250
251namespace {
252class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
253public:
254  ExplodedGraphViewer() {}
255  void checkEndAnalysis(ExplodedGraph &GBugReporter &B,ExprEngine &Engconst {
256    Eng.ViewGraph(0);
257  }
258};
259
260}
261
262void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
263  mgr.registerChecker<ExplodedGraphViewer>();
264}
265
266bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) {
267  return true;
268}
269
270//===----------------------------------------------------------------------===//
271// Emits a report for every Stmt that the analyzer visits.
272//===----------------------------------------------------------------------===//
273
274namespace {
275
276class ReportStmts : public Checker<check::PreStmt<Stmt>> {
277  BuiltinBug BT_stmtLoc{this"Statement"};
278
279public:
280  void checkPreStmt(const Stmt *SCheckerContext &Cconst {
281    ExplodedNode *Node = C.generateNonFatalErrorNode();
282    if (!Node)
283      return;
284
285    auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node);
286
287    C.emitReport(std::move(Report));
288  }
289};
290
291// end of anonymous namespace
292
293void ento::registerReportStmts(CheckerManager &mgr) {
294  mgr.registerChecker<ReportStmts>();
295}
296
297bool ento::shouldRegisterReportStmts(const LangOptions &LO) {
298  return true;
299}
300