[cfe-commits] r91926 - in /cfe/trunk: include/clang/Analysis/PathSensitive/CheckerVisitor.def include/clang/Analysis/PathSensitive/GRExprEngine.h lib/Analysis/CFRefCount.cpp lib/Analysis/GRExprEngine.cpp test/Analysis/misc-ps-region-store.mm

Ted Kremenek kremenek at apple.com
Tue Dec 22 14:13:47 PST 2009


Author: kremenek
Date: Tue Dec 22 16:13:46 2009
New Revision: 91926

URL: http://llvm.org/viewvc/llvm-project?rev=91926&view=rev
Log:
Add transfer functions support for visiting an Objective-C message expression as an lvalue when the return type is a C++ reference.

Added:
    cfe/trunk/test/Analysis/misc-ps-region-store.mm
Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/CheckerVisitor.def
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/lib/Analysis/CFRefCount.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/CheckerVisitor.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/CheckerVisitor.def?rev=91926&r1=91925&r2=91926&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/CheckerVisitor.def (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/CheckerVisitor.def Tue Dec 22 16:13:46 2009
@@ -28,10 +28,11 @@
 PREVISIT(ObjCMessageExpr, Stmt)
 PREVISIT(ReturnStmt, Stmt)
 
-POSTVISIT(CallExpr, Stmt)
-POSTVISIT(CXXOperatorCallExpr, CallExpr)
 POSTVISIT(BlockExpr, Stmt)
 POSTVISIT(BinaryOperator, Stmt)
+POSTVISIT(CallExpr, Stmt)
+POSTVISIT(CXXOperatorCallExpr, CallExpr)
+POSTVISIT(ObjCMessageExpr, Stmt)
 
 #undef PREVISIT
 #undef POSTVISIT

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=91926&r1=91925&r2=91926&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Tue Dec 22 16:13:46 2009
@@ -319,16 +319,18 @@
 
   /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
   void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, 
-                            ExplodedNodeSet& Dst);
+                            ExplodedNodeSet& Dst, bool asLValue);
 
   void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
                                      ObjCMessageExpr::arg_iterator I,
                                      ObjCMessageExpr::arg_iterator E,
-                                     ExplodedNode* Pred, ExplodedNodeSet& Dst);
+                                     ExplodedNode* Pred, ExplodedNodeSet& Dst,
+                                     bool asLValue);
 
   void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, 
                                           ExplodedNode* Pred,
-                                          ExplodedNodeSet& Dst);
+                                          ExplodedNodeSet& Dst,
+                                          bool asLValue);
 
   /// VisitReturnStmt - Transfer function logic for return statements.
   void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);

Modified: cfe/trunk/lib/Analysis/CFRefCount.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFRefCount.cpp?rev=91926&r1=91925&r2=91926&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Tue Dec 22 16:13:46 2009
@@ -2945,12 +2945,13 @@
       // For CallExpr, use the result type to know if it returns a reference.
       if (const CallExpr *CE = dyn_cast<CallExpr>(Ex)) {
         const Expr *Callee = CE->getCallee();
-        SVal L = state->getSVal(Callee);
-        
-        const FunctionDecl *FD = L.getAsFunctionDecl();
-        if (FD)
+        if (const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl())
           T = FD->getResultType();
       }
+      else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(Ex)) {
+        if (const ObjCMethodDecl *MD = ME->getMethodDecl())
+          T = MD->getResultType();
+      }
 
       if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
         unsigned Count = Builder.getCurrentBlockCount();

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=91926&r1=91925&r2=91926&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Tue Dec 22 16:13:46 2009
@@ -46,11 +46,11 @@
   return Ctx.Selectors.getSelector(0, &II);
 }
 
+
 static bool CalleeReturnsReference(const CallExpr *CE) { 
   const Expr *Callee = CE->getCallee();
   QualType T = Callee->getType();
   
-  
   if (const PointerType *PT = T->getAs<PointerType>()) {
     const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
     T = FT->getResultType();
@@ -58,11 +58,17 @@
   else {
     const BlockPointerType *BT = T->getAs<BlockPointerType>();
     T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
-  }
-  
+  }  
   return T->isReferenceType();
 }
 
