[objcmt] When rewriting to array/dictionary literals, add an explicit
cast to 'id' for any argument that requires it.

Part of rdar://11438360.

llvm-svn: 156782
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 24a0db1..8c3c7a5 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -229,6 +229,9 @@
 // rewriteToArrayLiteral.
 //===----------------------------------------------------------------------===//
 
+/// \brief Adds an explicit cast to 'id' if the type is not objc object.
+static void objectifyExpr(const Expr *E, Commit &commit);
+
 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
                                   const NSAPI &NS, Commit &commit) {
   Selector Sel = Msg->getSelector();
@@ -244,6 +247,7 @@
   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
     if (Msg->getNumArgs() != 1)
       return false;
+    objectifyExpr(Msg->getArg(0), commit);
     SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
     commit.replaceWithInner(MsgRange, ArgRange);
     commit.insertWrap("@[", ArgRange, "]");
@@ -257,6 +261,9 @@
     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
       return false;
 
+    for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
+      objectifyExpr(Msg->getArg(i), commit);
+
     if (Msg->getNumArgs() == 1) {
       commit.replace(MsgRange, "@[]");
       return true;
@@ -291,6 +298,10 @@
                                     NSAPI::NSDict_dictionaryWithObjectForKey)) {
     if (Msg->getNumArgs() != 2)
       return false;
+
+    objectifyExpr(Msg->getArg(0), commit);
+    objectifyExpr(Msg->getArg(1), commit);
+
     SourceRange ValRange = Msg->getArg(0)->getSourceRange();
     SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
     // Insert key before the value.
@@ -319,6 +330,9 @@
     }
 
     for (unsigned i = 0; i < SentinelIdx; i += 2) {
+      objectifyExpr(Msg->getArg(i), commit);
+      objectifyExpr(Msg->getArg(i+1), commit);
+
       SourceRange ValRange = Msg->getArg(i)->getSourceRange();
       SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
       // Insert value after key.
@@ -585,3 +599,52 @@
   }
   return true;
 }
+
+static bool castOperatorNeedsParens(const Expr *FullExpr) {
+  const Expr* Expr = FullExpr->IgnoreImpCasts();
+  if (isa<ArraySubscriptExpr>(Expr) ||
+      isa<CallExpr>(Expr) ||
+      isa<DeclRefExpr>(Expr) ||
+      isa<CastExpr>(Expr) ||
+      isa<CXXNewExpr>(Expr) ||
+      isa<CXXConstructExpr>(Expr) ||
+      isa<CXXDeleteExpr>(Expr) ||
+      isa<CXXNoexceptExpr>(Expr) ||
+      isa<CXXPseudoDestructorExpr>(Expr) ||
+      isa<CXXScalarValueInitExpr>(Expr) ||
+      isa<CXXThisExpr>(Expr) ||
+      isa<CXXTypeidExpr>(Expr) ||
+      isa<CXXUnresolvedConstructExpr>(Expr) ||
+      isa<ObjCMessageExpr>(Expr) ||
+      isa<ObjCPropertyRefExpr>(Expr) ||
+      isa<ObjCProtocolExpr>(Expr) ||
+      isa<MemberExpr>(Expr) ||
+      isa<ParenExpr>(FullExpr) ||
+      isa<ParenListExpr>(Expr) ||
+      isa<SizeOfPackExpr>(Expr) ||
+      isa<UnaryOperator>(Expr))
+    return false;
+
+  return true;
+}
+
+static void objectifyExpr(const Expr *E, Commit &commit) {
+  if (!E) return;
+
+  QualType T = E->getType();
+  if (T->isObjCObjectPointerType()) {
+    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+      if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
+        return;
+    } else {
+      return;
+    }
+  } else if (!T->isPointerType()) {
+    return;
+  }
+
+  SourceRange Range = E->getSourceRange();
+  if (castOperatorNeedsParens(E))
+    commit.insertWrap("(", Range, ")");
+  commit.insertBefore(Range.getBegin(), "(id)");
+}