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