Refactor BugReporter interface to have a new 'BugReporterContext' and
'BugReporterVisitor'. This simplifies callbacks from BugReporter to BugReports
(via VisitNode). It also lays the foundation for arbitrary visitor "call backs"
that can be registered to a BugReporterContext as a PathDiagnostic is
constructed. These call backs can help operate as separate "experts" that can
work on constructed pieces of a PathDiagnostic for which they possess special
knowledge.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71121 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 77a83fe..36dc6b7 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -30,6 +30,12 @@
 
 using namespace clang;
 
+BugReporterVisitor::~BugReporterVisitor() {}
+BugReporterContext::~BugReporterContext() {
+  for (visitor_iterator I = visitor_begin(), E = visitor_end(); I != E; ++I)
+    if ((*I)->isOwnedByReporterContext()) delete *I;
+}
+
 //===----------------------------------------------------------------------===//
 // Helper routines for walking the ExplodedGraph and fetching statements.
 //===----------------------------------------------------------------------===//
@@ -118,21 +124,20 @@
   }
 };
   
-class VISIBILITY_HIDDEN PathDiagnosticBuilder {
-  GRBugReporter &BR;
-  SourceManager &SMgr;
-  ExplodedGraph<GRState> *ReportGraph;
+class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext {
   BugReport *R;
-  const Decl& CodeDecl;
   PathDiagnosticClient *PDC;
   llvm::OwningPtr<ParentMap> PM;
   NodeMapClosure NMC;
 public:  
-  PathDiagnosticBuilder(GRBugReporter &br, ExplodedGraph<GRState> *reportGraph,
+  PathDiagnosticBuilder(GRBugReporter &br,
                         BugReport *r, NodeBackMap *Backmap, 
-                        const Decl& codedecl, PathDiagnosticClient *pdc)
-    : BR(br), SMgr(BR.getSourceManager()), ReportGraph(reportGraph), R(r),
-      CodeDecl(codedecl), PDC(pdc), NMC(Backmap) {}
+                        PathDiagnosticClient *pdc)
+    : BugReporterContext(br),
+      R(r), PDC(pdc), NMC(Backmap)
+  {
+    addVisitor(R);
+  }
   
   PathDiagnosticLocation ExecutionContinues(const ExplodedNode<GRState>* N);
   
@@ -140,29 +145,17 @@
                                             const ExplodedNode<GRState>* N);
   
   ParentMap& getParentMap() {
-    if (PM.get() == 0) PM.reset(new ParentMap(CodeDecl.getBody(getContext())));
+    if (PM.get() == 0)
+      PM.reset(new ParentMap(getCodeDecl().getBody(getASTContext())));
     return *PM.get();
   }
   
   const Stmt *getParent(const Stmt *S) {
     return getParentMap().getParent(S);
   }
-  
-  const CFG& getCFG() {
-    return *BR.getCFG();
-  }
-  
-  const Decl& getCodeDecl() {
-    return BR.getStateManager().getCodeDecl();
-  }
-  
-  ExplodedGraph<GRState>& getGraph() { return *ReportGraph; }
-  NodeMapClosure& getNodeMapClosure() { return NMC; }
-  ASTContext& getContext() { return BR.getContext(); }
-  SourceManager& getSourceManager() { return SMgr; }
+      
+  virtual NodeMapClosure& getNodeResolver() { return NMC; }
   BugReport& getReport() { return *R; }
-  GRBugReporter& getBugReporter() { return BR; }
-  GRStateManager& getStateManager() { return BR.getStateManager(); }
 
   PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S);
   
@@ -187,9 +180,10 @@
 PathDiagnosticLocation
 PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode<GRState>* N) {
   if (Stmt *S = GetNextStmt(N))
-    return PathDiagnosticLocation(S, SMgr);
+    return PathDiagnosticLocation(S, getSourceManager());
 
-  return FullSourceLoc(CodeDecl.getBodyRBrace(getContext()), SMgr);
+  return FullSourceLoc(getCodeDecl().getBodyRBrace(getASTContext()),
+                       getSourceManager());
 }
   
 PathDiagnosticLocation
@@ -204,10 +198,11 @@
   
   if (Loc.asStmt())
     os << "Execution continues on line "
-       << SMgr.getInstantiationLineNumber(Loc.asLocation()) << '.';
+       << getSourceManager().getInstantiationLineNumber(Loc.asLocation())
+       << '.';
   else
     os << "Execution jumps to the end of the "
-       << (isa<ObjCMethodDecl>(CodeDecl) ? "method" : "function") << '.';
+       << (isa<ObjCMethodDecl>(getCodeDecl()) ? "method" : "function") << '.';
   
   return Loc;
 }
@@ -216,6 +211,7 @@
 PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) {
   assert(S && "Null Stmt* passed to getEnclosingStmtLocation");
   ParentMap &P = getParentMap(); 
+  SourceManager &SMgr = getSourceManager();
     
   while (isa<Expr>(S) && P.isConsumedExpr(cast<Expr>(S))) {
     const Stmt *Parent = P.getParent(S);
@@ -459,7 +455,7 @@
 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());
@@ -541,7 +537,7 @@
                 }
 
                 if (GetRawInt)
