[analyze] Convert EndOfPath callback to use CheckerContext

Get rid of the EndOfPathBuilder completely.
Use the generic NodeBuilder to generate nodes.
Enqueue the end of path frontier explicitly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142943 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 2607db8..e975dd5 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -58,7 +58,7 @@
   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
   void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
-  void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+  void checkEndPath(CheckerContext &Ctx) const;
 
 private:
   typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
@@ -557,9 +557,8 @@
 }
 
 // TODO: Remove this after we ensure that checkDeadSymbols are always called.
-void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
-                                           ExprEngine &Eng) const {
-  const ProgramState *state = B.getState();
+void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &Ctx) const {
+  const ProgramState *state = Ctx.getState();
   AllocatedSetTy AS = state->get<AllocatedData>();
   if (AS.isEmpty())
     return;
@@ -575,7 +574,7 @@
     // allocation, do not report.
     if (state->getSymVal(I.getKey()) ||
         definitelyReturnedError(I->second.Region, state,
-                                Eng.getSValBuilder())) {
+                                Ctx.getSValBuilder())) {
       continue;
     }
     Errors.push_back(std::make_pair(I->first, &I->second));
@@ -585,15 +584,14 @@
   if (!Changed)
     return;
 
-  ExplodedNode *N = B.generateNode(state);
+  ExplodedNode *N = Ctx.generateNode(state);
   if (!N)
     return;
 
   // Generate the error reports.
   for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
                                                        I != E; ++I) {
-    Eng.getBugReporter().EmitReport(
-      generateAllocatedDataNotReleasedReport(*I, N));
+    Ctx.EmitReport(generateAllocatedDataNotReleasedReport(*I, N));
   }
 }
 
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 5631802..a04f024 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -78,7 +78,7 @@
 
   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
-  void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+  void checkEndPath(CheckerContext &C) const;
   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
   const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
                             bool Assumption) const;
@@ -604,21 +604,20 @@
   }
 }
 
-void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
-                                 ExprEngine &Eng) const {
-  const ProgramState *state = B.getState();
+void MallocChecker::checkEndPath(CheckerContext &Ctx) const {
+  const ProgramState *state = Ctx.getState();
   RegionStateTy M = state->get<RegionState>();
 
   for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
     RefState RS = I->second;
     if (RS.isAllocated()) {
-      ExplodedNode *N = B.generateNode(state);
+      ExplodedNode *N = Ctx.generateNode(state);
       if (N) {
         if (!BT_Leak)
           BT_Leak.reset(new BuiltinBug("Memory leak",
                     "Allocated memory never released. Potential memory leak."));
         BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
-        Eng.getBugReporter().EmitReport(R);
+        Ctx.EmitReport(R);
       }
     }
   }
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index fcf0af9..c7d108b 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -47,24 +47,13 @@
   EndOfFunctionNodeBuilder *ENB;
 public:
   GenericNodeBuilderRefCount(CheckerContext &c,
-                             const ProgramPointTag *t)
+                             const ProgramPointTag *t = 0)
   : C(&c), tag(t), ENB(0) {}
 
-  GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb)
-  : C(0), tag(0), ENB(&enb) {}
-
   ExplodedNode *MakeNode(const ProgramState *state, ExplodedNode *Pred,
                          bool MarkAsSink = false) {
-    if (C) {
-        return C->generateNode(state, Pred, tag, false, MarkAsSink);
-    }
-
-    assert(ENB);
-    ExplodedNode *N = ENB->generateNode(state, Pred);
-    if (MarkAsSink) 
-      N->markAsSink();
-    
-    return N;
+    assert(C);
+    return C->generateNode(state, Pred, tag, false, MarkAsSink);
   }
 };
 } // end anonymous namespace
@@ -2445,7 +2434,7 @@
                                 SymbolRef Sym, const ProgramState *state) const;
                                               
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
-  void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const;
+  void checkEndPath(CheckerContext &C) const;
 
   const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym,
                                    RefVal V, ArgEffect E, RefVal::Kind &hasErr,
@@ -3439,12 +3428,12 @@
   return N;
 }
 
