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.
350 lines
10 KiB
C++
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;
|
|
}
|