]> granicus.if.org Git - clang/commitdiff
[analyzer] Refactor VisitObjCMessage and VisitCallExpr to rely on the
authorAnna Zaks <ganna@apple.com>
Thu, 19 Jul 2012 23:38:13 +0000 (23:38 +0000)
committerAnna Zaks <ganna@apple.com>
Thu, 19 Jul 2012 23:38:13 +0000 (23:38 +0000)
same implementation for call evaluation.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160530 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
lib/StaticAnalyzer/Core/CheckerManager.cpp
lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

index 810331521cb613e419e782abd8ee3207211266fa..eeb4c57f34e7e49a2be49eae23ac22b9b06c2cd1 100644 (file)
@@ -467,9 +467,17 @@ public:
                  ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
                  const ProgramPointTag *tag = 0);
 
+  /// \brief Create a new state in which the call return value is binded to the
+  /// call origin expression.
+  ProgramStateRef bindReturnValue(const CallEvent &Call,
+                                  const LocationContext *LCtx,
+                                  ProgramStateRef State);
+
   void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
                 const SimpleCall &Call);
-  void defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+
+  /// \bried Default implementation of call evaluation.
+  void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred,
                        const CallEvent &Call);
 private:
   void evalLoadCommon(ExplodedNodeSet &Dst,
@@ -491,8 +499,7 @@ private:
                     const ProgramPointTag *tag, bool isLoad);
 
   bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
-  bool inlineCall(ExplodedNodeSet &Dst, const CallEvent &Call,
-                  ExplodedNode *Pred);
+  bool inlineCall(const CallEvent &Call, ExplodedNode *Pred);
 
   bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
 };
index d0d212130ace6a405f8f7d1bfb6483ad63b57eaa..591609d2856ad6df526cbdfb5c019647ed405f5e 100644 (file)
@@ -568,8 +568,10 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
     }
     
     // If none of the checkers evaluated the call, ask ExprEngine to handle it.
-    if (!anyEvaluated)
-      Eng.defaultEvalCall(Dst, Pred, Call);
+    if (!anyEvaluated) {
+      NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
+      Eng.defaultEvalCall(B, Pred, Call);
+    }
   }
 }
 
index f786a4f8c51cf3a87200485356f085670c5d29fc..7c3000ee0da6269f03267ef70914c19ba4bca2d5 100644 (file)
@@ -54,9 +54,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
                                             Call, *this);
 
   ExplodedNodeSet DstInvalidated;
+  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
-    defaultEvalCall(DstInvalidated, *I, Call);
+    defaultEvalCall(Bldr, *I, Call);
 
   ExplodedNodeSet DstPostCall;
   getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
@@ -77,9 +78,10 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
                                             Call, *this);
 
   ExplodedNodeSet DstInvalidated;
+  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
-    defaultEvalCall(DstInvalidated, *I, Call);
+    defaultEvalCall(Bldr, *I, Call);
 
   ExplodedNodeSet DstPostCall;
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,
index 7cedb7ac5e85813520dcc6dbc12218c26335378c..cc257eb38b46073780db51009aa91c26ba8743d6 100644 (file)
@@ -266,8 +266,7 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
   return true;
 }
 
-bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
-                            const CallEvent &Call,
+bool ExprEngine::inlineCall(const CallEvent &Call,
                             ExplodedNode *Pred) {
   if (!getAnalysisManager().shouldInlineCall())
     return false;
@@ -342,16 +341,16 @@ bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
   return true;
 }
 
-static ProgramStateRef getInlineFailedState(ExplodedNode *&N,
+static ProgramStateRef getInlineFailedState(ProgramStateRef State,
                                             const Stmt *CallE) {
-  void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
+  void *ReplayState = State->get<ReplayWithoutInlining>();
   if (!ReplayState)
     return 0;
 
   assert(ReplayState == (const void*)CallE && "Backtracked to the wrong call.");
   (void)CallE;
 
-  return N->getState()->remove<ReplayWithoutInlining>();
+  return State->remove<ReplayWithoutInlining>();
 }
 
 void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
@@ -419,38 +418,69 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
                                              Call, *this);
 }
 