-                  os << LHS->EvaluateAsInt(Ctx);
+                  os << LHS->EvaluateAsInt(PDB.getASTContext());
 
                 os << ":'  at line "
                 << End.asLocation().getInstantiationLineNumber();
@@ -714,12 +710,11 @@
       }
     }
     
-    if (PathDiagnosticPiece* p =
-        PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
-                                  PDB.getBugReporter(),
-                                  PDB.getNodeMapClosure())) {
-          PD.push_front(p);
-        }
+    for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(),
+         E = PDB.visitor_end(); I!=E; ++I) {
+      if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB))
+        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
@@ -834,7 +829,7 @@
     // statement (if it doesn't already exist).
     // FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
     if (const CompoundStmt *CS =
-          PDB.getCodeDecl().getCompoundBody(PDB.getContext()))
+          PDB.getCodeDecl().getCompoundBody(PDB.getASTContext()))
       if (!CS->body_empty()) {
         SourceLocation Loc = (*CS->body_begin())->getLocStart();
         rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager()));
@@ -1105,17 +1100,16 @@
       continue;
     }
     
-    PathDiagnosticPiece* p =
-      PDB.getReport().VisitNode(N, NextNode, PDB.getGraph(),
-                                PDB.getBugReporter(), PDB.getNodeMapClosure());
-    
-    if (p) {
-      const PathDiagnosticLocation &Loc = p->getLocation();
-      EB.addEdge(Loc, true);
-      PD.push_front(p);
-      if (const Stmt *S = Loc.asStmt())
-        EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());      
-    }
+    for (BugReporterContext::visitor_iterator I = PDB.visitor_begin(),
+         E = PDB.visitor_end(); I!=E; ++I) {
+      if (PathDiagnosticPiece* p = (*I)->VisitNode(N, NextNode, PDB)) {
+        const PathDiagnosticLocation &Loc = p->getLocation();
+        EB.addEdge(Loc, true);
+        PD.push_front(p);
+        if (const Stmt *S = Loc.asStmt())
+          EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt());      
+      }
+    }  
   }
 }
 
@@ -1144,19 +1138,19 @@
 }
 
 PathDiagnosticPiece*
-BugReport::getEndPath(BugReporter& BR,
+BugReport::getEndPath(BugReporterContext& BRC,
                       const ExplodedNode<GRState>* EndPathNode) {
   
-  Stmt* S = getStmt(BR);
+  Stmt* S = getStmt(BRC.getBugReporter());
   
   if (!S)
     return NULL;
   
-  FullSourceLoc L(S->getLocStart(), BR.getContext().getSourceManager());
+  FullSourceLoc L(S->getLocStart(), BRC.getSourceManager());
   PathDiagnosticPiece* P = new PathDiagnosticEventPiece(L, getDescription());
   
   const SourceRange *Beg, *End;
-  getRanges(BR, Beg, End);  
+  getRanges(BRC.getBugReporter(), Beg, End);
   
   for (; Beg != End; ++Beg)
     P->addRange(*Beg);
@@ -1192,9 +1186,7 @@
 
 PathDiagnosticPiece* BugReport::VisitNode(const ExplodedNode<GRState>* N,
                                           const ExplodedNode<GRState>* PrevN,
-                                          const ExplodedGraph<GRState>& G,
-                                          BugReporter& BR,
-                                          NodeResolver &NR) {
+                                          BugReporterContext &BRC) {
   return NULL;
 }
 
@@ -1203,7 +1195,7 @@
 //===----------------------------------------------------------------------===//
 
 BugReportEquivClass::~BugReportEquivClass() {
-  for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;  
+  for (iterator I=begin(), E=end(); I!=E; ++I) delete *I;
 }
 
 GRBugReporter::~GRBugReporter() { FlushReports(); }
@@ -1477,7 +1469,7 @@
 }
 
 void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
-                                          BugReportEquivClass& EQ) {
+                                           BugReportEquivClass& EQ) {
  
   std::vector<const ExplodedNode<GRState>*> Nodes;
   
@@ -1507,19 +1499,18 @@
   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))
+  // Start building the path diagnostic... 
+  PathDiagnosticBuilder PDB(*this, R, BackMap.get(), getPathDiagnosticClient());
+  
+  if (PathDiagnosticPiece* Piece = R->getEndPath(PDB, N))
     PD.push_back(Piece);
   else
     return;
 
-  PathDiagnosticBuilder PDB(*this, ReportGraph.get(), R, BackMap.get(),
-                            getStateManager().getCodeDecl(),
-                            getPathDiagnosticClient());
   
   switch (PDB.getGenerationScheme()) {
     case PathDiagnosticClient::Extensive:
-      GenerateExtensivePathDiagnostic(PD,PDB, N);
+      GenerateExtensivePathDiagnostic(PD, PDB, N);
       break;
     case PathDiagnosticClient::Minimal:
       GenerateMinimalPathDiagnostic(PD, PDB, N);