Restore Zhongxing's commits r97122 r97127 r97129 r97131 which were reverted due to a Clang-on-Clang failure

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97162 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/CallInliner.cpp b/lib/Checker/CallInliner.cpp
index 0279d46..659d9b8 100644
--- a/lib/Checker/CallInliner.cpp
+++ b/lib/Checker/CallInliner.cpp
@@ -26,7 +26,6 @@
   }
 
   virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE);
-  virtual void EvalEndPath(GREndPathNodeBuilder &B,void *tag,GRExprEngine &Eng);
 };
 }
 
@@ -46,79 +45,10 @@
   if (!FD->isThisDeclarationADefinition())
     return false;
 
-  GRStmtNodeBuilder &Builder = C.getNodeBuilder();
-  // Make a new LocationContext.
-  const StackFrameContext *LocCtx = C.getAnalysisManager().getStackFrame(FD, 
-                                   C.getPredecessor()->getLocationContext(), CE,
-                                   Builder.getBlock(), Builder.getIndex());
-
-  CFGBlock const *Entry = &(LocCtx->getCFG()->getEntry());
-
-  assert (Entry->empty() && "Entry block must be empty.");
-
-  assert (Entry->succ_size() == 1 && "Entry block must have 1 successor.");
-
-  // Get the solitary successor.
-  CFGBlock const *SuccB = *(Entry->succ_begin());
-
-  // Construct an edge representing the starting location in the function.
-  BlockEdge Loc(Entry, SuccB, LocCtx);
-
-  state = C.getStoreManager().EnterStackFrame(state, LocCtx);
-
-  // This is a hack. We really should not use the GRStmtNodeBuilder.
-  bool isNew;
-  GRExprEngine &Eng = C.getEngine();
-  ExplodedNode *Pred = C.getPredecessor();
-  
-
-  ExplodedNode *SuccN = Eng.getGraph().getNode(Loc, state, &isNew);
-  SuccN->addPredecessor(Pred, Eng.getGraph());
-  C.getNodeBuilder().Deferred.erase(Pred);
-  
-  if (isNew)
-    Builder.getWorkList()->Enqueue(SuccN);
-
-  Builder.HasGeneratedNode = true;
+  // Now we have the definition of the callee, create a CallEnter node.
+  CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext());
+  C.addTransition(state, Loc);
 
   return true;
 }
 
-void CallInliner::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
-                              GRExprEngine &Eng) {
-  const GRState *state = B.getState();
-
-  ExplodedNode *Pred = B.getPredecessor();
-
-  const StackFrameContext *LocCtx = 
-                         cast<StackFrameContext>(Pred->getLocationContext());
-  // Check if this is the top level stack frame.
-  if (!LocCtx->getParent())
-    return;
-
-  const StackFrameContext *ParentSF = 
-                                   cast<StackFrameContext>(LocCtx->getParent());
-
-  SymbolReaper SymReaper(*ParentSF->getLiveVariables(), Eng.getSymbolManager(), 
-                         ParentSF);
-  const Stmt *CE = LocCtx->getCallSite();
-
-  state = Eng.getStateManager().RemoveDeadBindings(state, const_cast<Stmt*>(CE),
-                                                   SymReaper);
-
-
-  PostStmt NodeLoc(CE, LocCtx->getParent());
-
-  bool isNew;
-  ExplodedNode *Succ = Eng.getGraph().getNode(NodeLoc, state, &isNew);
-  Succ->addPredecessor(Pred, Eng.getGraph());
-
-  // When creating the new work list unit, increment the statement index to
-  // point to the statement after the CallExpr.
-  if (isNew)
-    B.getWorkList().Enqueue(Succ, 
-                            *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
-                            LocCtx->getIndex() + 1);
-
-  B.HasGeneratedNode = true;
-}
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index d54b077..cc8abc8 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -144,6 +144,14 @@
   SubEngine.ProcessSwitch(Builder);
 }
 
+void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) {
+  SubEngine.ProcessCallEnter(Builder);
+}
+
+void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) {
+  SubEngine.ProcessCallExit(Builder);
+}
+
 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
 bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) {
 
@@ -196,6 +204,15 @@
         assert (false && "BlockExit location never occur in forward analysis.");
         break;
 
+      case ProgramPoint::CallEnterKind:
+        HandleCallEnter(cast<CallEnter>(Node->getLocation()), WU.getBlock(), 
+                        WU.getIndex(), Node);
+        break;
+
+      case ProgramPoint::CallExitKind:
+        HandleCallExit(cast<CallExit>(Node->getLocation()), Node);
+        break;
+
       default:
         assert(isa<PostStmt>(Node->getLocation()));
         HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
@@ -207,6 +224,17 @@
   return WList->hasWork();
 }
 
