[cfe-commits] r68157 - /cfe/trunk/lib/Analysis/BugReporter.cpp

Ted Kremenek kremenek at apple.com
Tue Mar 31 16:00:33 PDT 2009


Author: kremenek
Date: Tue Mar 31 18:00:32 2009
New Revision: 68157

URL: http://llvm.org/viewvc/llvm-project?rev=68157&view=rev
Log:
More code reshuffling.  No functionality change.

Modified:
    cfe/trunk/lib/Analysis/BugReporter.cpp

Modified: cfe/trunk/lib/Analysis/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BugReporter.cpp?rev=68157&r1=68156&r2=68157&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/BugReporter.cpp (original)
+++ cfe/trunk/lib/Analysis/BugReporter.cpp Tue Mar 31 18:00:32 2009
@@ -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 @@
 }
 
 //===----------------------------------------------------------------------===//
-// Diagnostics for 'execution continues on line XXX'.
+// PathDiagnosticBuilder and its associated routines and helper objects.
 //===----------------------------------------------------------------------===//
 
 typedef llvm::DenseMap<const ExplodedNode<GRState>*,
@@ -252,601 +252,192 @@
 }
 
 //===----------------------------------------------------------------------===//
-// Methods for BugType and subclasses.
-//===----------------------------------------------------------------------===//
-BugType::~BugType() {}
-void BugType::FlushReports(BugReporter &BR) {}
-
-//===----------------------------------------------------------------------===//
-// Methods for BugReport and subclasses.
+// ScanNotableSymbols: closure-like callback for scanning Store bindings.
 //===----------------------------------------------------------------------===//
-BugReport::~BugReport() {}
-RangedBugReport::~RangedBugReport() {}
 
