From 554bcb69c2d785a011a30e7db87a36a87fe7db10 Mon Sep 17 00:00:00 2001
From: dim <dim@FreeBSD.org>
Date: Wed, 15 Aug 2012 20:02:54 +0000
Subject: Vendor import of clang trunk r161861:
 http://llvm.org/svn/llvm-project/cfe/trunk@161861

---
 lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 211 ++++++++++++++---------------
 1 file changed, 99 insertions(+), 112 deletions(-)

(limited to 'lib/StaticAnalyzer/Core/ExprEngineObjC.cpp')

diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index c8ad70a..e3bc498 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -13,8 +13,8 @@
 
 #include "clang/AST/StmtObjC.h"
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
 
 using namespace clang;
 using namespace ento;
@@ -74,7 +74,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
   const Stmt *elem = S->getElement();
   ProgramStateRef state = Pred->getState();
   SVal elementV;
-  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
   
   if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
     const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
@@ -86,10 +85,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
   }
   
   ExplodedNodeSet dstLocation;
-  Bldr.takeNodes(Pred);
   evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false);
-  Bldr.addNodes(dstLocation);
-  
+
+  ExplodedNodeSet Tmp;
+  StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext);
+
   for (ExplodedNodeSet::iterator NI = dstLocation.begin(),
        NE = dstLocation.end(); NI!=NE; ++NI) {
     Pred = *NI;
@@ -126,148 +126,135 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
     Bldr.generateNode(S, Pred, hasElems);
     Bldr.generateNode(S, Pred, noElems);
   }
+
+  // Finally, run any custom checkers.
+  // FIXME: Eventually all pre- and post-checks should live in VisitStmt.
+  getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+}
+
+static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
+  if (!Class)
+    return false;
+  if (Class->getIdentifier() == II)
+    return true;
+  return isSubclass(Class->getSuperClass(), II);
 }
 
-void ExprEngine::VisitObjCMessage(const ObjCMessage &msg,
+void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
                                   ExplodedNode *Pred,
                                   ExplodedNodeSet &Dst) {
-  
+  CallEventManager &CEMgr = getStateManager().getCallEventManager();
+  CallEventRef<ObjCMethodCall> Msg =
+    CEMgr.getObjCMethodCall(ME, Pred->getState(), Pred->getLocationContext());
+
   // Handle the previsits checks.
   ExplodedNodeSet dstPrevisit;
-  getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, 
-                                                   msg, *this);
-  
+  getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
+                                                   *Msg, *this);
+  ExplodedNodeSet dstGenericPrevisit;
+  getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
+                                            *Msg, *this);
+
   // Proceed with evaluate the message expression.
   ExplodedNodeSet dstEval;
-  StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
+  StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
 