+static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
+  const ObjCMethodDecl *MD = ME->getMethodDecl();
+  if (!MD)
+    return false;
+  return MD->getResultType()->isReferenceType();
+}
+
 //===----------------------------------------------------------------------===//
 // Batch auditor.  DEPRECATED.
 //===----------------------------------------------------------------------===//
@@ -672,10 +678,9 @@
       VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
       break;
 
-    case Stmt::ObjCMessageExprClass: {
-      VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
+    case Stmt::ObjCMessageExprClass:
+      VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst, false);
       break;
-    }
 
     case Stmt::ObjCAtThrowStmtClass: {
       // FIXME: This is not complete.  We basically treat @throw as
@@ -764,7 +769,7 @@
       
     case Stmt::CallExprClass:
     case Stmt::CXXOperatorCallExprClass: {
-      CallExpr* C = cast<CallExpr>(Ex);
+      CallExpr *C = cast<CallExpr>(Ex);
       assert(CalleeReturnsReference(C));
       VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);      
       break;
@@ -785,6 +790,13 @@
     case Stmt::ObjCIvarRefExprClass:
       VisitObjCIvarRefExpr(cast<ObjCIvarRefExpr>(Ex), Pred, Dst, true);
       return;
+      
+    case Stmt::ObjCMessageExprClass: {
+      ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
+      assert(ReceiverReturnsReference(ME));
+      VisitObjCMessageExpr(ME, Pred, Dst, true); 
+      return;
+    }
 
     case Stmt::ObjCPropertyRefExprClass:
     case Stmt::ObjCImplicitSetterGetterRefExprClass:
@@ -1888,16 +1900,18 @@
 //===----------------------------------------------------------------------===//
 
 void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
-                                        ExplodedNodeSet& Dst){
+                                        ExplodedNodeSet& Dst, bool asLValue){
 
   VisitObjCMessageExprArgHelper(ME, ME->arg_begin(), ME->arg_end(),
-                                Pred, Dst);
+                                Pred, Dst, asLValue);
 }
 
 void GRExprEngine::VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME,
-                                              ObjCMessageExpr::arg_iterator AI,
-                                              ObjCMessageExpr::arg_iterator AE,
-                                     ExplodedNode* Pred, ExplodedNodeSet& Dst) {
+                                               ObjCMessageExpr::arg_iterator AI,
+                                               ObjCMessageExpr::arg_iterator AE,
+                                                 ExplodedNode* Pred,
+                                                 ExplodedNodeSet& Dst,
+                                                 bool asLValue) {
   if (AI == AE) {
 
     // Process the receiver.
@@ -1908,12 +1922,12 @@
 
       for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI != NE;
            ++NI)
-        VisitObjCMessageExprDispatchHelper(ME, *NI, Dst);
+        VisitObjCMessageExprDispatchHelper(ME, *NI, Dst, asLValue);
 
       return;
     }
 
-    VisitObjCMessageExprDispatchHelper(ME, Pred, Dst);
+    VisitObjCMessageExprDispatchHelper(ME, Pred, Dst, asLValue);
     return;
   }
 
@@ -1923,12 +1937,13 @@
   ++AI;
 
   for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
-    VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst);
+    VisitObjCMessageExprArgHelper(ME, AI, AE, *NI, Dst, asLValue);
 }
 
 void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
                                                       ExplodedNode* Pred,