-void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
+                                            const LocationContext *LCtx,
+                                            ProgramStateRef State) {
+  const Expr *E = Call.getOriginExpr();
+  if (!E)
+    return State;
+
+  // Some method families have known return values.
+  if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
+    switch (Msg->getMethodFamily()) {
+    default:
+      break;
+    case OMF_autorelease:
+    case OMF_retain:
+    case OMF_self: {
+      // These methods return their receivers.
+      return State->BindExpr(E, LCtx, Msg->getReceiverSVal());
+      break;
+    }
+    }
+  }
+
+  // Conjure a symbol if the return value is unknown.
+  QualType ResultTy = Call.getResultType();
+  SValBuilder &SVB = getSValBuilder();
+  unsigned Count = currentBuilderContext->getCurrentBlockCount();
+  SVal R = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+  return State->BindExpr(E, LCtx, R);
+}
+
+void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
                                  const CallEvent &Call) {
+  ProgramStateRef State = 0;
+  const Expr *E = Call.getOriginExpr();
+
   // Try to inline the call.
   // The origin expression here is just used as a kind of checksum;
   // for CallEvents that do not have origin expressions, this should still be
   // safe.
-  const Expr *E = Call.getOriginExpr();
-  ProgramStateRef state = getInlineFailedState(Pred, E);
-  if (state == 0 && inlineCall(Dst, Call, Pred))
-    return;
+  if (!isa<ObjCMethodCall>(Call)) {
+    State = getInlineFailedState(Pred->getState(), E);
+    if (State == 0 && inlineCall(Call, Pred)) {
+      // If we inlined the call, the successor has been manually added onto
+      // the work list and we should not consider it for subsequent call
+      // handling steps.
+      Bldr.takeNodes(Pred);
+      return;
+    }
+  }
 
   // If we can't inline it, handle the return value and invalidate the regions.
-  NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+  if (State == 0)
+    State = Pred->getState();
 
   // Invalidate any regions touched by the call.
   unsigned Count = currentBuilderContext->getCurrentBlockCount();
-  if (state == 0)
-    state = Pred->getState();
-  state = Call.invalidateRegions(Count, state);
-
-  // Conjure a symbol value to use as the result.
-  if (E) {
-    QualType ResultTy = Call.getResultType();
-    SValBuilder &SVB = getSValBuilder();
-    const LocationContext *LCtx = Pred->getLocationContext();
-    SVal RetVal = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
-
-    state = state->BindExpr(E, LCtx, RetVal);
-  }
+  State = Call.invalidateRegions(Count, State);
+
+  // Construct and bind the return value.
+  State = bindReturnValue(Call, Pred->getLocationContext(), State);
 
   // And make the result node.
-  Bldr.generateNode(Call.getProgramPoint(), state, Pred);
+  Bldr.generateNode(Call.getProgramPoint(), State, Pred);
 }
 
 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
index f99fe5ff3745e35618ffe29a1d08f833a52d7e3b..a8e0b3b809b448e2ef8903541e4da7dbc8223bfd 100644 (file)
@@ -158,9 +158,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
 
   for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
        DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
-    
     ExplodedNode *Pred = *DI;
-    bool RaisesException = false;
     
     if (msg.isInstanceMessage()) {
       SVal recVal = msg.getReceiverSVal();
@@ -182,13 +180,19 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
         
         // 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, 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, notNilState, RaisesException);
+        // Generate a transition to non-Nil state.
+        if (notNilState != state)
+          Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
+
+        // Evaluate the call.
+        defaultEvalCall(Bldr, Pred, msg);
       }
     } else {
       // Check for special class methods.
@@ -222,19 +226,25 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
           }
           
           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, msg);
     }
   }
   
@@ -246,48 +256,3 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
   getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
                                                     msg, *this);
 }
-
-void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
-                                 const ObjCMethodCall &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.
-    ReturnValue = msg.getReceiverSVal();
-    break;
-  }
-  }
-
-  const LocationContext *LCtx = Pred->getLocationContext();
-  unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
-
-  // If we failed to figure out the return value, use a conjured value instead.
-  if (ReturnValue.isUnknown()) {
-    SValBuilder &SVB = getSValBuilder();
-    QualType ResultTy = msg.getResultType();
-    const Expr *CurrentE = cast<Expr>(currentStmt);
-    ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy,
-                                           BlockCount);
-  }
-
-  // Bind the return value.
-  state = state->BindExpr(currentStmt, LCtx, ReturnValue);
-
-  // Invalidate the arguments (and the receiver)
-  state = msg.invalidateRegions(BlockCount, state);
-
-  // And create the new node.
-  Bldr.generateNode(currentStmt, Pred, state, GenSink);
-  assert(Bldr.hasGeneratedNodes());
-}
-