-void RetainCountChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder,
-                                      ExprEngine &Eng) const {
-  const ProgramState *state = Builder.getState();
-  GenericNodeBuilderRefCount Bd(Builder);
+void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
+  const ProgramState *state = Ctx.getState();
+  GenericNodeBuilderRefCount Bd(Ctx);
   RefBindings B = state->get<RefBindings>();
-  ExplodedNode *Pred = Builder.getPredecessor();
+  ExplodedNode *Pred = Ctx.getPredecessor();
+  ExprEngine &Eng = Ctx.getEngine();
 
   for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
     llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng,
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 91c4b96..fed9c20 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -31,7 +31,7 @@
 
 public:
   void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
-  void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+  void checkEndPath(CheckerContext &Ctx) const;
 private:
   void EmitStackError(CheckerContext &C, const MemRegion *R,
                       const Expr *RetE) const;
@@ -136,22 +136,22 @@
   }
 }
 
-void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
-                                        ExprEngine &Eng) const {
-
-  const ProgramState *state = B.getState();
+void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
+  const ProgramState *state = Ctx.getState();
 
   // Iterate over all bindings to global variables and see if it contains
   // a memory region in the stack space.
   class CallBack : public StoreManager::BindingsHandler {
   private:
-    ExprEngine &Eng;
+    CheckerContext &Ctx;
     const StackFrameContext *CurSFC;
   public:
     SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
 
-    CallBack(ExprEngine &Eng, const LocationContext *LCtx)
-      : Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
+    CallBack(CheckerContext &CC) :
+      Ctx(CC),
+      CurSFC(CC.getPredecessor()->getLocationContext()->getCurrentStackFrame())
+    {}
     
     bool HandleBinding(StoreManager &SMgr, Store store,
                        const MemRegion *region, SVal val) {
@@ -165,7 +165,7 @@
         
       // Under automated retain release, it is okay to assign a block
       // directly to a global variable.
-      if (Eng.getContext().getLangOptions().ObjCAutoRefCount &&
+      if (Ctx.getASTContext().getLangOptions().ObjCAutoRefCount &&
           isa<BlockDataRegion>(vR))
         return true;
 
@@ -181,14 +181,14 @@
     }
   };
     
-  CallBack cb(Eng, B.getPredecessor()->getLocationContext());
+  CallBack cb(Ctx);
   state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
 
   if (cb.V.empty())
     return;
 
   // Generate an error node.
-  ExplodedNode *N = B.generateNode(state);
+  ExplodedNode *N = Ctx.generateNode(state);
   if (!N)
     return;
 
@@ -204,7 +204,7 @@
     llvm::SmallString<512> buf;
     llvm::raw_svector_ostream os(buf);
     SourceRange range = GenName(os, cb.V[i].second,
-                                Eng.getContext().getSourceManager());
+                                Ctx.getSourceManager());
     os << " is still referred to by the global variable '";
     const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
     os << *VR->getDecl()
@@ -213,7 +213,7 @@
     if (range.isValid())
       report->addRange(range);
 
-    Eng.getBugReporter().EmitReport(report);
+    Ctx.EmitReport(report);
   }
 }
 
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 1d14e9e..8010e8d 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -75,7 +75,7 @@
 
   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
-  void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
+  void checkEndPath(CheckerContext &Ctx) const;
   void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
 
 private:
@@ -418,23 +418,22 @@
   }
 }
 
-void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
-                                 ExprEngine &Eng) const {
-  const ProgramState *state = B.getState();
+void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
+  const ProgramState *state = Ctx.getState();
   typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
   SymMap M = state->get<StreamState>();
   
   for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
     StreamState SS = I->second;
     if (SS.isOpened()) {
-      ExplodedNode *N = B.generateNode(state);
+      ExplodedNode *N = Ctx.generateNode(state);
       if (N) {
         if (!BT_ResourceLeak)
           BT_ResourceLeak.reset(new BuiltinBug("Resource Leak", 
                          "Opened File never closed. Potential Resource leak."));
         BugReport *R = new BugReport(*BT_ResourceLeak, 
                                      BT_ResourceLeak->getDescription(), N);
-        Eng.getBugReporter().EmitReport(R);
+        Ctx.EmitReport(R);
       }
     }
   }
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index b24f9a0..67fe4d6 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -298,12 +298,25 @@
 }
 
 /// \brief Run checkers for end of path.
-void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B,
+// Note, We do not chain the checker output (like in expandGraphWithCheckers)
+// for this callback since end of path nodes are expected to be final.
+void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
+                                           ExplodedNodeSet &Dst,
                                            ExprEngine &Eng) {
+  ExplodedNode *Pred = BC.Pred;
+  
+  // We define the builder outside of the loop bacause if at least one checkers
+  // creates a sucsessor for Pred, we do not need to generate an 
+  // autotransition for it.
+  NodeBuilder Bldr(Pred, Dst, BC);
   for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
-    CheckEndPathFunc fn = EndPathCheckers[i];
-    EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker);
-    fn(specialB, Eng);
+    CheckEndPathFunc checkFn = EndPathCheckers[i];
+
+    const ProgramPoint &L = BlockEntrance(BC.Block,
+                                          Pred->getLocationContext(),
+                                          checkFn.Checker);
+    CheckerContext C(Bldr, Eng, Pred, L, 0);
+    checkFn(C);
   }
 }
 
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 6a14815..6b8c7df 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -269,8 +269,8 @@
             && "EXIT block cannot contain Stmts.");
 
     // Process the final state transition.
