Hard bifurcate the state into nil receiver and non-nil receiver, so that
we don't need to use the DoneEvaluation hack when check for 
ObjCMessageExpr.

PreVisitObjCMessageExpr() only checks for undefined receiver or arguments.

Add checker interface EvalNilReceiver(). This is a 'once-and-done' interface.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90296 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index b95f981..0e4c1b1 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -1985,7 +1985,7 @@
                    Expr* Receiver,
                    const RetainSummary& Summ,
                    ExprIterator arg_beg, ExprIterator arg_end,
-                   ExplodedNode* Pred);
+                   ExplodedNode* Pred, const GRState *state);
 
   virtual void EvalCall(ExplodedNodeSet& Dst,
                         GRExprEngine& Eng,
@@ -1998,7 +1998,8 @@
                                    GRExprEngine& Engine,
                                    GRStmtNodeBuilder& Builder,
                                    ObjCMessageExpr* ME,
-                                   ExplodedNode* Pred);
+                                   ExplodedNode* Pred,
+                                   const GRState *state);
 
   bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst,
                               GRExprEngine& Engine,
@@ -2777,10 +2778,7 @@
                              Expr* Receiver,
                              const RetainSummary& Summ,
                              ExprIterator arg_beg, ExprIterator arg_end,
-                             ExplodedNode* Pred) {
-
-  // Get the state.
-  const GRState *state = Builder.GetState(Pred);
+                             ExplodedNode* Pred, const GRState *state) {
 
   // Evaluate the effect of the arguments.
   RefVal::Kind hasErr = (RefVal::Kind) 0;
@@ -3013,34 +3011,23 @@
 
   assert(Summ);
   EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
-              CE->arg_begin(), CE->arg_end(), Pred);
+              CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
 }
 
 void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
                                      GRExprEngine& Eng,
                                      GRStmtNodeBuilder& Builder,
                                      ObjCMessageExpr* ME,
-                                     ExplodedNode* Pred) {
-  // FIXME: Since we moved the nil check into a checker, we could get nil
-  // receiver here. Need a better way to check such case. 
-  if (Expr* Receiver = ME->getReceiver()) {
-    const GRState *state = Pred->getState();
-    DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-    if (!state->Assume(L, true)) {
-      Dst.Add(Pred);
-      return;
-    }
-  }
-  
+                                     ExplodedNode* Pred,
+                                     const GRState *state) {
   RetainSummary *Summ =
     ME->getReceiver()
-      ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
-                                           Pred->getLocationContext())
+      ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
       : Summaries.getClassMethodSummary(ME);
 
   assert(Summ && "RetainSummary is null");
   EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
-              ME->arg_begin(), ME->arg_end(), Pred);
+              ME->arg_begin(), ME->arg_end(), Pred, state);
 }
 
 namespace {
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp
index d8dd16c..c287354 100644
--- a/lib/Analysis/CallAndMessageChecker.cpp
+++ b/lib/Analysis/CallAndMessageChecker.cpp
@@ -41,6 +41,7 @@
 
   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
   void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+  bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
 
 private:
   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
@@ -148,28 +149,12 @@
       }
     }
   }
+}
 
-  // Check if the receiver was nil and then returns a value that may
-  // be garbage.
-  if (const Expr *Receiver = ME->getReceiver()) {
-    DefinedOrUnknownSVal receiverVal =
-      cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-    
-    const GRState *notNullState, *nullState;
-    llvm::tie(notNullState, nullState) = state->Assume(receiverVal);
-    
-    if (nullState && !notNullState) {
-      HandleNilReceiver(C, nullState, ME);
-      C.setDoneEvaluating(); // FIXME: eventually remove.
-      return;
-    }
-    
-    assert(notNullState);
-    state = notNullState;
-  }
-  
-  // Add a state transition if the state has changed.
-  C.addTransition(state);
+bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
+                                            const ObjCMessageExpr *ME) {
+  HandleNilReceiver(C, C.getState(), ME);
+  return true; // Nil receiver is not handled elsewhere.
 }
 
 void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 20820d4..c361e93 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -116,20 +116,18 @@
 // Checker worklist routines.
 //===----------------------------------------------------------------------===//
 
-bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
                                 ExplodedNodeSet &Src, bool isPrevisit) {
 
   if (Checkers.empty()) {
-    Dst.insert(Src);
-    return false;
+    Dst = Src;
+    return;
   }
 
   ExplodedNodeSet Tmp;
   ExplodedNodeSet *PrevSet = &Src;
-  bool stopProcessingAfterCurrentChecker = false;
 
-  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
-  {
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
     ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst 
                                           : (PrevSet == &Tmp) ? &Src : &Tmp;
 
@@ -138,31 +136,26 @@
     Checker *checker = I->second;
     
     for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
-         NI != NE; ++NI) {
-      // FIXME: Halting evaluation of the checkers is something we may
-      // not support later.  The design is still evolving.      
-      if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI,
-                            tag, isPrevisit)) {
-        if (CurrSet != &Dst)
-          Dst.insert(*CurrSet);
-
-        stopProcessingAfterCurrentChecker = true;
-        continue;
-      }
-      assert(stopProcessingAfterCurrentChecker == false &&
-             "Inconsistent setting of 'stopProcessingAfterCurrentChecker'");
-    }
-    
-    if (stopProcessingAfterCurrentChecker)
-      return true;
-
-    // Continue on to the next checker.  Update the current NodeSet.
+         NI != NE; ++NI)
+      checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
     PrevSet = CurrSet;
   }
 
   // Don't autotransition.  The CheckerContext objects should do this
   // automatically.
-  return false;
+}
+
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, 
+                                          ExplodedNodeSet &Dst,
+                                          const GRState *state,
+                                          ExplodedNode *Pred) {
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    if (checker->GR_EvalNilReceiver(Dst, *Builder, *this, ME, Pred, state, tag))
+      break;
+  }
 }
 
 // FIXME: This is largely copy-paste from CheckerVisit().  Need to 
@@ -1922,10 +1915,7 @@
   ExplodedNodeSet Src, DstTmp;
   Src.Add(Pred);
   
-  if (CheckerVisit(ME, DstTmp, Src, true)) {
-    Dst.insert(DstTmp);
-    return;
-  }
+  CheckerVisit(ME, DstTmp, Src, true);
   
   unsigned size = Dst.size();
 
@@ -1934,10 +1924,38 @@
     Pred = *DI;
     bool RaisesException = false;
 
-    if (ME->getReceiver()) {
+    if (const Expr *Receiver = ME->getReceiver()) {
+      const GRState *state = Pred->getState();
+
+      // Bifurcate the state into nil and non-nil ones.
+      DefinedOrUnknownSVal receiverVal = 
+        cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+
+      const GRState *notNilState, *nilState;
+      llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
+
+      // There are three cases: can be nil or non-nil, must be nil, must be 
+      // non-nil. We handle must be nil, and merge the rest two into non-nil.
+      if (nilState && !notNilState) {
+        CheckerEvalNilReceiver(ME, Dst, nilState, Pred);
+        return;
+      }
+
+      assert(notNilState);
+
       // Check if the "raise" message was sent.
       if (ME->getSelector() == RaiseSel)
         RaisesException = true;
+
+      // Check if we raise an exception.  For now treat these as sinks.
+      // Eventually we will want to handle exceptions properly.
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      if (RaisesException)
+        Builder->BuildSinks = true;
+
+      // Dispatch to plug-in transfer function.
+      SaveOr OldHasGen(Builder->HasGeneratedNode);  
+      EvalObjCMessageExpr(Dst, ME, Pred, notNilState);
     }
     else {
 
@@ -1984,17 +2002,17 @@
             RaisesException = true; break;
           }
       }
+
+      // Check if we raise an exception.  For now treat these as sinks.
+      // Eventually we will want to handle exceptions properly.
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      if (RaisesException)
+        Builder->BuildSinks = true;
+
+      // Dispatch to plug-in transfer function.
+      SaveOr OldHasGen(Builder->HasGeneratedNode);  
+      EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred));
     }
-
-    // Check if we raise an exception.  For now treat these as sinks.  Eventually
-    // we will want to handle exceptions properly.
-    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
-    if (RaisesException)
-      Builder->BuildSinks = true;
-
-    // Dispatch to plug-in transfer function.
-    SaveOr OldHasGen(Builder->HasGeneratedNode);  
-    EvalObjCMessageExpr(Dst, ME, Pred);
   }
 
   // Handle the case where no nodes where generated.  Auto-generate that