Rework ExprEngine::processCFGBlockEntrance()
to use a node builder.  This paves the way
for Checkers to interpose (via a "visit" method)
at the entrance to blocks.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123217 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index 5dd5d72..e6d9d71 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -1077,11 +1077,22 @@
 // Block entrance.  (Update counters).
 //===----------------------------------------------------------------------===//
 
-bool ExprEngine::processCFGBlockEntrance(const CFGBlock* B, 
-                                        const ExplodedNode *Pred,
-                                        BlockCounter BC) {
-  return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), 
-                          B->getBlockID()) < AMgr.getMaxVisit();
+void ExprEngine::processCFGBlockEntrance(ExplodedNodeSet &dstNodes,
+                               GenericNodeBuilder<BlockEntrance> &nodeBuilder){
+  
+  // FIXME: Refactor this into a checker.
+  const CFGBlock *block = nodeBuilder.getProgramPoint().getBlock();
+  ExplodedNode *pred = nodeBuilder.getPredecessor();
+  
+  if (nodeBuilder.getBlockCounter().getNumVisited(
+                       pred->getLocationContext()->getCurrentStackFrame(), 
+                       block->getBlockID()) >= AMgr.getMaxVisit()) {
+
+    static int tag = 0;
+    const BlockEntrance &BE = nodeBuilder.getProgramPoint();
+    BlockEntrance BE_tagged(BE.getBlock(), BE.getLocationContext(), &tag);
+    nodeBuilder.generateNode(pred->getState(), pred, BE_tagged, true);
+  }
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/CoreEngine.cpp b/lib/StaticAnalyzer/CoreEngine.cpp
index d5158ad..9ccc447 100644
--- a/lib/StaticAnalyzer/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/CoreEngine.cpp
@@ -288,13 +288,29 @@
     return;
   }
 
-  // FIXME: Should we allow processCFGBlockEntrance to also manipulate state?
+  // Call into the subengine to process entering the CFGBlock.
+  ExplodedNodeSet dstNodes;
+  BlockEntrance BE(Blk, Pred->getLocationContext());
+  GenericNodeBuilder<BlockEntrance> nodeBuilder(*this, Pred, BE);
+  SubEng.processCFGBlockEntrance(dstNodes, nodeBuilder);
 
-  if (SubEng.processCFGBlockEntrance(Blk, Pred, WList->getBlockCounter()))
-    generateNode(BlockEntrance(Blk, Pred->getLocationContext()),
-                 Pred->State, Pred);
+  if (dstNodes.empty()) {
+    if (!nodeBuilder.hasGeneratedNode()) {
+      // Auto-generate a node and enqueue it to the worklist.
+      generateNode(BE, Pred->State, Pred);    
+    }
+  }
   else {
-    blocksAborted.push_back(std::make_pair(L, Pred));
+    for (ExplodedNodeSet::iterator I = dstNodes.begin(), E = dstNodes.end();
+         I != E; ++I) {
+      WList->enqueue(*I);
+    }
+  }
+
+  for (llvm::SmallVectorImpl<ExplodedNode*>::const_iterator
+       I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end();
+       I != E; ++I) {
+    blocksAborted.push_back(std::make_pair(L, *I));
   }
 }
 
@@ -446,6 +462,27 @@
   if (IsNew) WList->enqueue(Node);
 }
 
+ExplodedNode *
+GenericNodeBuilderImpl::generateNodeImpl(const GRState *state,
+                                         ExplodedNode *pred,
+                                         ProgramPoint programPoint,
+                                         bool asSink) {
+  
+  HasGeneratedNode = true;
+  bool isNew;
+  ExplodedNode *node = engine.getGraph().getNode(programPoint, state, &isNew);
+  if (pred)
+    node->addPredecessor(pred, engine.getGraph());
+  if (isNew) {
+    if (asSink) {
+      node->markAsSink();
+      sinksGenerated.push_back(node);
+    }
+    return node;
+  }
+  return 0;
+}
+
 StmtNodeBuilder::StmtNodeBuilder(const CFGBlock* b, unsigned idx,
                                      ExplodedNode* N, CoreEngine* e,
                                      GRStateManager &mgr)