[analyzer] Handle the dot syntax for properties in the ExprEngine.

We translate property accesses to obj-c messages by simulating "loads" or "stores" to properties
using a pseudo-location SVal kind (ObjCPropRef).

Checkers can now reason about obj-c messages for both explicit message expressions and implicit
messages due to property accesses.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124161 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/BasicStore.cpp b/lib/StaticAnalyzer/BasicStore.cpp
index 42fd339..0254ba7 100644
--- a/lib/StaticAnalyzer/BasicStore.cpp
+++ b/lib/StaticAnalyzer/BasicStore.cpp
@@ -196,6 +196,7 @@
       return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
     }
 
+    case loc::ObjCPropRefKind:
     case loc::ConcreteIntKind:
       // Support direct accesses to memory.  It's up to individual checkers
       // to flag an error.
diff --git a/lib/StaticAnalyzer/CFRefCount.cpp b/lib/StaticAnalyzer/CFRefCount.cpp
index 5cc4a3c..473b731 100644
--- a/lib/StaticAnalyzer/CFRefCount.cpp
+++ b/lib/StaticAnalyzer/CFRefCount.cpp
@@ -2033,9 +2033,10 @@
       else
         os << "function call";
     }
-    else {
-      assert (isa<ObjCMessageExpr>(S));
+    else if (isa<ObjCMessageExpr>(S)) {
       os << "Method";
+    } else {
+      os << "Property";
     }
 
     if (CurrV.getObjKind() == RetEffect::CF) {
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index e6a40bb..1f5f233 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -246,10 +246,11 @@
       return;
     }
 
+  const char *bugDesc = msg.isPropertySetter() ?
+                     "Argument for property setter is an uninitialized value"
+                   : "Argument in message expression is an uninitialized value";
   // Check for any arguments that are uninitialized/undefined.
-  PreVisitProcessArgs(C, CallOrObjCMessage(msg, state),
-                      "Argument in message expression "
-                      "is an uninitialized value", BT_msg_arg);
+  PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg);
 }
 
 bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index 9a74bd9..53931dc 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -865,6 +865,10 @@
       VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
       break;
 
+    case Stmt::ObjCPropertyRefExprClass:
+      VisitObjCPropertyRefExpr(cast<ObjCPropertyRefExpr>(S), Pred, Dst);
+      break;
+
     // Cases not handled yet; but will handle some day.
     case Stmt::DesignatedInitExprClass:
     case Stmt::ExtVectorElementExprClass:
@@ -875,7 +879,6 @@
     case Stmt::ObjCAtTryStmtClass:
     case Stmt::ObjCEncodeExprClass:
     case Stmt::ObjCIsaExprClass:
-    case Stmt::ObjCPropertyRefExprClass:
     case Stmt::ObjCProtocolExprClass:
     case Stmt::ObjCSelectorExprClass:
     case Stmt::ObjCStringLiteralClass:
@@ -1799,6 +1802,17 @@
 
   assert(Builder && "StmtNodeBuilder must be defined.");
 
+  // Proceed with the store.  We use AssignE as the anchor for the PostStore
+  // ProgramPoint if it is non-NULL, and LocationE otherwise.
+  const Expr *StoreE = AssignE ? AssignE : LocationE;
+
+  if (isa<loc::ObjCPropRef>(location)) {
+    loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
+    ExplodedNodeSet src = Pred;
+    return VisitObjCMessage(ObjCPropertySetter(prop.getPropRefExpr(),
+                                               StoreE, Val), src, Dst);
+  }
+
   // Evaluate the location (checks for bad dereferences).
   ExplodedNodeSet Tmp;
   evalLocation(Tmp, LocationE, Pred, state, location, tag, false);
@@ -1811,10 +1825,6 @@
   SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
                                                    ProgramPoint::PostStoreKind);
 
-  // Proceed with the store.  We use AssignE as the anchor for the PostStore
-  // ProgramPoint if it is non-NULL, and LocationE otherwise.
-  const Expr *StoreE = AssignE ? AssignE : LocationE;
-
   for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
     evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val);
 }