-  for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
-       DE = dstPrevisit.end(); DI != DE; ++DI) {
-    
+  for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
+       DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
     ExplodedNode *Pred = *DI;
-    bool RaisesException = false;
+    ProgramStateRef State = Pred->getState();
+    CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
     
-    if (const Expr *Receiver = msg.getInstanceReceiver()) {
-      ProgramStateRef state = Pred->getState();
-      SVal recVal = state->getSVal(Receiver, Pred->getLocationContext());
+    if (UpdatedMsg->isInstanceMessage()) {
+      SVal recVal = UpdatedMsg->getReceiverSVal();
       if (!recVal.isUndef()) {
         // Bifurcate the state into nil and non-nil ones.
         DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
         
         ProgramStateRef notNilState, nilState;
-        llvm::tie(notNilState, nilState) = state->assume(receiverVal);
+        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 ignore must be nil, and merge the rest two into non-nil.
+        // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
+        // Revisit once we have lazier constraints.
         if (nilState && !notNilState) {
           continue;
         }
         
         // Check if the "raise" message was sent.
         assert(notNilState);
-        if (msg.getSelector() == RaiseSel)
-          RaisesException = true;
+        if (Msg->getSelector() == RaiseSel) {
+          // If we raise an exception, for now treat it as a sink.
+          // Eventually we will want to handle exceptions properly.
+          Bldr.generateNode(currentStmt, Pred, State, true);
+          continue;
+        }
         
-        // If we raise an exception, for now treat it as a sink.
-        // Eventually we will want to handle exceptions properly.
-        // Dispatch to plug-in transfer function.
-        evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
-      }
-    }
-    else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) {
-      IdentifierInfo* ClsName = Iface->getIdentifier();
-      Selector S = msg.getSelector();
-      
-      // Check for special instance methods.
-      if (!NSExceptionII) {
-        ASTContext &Ctx = getContext();
-        NSExceptionII = &Ctx.Idents.get("NSException");
+        // Generate a transition to non-Nil state.
+        if (notNilState != State)
+          Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
       }
-      
-      if (ClsName == NSExceptionII) {
-        enum { NUM_RAISE_SELECTORS = 2 };
-        
-        // Lazily create a cache of the selectors.
-        if (!NSExceptionInstanceRaiseSelectors) {
+    } else {
+      // Check for special class methods.
+      if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) {
+        if (!NSExceptionII) {
           ASTContext &Ctx = getContext();
-          NSExceptionInstanceRaiseSelectors =
-          new Selector[NUM_RAISE_SELECTORS];
-          SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
-          unsigned idx = 0;
-          
-          // raise:format:
-          II.push_back(&Ctx.Idents.get("raise"));
-          II.push_back(&Ctx.Idents.get("format"));
-          NSExceptionInstanceRaiseSelectors[idx++] =
-          Ctx.Selectors.getSelector(II.size(), &II[0]);
-          
-          // raise:format::arguments:
-          II.push_back(&Ctx.Idents.get("arguments"));
-          NSExceptionInstanceRaiseSelectors[idx++] =
-          Ctx.Selectors.getSelector(II.size(), &II[0]);
+          NSExceptionII = &Ctx.Idents.get("NSException");
         }
         
-        for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
-          if (S == NSExceptionInstanceRaiseSelectors[i]) {
-            RaisesException = true;
-            break;
+        if (isSubclass(Iface, NSExceptionII)) {
+          enum { NUM_RAISE_SELECTORS = 2 };
+          
+          // Lazily create a cache of the selectors.
+          if (!NSExceptionInstanceRaiseSelectors) {
+            ASTContext &Ctx = getContext();
+            NSExceptionInstanceRaiseSelectors =
+              new Selector[NUM_RAISE_SELECTORS];
+            SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
+            unsigned idx = 0;
+            
+            // raise:format:
+            II.push_back(&Ctx.Idents.get("raise"));
+            II.push_back(&Ctx.Idents.get("format"));
+            NSExceptionInstanceRaiseSelectors[idx++] =
+              Ctx.Selectors.getSelector(II.size(), &II[0]);
+            
+            // raise:format:arguments:
+            II.push_back(&Ctx.Idents.get("arguments"));
+            NSExceptionInstanceRaiseSelectors[idx++] =
+              Ctx.Selectors.getSelector(II.size(), &II[0]);
           }
+          
+          Selector S = Msg->getSelector();
+          bool RaisesException = false;
+          for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
+            if (S == NSExceptionInstanceRaiseSelectors[i]) {
+              RaisesException = true;
+              break;
+            }
+          }
+          if (RaisesException) {
+            // If we raise an exception, for now treat it as a sink.
+            // Eventually we will want to handle exceptions properly.
+            Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
+            continue;
+          }
+
+        }
       }
-      
-      // If we raise an exception, for now treat it as a sink.
-      // Eventually we will want to handle exceptions properly.
-      // Dispatch to plug-in transfer function.
-      evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException);
     }
+
+    // Evaluate the call.
+    defaultEvalCall(Bldr, Pred, *UpdatedMsg);
   }
   
+  ExplodedNodeSet dstPostvisit;
+  getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
+                                             *Msg, *this);
+
   // Finally, perform the post-condition check of the ObjCMessageExpr and store
   // the created nodes in 'Dst'.
-  getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
+  getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
+                                                    *Msg, *this);
 }
-
-void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
-                                 const ObjCMessage &msg,
-                                 ExplodedNode *Pred,
-                                 ProgramStateRef state,
-                                 bool GenSink) {
-  // First handle the return value.
-  SVal ReturnValue = UnknownVal();
-
-  // Some method families have known return values.
-  switch (msg.getMethodFamily()) {
-  default:
-    break;
-  case OMF_autorelease:
-  case OMF_retain:
-  case OMF_self: {
-    // These methods return their receivers.
-    const Expr *ReceiverE = msg.getInstanceReceiver();
-    if (ReceiverE)
-      ReturnValue = state->getSVal(ReceiverE, Pred->getLocationContext());
-    break;
-  }
-  }
-
-  // If we failed to figure out the return value, use a conjured value instead.
-  if (ReturnValue.isUnknown()) {
-    SValBuilder &SVB = getSValBuilder();
-    QualType ResultTy = msg.getResultType(getContext());
-    unsigned Count = currentBuilderContext->getCurrentBlockCount();
-    const Expr *CurrentE = cast<Expr>(currentStmt);
-    const LocationContext *LCtx = Pred->getLocationContext();
-    ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy, Count);
-  }
-
-  // Bind the return value.
-  const LocationContext *LCtx = Pred->getLocationContext();
-  state = state->BindExpr(currentStmt, LCtx, ReturnValue);
-
-  // Invalidate the arguments (and the receiver)
-  state = invalidateArguments(state, CallOrObjCMessage(msg, state, LCtx), LCtx);
-
-  // And create the new node.
-  Bldr.generateNode(msg.getMessageExpr(), Pred, state, GenSink);
-  assert(Bldr.hasGeneratedNodes());
-}
-
-- 
cgit v1.1