-Stmt* BugReport::getStmt(BugReporter& BR) const {  
-  ProgramPoint ProgP = EndNode->getLocation();  
-  Stmt *S = NULL;
+static const VarDecl*
+GetMostRecentVarDeclBinding(const ExplodedNode<GRState>* N,
+                            GRStateManager& VMgr, SVal X) {
   
-  if (BlockEntrance* BE = dyn_cast<BlockEntrance>(&ProgP)) {
-    if (BE->getBlock() == &BR.getCFG()->getExit()) S = GetPreviousStmt(EndNode);
+  for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
+    
+    ProgramPoint P = N->getLocation();
+    
+    if (!isa<PostStmt>(P))
+      continue;
+    
+    DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
+    
+    if (!DR)
+      continue;
+    
+    SVal Y = VMgr.GetSVal(N->getState(), DR);
+    
+    if (X != Y)
+      continue;
+    
+    VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
+    
+    if (!VD)
+      continue;
+    
+    return VD;
   }
-  if (!S) S = GetStmt(ProgP);  
   
-  return S;  
+  return 0;
 }
 
-PathDiagnosticPiece*
-BugReport::getEndPath(BugReporter& BR,
-                      const ExplodedNode<GRState>* EndPathNode) {
+namespace {
+class VISIBILITY_HIDDEN NotableSymbolHandler 
+: public StoreManager::BindingsHandler {
   
-  Stmt* S = getStmt(BR);
+  SymbolRef Sym;
+  const GRState* PrevSt;
+  const Stmt* S;
+  GRStateManager& VMgr;
+  const ExplodedNode<GRState>* Pred;
+  PathDiagnostic& PD; 
+  BugReporter& BR;
   
-  if (!S)
-    return NULL;
+public:
   
-  FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
-  PathDiagnosticPiece* P = new PathDiagnosticEventPiece(L, getDescription());
+  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) {}
   
-  const SourceRange *Beg, *End;
-  getRanges(BR, Beg, End);  
+  bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
+                     SVal V) {
+    
+    SymbolRef ScanSym = V.getAsSymbol();
+    
+    if (ScanSym != Sym)
+      return true;
+    
+    // Check if the previous state has this binding.    
+    SVal X = VMgr.GetSVal(PrevSt, loc::MemRegionVal(R));
+    
+    if (X == V) // Same binding?
+      return true;
+    
+    // Different binding.  Only handle assignments for now.  We don't pull
+    // this check out of the loop because we will eventually handle other 
+    // cases.
+    
+    VarDecl *VD = 0;
+    
+    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
+      if (!B->isAssignmentOp())
+        return true;
+      
+      // What variable did we assign to?
+      DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
+      
+      if (!DR)
+        return true;
+      
+      VD = dyn_cast<VarDecl>(DR->getDecl());
+    }
+    else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
+      // FIXME: Eventually CFGs won't have DeclStmts.  Right now we
+      //  assume that each DeclStmt has a single Decl.  This invariant
+      //  holds by contruction in the CFG.
+      VD = dyn_cast<VarDecl>(*DS->decl_begin());
+    }
+    
+    if (!VD)
+      return true;
+    
+    // What is the most recently referenced variable with this binding?
+    const VarDecl* MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
+    
+    if (!MostRecent)
+      return true;
+    
+    // Create the diagnostic.
+    FullSourceLoc L(S->getLocStart(), BR.getSourceManager());
+    
+    if (Loc::IsLocType(VD->getType())) {
+      std::string msg = "'" + std::string(VD->getNameAsString()) +
+      "' now aliases '" + MostRecent->getNameAsString() + "'";
+      
+      PD.push_front(new PathDiagnosticEventPiece(L, msg));
+    }
+    
+    return true;
+  }  
+};
+}
+
+static void HandleNotableSymbol(const ExplodedNode<GRState>* N,
+                                const Stmt* S,
+                                SymbolRef Sym, BugReporter& BR,
+                                PathDiagnostic& PD) {
   
-  for (; Beg != End; ++Beg)
-    P->addRange(*Beg);
+  const ExplodedNode<GRState>* Pred = N->pred_empty() ? 0 : *N->pred_begin();
+  const GRState* PrevSt = Pred ? Pred->getState() : 0;
   
-  return P;
+  if (!PrevSt)
+    return;
+  
+  // Look at the region bindings of the current state that map to the
+  // specified symbol.  Are any of them not in the previous state?
+  GRStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
+  NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
+  cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
 }
 
-void BugReport::getRanges(BugReporter& BR, const SourceRange*& beg,
-                          const SourceRange*& end) {  
+namespace {
+class VISIBILITY_HIDDEN ScanNotableSymbols
+: public StoreManager::BindingsHandler {
   
-  if (Expr* E = dyn_cast_or_null<Expr>(getStmt(BR))) {
-    R = E->getSourceRange();
-    assert(R.isValid());
-    beg = &R;
-    end = beg+1;
+  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) {}
+  
+  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;
   }
-  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;
-}
+};
+} // end anonymous namespace
 
 //===----------------------------------------------------------------------===//
-// Methods for BugReporter and subclasses.
+// "Minimal" path diagnostic generation algorithm.
 //===----------------------------------------------------------------------===//
 
