When building PathDiagnostics for bug reports, generate a trimmed ExplodedGraph with a single path that BugReport objects can safely walk and introspect.

llvm-svn: 50194
This commit is contained in:
Ted Kremenek 2008-04-23 23:02:12 +00:00
parent 8bfd6de8db
commit f26bc55b9a
2 changed files with 56 additions and 19 deletions

View File

@ -167,6 +167,10 @@ public:
Profile(ID, getLocation(), getState()); Profile(ID, getLocation(), getState());
} }
void addPredecessor(ExplodedNode* V) {
ExplodedNodeImpl::addPredecessor(V);
}
// Iterators over successor and predecessor vertices. // Iterators over successor and predecessor vertices.
typedef ExplodedNode** succ_iterator; typedef ExplodedNode** succ_iterator;
typedef const ExplodedNode** const_succ_iterator; typedef const ExplodedNode** const_succ_iterator;
@ -270,7 +274,8 @@ public:
llvm::BumpPtrAllocator& getAllocator() { return Allocator; } llvm::BumpPtrAllocator& getAllocator() { return Allocator; }
CFG& getCFG() { return cfg; } CFG& getCFG() { return cfg; }
ASTContext& getContext() { return Ctx; } ASTContext& getContext() { return Ctx; }
Decl& getCodeDecl() { return CodeDecl; }
const Decl& getCodeDecl() const { return CodeDecl; } const Decl& getCodeDecl() const { return CodeDecl; }
const FunctionDecl* getFunctionDecl() const { const FunctionDecl* getFunctionDecl() const {

View File

@ -139,35 +139,66 @@ PathDiagnosticPiece* BugReport::VisitNode(ExplodedNode<ValueState>* N,
return NULL; return NULL;
} }
void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, static std::pair<ExplodedGraph<ValueState>*, ExplodedNode<ValueState>*>
BugReport& R) { MakeReportGraph(ExplodedGraph<ValueState>* G, ExplodedNode<ValueState>* N) {
ExplodedNode<ValueState>* N = R.getEndNode();
if (!N)
return;
llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(getGraph().Trim(&N, &N+1)); llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(G->Trim(&N, &N+1));
// Find the sink in the trimmed graph. // Find the sink node in the trimmed graph.
// FIXME: Should we eventually have a sink iterator?
ExplodedNode<ValueState>* NewN = 0; N = NULL;
for (ExplodedGraph<ValueState>::node_iterator for (ExplodedGraph<ValueState>::node_iterator
I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) { I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {
if (I->isSink()) { if (I->isSink()) {
NewN = &*I; N = &*I;
break; break;
} }
} }
assert (NewN); assert(N);
assert (NewN->getLocation() == N->getLocation());
N = NewN;
// Create a new graph with a single path.
G = new ExplodedGraph<ValueState>(GTrim->getCFG(), GTrim->getCodeDecl(),
GTrim->getContext());
ExplodedNode<ValueState>* Last = 0;
while (N) {
ExplodedNode<ValueState>* NewN =
G->getNode(N->getLocation(), N->getState());
if (Last) Last->addPredecessor(NewN);
Last = NewN;
N = N->pred_empty() ? 0 : *(N->pred_begin());
}
return std::make_pair(G, Last);
}
void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
BugReport& R) {
ExplodedNode<ValueState>* N = R.getEndNode();
if (!N) return;
// Construct a new graph that contains only a single path from the error
// node to a root.
const std::pair<ExplodedGraph<ValueState>*,ExplodedNode<ValueState>*>
GPair = MakeReportGraph(&getGraph(), N);
llvm::OwningPtr<ExplodedGraph<ValueState> > ReportGraph(GPair.first);
assert(GPair.second->getLocation() == N->getLocation());
N = GPair.second;
// Start building the path diagnostic...
if (PathDiagnosticPiece* Piece = R.getEndPath(*this, N)) if (PathDiagnosticPiece* Piece = R.getEndPath(*this, N))
PD.push_back(Piece); PD.push_back(Piece);
else else
@ -350,7 +381,8 @@ void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
} }
} }
else else
if (PathDiagnosticPiece* piece = R.VisitNode(N, NextNode, *GTrim, *this)) if (PathDiagnosticPiece* piece = R.VisitNode(N, NextNode,
*ReportGraph, *this))
PD.push_front(piece); PD.push_front(piece);
} }
} }