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)) {
385e17ee1eSKristof Umann       CFGDomTree Dom;
395e17ee1eSKristof Umann       Dom.buildDominatorTree(AC->getCFG());
405e17ee1eSKristof Umann       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 
50bda3dd0dSKirstóf Umann bool ento::shouldRegisterDominatorsTreeDumper(const CheckerManager &mgr) {
51058a7a45SKristof Umann   return true;
52058a7a45SKristof Umann }
53058a7a45SKristof Umann 
540062e749STed Kremenek //===----------------------------------------------------------------------===//
5571a9dc39SKristof Umann // PostDominatorsTreeDumper
5671a9dc39SKristof Umann //===----------------------------------------------------------------------===//
5771a9dc39SKristof Umann 
5871a9dc39SKristof Umann namespace {
5971a9dc39SKristof Umann class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> {
6071a9dc39SKristof Umann public:
6171a9dc39SKristof Umann   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
6271a9dc39SKristof Umann                         BugReporter &BR) const {
6371a9dc39SKristof Umann     if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
645e17ee1eSKristof Umann       CFGPostDomTree Dom;
655e17ee1eSKristof Umann       Dom.buildDominatorTree(AC->getCFG());
665e17ee1eSKristof Umann       Dom.dump();
6771a9dc39SKristof Umann     }
6871a9dc39SKristof Umann   }
6971a9dc39SKristof Umann };
7071a9dc39SKristof Umann }
7171a9dc39SKristof Umann 
7271a9dc39SKristof Umann void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) {
7371a9dc39SKristof Umann   mgr.registerChecker<PostDominatorsTreeDumper>();
7471a9dc39SKristof Umann }
7571a9dc39SKristof Umann 
76bda3dd0dSKirstóf Umann bool ento::shouldRegisterPostDominatorsTreeDumper(const CheckerManager &mgr) {
7771a9dc39SKristof Umann   return true;
7871a9dc39SKristof Umann }
7971a9dc39SKristof Umann 
8071a9dc39SKristof Umann //===----------------------------------------------------------------------===//
815e17ee1eSKristof Umann // ControlDependencyTreeDumper
825e17ee1eSKristof Umann //===----------------------------------------------------------------------===//
835e17ee1eSKristof Umann 
845e17ee1eSKristof Umann namespace {
855e17ee1eSKristof Umann class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> {
865e17ee1eSKristof Umann public:
875e17ee1eSKristof Umann   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
885e17ee1eSKristof Umann                         BugReporter &BR) const {
895e17ee1eSKristof Umann     if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
905e17ee1eSKristof Umann       ControlDependencyCalculator Dom(AC->getCFG());
915e17ee1eSKristof Umann       Dom.dump();
925e17ee1eSKristof Umann     }
935e17ee1eSKristof Umann   }
945e17ee1eSKristof Umann };
955e17ee1eSKristof Umann }
965e17ee1eSKristof Umann 
975e17ee1eSKristof Umann void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) {
985e17ee1eSKristof Umann   mgr.registerChecker<ControlDependencyTreeDumper>();
995e17ee1eSKristof Umann }
1005e17ee1eSKristof Umann 
101bda3dd0dSKirstóf Umann bool ento::shouldRegisterControlDependencyTreeDumper(const CheckerManager &mgr) {
1025e17ee1eSKristof Umann   return true;
1035e17ee1eSKristof Umann }
1045e17ee1eSKristof Umann 
1055e17ee1eSKristof Umann //===----------------------------------------------------------------------===//
10657d736fdSArgyrios Kyrtzidis // LiveVariablesDumper
10757d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
10857d736fdSArgyrios Kyrtzidis 
10957d736fdSArgyrios Kyrtzidis namespace {
1106a5674ffSArgyrios Kyrtzidis class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
11157d736fdSArgyrios Kyrtzidis public:
11257d736fdSArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
11357d736fdSArgyrios Kyrtzidis                         BugReporter &BR) const {
114dccc2b22STed Kremenek     if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
11557d736fdSArgyrios Kyrtzidis       L->dumpBlockLiveness(mgr.getSourceManager());
11657d736fdSArgyrios Kyrtzidis     }
11757d736fdSArgyrios Kyrtzidis   }
11857d736fdSArgyrios Kyrtzidis };
119ab9db510SAlexander Kornienko }
12057d736fdSArgyrios Kyrtzidis 
12157d736fdSArgyrios Kyrtzidis void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
12257d736fdSArgyrios Kyrtzidis   mgr.registerChecker<LiveVariablesDumper>();
12357d736fdSArgyrios Kyrtzidis }
12457d736fdSArgyrios Kyrtzidis 
125bda3dd0dSKirstóf Umann bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) {
126058a7a45SKristof Umann   return true;
127058a7a45SKristof Umann }
128058a7a45SKristof Umann 
12957d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
130dda42164SArtem Dergachev // LiveStatementsDumper
131dda42164SArtem Dergachev //===----------------------------------------------------------------------===//
132dda42164SArtem Dergachev 
133dda42164SArtem Dergachev namespace {
134*dd1d5488SKristóf Umann class LiveExpressionsDumper : public Checker<check::ASTCodeBody> {
135dda42164SArtem Dergachev public:
136dda42164SArtem Dergachev   void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
137dda42164SArtem Dergachev                         BugReporter &BR) const {
138dda42164SArtem Dergachev     if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
139*dd1d5488SKristóf Umann       L->dumpExprLiveness(Mgr.getSourceManager());
140dda42164SArtem Dergachev   }
141dda42164SArtem Dergachev };
142dda42164SArtem Dergachev }
143dda42164SArtem Dergachev 
144*dd1d5488SKristóf Umann void ento::registerLiveExpressionsDumper(CheckerManager &mgr) {
145*dd1d5488SKristóf Umann   mgr.registerChecker<LiveExpressionsDumper>();
146dda42164SArtem Dergachev }
147dda42164SArtem Dergachev 
148*dd1d5488SKristóf Umann bool ento::shouldRegisterLiveExpressionsDumper(const CheckerManager &mgr) {
149058a7a45SKristof Umann   return true;
150058a7a45SKristof Umann }
151058a7a45SKristof Umann 
152dda42164SArtem Dergachev //===----------------------------------------------------------------------===//
15357d736fdSArgyrios Kyrtzidis // CFGViewer
15457d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
15557d736fdSArgyrios Kyrtzidis 
15657d736fdSArgyrios Kyrtzidis namespace {
1576a5674ffSArgyrios Kyrtzidis class CFGViewer : public Checker<check::ASTCodeBody> {
15857d736fdSArgyrios Kyrtzidis public:
15957d736fdSArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
16057d736fdSArgyrios Kyrtzidis                         BugReporter &BR) const {
16157d736fdSArgyrios Kyrtzidis     if (CFG *cfg = mgr.getCFG(D)) {
162bbafb8a7SDavid Blaikie       cfg->viewCFG(mgr.getLangOpts());
16357d736fdSArgyrios Kyrtzidis     }
16457d736fdSArgyrios Kyrtzidis   }
16557d736fdSArgyrios Kyrtzidis };
166ab9db510SAlexander Kornienko }
16757d736fdSArgyrios Kyrtzidis 
16857d736fdSArgyrios Kyrtzidis void ento::registerCFGViewer(CheckerManager &mgr) {
16957d736fdSArgyrios Kyrtzidis   mgr.registerChecker<CFGViewer>();
17057d736fdSArgyrios Kyrtzidis }
17157d736fdSArgyrios Kyrtzidis 
172bda3dd0dSKirstóf Umann bool ento::shouldRegisterCFGViewer(const CheckerManager &mgr) {
173058a7a45SKristof Umann   return true;
174058a7a45SKristof Umann }
175058a7a45SKristof Umann 
17657d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
17757d736fdSArgyrios Kyrtzidis // CFGDumper
17857d736fdSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
17957d736fdSArgyrios Kyrtzidis 
18057d736fdSArgyrios Kyrtzidis namespace {
1816a5674ffSArgyrios Kyrtzidis class CFGDumper : public Checker<check::ASTCodeBody> {
18257d736fdSArgyrios Kyrtzidis public:
18357d736fdSArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
18457d736fdSArgyrios Kyrtzidis                         BugReporter &BR) const {
185e02e96a6SJordan Rose     PrintingPolicy Policy(mgr.getLangOpts());
186e02e96a6SJordan Rose     Policy.TerseOutput = true;
187e02e96a6SJordan Rose     Policy.PolishForDeclaration = true;
188e02e96a6SJordan Rose     D->print(llvm::errs(), Policy);
189e02e96a6SJordan Rose 
19057d736fdSArgyrios Kyrtzidis     if (CFG *cfg = mgr.getCFG(D)) {
191bbafb8a7SDavid Blaikie       cfg->dump(mgr.getLangOpts(),
19272be32afSTed Kremenek                 llvm::sys::Process::StandardErrHasColors());
19357d736fdSArgyrios Kyrtzidis     }
19457d736fdSArgyrios Kyrtzidis   }
19557d736fdSArgyrios Kyrtzidis };
196ab9db510SAlexander Kornienko }
19757d736fdSArgyrios Kyrtzidis 
19857d736fdSArgyrios Kyrtzidis void ento::registerCFGDumper(CheckerManager &mgr) {
19957d736fdSArgyrios Kyrtzidis   mgr.registerChecker<CFGDumper>();
20057d736fdSArgyrios Kyrtzidis }
201c000e7edSAnna Zaks 
202bda3dd0dSKirstóf Umann bool ento::shouldRegisterCFGDumper(const CheckerManager &mgr) {
203058a7a45SKristof Umann   return true;
204058a7a45SKristof Umann }
205058a7a45SKristof Umann 
206c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
207c000e7edSAnna Zaks // CallGraphViewer
208c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
209c000e7edSAnna Zaks 
210c000e7edSAnna Zaks namespace {
211c000e7edSAnna Zaks class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
212c000e7edSAnna Zaks public:
213c000e7edSAnna Zaks   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
214c000e7edSAnna Zaks                     BugReporter &BR) const {
215c000e7edSAnna Zaks     CallGraph CG;
216c000e7edSAnna Zaks     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
217c000e7edSAnna Zaks     CG.viewGraph();
218c000e7edSAnna Zaks   }
219c000e7edSAnna Zaks };
220ab9db510SAlexander Kornienko }
221c000e7edSAnna Zaks 
222c000e7edSAnna Zaks void ento::registerCallGraphViewer(CheckerManager &mgr) {
223c000e7edSAnna Zaks   mgr.registerChecker<CallGraphViewer>();
224c000e7edSAnna Zaks }
225c000e7edSAnna Zaks 
226bda3dd0dSKirstóf Umann bool ento::shouldRegisterCallGraphViewer(const CheckerManager &mgr) {
227058a7a45SKristof Umann   return true;
228058a7a45SKristof Umann }
229058a7a45SKristof Umann 
230c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
231c000e7edSAnna Zaks // CallGraphDumper
232c000e7edSAnna Zaks //===----------------------------------------------------------------------===//
233c000e7edSAnna Zaks 
234c000e7edSAnna Zaks namespace {
235c000e7edSAnna Zaks class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
236c000e7edSAnna Zaks public:
237c000e7edSAnna Zaks   void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
238c000e7edSAnna Zaks                     BugReporter &BR) const {
239c000e7edSAnna Zaks     CallGraph CG;
240c000e7edSAnna Zaks     CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
241c000e7edSAnna Zaks     CG.dump();
242c000e7edSAnna Zaks   }
243c000e7edSAnna Zaks };
244ab9db510SAlexander Kornienko }
245c000e7edSAnna Zaks 
246c000e7edSAnna Zaks void ento::registerCallGraphDumper(CheckerManager &mgr) {
247c000e7edSAnna Zaks   mgr.registerChecker<CallGraphDumper>();
248c000e7edSAnna Zaks }
24986917fdbSTed Kremenek 
250bda3dd0dSKirstóf Umann bool ento::shouldRegisterCallGraphDumper(const CheckerManager &mgr) {
251058a7a45SKristof Umann   return true;
252058a7a45SKristof Umann }
25386917fdbSTed Kremenek 
25486917fdbSTed Kremenek //===----------------------------------------------------------------------===//
25586917fdbSTed Kremenek // ConfigDumper
25686917fdbSTed Kremenek //===----------------------------------------------------------------------===//
25786917fdbSTed Kremenek 
25886917fdbSTed Kremenek namespace {
25986917fdbSTed Kremenek class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
260a92b80f8SBenjamin Kramer   typedef AnalyzerOptions::ConfigTable Table;
261a92b80f8SBenjamin Kramer 
2624cadf292SBenjamin Kramer   static int compareEntry(const Table::MapEntryTy *const *LHS,
2634cadf292SBenjamin Kramer                           const Table::MapEntryTy *const *RHS) {
2644cadf292SBenjamin Kramer     return (*LHS)->getKey().compare((*RHS)->getKey());
2654cadf292SBenjamin Kramer   }
2664cadf292SBenjamin Kramer 
26786917fdbSTed Kremenek public:
26886917fdbSTed Kremenek   void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
26986917fdbSTed Kremenek                                  AnalysisManager& mgr,
27086917fdbSTed Kremenek                                  BugReporter &BR) const {
271a92b80f8SBenjamin Kramer     const Table &Config = mgr.options.Config;
27286917fdbSTed Kremenek 
273a92b80f8SBenjamin Kramer     SmallVector<const Table::MapEntryTy *, 32> Keys;
274a92b80f8SBenjamin Kramer     for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
275a92b80f8SBenjamin Kramer          ++I)
276a92b80f8SBenjamin Kramer       Keys.push_back(&*I);
2774cadf292SBenjamin Kramer     llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
27886917fdbSTed Kremenek 
27986917fdbSTed Kremenek     llvm::errs() << "[config]\n";
280a92b80f8SBenjamin Kramer     for (unsigned I = 0, E = Keys.size(); I != E; ++I)
281549f9cd4SKristof Umann       llvm::errs() << Keys[I]->getKey() << " = "
282549f9cd4SKristof Umann                    << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
283549f9cd4SKristof Umann                    << '\n';
28486917fdbSTed Kremenek   }
28586917fdbSTed Kremenek };
286ab9db510SAlexander Kornienko }
28786917fdbSTed Kremenek 
28886917fdbSTed Kremenek void ento::registerConfigDumper(CheckerManager &mgr) {
28986917fdbSTed Kremenek   mgr.registerChecker<ConfigDumper>();
29086917fdbSTed Kremenek }
2917925e3dbSAnna Zaks 
292bda3dd0dSKirstóf Umann bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) {
293058a7a45SKristof Umann   return true;
294058a7a45SKristof Umann }
295058a7a45SKristof Umann 
2967925e3dbSAnna Zaks //===----------------------------------------------------------------------===//
2977925e3dbSAnna Zaks // ExplodedGraph Viewer
2987925e3dbSAnna Zaks //===----------------------------------------------------------------------===//
2997925e3dbSAnna Zaks 
3007925e3dbSAnna Zaks namespace {
3017925e3dbSAnna Zaks class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
3027925e3dbSAnna Zaks public:
3037925e3dbSAnna Zaks   ExplodedGraphViewer() {}
3047925e3dbSAnna Zaks   void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
3057925e3dbSAnna Zaks     Eng.ViewGraph(0);
3067925e3dbSAnna Zaks   }
3077925e3dbSAnna Zaks };
3087925e3dbSAnna Zaks 
3097925e3dbSAnna Zaks }
3107925e3dbSAnna Zaks 
3117925e3dbSAnna Zaks void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
3127925e3dbSAnna Zaks   mgr.registerChecker<ExplodedGraphViewer>();
3137925e3dbSAnna Zaks }
314efec1630SGabor Horvath 
315bda3dd0dSKirstóf Umann bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) {
316058a7a45SKristof Umann   return true;
317058a7a45SKristof Umann }
3184962816eSKristof Umann 
3194962816eSKristof Umann //===----------------------------------------------------------------------===//
3204962816eSKristof Umann // Emits a report for every Stmt that the analyzer visits.
3214962816eSKristof Umann //===----------------------------------------------------------------------===//
3224962816eSKristof Umann 
3234962816eSKristof Umann namespace {
3244962816eSKristof Umann 
3254962816eSKristof Umann class ReportStmts : public Checker<check::PreStmt<Stmt>> {
3264962816eSKristof Umann   BuiltinBug BT_stmtLoc{this, "Statement"};
3274962816eSKristof Umann 
3284962816eSKristof Umann public:
3294962816eSKristof Umann   void checkPreStmt(const Stmt *S, CheckerContext &C) const {
3304962816eSKristof Umann     ExplodedNode *Node = C.generateNonFatalErrorNode();
3314962816eSKristof Umann     if (!Node)
3324962816eSKristof Umann       return;
3334962816eSKristof Umann 
3342f169e7cSArtem Dergachev     auto Report =
3352f169e7cSArtem Dergachev         std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node);
3364962816eSKristof Umann 
3374962816eSKristof Umann     C.emitReport(std::move(Report));
3384962816eSKristof Umann   }
3394962816eSKristof Umann };
3404962816eSKristof Umann 
3414962816eSKristof Umann } // end of anonymous namespace
3424962816eSKristof Umann 
3434962816eSKristof Umann void ento::registerReportStmts(CheckerManager &mgr) {
3444962816eSKristof Umann   mgr.registerChecker<ReportStmts>();
3454962816eSKristof Umann }
3464962816eSKristof Umann 
347bda3dd0dSKirstóf Umann bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) {
3484962816eSKristof Umann   return true;
3494962816eSKristof Umann }
350