157d736fdSArgyrios Kyrtzidis //==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==//
257d736fdSArgyrios Kyrtzidis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
657d736fdSArgyrios Kyrtzidis //
757d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
857d736fdSArgyrios Kyrtzidis //
973b75e01SJordan Rose //  This file defines checkers that display debugging information.
1057d736fdSArgyrios Kyrtzidis //
1157d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
1257d736fdSArgyrios Kyrtzidis 
1376a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
143a02247dSChandler Carruth #include "clang/Analysis/Analyses/Dominators.h"
153a02247dSChandler Carruth #include "clang/Analysis/Analyses/LiveVariables.h"
163a02247dSChandler Carruth #include "clang/Analysis/CallGraph.h"
176a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
18efec1630SGabor Horvath #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1957d736fdSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20efec1630SGabor Horvath #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
217925e3dbSAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
227925e3dbSAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
2372be32afSTed Kremenek #include "llvm/Support/Process.h"
2457d736fdSArgyrios Kyrtzidis 
2557d736fdSArgyrios Kyrtzidis using namespace clang;
2657d736fdSArgyrios Kyrtzidis using namespace ento;
2757d736fdSArgyrios Kyrtzidis 
2857d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
290062e749STed Kremenek // DominatorsTreeDumper
300062e749STed Kremenek //===----------------------------------------------------------------------===//
310062e749STed Kremenek 
320062e749STed Kremenek namespace {
330062e749STed Kremenek class DominatorsTreeDumper : public Checker<check::ASTCodeBody> {
340062e749STed Kremenek public:
350062e749STed Kremenek   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
360062e749STed Kremenek                         BugReporter &BR) const {
370062e749STed Kremenek     if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
3802a1fc1dSAnna Zaks       DominatorTree dom;
3902a1fc1dSAnna Zaks       dom.buildDominatorTree(*AC);
400062e749STed Kremenek       dom.dump();
410062e749STed Kremenek     }
420062e749STed Kremenek   }
430062e749STed Kremenek };
44ab9db510SAlexander Kornienko }
450062e749STed Kremenek 
460062e749STed Kremenek void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
470062e749STed Kremenek   mgr.registerChecker<DominatorsTreeDumper>();
480062e749STed Kremenek }
490062e749STed Kremenek 
50058a7a45SKristof Umann bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) {
51058a7a45SKristof Umann   return true;
52058a7a45SKristof Umann }
53058a7a45SKristof Umann 
540062e749STed Kremenek //===----------------------------------------------------------------------===//
5557d736fdSArgyrios Kyrtzidis // LiveVariablesDumper
5657d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
5757d736fdSArgyrios Kyrtzidis 
5857d736fdSArgyrios Kyrtzidis namespace {
596a5674ffSArgyrios Kyrtzidis class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
6057d736fdSArgyrios Kyrtzidis public:
6157d736fdSArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
6257d736fdSArgyrios Kyrtzidis                         BugReporter &BR) const {
63dccc2b22STed Kremenek     if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
6457d736fdSArgyrios Kyrtzidis       L->dumpBlockLiveness(mgr.getSourceManager());
6557d736fdSArgyrios Kyrtzidis     }
6657d736fdSArgyrios Kyrtzidis   }
6757d736fdSArgyrios Kyrtzidis };
68ab9db510SAlexander Kornienko }
6957d736fdSArgyrios Kyrtzidis 
7057d736fdSArgyrios Kyrtzidis void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
7157d736fdSArgyrios Kyrtzidis   mgr.registerChecker<LiveVariablesDumper>();
7257d736fdSArgyrios Kyrtzidis }
7357d736fdSArgyrios Kyrtzidis 
74058a7a45SKristof Umann bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) {
75058a7a45SKristof Umann   return true;
76058a7a45SKristof Umann }
77058a7a45SKristof Umann 
7857d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
79dda42164SArtem Dergachev // LiveStatementsDumper
80dda42164SArtem Dergachev //===----------------------------------------------------------------------===//
81dda42164SArtem Dergachev 
82dda42164SArtem Dergachev namespace {
83dda42164SArtem Dergachev class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
84dda42164SArtem Dergachev public:
85dda42164SArtem Dergachev   void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
86dda42164SArtem Dergachev                         BugReporter &BR) const {
87dda42164SArtem Dergachev     if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
88dda42164SArtem Dergachev       L->dumpStmtLiveness(Mgr.getSourceManager());
89dda42164SArtem Dergachev   }
90dda42164SArtem Dergachev };
91dda42164SArtem Dergachev }
92dda42164SArtem Dergachev 
93dda42164SArtem Dergachev void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
94dda42164SArtem Dergachev   mgr.registerChecker<LiveStatementsDumper>();
95dda42164SArtem Dergachev }
96dda42164SArtem Dergachev 
97058a7a45SKristof Umann bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) {
98058a7a45SKristof Umann   return true;
99058a7a45SKristof Umann }
100058a7a45SKristof Umann 
101dda42164SArtem Dergachev //===----------------------------------------------------------------------===//
10257d736fdSArgyrios Kyrtzidis // CFGViewer
10357d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
10457d736fdSArgyrios Kyrtzidis 
10557d736fdSArgyrios Kyrtzidis namespace {
1066a5674ffSArgyrios Kyrtzidis class CFGViewer : public Checker<check::ASTCodeBody> {
10757d736fdSArgyrios Kyrtzidis public:
10857d736fdSArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
10957d736fdSArgyrios Kyrtzidis                         BugReporter &BR) const {
11057d736fdSArgyrios Kyrtzidis     if (CFG *cfg = mgr.getCFG(D)) {
111bbafb8a7SDavid Blaikie       cfg->viewCFG(mgr.getLangOpts());
11257d736fdSArgyrios Kyrtzidis     }
11357d736fdSArgyrios Kyrtzidis   }
11457d736fdSArgyrios Kyrtzidis };
115ab9db510SAlexander Kornienko }
11657d736fdSArgyrios Kyrtzidis 
11757d736fdSArgyrios Kyrtzidis void ento::registerCFGViewer(CheckerManager &mgr) {
11857d736fdSArgyrios Kyrtzidis   mgr.registerChecker<CFGViewer>();
11957d736fdSArgyrios Kyrtzidis }
12057d736fdSArgyrios Kyrtzidis 
121058a7a45SKristof Umann bool ento::shouldRegisterCFGViewer(const LangOptions &LO) {
122058a7a45SKristof Umann   return true;
123058a7a45SKristof Umann }
124058a7a45SKristof Umann 
12557d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
12657d736fdSArgyrios Kyrtzidis // CFGDumper
12757d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
12857d736fdSArgyrios Kyrtzidis 
12957d736fdSArgyrios Kyrtzidis namespace {
1306a5674ffSArgyrios Kyrtzidis class CFGDumper : public Checker<check::ASTCodeBody> {
13157d736fdSArgyrios Kyrtzidis public:
13257d736fdSArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
13357d736fdSArgyrios Kyrtzidis                         BugReporter &BR) const {
134e02e96a6SJordan Rose     PrintingPolicy Policy(mgr.getLangOpts());
135e02e96a6SJordan Rose     Policy.TerseOutput = true;
136e02e96a6SJordan Rose     Policy.PolishForDeclaration = true;
137e02e96a6SJordan Rose     D->print(llvm::errs(), Policy);
138e02e96a6SJordan Rose 
13957d736fdSArgyrios Kyrtzidis     if (CFG *cfg = mgr.getCFG(D)) {
140bbafb8a7SDavid Blaikie       cfg->dump(mgr.getLangOpts(),
14172be32afSTed Kremenek                 llvm::sys::Process::StandardErrHasColors());
14257d736fdSArgyrios Kyrtzidis     }
14357d736fdSArgyrios Kyrtzidis   }
14457d736fdSArgyrios Kyrtzidis };
145ab9db510SAlexander Kornienko }
14657d736fdSArgyrios Kyrtzidis 
14757d736fdSArgyrios Kyrtzidis void ento::registerCFGDumper(CheckerManager &mgr) {
14857d736fdSArgyrios Kyrtzidis   mgr.registerChecker<CFGDumper>();
14957d736fdSArgyrios Kyrtzidis }
150c000e7edSAnna Zaks 
151058a7a45SKristof Umann bool ento::shouldRegisterCFGDumper(const LangOptions &LO) {
152058a7a45SKristof Umann   return true;
153058a7a45SKristof Umann }
154058a7a45SKristof Umann 
155c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
156c000e7edSAnna Zaks // CallGraphViewer
157c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
158c000e7edSAnna Zaks 
159c000e7edSAnna Zaks namespace {
160c000e7edSAnna Zaks class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
161c000e7edSAnna Zaks public:
162c000e7edSAnna Zaks   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
163c000e7edSAnna Zaks                     BugReporter &BR) const {
164c000e7edSAnna Zaks     CallGraph CG;
165c000e7edSAnna Zaks     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
166c000e7edSAnna Zaks     CG.viewGraph();
167c000e7edSAnna Zaks   }
168c000e7edSAnna Zaks };
169ab9db510SAlexander Kornienko }
170c000e7edSAnna Zaks 
171c000e7edSAnna Zaks void ento::registerCallGraphViewer(CheckerManager &mgr) {
172c000e7edSAnna Zaks   mgr.registerChecker<CallGraphViewer>();
173c000e7edSAnna Zaks }
174c000e7edSAnna Zaks 
175058a7a45SKristof Umann bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) {
176058a7a45SKristof Umann   return true;
177058a7a45SKristof Umann }
178058a7a45SKristof Umann 
179c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
180c000e7edSAnna Zaks // CallGraphDumper
181c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
182c000e7edSAnna Zaks 
183c000e7edSAnna Zaks namespace {
184c000e7edSAnna Zaks class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
185c000e7edSAnna Zaks public:
186c000e7edSAnna Zaks   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
187c000e7edSAnna Zaks                     BugReporter &BR) const {
188c000e7edSAnna Zaks     CallGraph CG;
189c000e7edSAnna Zaks     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
190c000e7edSAnna Zaks     CG.dump();
191c000e7edSAnna Zaks   }
192c000e7edSAnna Zaks };
193ab9db510SAlexander Kornienko }
194c000e7edSAnna Zaks 
195c000e7edSAnna Zaks void ento::registerCallGraphDumper(CheckerManager &mgr) {
196c000e7edSAnna Zaks   mgr.registerChecker<CallGraphDumper>();
197c000e7edSAnna Zaks }
19886917fdbSTed Kremenek 
199058a7a45SKristof Umann bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) {
200058a7a45SKristof Umann   return true;
201058a7a45SKristof Umann }
20286917fdbSTed Kremenek 
20386917fdbSTed Kremenek //===----------------------------------------------------------------------===//
20486917fdbSTed Kremenek // ConfigDumper
20586917fdbSTed Kremenek //===----------------------------------------------------------------------===//
20686917fdbSTed Kremenek 
20786917fdbSTed Kremenek namespace {
20886917fdbSTed Kremenek class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
209a92b80f8SBenjamin Kramer   typedef AnalyzerOptions::ConfigTable Table;
210a92b80f8SBenjamin Kramer 
2114cadf292SBenjamin Kramer   static int compareEntry(const Table::MapEntryTy *const *LHS,
2124cadf292SBenjamin Kramer                           const Table::MapEntryTy *const *RHS) {
2134cadf292SBenjamin Kramer     return (*LHS)->getKey().compare((*RHS)->getKey());
2144cadf292SBenjamin Kramer   }
2154cadf292SBenjamin Kramer 
21686917fdbSTed Kremenek public:
21786917fdbSTed Kremenek   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
21886917fdbSTed Kremenek                                  AnalysisManager& mgr,
21986917fdbSTed Kremenek                                  BugReporter &BR) const {
220a92b80f8SBenjamin Kramer     const Table &Config = mgr.options.Config;
22186917fdbSTed Kremenek 
222a92b80f8SBenjamin Kramer     SmallVector<const Table::MapEntryTy *, 32> Keys;
223a92b80f8SBenjamin Kramer     for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
224a92b80f8SBenjamin Kramer          ++I)
225a92b80f8SBenjamin Kramer       Keys.push_back(&*I);
2264cadf292SBenjamin Kramer     llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
22786917fdbSTed Kremenek 
22886917fdbSTed Kremenek     llvm::errs() << "[config]\n";
229a92b80f8SBenjamin Kramer     for (unsigned I = 0, E = Keys.size(); I != E; ++I)
230549f9cd4SKristof Umann       llvm::errs() << Keys[I]->getKey() << " = "
231549f9cd4SKristof Umann                    << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
232549f9cd4SKristof Umann                    << '\n';
233a92b80f8SBenjamin Kramer 
23486917fdbSTed Kremenek     llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n';
23586917fdbSTed Kremenek   }
23686917fdbSTed Kremenek };
237ab9db510SAlexander Kornienko }
23886917fdbSTed Kremenek 
23986917fdbSTed Kremenek void ento::registerConfigDumper(CheckerManager &mgr) {
24086917fdbSTed Kremenek   mgr.registerChecker<ConfigDumper>();
24186917fdbSTed Kremenek }
2427925e3dbSAnna Zaks 
243058a7a45SKristof Umann bool ento::shouldRegisterConfigDumper(const LangOptions &LO) {
244058a7a45SKristof Umann   return true;
245058a7a45SKristof Umann }
246058a7a45SKristof Umann 
2477925e3dbSAnna Zaks //===----------------------------------------------------------------------===//
2487925e3dbSAnna Zaks // ExplodedGraph Viewer
2497925e3dbSAnna Zaks //===----------------------------------------------------------------------===//
2507925e3dbSAnna Zaks 
2517925e3dbSAnna Zaks namespace {
2527925e3dbSAnna Zaks class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
2537925e3dbSAnna Zaks public:
2547925e3dbSAnna Zaks   ExplodedGraphViewer() {}
2557925e3dbSAnna Zaks   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
2567925e3dbSAnna Zaks     Eng.ViewGraph(0);
2577925e3dbSAnna Zaks   }
2587925e3dbSAnna Zaks };
2597925e3dbSAnna Zaks 
2607925e3dbSAnna Zaks }
2617925e3dbSAnna Zaks 
2627925e3dbSAnna Zaks void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
2637925e3dbSAnna Zaks   mgr.registerChecker<ExplodedGraphViewer>();
2647925e3dbSAnna Zaks }
265efec1630SGabor Horvath 
266058a7a45SKristof Umann bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) {
267058a7a45SKristof Umann   return true;
268058a7a45SKristof Umann }
269*4962816eSKristof Umann 
270*4962816eSKristof Umann //===----------------------------------------------------------------------===//
271*4962816eSKristof Umann // Emits a report for every Stmt that the analyzer visits.
272*4962816eSKristof Umann //===----------------------------------------------------------------------===//
273*4962816eSKristof Umann 
274*4962816eSKristof Umann namespace {
275*4962816eSKristof Umann 
276*4962816eSKristof Umann class ReportStmts : public Checker<check::PreStmt<Stmt>> {
277*4962816eSKristof Umann   BuiltinBug BT_stmtLoc{this, "Statement"};
278*4962816eSKristof Umann 
279*4962816eSKristof Umann public:
280*4962816eSKristof Umann   void checkPreStmt(const Stmt *S, CheckerContext &C) const {
281*4962816eSKristof Umann     ExplodedNode *Node = C.generateNonFatalErrorNode();
282*4962816eSKristof Umann     if (!Node)
283*4962816eSKristof Umann       return;
284*4962816eSKristof Umann 
285*4962816eSKristof Umann     auto Report = llvm::make_unique<BugReport>(BT_stmtLoc, "Statement", Node);
286*4962816eSKristof Umann 
287*4962816eSKristof Umann     C.emitReport(std::move(Report));
288*4962816eSKristof Umann   }
289*4962816eSKristof Umann };
290*4962816eSKristof Umann 
291*4962816eSKristof Umann } // end of anonymous namespace
292*4962816eSKristof Umann 
293*4962816eSKristof Umann void ento::registerReportStmts(CheckerManager &mgr) {
294*4962816eSKristof Umann   mgr.registerChecker<ReportStmts>();
295*4962816eSKristof Umann }
296*4962816eSKristof Umann 
297*4962816eSKristof Umann bool ento::shouldRegisterReportStmts(const LangOptions &LO) {
298*4962816eSKristof Umann   return true;
299*4962816eSKristof Umann }
300