-    EndOfFunctionNodeBuilder Builder(Blk, Pred, this);
-    SubEng.processEndOfFunction(Builder);
+    NodeBuilderContext BuilderCtx(*this, Blk, Pred);
+    SubEng.processEndOfFunction(BuilderCtx);
 
     // This path is done. Don't enqueue any more nodes.
     return;
@@ -597,57 +597,6 @@
   return NULL;
 }
 
-EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
-  // Auto-generate an EOP node if one has not been generated.
-  if (!hasGeneratedNode) {
-    // If we are in an inlined call, generate CallExit node.
-    if (Pred->getLocationContext()->getParent())
-      GenerateCallExitNode(Pred->State);
-    else
-      generateNode(Pred->State);
-  }
-}
-
-ExplodedNode*
-EndOfFunctionNodeBuilder::generateNode(const ProgramState *State,
-                                       ExplodedNode *P,
-                                       const ProgramPointTag *tag) {
-  hasGeneratedNode = true;
-  bool IsNew;
-
-  ExplodedNode *Node = Eng.G->getNode(BlockEntrance(&B,
-                               Pred->getLocationContext(), tag ? tag : Tag),
-                               State, &IsNew);
-
-  Node->addPredecessor(P ? P : Pred, *Eng.G);
-
-  if (IsNew) {
-    Eng.G->addEndOfPath(Node);
-    return Node;
-  }
-
-  return NULL;
-}
-
-void EndOfFunctionNodeBuilder::GenerateCallExitNode(const ProgramState *state) {
-  hasGeneratedNode = true;
-  // Create a CallExit node and enqueue it.
-  const StackFrameContext *LocCtx
-                         = cast<StackFrameContext>(Pred->getLocationContext());
-  const Stmt *CE = LocCtx->getCallSite();
-
-  // Use the the callee location context.
-  CallExit Loc(CE, LocCtx);
-
-  bool isNew;
-  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
-  Node->addPredecessor(Pred, *Eng.G);
-
-  if (isNew)
-    Eng.WList->enqueue(Node);
-}
-                                                
-
 void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
   // Check if the callee is in the same translation unit.
   if (CalleeCtx->getTranslationUnit() != 
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 13550c7..3e5a31c 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1153,11 +1153,42 @@
     builder.generateNode(I, state);
 }
 
+// TODO: The next two functions should be moved into CoreEngine.
+void ExprEngine::GenerateCallExitNode(ExplodedNode *N) {
+  // Create a CallExit node and enqueue it.
+  const StackFrameContext *LocCtx
+                         = cast<StackFrameContext>(N->getLocationContext());
+  const Stmt *CE = LocCtx->getCallSite();
+
+  // Use the the callee location context.
+  CallExit Loc(CE, LocCtx);
+
+  bool isNew;
+  ExplodedNode *Node = Engine.G->getNode(Loc, N->getState(), &isNew);
+  Node->addPredecessor(N, *Engine.G);
+
+  if (isNew)
+    Engine.WList->enqueue(Node);
+}
+
+void ExprEngine::enqueueEndOfPath(ExplodedNodeSet &S) {
+  for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I) {
+    ExplodedNode *N = *I;
+    // If we are in an inlined call, generate CallExit node.
+    if (N->getLocationContext()->getParent())
+      GenerateCallExitNode(N);
+    else
+      Engine.G->addEndOfPath(N);
+  }
+}
+
 /// ProcessEndPath - Called by CoreEngine.  Used to generate end-of-path
 ///  nodes when the control reaches the end of a function.
-void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
-  StateMgr.EndPath(builder.getState());
-  getCheckerManager().runCheckersForEndPath(builder, *this);
+void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) {
+  StateMgr.EndPath(BC.Pred->getState());
+  ExplodedNodeSet Dst;
+  getCheckerManager().runCheckersForEndPath(BC, Dst, *this);
+  enqueueEndOfPath(Dst);
 }
 
 /// ProcessSwitch - Called by CoreEngine.  Used to generate successor