-                                                      ExplodedNodeSet& Dst) {
+                                                      ExplodedNodeSet& Dst,
+                                                      bool asLValue) {
 
   // Handle previsits checks.
   ExplodedNodeSet Src, DstTmp;
@@ -1936,12 +1951,17 @@
   
   CheckerVisit(ME, DstTmp, Src, true);
   
-  unsigned size = Dst.size();
+  ExplodedNodeSet PostVisitSrc;
 
   for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
        DI!=DE; ++DI) {    
+
     Pred = *DI;
     bool RaisesException = false;
+    
+    unsigned OldSize = PostVisitSrc.size();
+    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+    SaveOr OldHasGen(Builder->HasGeneratedNode);  
 
     if (const Expr *Receiver = ME->getReceiver()) {
       const GRState *state = Pred->getState();
@@ -1956,8 +1976,8 @@
       // 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;
+        CheckerEvalNilReceiver(ME, PostVisitSrc, nilState, Pred);
+        continue;
       }
 
       assert(notNilState);
@@ -1968,39 +1988,29 @@
 
       // 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);
+      EvalObjCMessageExpr(PostVisitSrc, ME, Pred, notNilState);
     }
     else {
-
       IdentifierInfo* ClsName = ME->getClassName();
       Selector S = ME->getSelector();
 
       // Check for special instance methods.
-
       if (!NSExceptionII) {
         ASTContext& Ctx = getContext();
-
         NSExceptionII = &Ctx.Idents.get("NSException");
       }
 
       if (ClsName == NSExceptionII) {
-
         enum { NUM_RAISE_SELECTORS = 2 };
 
         // Lazily create a cache of the selectors.
-
         if (!NSExceptionInstanceRaiseSelectors) {
-
           ASTContext& Ctx = getContext();
-
           NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
-
           llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
           unsigned idx = 0;
 
@@ -2018,26 +2028,51 @@
 
         for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
           if (S == NSExceptionInstanceRaiseSelectors[i]) {
-            RaisesException = true; break;
+            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));
+      EvalObjCMessageExpr(PostVisitSrc, ME, Pred, Builder->GetState(Pred));
     }
+    
+    // Handle the case where no nodes where generated.  Auto-generate that
+    // contains the updated state if we aren't generating sinks.
+    if (!Builder->BuildSinks && PostVisitSrc.size() == OldSize &&
+        !Builder->HasGeneratedNode)
+      MakeNode(PostVisitSrc, ME, Pred, GetState(Pred));
   }
 
-  // Handle the case where no nodes where generated.  Auto-generate that
-  // contains the updated state if we aren't generating sinks.
-  if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
-    MakeNode(Dst, ME, Pred, GetState(Pred));
+  // Finally, perform the post-condition check of the ObjCMessageExpr and store
+  // the created nodes in 'Dst'.
+  if (!(!asLValue && ReceiverReturnsReference(ME))) {
+    CheckerVisit(ME, Dst, PostVisitSrc, false);
+    return;
+  }
+  
+  // Handle the case where the message expression returns a reference but
+  // we expect an rvalue.  For such cases, convert the reference to
+  // an rvalue.  
+  // FIXME: This conversion doesn't actually happen unless the result
+  //  of ObjCMessageExpr is consumed by another expression.
+  ExplodedNodeSet DstRValueConvert;
+  CheckerVisit(ME, DstRValueConvert, PostVisitSrc, false);
+  QualType LoadTy = ME->getType();
+  
+  static int *ConvertToRvalueTag = 0;
+  for (ExplodedNodeSet::iterator NI = DstRValueConvert.begin(),
+       NE = DstRValueConvert.end();
+       NI!=NE; ++NI) {
+    const GRState *state = GetState(*NI);
+    EvalLoad(Dst, ME, *NI, state, state->getSVal(ME),
+             &ConvertToRvalueTag, LoadTy);
+  }
 }
 
 //===----------------------------------------------------------------------===//

Added: cfe/trunk/test/Analysis/misc-ps-region-store.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/misc-ps-region-store.mm?rev=91926&view=auto

==============================================================================
--- cfe/trunk/test/Analysis/misc-ps-region-store.mm (added)
+++ cfe/trunk/test/Analysis/misc-ps-region-store.mm Tue Dec 22 16:13:46 2009
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-experimental-internal-checks -checker-cfref -analyzer-store=region -verify -fblocks   -analyzer-opt-analyze-nested-blocks %s
+
+//===------------------------------------------------------------------------------------------===//
+// This files tests our path-sensitive handling of Objective-c++ files.
+//===------------------------------------------------------------------------------------------===//
+
+// Test basic handling of references.
+char &test1_aux();
+char *test1() {
+  return &test1_aux();
+}
+
+// Test test1_aux() evaluates to char &.
+char test1_as_rvalue() {
+  return test1_aux();
+}
+
+// Test basic handling of references with Objective-C classes.
+ at interface Test1
+- (char&) foo;
+ at end
+
+char* Test1_harness(Test1 *p) {
+  return &[p foo];
+}
+
+char Test1_harness_b(Test1 *p) {
+  return [p foo];
+}
+





More information about the cfe-commits mailing list