-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),
-                        std::make_pair(First, NodeIndex));
-}
-
-static const VarDecl*
-GetMostRecentVarDeclBinding(const ExplodedNode<GRState>* N,
-                            GRStateManager& VMgr, SVal X) {
-  
-  for ( ; N ; N = N->pred_empty() ? 0 : *N->pred_begin()) {
-    
-    ProgramPoint P = N->getLocation();
-    
-    if (!isa<PostStmt>(P))
-      continue;
-    
-    DeclRefExpr* DR = dyn_cast<DeclRefExpr>(cast<PostStmt>(P).getStmt());
-    
-    if (!DR)
-      continue;
-    
-    SVal Y = VMgr.GetSVal(N->getState(), DR);
-    
-    if (X != Y)
-      continue;
-    
-    VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl());
-    
-    if (!VD)
-      continue;
-    
-    return VD;
-  }
-  
-  return 0;
-}
-
-namespace {
-class VISIBILITY_HIDDEN NotableSymbolHandler 
-  : public StoreManager::BindingsHandler {
-    
-  SymbolRef Sym;
-  const GRState* PrevSt;
-  const Stmt* S;
-  GRStateManager& VMgr;
-  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) {}
-                        
-  bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
-                     SVal V) {
-
-    SymbolRef ScanSym = V.getAsSymbol();
-
-    if (ScanSym != Sym)
-      return true;
-    
-    // Check if the previous state has this binding.    
-    SVal X = VMgr.GetSVal(PrevSt, loc::MemRegionVal(R));
-    
-    if (X == V) // Same binding?
-      return true;
-    
-    // Different binding.  Only handle assignments for now.  We don't pull
-    // this check out of the loop because we will eventually handle other 
-    // cases.
-    
-    VarDecl *VD = 0;
-    
-    if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
-      if (!B->isAssignmentOp())
-        return true;
-      
-      // What variable did we assign to?
-      DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenCasts());
-      
-      if (!DR)
-        return true;
-      
-      VD = dyn_cast<VarDecl>(DR->getDecl());
-    }
-    else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
-      // FIXME: Eventually CFGs won't have DeclStmts.  Right now we
-      //  assume that each DeclStmt has a single Decl.  This invariant
-      //  holds by contruction in the CFG.
-      VD = dyn_cast<VarDecl>(*DS->decl_begin());
-    }
-    
-    if (!VD)
-      return true;
-    
-    // What is the most recently referenced variable with this binding?
-    const VarDecl* MostRecent = GetMostRecentVarDeclBinding(Pred, VMgr, V);
-    
-    if (!MostRecent)
-      return true;
-    
-    // Create the diagnostic.
-    FullSourceLoc L(S->getLocStart(), BR.getSourceManager());
-    
-    if (Loc::IsLocType(VD->getType())) {
-      std::string msg = "'" + std::string(VD->getNameAsString()) +
-      "' now aliases '" + MostRecent->getNameAsString() + "'";
-      
-      PD.push_front(new PathDiagnosticEventPiece(L, msg));
-    }
-    
-    return true;
-  }  
-};
-}
-
-static void HandleNotableSymbol(const ExplodedNode<GRState>* N,
-                                const Stmt* S,
-                                SymbolRef Sym, BugReporter& BR,
-                                PathDiagnostic& PD) {
-  
-  const ExplodedNode<GRState>* Pred = N->pred_empty() ? 0 : *N->pred_begin();
-  const GRState* PrevSt = Pred ? Pred->getState() : 0;
-  
-  if (!PrevSt)
-    return;
-  
-  // Look at the region bindings of the current state that map to the
-  // specified symbol.  Are any of them not in the previous state?
-  GRStateManager& VMgr = cast<GRBugReporter>(BR).getStateManager();
-  NotableSymbolHandler H(Sym, PrevSt, S, VMgr, Pred, PD, BR);
-  cast<GRBugReporter>(BR).getStateManager().iterBindings(N->getState(), H);
-}
-
-namespace {
-class VISIBILITY_HIDDEN ScanNotableSymbols
-  : 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) {}
-  
-  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());  
-}
-
-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());
-
-  while (NextNode) {
-    N = NextNode;    
-    NextNode = GetPredecessorNode(N);
+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());
+  while (NextNode) {
+    N = NextNode;    
+    NextNode = GetPredecessorNode(N);
     
     ProgramPoint P = N->getLocation();
     
@@ -876,7 +467,7 @@
           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 @@
           // 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 @@
                   // 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 @@
                 }       
                 
                 os << ":'  at line "
-                   << End.asLocation().getInstantiationLineNumber();
+                << End.asLocation().getInstantiationLineNumber();
                 break;
               }
             }