+void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
+                                   unsigned Index, ExplodedNode *Pred) {
+  GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), 
+                                 Block, Index);
+  ProcessCallEnter(Builder);
+}
+
+void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) {
+  GRCallExitNodeBuilder Builder(*this, Pred);
+  ProcessCallExit(Builder);
+}
 
 void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) {
 
@@ -400,6 +428,14 @@
 void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
   assert (!N->isSink());
 
+  // Check if this node entered a callee.
+  if (isa<CallEnter>(N->getLocation())) {
+    // Still use the index of the CallExpr. It's needed to create the callee
+    // StackFrameContext.
+    Eng.WList->Enqueue(N, B, Idx);
+    return;
+  }
+
   PostStmt Loc(getStmt(), N->getLocationContext());
 
   if (Loc == N->getLocation()) {
@@ -576,7 +612,13 @@
 
 GREndPathNodeBuilder::~GREndPathNodeBuilder() {
   // Auto-generate an EOP node if one has not been generated.
-  if (!HasGeneratedNode) generateNode(Pred->State);
+  if (!HasGeneratedNode) {
+    // If we are in an inlined call, generate CallExit node.
+    if (Pred->getLocationContext()->getParent())
+      GenerateCallExitNode(Pred->State);
+    else
+      generateNode(Pred->State);
+  }
 }
 
 ExplodedNode*
@@ -597,3 +639,57 @@
 
   return NULL;
 }
+
+void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *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 GRCallEnterNodeBuilder::GenerateNode(const GRState *state,
+                                          const LocationContext *LocCtx) {
+  // Get the callee entry block.
+  const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry());
+  assert(Entry->empty());
+  assert(Entry->succ_size() == 1);
+
+  // Get the solitary successor.
+  const CFGBlock *SuccB = *(Entry->succ_begin());
+
+  // Construct an edge representing the starting location in the callee.
+  BlockEdge Loc(Entry, SuccB, LocCtx);
+
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+
+  if (isNew)
+    Eng.WList->Enqueue(Node);
+}
+
+void GRCallExitNodeBuilder::GenerateNode(const GRState *state) {
+  // Get the callee's location context.
+  const StackFrameContext *LocCtx 
+                         = cast<StackFrameContext>(Pred->getLocationContext());
+
+  PostStmt Loc(LocCtx->getCallSite(), LocCtx->getParent());
+  bool isNew;
+  ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
+  Node->addPredecessor(const_cast<ExplodedNode*>(Pred), *Eng.G);
+  if (isNew)
+    Eng.WList->Enqueue(Node, *const_cast<CFGBlock*>(LocCtx->getCallSiteBlock()),
+                       LocCtx->getIndex() + 1);
+}
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index 7689a35..30b82f7 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -1290,6 +1290,38 @@
   if (defaultIsFeasible) builder.generateDefaultCaseNode(DefaultSt);
 }
 
+void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) {
+  const FunctionDecl *FD = B.getCallee();
+  const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, 
+                                                       B.getLocationContext(),
+                                                       B.getCallExpr(),
+                                                       B.getBlock(),
+                                                       B.getIndex());
+
+  const GRState *state = B.getState();
+  state = getStoreManager().EnterStackFrame(state, LocCtx);
+
+  B.GenerateNode(state, LocCtx);
+}
+
+void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) {
+  const GRState *state = B.getState();
+  const ExplodedNode *Pred = B.getPredecessor();
+  const StackFrameContext *LocCtx = 
+                            cast<StackFrameContext>(Pred->getLocationContext());
+  const StackFrameContext *ParentSF = 
+                            cast<StackFrameContext>(LocCtx->getParent());
+
+  SymbolReaper SymReaper(*ParentSF->getLiveVariables(), getSymbolManager(),
+                         ParentSF);
+  const Stmt *CE = LocCtx->getCallSite();
+
+  state = getStateManager().RemoveDeadBindings(state, const_cast<Stmt*>(CE),
+                                               SymReaper);
+  
+  B.GenerateNode(state);
+}
+
 //===----------------------------------------------------------------------===//
 // Transfer functions: logical operations ('&&', '||').
 //===----------------------------------------------------------------------===//
@@ -3141,6 +3173,14 @@
         assert (false);
         break;
 
+      case ProgramPoint::CallEnterKind:
+        Out << "CallEnter";
+        break;
+
+      case ProgramPoint::CallExitKind:
+        Out << "CallExit";
+        break;
+
       default: {
         if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
           const Stmt* S = L->getStmt();