[objcmt] Rewrite messages to NSString's stringWithUTF8String:/stringWithCString:
to use the @() boxing syntax.

It will also rewrite uses of stringWithCString:encoding: where the encoding that is
used is NSASCIIStringEncoding or NSUTF8StringEncoding.

rdar://11438360

llvm-svn: 156868
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 1d368d6..38584d6 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -211,6 +211,8 @@
                                   const NSAPI &NS, Commit &commit);
 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
                                             const NSAPI &NS, Commit &commit);
+static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
+                                           const NSAPI &NS, Commit &commit);
 
 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
                                       const NSAPI &NS, Commit &commit) {
@@ -224,6 +226,8 @@
     return rewriteToDictionaryLiteral(Msg, NS, commit);
   if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
     return rewriteToNumberLiteral(Msg, NS, commit);
+  if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
+    return rewriteToStringBoxedExpression(Msg, NS, commit);
 
   return false;
 }
@@ -791,7 +795,7 @@
     return false;
 
   SourceRange ArgRange = OrigArg->getSourceRange();
-  commit.replaceWithInner(Msg->getSourceRange(), OrigArg->getSourceRange());
+  commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
 
   if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
     commit.insertBefore(ArgRange.getBegin(), "@");
@@ -800,3 +804,68 @@
 
   return true;
 }
+
+//===----------------------------------------------------------------------===//
+// rewriteToStringBoxedExpression.
+//===----------------------------------------------------------------------===//
+
+static bool doRewriteToUTF8StringBoxedExpressionHelper(
+                                              const ObjCMessageExpr *Msg,
+                                              const NSAPI &NS, Commit &commit) {
+  const Expr *Arg = Msg->getArg(0);
+  if (Arg->isTypeDependent())
+    return false;
+
+  const Expr *OrigArg = Arg->IgnoreImpCasts();
+  QualType OrigTy = OrigArg->getType();
+
+  if (const StringLiteral *
+        StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
+    commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
+    commit.insert(StrE->getLocStart(), "@");
+    return true;
+  }
+
+  ASTContext &Ctx = NS.getASTContext();
+
+  if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
+    QualType PointeeType = PT->getPointeeType();
+    if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
+      SourceRange ArgRange = OrigArg->getSourceRange();
+      commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+
+      if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
+        commit.insertBefore(ArgRange.getBegin(), "@");
+      else
+        commit.insertWrap("@(", ArgRange, ")");
+      
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
+                                           const NSAPI &NS, Commit &commit) {
+  Selector Sel = Msg->getSelector();
+
+  if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
+      Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
+    if (Msg->getNumArgs() != 1)
+      return false;
+    return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
+  }
+
+  if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
+    if (Msg->getNumArgs() != 2)
+      return false;
+
+    const Expr *encodingArg = Msg->getArg(1);
+    if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
+        NS.isNSASCIIStringEncodingConstant(encodingArg))
+      return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
+  }
+
+  return false;
+}