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 *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
46void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
47  mgr.registerChecker<DominatorsTreeDumper>();
48}
49
50bool ento::shouldRegisterDominatorsTreeDumper(const CheckerManager &mgr) {
51  return true;
52}
53
54//===----------------------------------------------------------------------===//
55// PostDominatorsTreeDumper
56//===----------------------------------------------------------------------===//
57
58namespace {
59class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> {
60public:
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
72void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) {
73  mgr.registerChecker<PostDominatorsTreeDumper>();
74}
75
76bool ento::shouldRegisterPostDominatorsTreeDumper(const CheckerManager &mgr) {
77  return true;
78}
79
80//===----------------------------------------------------------------------===//
81// ControlDependencyTreeDumper
82//===----------------------------------------------------------------------===//
83
84namespace {
85class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> {
86public:
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
97void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) {
98  mgr.registerChecker<ControlDependencyTreeDumper>();
99}
100
101bool ento::shouldRegisterControlDependencyTreeDumper(const CheckerManager &mgr) {
102  return true;
103}
104
105//===----------------------------------------------------------------------===//
106// LiveVariablesDumper
107//===----------------------------------------------------------------------===//
108
109namespace {
110class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
111public:
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
121void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
122  mgr.registerChecker<LiveVariablesDumper>();
123}
124
125bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) {
126  return true;
127}
128
129//===----------------------------------------------------------------------===//
130// LiveStatementsDumper
131//===----------------------------------------------------------------------===//
132
133namespace {
134class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
135public:
136  void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
137                        BugReporter &BR) const {
138    if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
139      L->dumpStmtLiveness(Mgr.getSourceManager());
140  }
141};
142}
143
144void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
145  mgr.registerChecker<LiveStatementsDumper>();
146}
147
148bool ento::shouldRegisterLiveStatementsDumper(const CheckerManager &mgr) {
149  return true;
150}
151
152//===----------------------------------------------------------------------===//
153// CFGViewer
154//===----------------------------------------------------------------------===//
155
156namespace {
157class CFGViewer : public Checker<check::ASTCodeBody> {
158public:
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
168void ento::registerCFGViewer(CheckerManager &mgr) {
169  mgr.registerChecker<CFGViewer>();
170}
171
172bool ento::shouldRegisterCFGViewer(const CheckerManager &mgr) {
173  return true;
174}
175
176//===----------------------------------------------------------------------===//
177// CFGDumper
178//===----------------------------------------------------------------------===//
179
180namespace {
181class CFGDumper : public Checker<check::ASTCodeBody> {
182public:
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
198void ento::registerCFGDumper(CheckerManager &mgr) {
199  mgr.registerChecker<CFGDumper>();
200}
201
202bool ento::shouldRegisterCFGDumper(const CheckerManager &mgr) {
203  return true;
204}
205
206//===----------------------------------------------------------------------===//
207// CallGraphViewer
208//===----------------------------------------------------------------------===//
209
210namespace {
211class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
212public:
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
222void ento::registerCallGraphViewer(CheckerManager &mgr) {
223  mgr.registerChecker<CallGraphViewer>();
224}
225
226bool ento::shouldRegisterCallGraphViewer(const CheckerManager &mgr) {
227  return true;
228}
229
230//===----------------------------------------------------------------------===//
231// CallGraphDumper
232//===----------------------------------------------------------------------===//
233
234namespace {
235class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
236public:
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
246void ento::registerCallGraphDumper(CheckerManager &mgr) {
247  mgr.registerChecker<CallGraphDumper>();
248}
249
250bool ento::shouldRegisterCallGraphDumper(const CheckerManager &mgr) {
251  return true;
252}
253
254//===----------------------------------------------------------------------===//
255// ConfigDumper
256//===----------------------------------------------------------------------===//
257
258namespace {
259class 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
267public:
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 (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
275         ++I)
276      Keys.push_back(&*I);
277    llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
278
279    llvm::errs() << "[config]\n";
280    for (unsigned I = 0, E = Keys.size(); I != E; ++I)
281      llvm::errs() << Keys[I]->getKey() << " = "
282                   << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
283                   << '\n';
284  }
285};
286}
287
288void ento::registerConfigDumper(CheckerManager &mgr) {
289  mgr.registerChecker<ConfigDumper>();
290}
291
292bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) {
293  return true;
294}
295
296//===----------------------------------------------------------------------===//
297// ExplodedGraph Viewer
298//===----------------------------------------------------------------------===//
299
300namespace {
301class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
302public:
303  ExplodedGraphViewer() {}
304  void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
305    Eng.ViewGraph(0);
306  }
307};
308
309}
310
311void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
312  mgr.registerChecker<ExplodedGraphViewer>();
313}
314
315bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) {
316  return true;
317}
318
319//===----------------------------------------------------------------------===//
320// Emits a report for every Stmt that the analyzer visits.
321//===----------------------------------------------------------------------===//
322
323namespace {
324
325class ReportStmts : public Checker<check::PreStmt<Stmt>> {
326  BuiltinBug BT_stmtLoc{this, "Statement"};
327
328public:
329  void checkPreStmt(const Stmt *S, CheckerContext &C) const {
330    ExplodedNode *Node = C.generateNonFatalErrorNode();
331    if (!Node)
332      return;
333
334    auto Report =
335        std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node);
336
337    C.emitReport(std::move(Report));
338  }
339};
340
341} // end of anonymous namespace
342
343void ento::registerReportStmts(CheckerManager &mgr) {
344  mgr.registerChecker<ReportStmts>();
345}
346
347bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) {
348  return true;
349}
350