// 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 "llvm/ADT/STLExtras.h"
#include <queue>
using namespace clang;
//===----------------------------------------------------------------------===//
// static functions.
//===----------------------------------------------------------------------===//
static inline Stmt* GetStmt(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();
return 0;
}
static inline const ExplodedNode<GRState>*
GetPredecessorNode(const ExplodedNode<GRState>* N) {
return N->pred_empty() ? NULL : *(N->pred_begin());
}
static inline const ExplodedNode<GRState>*
GetSuccessorNode(const ExplodedNode<GRState>* N) {
return N->succ_empty() ? NULL : *(N->succ_begin());
}
static Stmt* GetPreviousStmt(const ExplodedNode<GRState>* N) {
for (N = GetPredecessorNode(N); N; N = GetPredecessorNode(N))
if (Stmt *S = GetStmt(N->getLocation()))
return S;
return 0;
}
static Stmt* GetNextStmt(const ExplodedNode<GRState>* N) {
for (N = GetSuccessorNode(N); N; N = GetSuccessorNode(N))
if (Stmt *S = GetStmt(N->getLocation()))
return S;
return 0;
}
static inline Stmt* GetCurrentOrPreviousStmt(const ExplodedNode<GRState>* N) {
if (Stmt *S = GetStmt(N->getLocation()))
return S;
return GetPreviousStmt(N);
}
static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode<GRState>* N) {
if (Stmt *S = GetStmt(N->getLocation()))
return S;
return GetNextStmt(N);
}
//===----------------------------------------------------------------------===//
// Diagnostics for 'execution continues on line XXX'.
//===----------------------------------------------------------------------===//
static SourceLocation ExecutionContinues(SourceManager& SMgr,
const ExplodedNode<GRState>* N,
const Decl& D,
bool* OutHasStmt = 0) {
if (Stmt *S = GetNextStmt(N)) {
if (OutHasStmt) *OutHasStmt = true;
return S->getLocStart();
}
else {
if (OutHasStmt) *OutHasStmt = false;
return D.getBody()->getRBracLoc();
}
}
static SourceLocation ExecutionContinues(llvm::raw_string_ostream& os,
SourceManager& SMgr,
const ExplodedNode<GRState>* N,
const Decl& D) {
// Slow, but probably doesn't matter.
if (os.str().empty())
os << ' ';
bool hasStmt;
SourceLocation Loc = ExecutionContinues(SMgr, N, D, &hasStmt);
if (hasStmt)
os << "Execution continues on line "
<< SMgr.getInstantiationLineNumber(Loc) << '.';
else
os << "Execution jumps to the end of the "
<< (isa<ObjCMethodDecl>(D) ? "method" : "function") << '.';
return Loc;
}
//===----------------------------------------------------------------------===//
// Methods for BugType and subclasses.
//===----------------------------------------------------------------------===//
BugType::~BugType() {}
void BugType::FlushReports