@@ -963,13 +554,13 @@
                                                            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 @@
           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 @@
           std::string sbuf;
           llvm::raw_string_ostream os(sbuf);
           os << "Left side of '";
-
+          
           if (B->getOpcode() == BinaryOperator::LAnd) {
             os << "&&" << "' is ";
             
@@ -1032,7 +623,7 @@
                                                                os.str()));                            
             }
           }
-
+          
           break;
         }
           
@@ -1043,7 +634,7 @@
             
             os << "Loop condition is true. ";
             PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
-
+            
             if (const Stmt *S = End.asStmt())
               End = PDB.getEnclosingStmtLocation(S);
             
@@ -1055,74 +646,483 @@
             
             if (const Stmt *S = End.asStmt())
               End = PDB.getEnclosingStmtLocation(S);
+            
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                              "Loop condition is false.  Exiting loop"));
+          }
+          
+          break;
+        }
+          
+        case Stmt::WhileStmtClass:
+        case Stmt::ForStmtClass: {          
+          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()));
+          }
+          else {
+            PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+            if (const Stmt *S = End.asStmt())
+              End = PDB.getEnclosingStmtLocation(S);
+            
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                             "Loop condition is true.  Entering loop body"));
+          }
+          
+          break;
+        }
+          
+        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"));
+          else  
+            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
+                                                             "Taking true branch"));
+          
+          break;
+        }
+      }
+    }
+    
+    if (PathDiagnosticPiece* 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
+      // lval binding.
+      ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
+      PDB.getStateManager().iterBindings(N->getState(), SNS);
+    }
+  }
+}
+
+//===----------------------------------------------------------------------===//
+// 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),
+                        std::make_pair(First, NodeIndex));
+}
 
-            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                    "Loop condition is false.  Exiting loop"));
-          }
-          
-          break;
-        }
-          
-        case Stmt::WhileStmtClass:
-        case Stmt::ForStmtClass: {          
-          if (*(Src->succ_begin()+1) == Dst) {
-            std::string sbuf;
-            llvm::raw_string_ostream os(sbuf);
+/// 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;
+    }
 
-            os << "Loop condition is false. ";
-            PathDiagnosticLocation End = PDB.ExecutionContinues(os, N);
-            if (const Stmt *S = End.asStmt())
-              End = PDB.getEnclosingStmtLocation(S);
+    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;
+    }
 
-            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                             os.str()));
-          }
-          else {
-            PathDiagnosticLocation End = PDB.ExecutionContinues(N);
-            if (const Stmt *S = End.asStmt())
-              End = PDB.getEnclosingStmtLocation(S);
-            
-            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                               "Loop condition is true.  Entering loop body"));
-          }
-          
-          break;
-        }
-          
-        case Stmt::IfStmtClass: {
-          PathDiagnosticLocation End = PDB.ExecutionContinues(N);
+    // We aren't in the same group.  Are we descending into a new macro
+    // or are part of an old one?
+    PathDiagnosticMacroPiece *MacroGroup = 0;
 
-          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"));
-          else  
-            PD.push_front(new PathDiagnosticControlFlowPiece(Start, End,
-                                                       "Taking true branch"));
-          
-          break;
-        }
+    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 (PathDiagnosticPiece* p =
-          PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
-                                        PDB.getBugReporter(),
-                                        PDB.getNodeMapClosure())) {
-      PD.push_front(p);
+      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);
     
-    if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {      
-      // Scan the region bindings, and see if a "notable" symbol has a new
-      // lval binding.
-      ScanNotableSymbols SNS(N, PS->getStmt(), PDB.getBugReporter(), PD);
-      PDB.getStateManager().iterBindings(N->getState(), SNS);
-    }
+  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);
   }
 }
 
+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());  
+}
 
 void BugReporter::Register(BugType *BT) {
   BugTypes = F.Add(BugTypes, BT);





More information about the cfe-commits mailing list