// BugReporter.cpp - Generate PathDiagnostics for Bugs ------------*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines BugReporter, a utility class for generating
// PathDiagnostics for analyses based on GRSimpleVals.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CFG.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseMap.h"
#include <sstream>
using namespace clang;
BugReporter::~BugReporter() {}
GRBugReporter::~GRBugReporter() {}
BugReporterData::~BugReporterData() {}
BugType::~BugType() {}
BugReport::~BugReport() {}
RangedBugReport::~RangedBugReport() {}
ExplodedGraph<GRState>& GRBugReporter::getGraph() {
return Eng.getGraph();
}
GRStateManager& GRBugReporter::getStateManager() {
return Eng.getStateManager();
}
static inline Stmt* GetStmt(const ProgramPoint& P) {
if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
return PS->getStmt();
}
else if (const BlockEdge* BE = dyn_cast<BlockEdge>(&P)) {
return BE->getSrc()->getTerminator();
}
else if (const BlockEntrance* BE = dyn_cast<BlockEntrance>(&P)) {
return BE->getFirstStmt();
}
assert (false && "Unsupported ProgramPoint.");
return NULL;
}
static inline Stmt* GetStmt(const CFGBlock* B) {
if (B->empty())
return const_cast<Stmt*>(B->getTerminator());
else
return (*B)[0];
}
static inline ExplodedNode<GRState>*
GetNextNode(ExplodedNode<GRState>* N) {
return N->pred_empty() ? NULL : *(N->pred_begin());
}
static Stmt* GetLastStmt(ExplodedNode<GRState>* N) {
assert (isa<BlockEntrance>(N->getLocation()));
for (N = GetNextNode(N); N; N = GetNextNode(N)) {
ProgramPoint P = N->getLocation();
if (PostStmt* PS = dyn_cast<PostStmt>(&P))
return PS->getStmt();
}
return NULL;
}
static void ExecutionContinues(std::ostringstream& os, SourceManager& SMgr,
Stmt* S) {
if (!S)
return;
// Slow, but probably doesn't matter.
if (os.str().empty())
os << ' ';
os << "Execution continues on line "
<< SMgr.getInstantiationLineNumber(S->getLocStart()) << '.';
}
static inline void ExecutionContinues(std::ostringstream& os,
SourceManager& SMgr,
ExplodedNode<GRState>* N) {
ExecutionContinues(os, SMgr, GetStmt(N->getLocation()));
}
static inline void ExecutionContinues(std::ostringstream& os,
SourceManager& SMgr,
const CFGBlock* B) {
ExecutionContinues(os, SMgr, GetStmt(B));
}
Stmt* BugReport::getStmt(BugReporter& BR) const {
ProgramPoint ProgP = EndNode->getLocation();
Stmt *S = NULL;
if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP))
if (BE->getBlock() == &BR.getCFG()->getExit())
S = GetLastStmt(EndNode);
if (!S)
S = GetStmt(ProgP);
return S;
}
PathDiagnosticPiece*
BugReport::getEndPath(BugReporter& BR,
ExplodedNode<GRState>* EndPathNode) {
Stmt* S = getStmt(BR);
if (!S)
return NULL;
FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getDescription());
const SourceRange *Beg, *End;
getRanges(BR, Beg, End);
for (; Beg != End; ++Beg)
P->addRange(*Beg);
return P;
}
void BugReport::getRanges(BugReporter& BR, const SourceRange*& beg,
const SourceRange*& end) {
if (Expr* E = dyn_cast_or_null<Expr>(getStmt(BR))) {
R = E->getSourceRange();
beg = &R;
end = beg+1;
}
else
beg = end = 0;
}
FullSourceLoc BugReport::getLocation(SourceManager