objc-arc: Check on a variety of unsafe assignment of retained 
objects.  // rdar://9495837


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133806 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 6a09bf0..35b6e9a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -3720,15 +3720,50 @@
     diagnoseRetainCycle(*this, capturer, owner);
 }
 
-void Sema::checkUnsafeAssigns(SourceLocation Loc,
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
                               QualType LHS, Expr *RHS) {
   Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
   if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
-    return;
-  if (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS))
-    if (cast->getCastKind() == CK_ObjCConsumeObject)
+    return false;
+  // strip off any implicit cast added to get to the one arc-specific
+  while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+    if (cast->getCastKind() == CK_ObjCConsumeObject) {
       Diag(Loc, diag::warn_arc_retained_assign)
         << (LT == Qualifiers::OCL_ExplicitNone) 
         << RHS->getSourceRange();
+      return true;
+    }
+    RHS = cast->getSubExpr();
+  }
+  return false;
 }
 
+void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
+                              Expr *LHS, Expr *RHS) {
+  QualType LHSType = LHS->getType();
+  if (checkUnsafeAssigns(Loc, LHSType, RHS))
+    return;
+  Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+  // FIXME. Check for other life times.
+  if (LT != Qualifiers::OCL_None)
+    return;
+  
+  if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+    if (PRE->isImplicitProperty())
+      return;
+    const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+    if (!PD)
+      return;
+    
+    unsigned Attributes = PD->getPropertyAttributes();
+    if (Attributes & ObjCPropertyDecl::OBJC_PR_assign)
+      while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+        if (cast->getCastKind() == CK_ObjCConsumeObject) {
+          Diag(Loc, diag::warn_arc_retained_property_assign)
+          << RHS->getSourceRange();
+          return;
+        }
+        RHS = cast->getSubExpr();
+      }
+  }
+}