aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/BugReporter.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-03-31 23:00:32 +0000
committerTed Kremenek <kremenek@apple.com>2009-03-31 23:00:32 +0000
commit3106198188ac6eb2753f1764d5c28376b0b76351 (patch)
treeed28bbeaef6af8cb9e82b1ae0deac13635c6118f /lib/Analysis/BugReporter.cpp
parent35f38a2c22d68c22e2dbe8e9ee84c120c8f327bb (diff)
More code reshuffling. No functionality change.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68157 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/BugReporter.cpp')
-rw-r--r--lib/Analysis/BugReporter.cpp930
1 files changed, 465 insertions, 465 deletions
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 8a37d1a3c1..1d1c2fa7d0 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -31,7 +31,7 @@
using namespace clang;
//===----------------------------------------------------------------------===//
-// static functions.
+// Helper routines for walking the ExplodedGraph and fetching statements.
//===----------------------------------------------------------------------===//
static inline Stmt* GetStmt(ProgramPoint P) {
@@ -99,7 +99,7 @@ static inline Stmt* GetCurrentOrNextStmt(const ExplodedNode<GRState>* N) {
}
//===----------------------------------------------------------------------===//
-// Diagnostics for 'execution continues on line XXX'.
+// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
typedef llvm::DenseMap<const ExplodedNode<GRState>*,
@@ -252,270 +252,9 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
}
//===----------------------------------------------------------------------===//
-// Methods for BugType and subclasses.
-//===----------------------------------------------------------------------===//
-BugType::~BugType() {}
-void BugType::FlushReports(BugReporter &BR) {}
-
-//===----------------------------------------------------------------------===//
-// Methods for BugReport and subclasses.
-//===----------------------------------------------------------------------===//
-BugReport::~BugReport() {}
-RangedBugReport::~RangedBugReport() {}
-
-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 = GetPreviousStmt(EndNode);
- }
- if (!S) S = GetStmt(ProgP);
-
- return S;
-}
-
-PathDiagnosticPiece*
-BugReport::getEndPath(BugReporter& BR,
- const ExplodedNode<GRState>* EndPathNode) {
-
- Stmt* S = getStmt(BR);
-
- if (!S)
- return NULL;
-
- FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
- PathDiagnosticPiece* P = new PathDiagnosticEventPiece(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();
- assert(R.isValid());
- beg = &R;
- end = beg+1;
- }
- else
- beg = end = 0;
-}
-
-SourceLocation BugReport::getLocation() const {
- if (EndNode)
- if (Stmt* S = GetCurrentOrPreviousStmt(EndNode)) {
- // For member expressions, return the location of the '.' or '->'.
- if (MemberExpr* ME = dyn_cast<MemberExpr>(S))
- return ME->getMemberLoc();
-
- return S->getLocStart();
- }
-
- return FullSourceLoc();
-}
-
-PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode<GRState>* N,
- const ExplodedNode<GRState>* PrevN,
- const ExplodedGraph<GRState>& G,
- BugReporter& BR,
- NodeResolver &NR) {
- return NULL;
-}
-
-//===----------------------------------------------------------------------===//
-// Methods for BugReporter and subclasses.
-//===----------------------------------------------------------------------===//
-
-BugReportEquivClass::~BugReportEquivClass() {
- for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
-}
-
-GRBugReporter::~GRBugReporter() { FlushReports(); }
-BugReporterData::~BugReporterData() {}
-
-ExplodedGraph<GRState>&
-GRBugReporter::getGraph() { return Eng.getGraph(); }
-
-GRStateManager&
-GRBugReporter::getStateManager() { return Eng.getStateManager(); }
-
-BugReporter::~BugReporter() { FlushReports(); }
-
-void BugReporter::FlushReports() {
- if (BugTypes.isEmpty())
- return;
-
- // First flush the warnings for each BugType. This may end up creating new
- // warnings and new BugTypes. Because ImmutableSet is a functional data
- // structure, we do not need to worry about the iterators being invalidated.
- for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
- const_cast<BugType*>(*I)->FlushReports(*this);
-
- // Iterate through BugTypes a second time. BugTypes may have been updated
- // with new BugType objects and new warnings.
- for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I) {
- BugType *BT = const_cast<BugType*>(*I);
-
- typedef llvm::FoldingSet<BugReportEquivClass> SetTy;
- SetTy& EQClasses = BT->EQClasses;
-
- for (SetTy::iterator EI=EQClasses.begin(), EE=EQClasses.end(); EI!=EE;++EI){
- BugReportEquivClass& EQ = *EI;
- FlushReport(EQ);
- }
-
- // Delete the BugType object. This will also delete the equivalence
- // classes.
- delete BT;
- }
-
- // Remove all references to the BugType objects.
- BugTypes = F.GetEmptySet();
-}
-
-//===----------------------------------------------------------------------===//
-// PathDiagnostics generation.
+// ScanNotableSymbols: closure-like callback for scanning Store bindings.
//===----------------------------------------------------------------------===//
-static std::pair<std::pair<ExplodedGraph<GRState>*, NodeBackMap*>,
- std::pair<ExplodedNode<GRState>*, unsigned> >
-MakeReportGraph(const ExplodedGraph<GRState>* G,
- const ExplodedNode<GRState>** NStart,
- const ExplodedNode<GRState>** NEnd) {
-
- // Create the trimmed graph. It will contain the shortest paths from the
- // error nodes to the root. In the new graph we should only have one
- // error node unless there are two or more error nodes with the same minimum
- // path length.
- ExplodedGraph<GRState>* GTrim;
- InterExplodedGraphMap<GRState>* NMap;
-
- llvm::DenseMap<const void*, const void*> InverseMap;
- llvm::tie(GTrim, NMap) = G->Trim(NStart, NEnd, &InverseMap);
-
- // Create owning pointers for GTrim and NMap just to ensure that they are
- // released when this function exists.
- llvm::OwningPtr<ExplodedGraph<GRState> > AutoReleaseGTrim(GTrim);
- llvm::OwningPtr<InterExplodedGraphMap<GRState> > AutoReleaseNMap(NMap);
-
- // Find the (first) error node in the trimmed graph. We just need to consult
- // the node map (NMap) which maps from nodes in the original graph to nodes
- // in the new graph.
- const ExplodedNode<GRState>* N = 0;
- unsigned NodeIndex = 0;
-
- for (const ExplodedNode<GRState>** I = NStart; I != NEnd; ++I)
- if ((N = NMap->getMappedNode(*I))) {
- NodeIndex = (I - NStart) / sizeof(*I);
- break;
- }
-
- assert(N && "No error node found in the trimmed graph.");
-
- // Create a new (third!) graph with a single path. This is the graph
- // that will be returned to the caller.
- ExplodedGraph<GRState> *GNew =
- new ExplodedGraph<GRState>(GTrim->getCFG(), GTrim->getCodeDecl(),
- GTrim->getContext());
-
- // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS
- // to the root node, and then construct a new graph that contains only
- // a single path.
- llvm::DenseMap<const void*,unsigned> Visited;
- std::queue<const ExplodedNode<GRState>*> WS;
- WS.push(N);
-
- unsigned cnt = 0;
- const ExplodedNode<GRState>* Root = 0;
-
- while (!WS.empty()) {
- const ExplodedNode<GRState>* Node = WS.front();
- WS.pop();
-
- if (Visited.find(Node) != Visited.end())
- continue;
-
- Visited[Node] = cnt++;
-
- if (Node->pred_empty()) {
- Root = Node;
- break;
- }
-
- for (ExplodedNode<GRState>::const_pred_iterator I=Node->pred_begin(),
- E=Node->pred_end(); I!=E; ++I)
- WS.push(*I);
- }
-
- assert (Root);
-
- // Now walk from the root down the BFS path, always taking the successor
- // with the lowest number.
- ExplodedNode<GRState> *Last = 0, *First = 0;
- NodeBackMap *BM = new NodeBackMap();
-
- for ( N = Root ;;) {
- // Lookup the number associated with the current node.
- llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
- assert (I != Visited.end());
-
- // Create the equivalent node in the new graph with the same state
- // and location.
- ExplodedNode<GRState>* NewN =
- GNew->getNode(N->getLocation(), N->getState());
-
- // Store the mapping to the original node.
- llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
- assert(IMitr != InverseMap.end() && "No mapping to original node.");
- (*BM)[NewN] = (const ExplodedNode<GRState>*) IMitr->second;
-
- // Link up the new node with the previous node.
- if (Last)
- NewN->addPredecessor(Last);
-
- Last = NewN;
-
- // Are we at the final node?
- if (I->second == 0) {
- First = NewN;
- break;
- }
-
- // Find the next successor node. We choose the node that is marked
- // with the lowest DFS number.
- ExplodedNode<GRState>::const_succ_iterator SI = N->succ_begin();
- ExplodedNode<GRState>::const_succ_iterator SE = N->succ_end();
- N = 0;
-
- for (unsigned MinVal = 0; SI != SE; ++SI) {
-
- I = Visited.find(*SI);
-
- if (I == Visited.end())
- continue;
-
- if (!N || I->second < MinVal) {
- N = *SI;
- MinVal = I->second;
- }
- }
-
- assert (N);
- }
-
- assert (First);
- return std::make_pair(std::make_pair(GNew, BM),
- std::make_pair(First, NodeIndex));
-}
-
static const VarDecl*
GetMostRecentVarDeclBinding(const ExplodedNode<GRState>* N,
GRStateManager& VMgr, SVal X) {
@@ -550,8 +289,8 @@ GetMostRecentVarDeclBinding(const ExplodedNode<GRState>* N,
namespace {
class VISIBILITY_HIDDEN NotableSymbolHandler
- : public StoreManager::BindingsHandler {
-
+: public StoreManager::BindingsHandler {
+
SymbolRef Sym;
const GRState* PrevSt;
const Stmt* S;
@@ -559,19 +298,19 @@ class VISIBILITY_HIDDEN NotableSymbolHandler
const ExplodedNode<GRState>* Pred;
PathDiagnostic& PD;
BugReporter& BR;
-
+
public:
NotableSymbolHandler(SymbolRef sym, const GRState* prevst, const Stmt* s,
GRStateManager& vmgr, const ExplodedNode<GRState>* pred,
PathDiagnostic& pd, BugReporter& br)
- : Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {}
-
+ : Sym(sym), PrevSt(prevst), S(s), VMgr(vmgr), Pred(pred), PD(pd), BR(br) {}
+
bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
SVal V) {
-
+
SymbolRef ScanSym = V.getAsSymbol();
-
+
if (ScanSym != Sym)
return true;
@@ -650,200 +389,52 @@ static void HandleNotableSymbol(const ExplodedNode<GRState>* N,
namespace {
class VISIBILITY_HIDDEN ScanNotableSymbols
- : public StoreManager::BindingsHandler {
-
+: public StoreManager::BindingsHandler {
+
llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
const ExplodedNode<GRState>* N;
Stmt* S;
GRBugReporter& BR;
PathDiagnostic& PD;
-
+
public:
ScanNotableSymbols(const ExplodedNode<GRState>* n, Stmt* s, GRBugReporter& br,
PathDiagnostic& pd)
- : N(n), S(s), BR(br), PD(pd) {}
+ : N(n), S(s), BR(br), PD(pd) {}
bool HandleBinding(StoreManager& SMgr, Store store,
const MemRegion* R, SVal V) {
-
+
SymbolRef ScanSym = V.getAsSymbol();
-
+
if (!ScanSym)
return true;
-
+
if (!BR.isNotable(ScanSym))
return true;
-
+
if (AlreadyProcessed.count(ScanSym))
return true;
-
+
AlreadyProcessed.insert(ScanSym);
-
+
HandleNotableSymbol(N, S, ScanSym, BR, PD);
return true;
}
};
} // end anonymous namespace
-/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
-/// and collapses PathDiagosticPieces that are expanded by macros.
-static void CompactPathDiagnostic(PathDiagnostic &PD, const SourceManager& SM) {
- typedef std::vector<std::pair<PathDiagnosticMacroPiece*, SourceLocation> >
- MacroStackTy;
-
- typedef std::vector<PathDiagnosticPiece*>
- PiecesTy;
-
- MacroStackTy MacroStack;
- PiecesTy Pieces;
-
- for (PathDiagnostic::iterator I = PD.begin(), E = PD.end(); I!=E; ++I) {
- // Get the location of the PathDiagnosticPiece.
- const FullSourceLoc Loc = I->getLocation();
-
- // Determine the instantiation location, which is the location we group
- // related PathDiagnosticPieces.
- SourceLocation InstantiationLoc = Loc.isMacroID() ?
- SM.getInstantiationLoc(Loc) :
- SourceLocation();
-
- if (Loc.isFileID()) {
- MacroStack.clear();
- Pieces.push_back(&*I);
- continue;
- }
-
- assert(Loc.isMacroID());
-
- // Is the PathDiagnosticPiece within the same macro group?
- if (!MacroStack.empty() && InstantiationLoc == MacroStack.back().second) {
- MacroStack.back().first->push_back(&*I);
- continue;
- }
-
- // We aren't in the same group. Are we descending into a new macro
- // or are part of an old one?
- PathDiagnosticMacroPiece *MacroGroup = 0;
-
- SourceLocation ParentInstantiationLoc = InstantiationLoc.isMacroID() ?
- SM.getInstantiationLoc(Loc) :
- SourceLocation();
-
- // Walk the entire macro stack.
- while (!MacroStack.empty()) {
- if (InstantiationLoc == MacroStack.back().second) {
- MacroGroup = MacroStack.back().first;
- break;
- }
-
- if (ParentInstantiationLoc == MacroStack.back().second) {
- MacroGroup = MacroStack.back().first;
- break;
- }
-
- MacroStack.pop_back();
- }
-
- if (!MacroGroup || ParentInstantiationLoc == MacroStack.back().second) {
- // Create a new macro group and add it to the stack.
- PathDiagnosticMacroPiece *NewGroup = new PathDiagnosticMacroPiece(Loc);
-
- if (MacroGroup)
- MacroGroup->push_back(NewGroup);
- else {
- assert(InstantiationLoc.isFileID());
- Pieces.push_back(NewGroup);
- }
-
- MacroGroup = NewGroup;
- MacroStack.push_back(std::make_pair(MacroGroup, InstantiationLoc));
- }
-
- // Finally, add the PathDiagnosticPiece to the group.
- MacroGroup->push_back(&*I);
- }
-
- // Now take the pieces and construct a new PathDiagnostic.
- PD.resetPath(false);
-
- for (PiecesTy::iterator I=Pieces.begin(), E=Pieces.end(); I!=E; ++I) {
- if (PathDiagnosticMacroPiece *MP=dyn_cast<PathDiagnosticMacroPiece>(*I))
- if (!MP->containsEvent()) {
- delete MP;
- continue;
- }
-
- PD.push_back(*I);
- }
-}
-
-static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
- PathDiagnosticBuilder &PDB,
- const ExplodedNode<GRState> *N);
-
-void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
- BugReportEquivClass& EQ) {
-
- std::vector<const ExplodedNode<GRState>*> Nodes;
-
- for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I) {
- const ExplodedNode<GRState>* N = I->getEndNode();
- if (N) Nodes.push_back(N);
- }
-
- if (Nodes.empty())
- return;
-
- // Construct a new graph that contains only a single path from the error
- // node to a root.
- const std::pair<std::pair<ExplodedGraph<GRState>*, NodeBackMap*>,
- std::pair<ExplodedNode<GRState>*, unsigned> >&
- GPair = MakeReportGraph(&getGraph(), &Nodes[0], &Nodes[0] + Nodes.size());
-
- // Find the BugReport with the original location.
- BugReport *R = 0;
- unsigned i = 0;
- for (BugReportEquivClass::iterator I=EQ.begin(), E=EQ.end(); I!=E; ++I, ++i)
- if (i == GPair.second.second) { R = *I; break; }
-
- assert(R && "No original report found for sliced graph.");
-
- llvm::OwningPtr<ExplodedGraph<GRState> > ReportGraph(GPair.first.first);
- llvm::OwningPtr<NodeBackMap> BackMap(GPair.first.second);
- const ExplodedNode<GRState> *N = GPair.second.first;
-
- // Start building the path diagnostic...
- if (PathDiagnosticPiece* Piece = R->getEndPath(*this, N))
- PD.push_back(Piece);
- else
- return;
-
- PathDiagnosticBuilder PDB(*this, ReportGraph.get(), R, BackMap.get(),
- getStateManager().getCodeDecl(),
- getPathDiagnosticClient());
-
- switch (PDB.getGenerationScheme()) {
- case PathDiagnosticClient::Extensive:
- case PathDiagnosticClient::Minimal:
- GenerateMinimalPathDiagnostic(PD, PDB, N);
- break;
- }
-
- // After constructing the full PathDiagnostic, do a pass over it to compact
- // PathDiagnosticPieces that occur within a macro.
- CompactPathDiagnostic(PD, PDB.getSourceManager());
-}
+//===----------------------------------------------------------------------===//
+// "Minimal" path diagnostic generation algorithm.
+//===----------------------------------------------------------------------===//
static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode<GRState> *N) {
-
-
ASTContext& Ctx = PDB.getContext();
SourceManager& SMgr = PDB.getSourceManager();
const ExplodedNode<GRState>* NextNode = N->pred_empty()
- ? NULL : *(N->pred_begin());
-
+ ? NULL : *(N->pred_begin());
while (NextNode) {
N = NextNode;
NextNode = GetPredecessorNode(N);
@@ -876,7 +467,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S);
os << "Control jumps to line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getInstantiationLineNumber();
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
break;
@@ -886,19 +477,19 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
// Figure out what case arm we took.
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
-
+
if (Stmt* S = Dst->getLabel()) {
PathDiagnosticLocation End(S, SMgr);
-
+
switch (S->getStmtClass()) {
default:
os << "No cases match in the switch statement. "
- "Control jumps to line "
- << End.asLocation().getInstantiationLineNumber();
+ "Control jumps to line "
+ << End.asLocation().getInstantiationLineNumber();
break;
case Stmt::DefaultStmtClass:
os << "Control jumps to the 'default' case at line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getInstantiationLineNumber();
break;
case Stmt::CaseStmtClass: {
@@ -913,16 +504,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
// FIXME: Maybe this should be an assertion. Are there cases
// were it is not an EnumConstantDecl?
EnumConstantDecl* D =
- dyn_cast<EnumConstantDecl>(DR->getDecl());
-
+ dyn_cast<EnumConstantDecl>(DR->getDecl());
+
if (D) {
GetRawInt = false;
os << D->getNameAsString();
}
}
-
- if (GetRawInt) {
+ if (GetRawInt) {
+
// Not an enum.
Expr* CondE = cast<SwitchStmt>(T)->getCond();
unsigned bits = Ctx.getTypeSize(CondE->getType());
@@ -937,7 +528,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
os << ":' at line "
- << End.asLocation().getInstantiationLineNumber();
+ << End.asLocation().getInstantiationLineNumber();
break;
}
}
@@ -963,13 +554,13 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os.str()));
break;
}
-
- // Determine control-flow for ternary '?'.
+
+ // Determine control-flow for ternary '?'.
case Stmt::ConditionalOperatorClass: {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
os << "'?' condition is ";
-
+
if (*(Src->succ_begin()+1) == Dst)
os << "false";
else
@@ -985,7 +576,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
break;
}
- // Determine control-flow for short-circuited '&&' and '||'.
+ // Determine control-flow for short-circuited '&&' and '||'.
case Stmt::BinaryOperatorClass: {
if (!PDB.supportsLogicalOpControlFlow())
break;
@@ -994,7 +585,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
os << "Left side of '";
-
+
if (B->getOpcode() == BinaryOperator::LAnd) {
os << "&&" << "' is ";
@@ -1032,7 +623,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os.str()));
}
}
-
+
break;
}
@@ -1043,7 +634,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
os << "Loop condition is true. ";
PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
-
+
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
@@ -1055,9 +646,9 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
-
+
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is false. Exiting loop"));
+ "Loop condition is false. Exiting loop"));
}
break;
@@ -1068,12 +659,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (*(Src->succ_begin()+1) == Dst) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
-
+
os << "Loop condition is false. ";
PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
-
+
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
os.str()));
}
@@ -1083,7 +674,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
End = PDB.getEnclosingStmtLocation(S);
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Loop condition is true. Entering loop body"));
+ "Loop condition is true. Entering loop body"));
}
break;
@@ -1091,28 +682,28 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
case Stmt::IfStmtClass: {
PathDiagnosticLocation End = PDB.ExecutionContinues(N);
-
+
if (const Stmt *S = End.asStmt())
End = PDB.getEnclosingStmtLocation(S);
if (*(Src->succ_begin()+1) == Dst)
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking false branch"));
+ "Taking false branch"));
else
PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
- "Taking true branch"));
+ "Taking true branch"));
break;
}
}
}
-
+
if (PathDiagnosticPiece* p =
- PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
- PDB.getBugReporter(),
- PDB.getNodeMapClosure())) {
- PD.push_front(p);
- }
+ PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
+ PDB.getBugReporter(),
+ PDB.getNodeMapClosure())) {
+ PD.push_front(p);
+ }
if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
// Scan the region bindings, and see if a "notable" symbol has a new
@@ -1123,6 +714,415 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
}
}
+//===----------------------------------------------------------------------===//
+// Methods for BugType and subclasses.
+//===----------------------------------------------------------------------===//
+BugType::~BugType() {}
+void BugType::FlushReports(BugReporter &BR) {}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugReport and subclasses.
+//===----------------------------------------------------------------------===//
+BugReport::~BugReport() {}
+RangedBugReport::~RangedBugReport() {}
+
+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 = GetPreviousStmt(EndNode);
+ }
+ if (!S) S = GetStmt(ProgP);
+
+ return S;
+}
+
+PathDiagnosticPiece*
+BugReport::getEndPath(BugReporter& BR,
+ const ExplodedNode<GRState>* EndPathNode) {
+
+ Stmt* S = getStmt(BR);
+
+ if (!S)
+ return NULL;
+
+ FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
+ PathDiagnosticPiece* P = new PathDiagnosticEventPiece(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();
+ assert(R.isValid());
+ beg = &R;
+ end = beg+1;
+ }
+ else
+ beg = end = 0;
+}
+
+SourceLocation BugReport::getLocation() const {
+ if (EndNode)
+ if (Stmt* S = GetCurrentOrPreviousStmt(EndNode)) {
+ // For member expressions, return the location of the '.' or '->'.
+ if (MemberExpr* ME = dyn_cast<MemberExpr>(S))
+ return ME->getMemberLoc();
+
+ return S->getLocStart();
+ }
+
+ return FullSourceLoc();
+}
+
+PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode<GRState>* N,
+ const ExplodedNode<GRState>* PrevN,
+ const ExplodedGraph<GRState>& G,
+ BugReporter& BR,
+ NodeResolver &NR) {
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Methods for BugReporter and subclasses.
+//===----------------------------------------------------------------------===//
+
+BugReportEquivClass::~BugReportEquivClass() {
+ for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
+}
+
+GRBugReporter::~GRBugReporter() { FlushReports(); }
+BugReporterData::~BugReporterData() {}
+
+ExplodedGraph<GRState>&
+GRBugReporter::getGraph() { return Eng.getGraph(); }
+
+GRStateManager&
+GRBugReporter::getStateManager() { return Eng.getStateManager(); }
+
+BugReporter::~BugReporter() { FlushReports(); }
+
+void BugReporter::FlushReports() {
+ if (BugTypes.isEmpty())
+ return;
+
+ // First flush the warnings for each BugType. This may end up creating new
+ // warnings and new BugTypes. Because ImmutableSet is a functional data
+ // structure, we do not need to worry about the iterators being invalidated.
+ for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I)
+ const_cast<BugType*>(*I)->FlushReports(*this);
+
+ // Iterate through BugTypes a second time. BugTypes may have been updated
+ // with new BugType objects and new warnings.
+ for (BugTypesTy::iterator I=BugTypes.begin(), E=BugTypes.end(); I!=E; ++I) {
+ BugType *BT = const_cast<BugType*>(*I);
+
+ typedef llvm::FoldingSet<BugReportEquivClass> SetTy;
+ SetTy& EQClasses = BT->EQClasses;
+
+ for (SetTy::iterator EI=EQClasses.begin(), EE=EQClasses.end(); EI!=EE;++EI){
+ BugReportEquivClass& EQ = *EI;
+ FlushReport(EQ);
+ }
+
+ // Delete the BugType object. This will also delete the equivalence
+ // classes.
+ delete BT;
+ }
+
+ // Remove all references to the BugType objects.
+ BugTypes = F.GetEmptySet();
+}
+
+//===----------------------------------------------------------------------===//
+// PathDiagnostics generation.
+//===----------------------------------------------------------------------===//
+
+static std::pair<std::pair<ExplodedGraph<GRState>*, NodeBackMap*>,
+ std::pair<ExplodedNode<GRState>*, unsigned> >
+MakeReportGraph(const ExplodedGraph<GRState>* G,
+ const ExplodedNode<GRState>** NStart,
+ const ExplodedNode<GRState>** NEnd) {
+
+ // Create the trimmed graph. It will contain the shortest paths from the
+ // error nodes to the root. In the new graph we should only have one
+ // error node unless there are two or more error nodes with the same minimum
+ // path length.
+ ExplodedGraph<GRState>* GTrim;
+ InterExplodedGraphMap<GRState>* NMap;
+
+ llvm::DenseMap<const void*, const void*> InverseMap;
+ llvm::tie(GTrim, NMap) = G->Trim(NStart, NEnd, &InverseMap);
+
+ // Create owning pointers for GTrim and NMap just to ensure that they are
+ // released when this function exists.
+ llvm::OwningPtr<ExplodedGraph<GRState> > AutoReleaseGTrim(GTrim);
+ llvm::OwningPtr<InterExplodedGraphMap<GRState> > AutoReleaseNMap(NMap);
+
+ // Find the (first) error node in the trimmed graph. We just need to consult
+ // the node map (NMap) which maps from nodes in the original graph to nodes
+ // in the new graph.
+ const ExplodedNode<GRState>* N = 0;
+ unsigned NodeIndex = 0;
+
+ for (const ExplodedNode<GRState>** I = NStart; I != NEnd; ++I)
+ if ((N = NMap->getMappedNode(*I))) {
+ NodeIndex = (I - NStart) / sizeof(*I);
+ break;
+ }
+
+ assert(N && "No error node found in the trimmed graph.");
+
+ // Create a new (third!) graph with a single path. This is the graph
+ // that will be returned to the caller.
+ ExplodedGraph<GRState> *GNew =
+ new ExplodedGraph<GRState>(GTrim->getCFG(), GTrim->getCodeDecl(),
+ GTrim->getContext());
+
+ // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS
+ // to the root node, and then construct a new graph that contains only
+ // a single path.
+ llvm::DenseMap<const void*,unsigned> Visited;
+ std::queue<const ExplodedNode<GRState>*> WS;
+ WS.push(N);
+
+ unsigned cnt = 0;
+ const ExplodedNode<GRState>* Root = 0;
+
+ while (!WS.empty()) {
+ const ExplodedNode<GRState>* Node = WS.front();
+ WS.pop();
+
+ if (Visited.find(Node) != Visited.end())
+ continue;
+
+ Visited[Node] = cnt++;
+
+ if (Node->pred_empty()) {
+ Root = Node;
+ break;
+ }
+
+ for (ExplodedNode<GRState>::const_pred_iterator I=Node->pred_begin(),
+ E=Node->pred_end(); I!=E; ++I)
+ WS.push(*I);
+ }
+
+ assert (Root);
+
+ // Now walk from the root down the BFS path, always taking the successor
+ // with the lowest number.
+ ExplodedNode<GRState> *Last = 0, *First = 0;
+ NodeBackMap *BM = new NodeBackMap();
+
+ for ( N = Root ;;) {
+ // Lookup the number associated with the current node.
+ llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
+ assert (I != Visited.end());
+
+ // Create the equivalent node in the new graph with the same state
+ // and location.
+ ExplodedNode<GRState>* NewN =
+ GNew->getNode(N->getLocation(), N->getState());
+
+ // Store the mapping to the original node.
+ llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
+ assert(IMitr != InverseMap.end() && "No mapping to original node.");
+ (*BM)[NewN] = (const ExplodedNode<GRState>*) IMitr->second;
+
+ // Link up the new node with the previous node.
+ if (Last)
+ NewN->addPredecessor(Last);
+
+ Last = NewN;
+
+ // Are we at the final node?
+ if (I->second == 0) {
+ First = NewN;
+ break;
+ }
+
+ // Find the next successor node. We choose the node that is marked
+ // with the lowest DFS number.
+ ExplodedNode<GRState>::const_succ_iterator SI = N->succ_begin();
+ ExplodedNode<GRState>::const_succ_iterator SE = N->succ_end();
+ N = 0;
+
+ for (unsigned MinVal = 0; SI != SE; ++SI) {
+
+ I = Visited.find(*SI);
+
+ if (I == Visited.end())
+ continue;
+
+ if (!N || I->second < MinVal) {
+ N = *SI;
+ MinVal = I->second;
+ }
+ }
+
+ assert (N);
+ }
+
+ assert (First);
+ return std::make_pair(std::make_pair(GNew, BM),
+