@@ -1825,6 +1835,13 @@
                             const void *tag, QualType LoadTy) {
   assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
 
+  if (isa<loc::ObjCPropRef>(location)) {
+    loc::ObjCPropRef prop = cast<loc::ObjCPropRef>(location);
+    ExplodedNodeSet src = Pred;
+    return VisitObjCMessage(ObjCPropertyGetter(prop.getPropRefExpr(), Ex),
+                            src, Dst);
+  }
+
   // Are we loading from a region?  This actually results in two loads; one
   // to fetch the address of the referenced value and one to fetch the
   // referenced value.
@@ -2048,6 +2065,34 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Transfer function: Objective-C dot-syntax to access a property.
+//===----------------------------------------------------------------------===//
+
+void ExprEngine::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Ex,
+                                          ExplodedNode *Pred,
+                                          ExplodedNodeSet &Dst) {
+
+  // Visit the base expression, which is needed for computing the lvalue
+  // of the ivar.
+  ExplodedNodeSet dstBase;
+  const Expr *baseExpr = Ex->getBase();
+  Visit(baseExpr, Pred, dstBase);
+
+  ExplodedNodeSet dstPropRef;
+
+  // Using the base, compute the lvalue of the instance variable.
+  for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
+       I!=E; ++I) {
+    ExplodedNode *nodeBase = *I;
+    const GRState *state = GetState(nodeBase);
+    SVal baseVal = state->getSVal(baseExpr);
+    MakeNode(dstPropRef, Ex, *I, state->BindExpr(Ex, loc::ObjCPropRef(Ex)));
+  }
+  
+  Dst.insert(dstPropRef);
+}
+
+//===----------------------------------------------------------------------===//
 // Transfer function: Objective-C ivar references.
 //===----------------------------------------------------------------------===//
 
@@ -2426,7 +2471,8 @@
   ExplodedNodeSet S2;
   CheckerVisit(CastE, S2, S1, PreVisitStmtCallback);
   
-  if (CastE->getCastKind() == CK_LValueToRValue) {
+  if (CastE->getCastKind() == CK_LValueToRValue ||
+      CastE->getCastKind() == CK_GetObjCProperty) {
     for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) {
       ExplodedNode *subExprNode = *I;
       const GRState *state = GetState(subExprNode);
diff --git a/lib/StaticAnalyzer/RegionStore.cpp b/lib/StaticAnalyzer/RegionStore.cpp
index 986278e..d5af1c2 100644
--- a/lib/StaticAnalyzer/RegionStore.cpp
+++ b/lib/StaticAnalyzer/RegionStore.cpp
@@ -985,6 +985,9 @@
   if (isa<loc::ConcreteInt>(L)) {
     return UnknownVal();
   }
+  if (!isa<loc::MemRegionVal>(L)) {
+    return UnknownVal();
+  }
 
   const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
 
diff --git a/lib/StaticAnalyzer/SVals.cpp b/lib/StaticAnalyzer/SVals.cpp
index dd8508a..1b2f1de 100644
--- a/lib/StaticAnalyzer/SVals.cpp
+++ b/lib/StaticAnalyzer/SVals.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/Basic/IdentifierTable.h"
 
 using namespace clang;
@@ -354,6 +355,22 @@
     case loc::MemRegionKind:
       os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
       break;
+    case loc::ObjCPropRefKind: {
+      const ObjCPropertyRefExpr *E = cast<loc::ObjCPropRef>(this)->getPropRefExpr();
+      os << "objc-prop{";
+      if (E->isSuperReceiver())
+        os << "super.";
+      else if (E->getBase())
+        os << "<base>.";
+
+      if (E->isImplicitProperty())
+        os << E->getImplicitPropertyGetter()->getSelector().getAsString();
+      else
+        os << E->getExplicitProperty()->getName();
+
+      os << "}";
+      break;
+    }
     default:
       assert(false && "Pretty-printing not implemented for this Loc.");
       break;