349 lines · 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-exception6//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// DominatorsTreeDumper30//===----------------------------------------------------------------------===//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// PostDominatorsTreeDumper56//===----------------------------------------------------------------------===//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// ControlDependencyTreeDumper82//===----------------------------------------------------------------------===//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// LiveVariablesDumper107//===----------------------------------------------------------------------===//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// LiveStatementsDumper131//===----------------------------------------------------------------------===//132 133namespace {134class LiveExpressionsDumper : 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->dumpExprLiveness(Mgr.getSourceManager());140 }141};142}143 144void ento::registerLiveExpressionsDumper(CheckerManager &mgr) {145 mgr.registerChecker<LiveExpressionsDumper>();146}147 148bool ento::shouldRegisterLiveExpressionsDumper(const CheckerManager &mgr) {149 return true;150}151 152//===----------------------------------------------------------------------===//153// CFGViewer154//===----------------------------------------------------------------------===//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// CFGDumper178//===----------------------------------------------------------------------===//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// CallGraphViewer208//===----------------------------------------------------------------------===//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// CallGraphDumper232//===----------------------------------------------------------------------===//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// ConfigDumper256//===----------------------------------------------------------------------===//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 (const auto &Entry : Config)275 Keys.push_back(&Entry);276 llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);277 278 llvm::errs() << "[config]\n";279 for (unsigned I = 0, E = Keys.size(); I != E; ++I)280 llvm::errs() << Keys[I]->getKey() << " = "281 << (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)282 << '\n';283 }284};285}286 287void ento::registerConfigDumper(CheckerManager &mgr) {288 mgr.registerChecker<ConfigDumper>();289}290 291bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) {292 return true;293}294 295//===----------------------------------------------------------------------===//296// ExplodedGraph Viewer297//===----------------------------------------------------------------------===//298 299namespace {300class ExplodedGraphViewer : public Checker< check::EndAnalysis > {301public:302 ExplodedGraphViewer() {}303 void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {304 Eng.ViewGraph(false);305 }306};307 308}309 310void ento::registerExplodedGraphViewer(CheckerManager &mgr) {311 mgr.registerChecker<ExplodedGraphViewer>();312}313 314bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) {315 return true;316}317 318//===----------------------------------------------------------------------===//319// Emits a report for every Stmt that the analyzer visits.320//===----------------------------------------------------------------------===//321 322namespace {323 324class ReportStmts : public Checker<check::PreStmt<Stmt>> {325 BugType BT_stmtLoc{this, "Statement"};326 327public:328 void checkPreStmt(const Stmt *S, CheckerContext &C) const {329 ExplodedNode *Node = C.generateNonFatalErrorNode();330 if (!Node)331 return;332 333 auto Report =334 std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node);335 336 C.emitReport(std::move(Report));337 }338};339 340} // end of anonymous namespace341 342void ento::registerReportStmts(CheckerManager &mgr) {343 mgr.registerChecker<ReportStmts>();344}345 346bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) {347 return true;348}349