Files
clang-p2996/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
Kirstóf Umann 268fa40daa [analyzer] Don't print the config count in debug.ConfigDumper
I think anyone who added a checker config wondered why is there a need
to test this. Its just a chore when adding a new config, so I removed
it.

To give some historic insight though, we used to not list **all**
options, but only those explicitly added to AnalyzerOptions, such as the
ones specified on the command line. However, past this change (and
arguably even before that) this line makes little sense.

There is an argument to be made against the entirety of
analyzer-config.c test file, but since this commit fixes some builtbots
and is landing without review, I wouldn't like to be too invasive.
2020-05-19 16:51:14 +02:00

350 lines
10 KiB
C++

//==- DebugCheckers.cpp - Debugging Checkers ---------------------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines checkers that display debugging information.
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/Analysis/Analyses/Dominators.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CallGraph.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/Support/Process.h"
using namespace clang;
using namespace ento;
//===----------------------------------------------------------------------===//
// DominatorsTreeDumper
//===----------------------------------------------------------------------===//
namespace {
class DominatorsTreeDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
CFGDomTree Dom;
Dom.buildDominatorTree(AC->getCFG());
Dom.dump();
}
}
};
}
void ento::registerDominatorsTreeDumper(CheckerManager &mgr) {
mgr.registerChecker<DominatorsTreeDumper>();
}
bool ento::shouldRegisterDominatorsTreeDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// PostDominatorsTreeDumper
//===----------------------------------------------------------------------===//
namespace {
class PostDominatorsTreeDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
CFGPostDomTree Dom;
Dom.buildDominatorTree(AC->getCFG());
Dom.dump();
}
}
};
}
void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) {
mgr.registerChecker<PostDominatorsTreeDumper>();
}
bool ento::shouldRegisterPostDominatorsTreeDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// ControlDependencyTreeDumper
//===----------------------------------------------------------------------===//
namespace {
class ControlDependencyTreeDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) {
ControlDependencyCalculator Dom(AC->getCFG());
Dom.dump();
}
}
};
}
void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) {
mgr.registerChecker<ControlDependencyTreeDumper>();
}
bool ento::shouldRegisterControlDependencyTreeDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// LiveVariablesDumper
//===----------------------------------------------------------------------===//
namespace {
class LiveVariablesDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (LiveVariables* L = mgr.getAnalysis<LiveVariables>(D)) {
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
};
}
void ento::registerLiveVariablesDumper(CheckerManager &mgr) {
mgr.registerChecker<LiveVariablesDumper>();
}
bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// LiveStatementsDumper
//===----------------------------------------------------------------------===//
namespace {
class LiveStatementsDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& Mgr,
BugReporter &BR) const {
if (LiveVariables *L = Mgr.getAnalysis<RelaxedLiveVariables>(D))
L->dumpStmtLiveness(Mgr.getSourceManager());
}
};
}
void ento::registerLiveStatementsDumper(CheckerManager &mgr) {
mgr.registerChecker<LiveStatementsDumper>();
}
bool ento::shouldRegisterLiveStatementsDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// CFGViewer
//===----------------------------------------------------------------------===//
namespace {
class CFGViewer : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
if (CFG *cfg = mgr.getCFG(D)) {
cfg->viewCFG(mgr.getLangOpts());
}
}
};
}
void ento::registerCFGViewer(CheckerManager &mgr) {
mgr.registerChecker<CFGViewer>();
}
bool ento::shouldRegisterCFGViewer(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// CFGDumper
//===----------------------------------------------------------------------===//
namespace {
class CFGDumper : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
PrintingPolicy Policy(mgr.getLangOpts());
Policy.TerseOutput = true;
Policy.PolishForDeclaration = true;
D->print(llvm::errs(), Policy);
if (CFG *cfg = mgr.getCFG(D)) {
cfg->dump(mgr.getLangOpts(),
llvm::sys::Process::StandardErrHasColors());
}
}
};
}
void ento::registerCFGDumper(CheckerManager &mgr) {
mgr.registerChecker<CFGDumper>();
}
bool ento::shouldRegisterCFGDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// CallGraphViewer
//===----------------------------------------------------------------------===//
namespace {
class CallGraphViewer : public Checker< check::ASTDecl<TranslationUnitDecl> > {
public:
void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
BugReporter &BR) const {
CallGraph CG;
CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
CG.viewGraph();
}
};
}
void ento::registerCallGraphViewer(CheckerManager &mgr) {
mgr.registerChecker<CallGraphViewer>();
}
bool ento::shouldRegisterCallGraphViewer(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// CallGraphDumper
//===----------------------------------------------------------------------===//
namespace {
class CallGraphDumper : public Checker< check::ASTDecl<TranslationUnitDecl> > {
public:
void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager& mgr,
BugReporter &BR) const {
CallGraph CG;
CG.addToCallGraph(const_cast<TranslationUnitDecl*>(TU));
CG.dump();
}
};
}
void ento::registerCallGraphDumper(CheckerManager &mgr) {
mgr.registerChecker<CallGraphDumper>();
}
bool ento::shouldRegisterCallGraphDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// ConfigDumper
//===----------------------------------------------------------------------===//
namespace {
class ConfigDumper : public Checker< check::EndOfTranslationUnit > {
typedef AnalyzerOptions::ConfigTable Table;
static int compareEntry(const Table::MapEntryTy *const *LHS,
const Table::MapEntryTy *const *RHS) {
return (*LHS)->getKey().compare((*RHS)->getKey());
}
public:
void checkEndOfTranslationUnit(const TranslationUnitDecl *TU,
AnalysisManager& mgr,
BugReporter &BR) const {
const Table &Config = mgr.options.Config;
SmallVector<const Table::MapEntryTy *, 32> Keys;
for (Table::const_iterator I = Config.begin(), E = Config.end(); I != E;
++I)
Keys.push_back(&*I);
llvm::array_pod_sort(Keys.begin(), Keys.end(), compareEntry);
llvm::errs() << "[config]\n";
for (unsigned I = 0, E = Keys.size(); I != E; ++I)
llvm::errs() << Keys[I]->getKey() << " = "
<< (Keys[I]->second.empty() ? "\"\"" : Keys[I]->second)
<< '\n';
}
};
}
void ento::registerConfigDumper(CheckerManager &mgr) {
mgr.registerChecker<ConfigDumper>();
}
bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// ExplodedGraph Viewer
//===----------------------------------------------------------------------===//
namespace {
class ExplodedGraphViewer : public Checker< check::EndAnalysis > {
public:
ExplodedGraphViewer() {}
void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const {
Eng.ViewGraph(0);
}
};
}
void ento::registerExplodedGraphViewer(CheckerManager &mgr) {
mgr.registerChecker<ExplodedGraphViewer>();
}
bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) {
return true;
}
//===----------------------------------------------------------------------===//
// Emits a report for every Stmt that the analyzer visits.
//===----------------------------------------------------------------------===//
namespace {
class ReportStmts : public Checker<check::PreStmt<Stmt>> {
BuiltinBug BT_stmtLoc{this, "Statement"};
public:
void checkPreStmt(const Stmt *S, CheckerContext &C) const {
ExplodedNode *Node = C.generateNonFatalErrorNode();
if (!Node)
return;
auto Report =
std::make_unique<PathSensitiveBugReport>(BT_stmtLoc, "Statement", Node);
C.emitReport(std::move(Report));
}
};
} // end of anonymous namespace
void ento::registerReportStmts(CheckerManager &mgr) {
mgr.registerChecker<ReportStmts>();
}
bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) {
return true;
}