clang API Documentation

RewriteObjCFoundationAPI.cpp
Go to the documentation of this file.
00001 //===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // Rewrites legacy method calls to modern syntax.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "clang/Edit/Rewriters.h"
00015 #include "clang/AST/ASTContext.h"
00016 #include "clang/AST/ExprCXX.h"
00017 #include "clang/AST/ExprObjC.h"
00018 #include "clang/AST/NSAPI.h"
00019 #include "clang/AST/ParentMap.h"
00020 #include "clang/Edit/Commit.h"
00021 #include "clang/Lex/Lexer.h"
00022 
00023 using namespace clang;
00024 using namespace edit;
00025 
00026 static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
00027                                     IdentifierInfo *&ClassId,
00028                                     const LangOptions &LangOpts) {
00029   if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
00030     return false;
00031 
00032   const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
00033   if (!Receiver)
00034     return false;
00035   ClassId = Receiver->getIdentifier();
00036 
00037   if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
00038     return true;
00039 
00040   // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
00041   // since the change from +1 to +0 will be handled fine by ARC.
00042   if (LangOpts.ObjCAutoRefCount) {
00043     if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
00044       if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
00045                            Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
00046         if (Rec->getMethodFamily() == OMF_alloc)
00047           return true;
00048       }
00049     }
00050   }
00051 
00052   return false;
00053 }
00054 
00055 //===----------------------------------------------------------------------===//
00056 // rewriteObjCRedundantCallWithLiteral.
00057 //===----------------------------------------------------------------------===//
00058 
00059 bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
00060                                               const NSAPI &NS, Commit &commit) {
00061   IdentifierInfo *II = nullptr;
00062   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
00063     return false;
00064   if (Msg->getNumArgs() != 1)
00065     return false;
00066 
00067   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
00068   Selector Sel = Msg->getSelector();
00069 
00070   if ((isa<ObjCStringLiteral>(Arg) &&
00071        NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
00072        (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
00073         NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel))   ||
00074 
00075       (isa<ObjCArrayLiteral>(Arg) &&
00076        NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
00077        (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
00078         NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel))     ||
00079 
00080       (isa<ObjCDictionaryLiteral>(Arg) &&
00081        NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
00082        (NS.getNSDictionarySelector(
00083                               NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
00084         NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
00085     
00086     commit.replaceWithInner(Msg->getSourceRange(),
00087                            Msg->getArg(0)->getSourceRange());
00088     return true;
00089   }
00090 
00091   return false;
00092 }
00093 
00094 //===----------------------------------------------------------------------===//
00095 // rewriteToObjCSubscriptSyntax.
00096 //===----------------------------------------------------------------------===//
00097 
00098 /// \brief Check for classes that accept 'objectForKey:' (or the other selectors
00099 /// that the migrator handles) but return their instances as 'id', resulting
00100 /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
00101 ///
00102 /// When checking if we can convert to subscripting syntax, check whether
00103 /// the receiver is a result of a class method from a hardcoded list of
00104 /// such classes. In such a case return the specific class as the interface
00105 /// of the receiver.
00106 ///
00107 /// FIXME: Remove this when these classes start using 'instancetype'.
00108 static const ObjCInterfaceDecl *
00109 maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
00110                                          const Expr *Receiver,
00111                                          ASTContext &Ctx) {
00112   assert(IFace && Receiver);
00113 
00114   // If the receiver has type 'id'...
00115   if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
00116     return IFace;
00117 
00118   const ObjCMessageExpr *
00119     InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
00120   if (!InnerMsg)
00121     return IFace;
00122 
00123   QualType ClassRec;
00124   switch (InnerMsg->getReceiverKind()) {
00125   case ObjCMessageExpr::Instance:
00126   case ObjCMessageExpr::SuperInstance:
00127     return IFace;
00128 
00129   case ObjCMessageExpr::Class:
00130     ClassRec = InnerMsg->getClassReceiver();
00131     break;
00132   case ObjCMessageExpr::SuperClass:
00133     ClassRec = InnerMsg->getSuperType();
00134     break;
00135   }
00136 
00137   if (ClassRec.isNull())
00138     return IFace;
00139 
00140   // ...and it is the result of a class message...
00141 
00142   const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
00143   if (!ObjTy)
00144     return IFace;
00145   const ObjCInterfaceDecl *OID = ObjTy->getInterface();
00146 
00147   // ...and the receiving class is NSMapTable or NSLocale, return that
00148   // class as the receiving interface.
00149   if (OID->getName() == "NSMapTable" ||
00150       OID->getName() == "NSLocale")
00151     return OID;
00152 
00153   return IFace;
00154 }
00155 
00156 static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
00157                                         const ObjCMessageExpr *Msg,
00158                                         ASTContext &Ctx,
00159                                         Selector subscriptSel) {
00160   const Expr *Rec = Msg->getInstanceReceiver();
00161   if (!Rec)
00162     return false;
00163   IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
00164 
00165   if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
00166     if (!MD->isUnavailable())
00167       return true;
00168   }
00169   return false;
00170 }
00171 
00172 static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
00173 
00174 static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
00175   if (subscriptOperatorNeedsParens(Receiver)) {
00176     SourceRange RecRange = Receiver->getSourceRange();
00177     commit.insertWrap("(", RecRange, ")");
00178   }
00179 }
00180 
00181 static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
00182                                         Commit &commit) {
00183   if (Msg->getNumArgs() != 1)
00184     return false;
00185   const Expr *Rec = Msg->getInstanceReceiver();
00186   if (!Rec)
00187     return false;
00188 
00189   SourceRange MsgRange = Msg->getSourceRange();
00190   SourceRange RecRange = Rec->getSourceRange();
00191   SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
00192 
00193   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
00194                                                        ArgRange.getBegin()),
00195                          CharSourceRange::getTokenRange(RecRange));
00196   commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
00197                          ArgRange);
00198   commit.insertWrap("[", ArgRange, "]");
00199   maybePutParensOnReceiver(Rec, commit);
00200   return true;
00201 }
00202 
00203 static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
00204                                        const ObjCMessageExpr *Msg,
00205                                        const NSAPI &NS,
00206                                        Commit &commit) {
00207   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
00208                                    NS.getObjectAtIndexedSubscriptSelector()))
00209     return false;
00210   return rewriteToSubscriptGetCommon(Msg, commit);
00211 }
00212 
00213 static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
00214                                             const ObjCMessageExpr *Msg,
00215                                             const NSAPI &NS,
00216                                             Commit &commit) {
00217   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
00218                                   NS.getObjectForKeyedSubscriptSelector()))
00219     return false;
00220   return rewriteToSubscriptGetCommon(Msg, commit);
00221 }
00222 
00223 static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
00224                                        const ObjCMessageExpr *Msg,
00225                                        const NSAPI &NS,
00226                                        Commit &commit) {
00227   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
00228                                    NS.getSetObjectAtIndexedSubscriptSelector()))
00229     return false;
00230 
00231   if (Msg->getNumArgs() != 2)
00232     return false;
00233   const Expr *Rec = Msg->getInstanceReceiver();
00234   if (!Rec)
00235     return false;
00236 
00237   SourceRange MsgRange = Msg->getSourceRange();
00238   SourceRange RecRange = Rec->getSourceRange();
00239   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
00240   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
00241 
00242   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
00243                                                        Arg0Range.getBegin()),
00244                          CharSourceRange::getTokenRange(RecRange));
00245   commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
00246                                                        Arg1Range.getBegin()),
00247                          CharSourceRange::getTokenRange(Arg0Range));
00248   commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
00249                          Arg1Range);
00250   commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
00251                                                        Arg1Range.getBegin()),
00252                     "] = ");
00253   maybePutParensOnReceiver(Rec, commit);
00254   return true;
00255 }
00256 
00257 static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
00258                                             const ObjCMessageExpr *Msg,
00259                                             const NSAPI &NS,
00260                                             Commit &commit) {
00261   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
00262                                    NS.getSetObjectForKeyedSubscriptSelector()))
00263     return false;
00264 
00265   if (Msg->getNumArgs() != 2)
00266     return false;
00267   const Expr *Rec = Msg->getInstanceReceiver();
00268   if (!Rec)
00269     return false;
00270 
00271   SourceRange MsgRange = Msg->getSourceRange();
00272   SourceRange RecRange = Rec->getSourceRange();
00273   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
00274   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
00275 
00276   SourceLocation LocBeforeVal = Arg0Range.getBegin();
00277   commit.insertBefore(LocBeforeVal, "] = ");
00278   commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
00279                          /*beforePreviousInsertions=*/true);
00280   commit.insertBefore(LocBeforeVal, "[");
00281   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
00282                                                        Arg0Range.getBegin()),
00283                          CharSourceRange::getTokenRange(RecRange));
00284   commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
00285                          Arg0Range);
00286   maybePutParensOnReceiver(Rec, commit);
00287   return true;
00288 }
00289 
00290 bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
00291                                         const NSAPI &NS, Commit &commit) {
00292   if (!Msg || Msg->isImplicit() ||
00293       Msg->getReceiverKind() != ObjCMessageExpr::Instance)
00294     return false;
00295   const ObjCMethodDecl *Method = Msg->getMethodDecl();
00296   if (!Method)
00297     return false;
00298 
00299   const ObjCInterfaceDecl *IFace =
00300       NS.getASTContext().getObjContainingInterface(Method);
00301   if (!IFace)
00302     return false;
00303   Selector Sel = Msg->getSelector();
00304 
00305   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
00306     return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
00307 
00308   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
00309     return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
00310 
00311   if (Msg->getNumArgs() != 2)
00312     return false;
00313 
00314   if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
00315     return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
00316 
00317   if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
00318     return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
00319 
00320   return false;
00321 }
00322 
00323 //===----------------------------------------------------------------------===//
00324 // rewriteToObjCLiteralSyntax.
00325 //===----------------------------------------------------------------------===//
00326 
00327 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
00328                                   const NSAPI &NS, Commit &commit,
00329                                   const ParentMap *PMap);
00330 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
00331                                   const NSAPI &NS, Commit &commit);
00332 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
00333                                   const NSAPI &NS, Commit &commit);
00334 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
00335                                             const NSAPI &NS, Commit &commit);
00336 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
00337                                            const NSAPI &NS, Commit &commit);
00338 
00339 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
00340                                       const NSAPI &NS, Commit &commit,
00341                                       const ParentMap *PMap) {
00342   IdentifierInfo *II = nullptr;
00343   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
00344     return false;
00345 
00346   if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
00347     return rewriteToArrayLiteral(Msg, NS, commit, PMap);
00348   if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
00349     return rewriteToDictionaryLiteral(Msg, NS, commit);
00350   if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
00351     return rewriteToNumberLiteral(Msg, NS, commit);
00352   if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
00353     return rewriteToStringBoxedExpression(Msg, NS, commit);
00354 
00355   return false;
00356 }
00357 
00358 /// \brief Returns true if the immediate message arguments of \c Msg should not
00359 /// be rewritten because it will interfere with the rewrite of the parent
00360 /// message expression. e.g.
00361 /// \code
00362 ///   [NSDictionary dictionaryWithObjects:
00363 ///                                 [NSArray arrayWithObjects:@"1", @"2", nil]
00364 ///                         forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
00365 /// \endcode
00366 /// It will return true for this because we are going to rewrite this directly
00367 /// to a dictionary literal without any array literals.
00368 static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
00369                                                  const NSAPI &NS);
00370 
00371 //===----------------------------------------------------------------------===//
00372 // rewriteToArrayLiteral.
00373 //===----------------------------------------------------------------------===//
00374 
00375 /// \brief Adds an explicit cast to 'id' if the type is not objc object.
00376 static void objectifyExpr(const Expr *E, Commit &commit);
00377 
00378 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
00379                                   const NSAPI &NS, Commit &commit,
00380                                   const ParentMap *PMap) {
00381   if (PMap) {
00382     const ObjCMessageExpr *ParentMsg =
00383         dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
00384     if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
00385       return false;
00386   }
00387 
00388   Selector Sel = Msg->getSelector();
00389   SourceRange MsgRange = Msg->getSourceRange();
00390 
00391   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
00392     if (Msg->getNumArgs() != 0)
00393       return false;
00394     commit.replace(MsgRange, "@[]");
00395     return true;
00396   }
00397 
00398   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
00399     if (Msg->getNumArgs() != 1)
00400       return false;
00401     objectifyExpr(Msg->getArg(0), commit);
00402     SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
00403     commit.replaceWithInner(MsgRange, ArgRange);
00404     commit.insertWrap("@[", ArgRange, "]");
00405     return true;
00406   }
00407 
00408   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
00409       Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
00410     if (Msg->getNumArgs() == 0)
00411       return false;
00412     const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
00413     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
00414       return false;
00415 
00416     for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
00417       objectifyExpr(Msg->getArg(i), commit);
00418 
00419     if (Msg->getNumArgs() == 1) {
00420       commit.replace(MsgRange, "@[]");
00421       return true;
00422     }
00423     SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
00424                          Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
00425     commit.replaceWithInner(MsgRange, ArgRange);
00426     commit.insertWrap("@[", ArgRange, "]");
00427     return true;
00428   }
00429 
00430   return false;
00431 }
00432 
00433 //===----------------------------------------------------------------------===//
00434 // rewriteToDictionaryLiteral.
00435 //===----------------------------------------------------------------------===//
00436 
00437 /// \brief If \c Msg is an NSArray creation message or literal, this gets the
00438 /// objects that were used to create it.
00439 /// \returns true if it is an NSArray and we got objects, or false otherwise.
00440 static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
00441                               SmallVectorImpl<const Expr *> &Objs) {
00442   if (!E)
00443     return false;
00444 
00445   E = E->IgnoreParenCasts();
00446   if (!E)
00447     return false;
00448 
00449   if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
00450     IdentifierInfo *Cls = nullptr;
00451     if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
00452       return false;
00453 
00454     if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
00455       return false;
00456 
00457     Selector Sel = Msg->getSelector();
00458     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
00459       return true; // empty array.
00460 
00461     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
00462       if (Msg->getNumArgs() != 1)
00463         return false;
00464       Objs.push_back(Msg->getArg(0));
00465       return true;
00466     }
00467 
00468     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
00469         Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
00470       if (Msg->getNumArgs() == 0)
00471         return false;
00472       const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
00473       if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
00474         return false;
00475 
00476       for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
00477         Objs.push_back(Msg->getArg(i));
00478       return true;
00479     }
00480 
00481   } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
00482     for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
00483       Objs.push_back(ArrLit->getElement(i));
00484     return true;
00485   }
00486 
00487   return false;
00488 }
00489 
00490 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
00491                                        const NSAPI &NS, Commit &commit) {
00492   Selector Sel = Msg->getSelector();
00493   SourceRange MsgRange = Msg->getSourceRange();
00494 
00495   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
00496     if (Msg->getNumArgs() != 0)
00497       return false;
00498     commit.replace(MsgRange, "@{}");
00499     return true;
00500   }
00501 
00502   if (Sel == NS.getNSDictionarySelector(
00503                                     NSAPI::NSDict_dictionaryWithObjectForKey)) {
00504     if (Msg->getNumArgs() != 2)
00505       return false;
00506 
00507     objectifyExpr(Msg->getArg(0), commit);
00508     objectifyExpr(Msg->getArg(1), commit);
00509 
00510     SourceRange ValRange = Msg->getArg(0)->getSourceRange();
00511     SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
00512     // Insert key before the value.
00513     commit.insertBefore(ValRange.getBegin(), ": ");
00514     commit.insertFromRange(ValRange.getBegin(),
00515                            CharSourceRange::getTokenRange(KeyRange),
00516                        /*afterToken=*/false, /*beforePreviousInsertions=*/true);
00517     commit.insertBefore(ValRange.getBegin(), "@{");
00518     commit.insertAfterToken(ValRange.getEnd(), "}");
00519     commit.replaceWithInner(MsgRange, ValRange);
00520     return true;
00521   }
00522 
00523   if (Sel == NS.getNSDictionarySelector(
00524                                   NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
00525       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
00526     if (Msg->getNumArgs() % 2 != 1)
00527       return false;
00528     unsigned SentinelIdx = Msg->getNumArgs() - 1;
00529     const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
00530     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
00531       return false;
00532 
00533     if (Msg->getNumArgs() == 1) {
00534       commit.replace(MsgRange, "@{}");
00535       return true;
00536     }
00537 
00538     for (unsigned i = 0; i < SentinelIdx; i += 2) {
00539       objectifyExpr(Msg->getArg(i), commit);
00540       objectifyExpr(Msg->getArg(i+1), commit);
00541 
00542       SourceRange ValRange = Msg->getArg(i)->getSourceRange();
00543       SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
00544       // Insert value after key.
00545       commit.insertAfterToken(KeyRange.getEnd(), ": ");
00546       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
00547       commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
00548                                                   KeyRange.getBegin()));
00549     }
00550     // Range of arguments up until and including the last key.
00551     // The sentinel and first value are cut off, the value will move after the
00552     // key.
00553     SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
00554                          Msg->getArg(SentinelIdx-1)->getLocEnd());
00555     commit.insertWrap("@{", ArgRange, "}");
00556     commit.replaceWithInner(MsgRange, ArgRange);
00557     return true;
00558   }
00559 
00560   if (Sel == NS.getNSDictionarySelector(
00561                                   NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
00562       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
00563     if (Msg->getNumArgs() != 2)
00564       return false;
00565 
00566     SmallVector<const Expr *, 8> Vals;
00567     if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
00568       return false;
00569 
00570     SmallVector<const Expr *, 8> Keys;
00571     if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
00572       return false;
00573 
00574     if (Vals.size() != Keys.size())
00575       return false;
00576 
00577     if (Vals.empty()) {
00578       commit.replace(MsgRange, "@{}");
00579       return true;
00580     }
00581 
00582     for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
00583       objectifyExpr(Vals[i], commit);
00584       objectifyExpr(Keys[i], commit);
00585 
00586       SourceRange ValRange = Vals[i]->getSourceRange();
00587       SourceRange KeyRange = Keys[i]->getSourceRange();
00588       // Insert value after key.
00589       commit.insertAfterToken(KeyRange.getEnd(), ": ");
00590       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
00591     }
00592     // Range of arguments up until and including the last key.
00593     // The first value is cut off, the value will move after the key.
00594     SourceRange ArgRange(Keys.front()->getLocStart(),
00595                          Keys.back()->getLocEnd());
00596     commit.insertWrap("@{", ArgRange, "}");
00597     commit.replaceWithInner(MsgRange, ArgRange);
00598     return true;
00599   }
00600 
00601   return false;
00602 }
00603 
00604 static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
00605                                                  const NSAPI &NS) {
00606   if (!Msg)
00607     return false;
00608 
00609   IdentifierInfo *II = nullptr;
00610   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
00611     return false;
00612 
00613   if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
00614     return false;
00615 
00616   Selector Sel = Msg->getSelector();
00617   if (Sel == NS.getNSDictionarySelector(
00618                                   NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
00619       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
00620     if (Msg->getNumArgs() != 2)
00621       return false;
00622 
00623     SmallVector<const Expr *, 8> Vals;
00624     if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
00625       return false;
00626 
00627     SmallVector<const Expr *, 8> Keys;
00628     if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
00629       return false;
00630 
00631     if (Vals.size() != Keys.size())
00632       return false;
00633 
00634     return true;
00635   }
00636 
00637   return false;
00638 }
00639 
00640 //===----------------------------------------------------------------------===//
00641 // rewriteToNumberLiteral.
00642 //===----------------------------------------------------------------------===//
00643 
00644 static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
00645                                    const CharacterLiteral *Arg,
00646                                    const NSAPI &NS, Commit &commit) {
00647   if (Arg->getKind() != CharacterLiteral::Ascii)
00648     return false;
00649   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
00650                                    Msg->getSelector())) {
00651     SourceRange ArgRange = Arg->getSourceRange();
00652     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
00653     commit.insert(ArgRange.getBegin(), "@");
00654     return true;
00655   }
00656 
00657   return rewriteToNumericBoxedExpression(Msg, NS, commit);
00658 }
00659 
00660 static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
00661                                    const Expr *Arg,
00662                                    const NSAPI &NS, Commit &commit) {
00663   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
00664                                    Msg->getSelector())) {
00665     SourceRange ArgRange = Arg->getSourceRange();
00666     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
00667     commit.insert(ArgRange.getBegin(), "@");
00668     return true;
00669   }
00670 
00671   return rewriteToNumericBoxedExpression(Msg, NS, commit);
00672 }
00673 
00674 namespace {
00675 
00676 struct LiteralInfo {
00677   bool Hex, Octal;
00678   StringRef U, F, L, LL;
00679   CharSourceRange WithoutSuffRange;
00680 };
00681 
00682 }
00683 
00684 static bool getLiteralInfo(SourceRange literalRange,
00685                            bool isFloat, bool isIntZero,
00686                           ASTContext &Ctx, LiteralInfo &Info) {
00687   if (literalRange.getBegin().isMacroID() ||
00688       literalRange.getEnd().isMacroID())
00689     return false;
00690   StringRef text = Lexer::getSourceText(
00691                                   CharSourceRange::getTokenRange(literalRange),
00692                                   Ctx.getSourceManager(), Ctx.getLangOpts());
00693   if (text.empty())
00694     return false;
00695 
00696   Optional<bool> UpperU, UpperL;
00697   bool UpperF = false;
00698 
00699   struct Suff {
00700     static bool has(StringRef suff, StringRef &text) {
00701       if (text.endswith(suff)) {
00702         text = text.substr(0, text.size()-suff.size());
00703         return true;
00704       }
00705       return false;
00706     }
00707   };
00708 
00709   while (1) {
00710     if (Suff::has("u", text)) {
00711       UpperU = false;
00712     } else if (Suff::has("U", text)) {
00713       UpperU = true;
00714     } else if (Suff::has("ll", text)) {
00715       UpperL = false;
00716     } else if (Suff::has("LL", text)) {
00717       UpperL = true;
00718     } else if (Suff::has("l", text)) {
00719       UpperL = false;
00720     } else if (Suff::has("L", text)) {
00721       UpperL = true;
00722     } else if (isFloat && Suff::has("f", text)) {
00723       UpperF = false;
00724     } else if (isFloat && Suff::has("F", text)) {
00725       UpperF = true;
00726     } else
00727       break;
00728   }
00729   
00730   if (!UpperU.hasValue() && !UpperL.hasValue())
00731     UpperU = UpperL = true;
00732   else if (UpperU.hasValue() && !UpperL.hasValue())
00733     UpperL = UpperU;
00734   else if (UpperL.hasValue() && !UpperU.hasValue())
00735     UpperU = UpperL;
00736 
00737   Info.U = *UpperU ? "U" : "u";
00738   Info.L = *UpperL ? "L" : "l";
00739   Info.LL = *UpperL ? "LL" : "ll";
00740   Info.F = UpperF ? "F" : "f";
00741   
00742   Info.Hex = Info.Octal = false;
00743   if (text.startswith("0x"))
00744     Info.Hex = true;
00745   else if (!isFloat && !isIntZero && text.startswith("0"))
00746     Info.Octal = true;
00747 
00748   SourceLocation B = literalRange.getBegin();
00749   Info.WithoutSuffRange =
00750       CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
00751   return true;
00752 }
00753 
00754 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
00755                                    const NSAPI &NS, Commit &commit) {
00756   if (Msg->getNumArgs() != 1)
00757     return false;
00758 
00759   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
00760   if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
00761     return rewriteToCharLiteral(Msg, CharE, NS, commit);
00762   if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
00763     return rewriteToBoolLiteral(Msg, BE, NS, commit);
00764   if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
00765     return rewriteToBoolLiteral(Msg, BE, NS, commit);
00766 
00767   const Expr *literalE = Arg;
00768   if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
00769     if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
00770       literalE = UOE->getSubExpr();
00771   }
00772 
00773   // Only integer and floating literals, otherwise try to rewrite to boxed
00774   // expression.
00775   if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
00776     return rewriteToNumericBoxedExpression(Msg, NS, commit);
00777 
00778   ASTContext &Ctx = NS.getASTContext();
00779   Selector Sel = Msg->getSelector();
00780   Optional<NSAPI::NSNumberLiteralMethodKind>
00781     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
00782   if (!MKOpt)
00783     return false;
00784   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
00785 
00786   bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
00787   bool CallIsFloating = false, CallIsDouble = false;
00788 
00789   switch (MK) {
00790   // We cannot have these calls with int/float literals.
00791   case NSAPI::NSNumberWithChar:
00792   case NSAPI::NSNumberWithUnsignedChar:
00793   case NSAPI::NSNumberWithShort:
00794   case NSAPI::NSNumberWithUnsignedShort:
00795   case NSAPI::NSNumberWithBool:
00796     return rewriteToNumericBoxedExpression(Msg, NS, commit);
00797 
00798   case NSAPI::NSNumberWithUnsignedInt:
00799   case NSAPI::NSNumberWithUnsignedInteger:
00800     CallIsUnsigned = true;
00801   case NSAPI::NSNumberWithInt:
00802   case NSAPI::NSNumberWithInteger:
00803     break;
00804 
00805   case NSAPI::NSNumberWithUnsignedLong:
00806     CallIsUnsigned = true;
00807   case NSAPI::NSNumberWithLong:
00808     CallIsLong = true;
00809     break;
00810 
00811   case NSAPI::NSNumberWithUnsignedLongLong:
00812     CallIsUnsigned = true;
00813   case NSAPI::NSNumberWithLongLong:
00814     CallIsLongLong = true;
00815     break;
00816 
00817   case NSAPI::NSNumberWithDouble:
00818     CallIsDouble = true;
00819   case NSAPI::NSNumberWithFloat:
00820     CallIsFloating = true;
00821     break;
00822   }
00823 
00824   SourceRange ArgRange = Arg->getSourceRange();
00825   QualType ArgTy = Arg->getType();
00826   QualType CallTy = Msg->getArg(0)->getType();
00827 
00828   // Check for the easy case, the literal maps directly to the call.
00829   if (Ctx.hasSameType(ArgTy, CallTy)) {
00830     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
00831     commit.insert(ArgRange.getBegin(), "@");
00832     return true;
00833   }
00834 
00835   // We will need to modify the literal suffix to get the same type as the call.
00836   // Try with boxed expression if it came from a macro.
00837   if (ArgRange.getBegin().isMacroID())
00838     return rewriteToNumericBoxedExpression(Msg, NS, commit);
00839 
00840   bool LitIsFloat = ArgTy->isFloatingType();
00841   // For a float passed to integer call, don't try rewriting to objc literal.
00842   // It is difficult and a very uncommon case anyway.
00843   // But try with boxed expression.
00844   if (LitIsFloat && !CallIsFloating)
00845     return rewriteToNumericBoxedExpression(Msg, NS, commit);
00846 
00847   // Try to modify the literal make it the same type as the method call.
00848   // -Modify the suffix, and/or
00849   // -Change integer to float
00850   
00851   LiteralInfo LitInfo;
00852   bool isIntZero = false;
00853   if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
00854     isIntZero = !IntE->getValue().getBoolValue();
00855   if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
00856     return rewriteToNumericBoxedExpression(Msg, NS, commit);
00857 
00858   // Not easy to do int -> float with hex/octal and uncommon anyway.
00859   if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
00860     return rewriteToNumericBoxedExpression(Msg, NS, commit);
00861   
00862   SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
00863   SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
00864 
00865   commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
00866                          LitInfo.WithoutSuffRange);
00867   commit.insert(LitB, "@");
00868 
00869   if (!LitIsFloat && CallIsFloating)
00870     commit.insert(LitE, ".0");
00871 
00872   if (CallIsFloating) {
00873     if (!CallIsDouble)
00874       commit.insert(LitE, LitInfo.F);
00875   } else {
00876     if (CallIsUnsigned)
00877       commit.insert(LitE, LitInfo.U);
00878   
00879     if (CallIsLong)
00880       commit.insert(LitE, LitInfo.L);
00881     else if (CallIsLongLong)
00882       commit.insert(LitE, LitInfo.LL);
00883   }
00884   return true;
00885 }
00886 
00887 // FIXME: Make determination of operator precedence more general and
00888 // make it broadly available.
00889 static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
00890   const Expr* Expr = FullExpr->IgnoreImpCasts();
00891   if (isa<ArraySubscriptExpr>(Expr) ||
00892       isa<CallExpr>(Expr) ||
00893       isa<DeclRefExpr>(Expr) ||
00894       isa<CXXNamedCastExpr>(Expr) ||
00895       isa<CXXConstructExpr>(Expr) ||
00896       isa<CXXThisExpr>(Expr) ||
00897       isa<CXXTypeidExpr>(Expr) ||
00898       isa<CXXUnresolvedConstructExpr>(Expr) ||
00899       isa<ObjCMessageExpr>(Expr) ||
00900       isa<ObjCPropertyRefExpr>(Expr) ||
00901       isa<ObjCProtocolExpr>(Expr) ||
00902       isa<MemberExpr>(Expr) ||
00903       isa<ObjCIvarRefExpr>(Expr) ||
00904       isa<ParenExpr>(FullExpr) ||
00905       isa<ParenListExpr>(Expr) ||
00906       isa<SizeOfPackExpr>(Expr))
00907     return false;
00908 
00909   return true;
00910 }
00911 static bool castOperatorNeedsParens(const Expr *FullExpr) {
00912   const Expr* Expr = FullExpr->IgnoreImpCasts();
00913   if (isa<ArraySubscriptExpr>(Expr) ||
00914       isa<CallExpr>(Expr) ||
00915       isa<DeclRefExpr>(Expr) ||
00916       isa<CastExpr>(Expr) ||
00917       isa<CXXNewExpr>(Expr) ||
00918       isa<CXXConstructExpr>(Expr) ||
00919       isa<CXXDeleteExpr>(Expr) ||
00920       isa<CXXNoexceptExpr>(Expr) ||
00921       isa<CXXPseudoDestructorExpr>(Expr) ||
00922       isa<CXXScalarValueInitExpr>(Expr) ||
00923       isa<CXXThisExpr>(Expr) ||
00924       isa<CXXTypeidExpr>(Expr) ||
00925       isa<CXXUnresolvedConstructExpr>(Expr) ||
00926       isa<ObjCMessageExpr>(Expr) ||
00927       isa<ObjCPropertyRefExpr>(Expr) ||
00928       isa<ObjCProtocolExpr>(Expr) ||
00929       isa<MemberExpr>(Expr) ||
00930       isa<ObjCIvarRefExpr>(Expr) ||
00931       isa<ParenExpr>(FullExpr) ||
00932       isa<ParenListExpr>(Expr) ||
00933       isa<SizeOfPackExpr>(Expr) ||
00934       isa<UnaryOperator>(Expr))
00935     return false;
00936 
00937   return true;
00938 }
00939 
00940 static void objectifyExpr(const Expr *E, Commit &commit) {
00941   if (!E) return;
00942 
00943   QualType T = E->getType();
00944   if (T->isObjCObjectPointerType()) {
00945     if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
00946       if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
00947         return;
00948     } else {
00949       return;
00950     }
00951   } else if (!T->isPointerType()) {
00952     return;
00953   }
00954 
00955   SourceRange Range = E->getSourceRange();
00956   if (castOperatorNeedsParens(E))
00957     commit.insertWrap("(", Range, ")");
00958   commit.insertBefore(Range.getBegin(), "(id)");
00959 }
00960 
00961 //===----------------------------------------------------------------------===//
00962 // rewriteToNumericBoxedExpression.
00963 //===----------------------------------------------------------------------===//
00964 
00965 static bool isEnumConstant(const Expr *E) {
00966   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
00967     if (const ValueDecl *VD = DRE->getDecl())
00968       return isa<EnumConstantDecl>(VD);
00969 
00970   return false;
00971 }
00972 
00973 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
00974                                             const NSAPI &NS, Commit &commit) {
00975   if (Msg->getNumArgs() != 1)
00976     return false;
00977 
00978   const Expr *Arg = Msg->getArg(0);
00979   if (Arg->isTypeDependent())
00980     return false;
00981 
00982   ASTContext &Ctx = NS.getASTContext();
00983   Selector Sel = Msg->getSelector();
00984   Optional<NSAPI::NSNumberLiteralMethodKind>
00985     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
00986   if (!MKOpt)
00987     return false;
00988   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
00989 
00990   const Expr *OrigArg = Arg->IgnoreImpCasts();
00991   QualType FinalTy = Arg->getType();
00992   QualType OrigTy = OrigArg->getType();
00993   uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
00994   uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
00995 
00996   bool isTruncated = FinalTySize < OrigTySize; 
00997   bool needsCast = false;
00998 
00999   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
01000     switch (ICE->getCastKind()) {
01001     case CK_LValueToRValue:
01002     case CK_NoOp:
01003     case CK_UserDefinedConversion:
01004       break;
01005 
01006     case CK_IntegralCast: {
01007       if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
01008         break;
01009       // Be more liberal with Integer/UnsignedInteger which are very commonly
01010       // used.
01011       if ((MK == NSAPI::NSNumberWithInteger ||
01012            MK == NSAPI::NSNumberWithUnsignedInteger) &&
01013           !isTruncated) {
01014         if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
01015           break;
01016         if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
01017             OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
01018           break;
01019       }
01020 
01021       needsCast = true;
01022       break;
01023     }
01024 
01025     case CK_PointerToBoolean:
01026     case CK_IntegralToBoolean:
01027     case CK_IntegralToFloating:
01028     case CK_FloatingToIntegral:
01029     case CK_FloatingToBoolean:
01030     case CK_FloatingCast:
01031     case CK_FloatingComplexToReal:
01032     case CK_FloatingComplexToBoolean:
01033     case CK_IntegralComplexToReal:
01034     case CK_IntegralComplexToBoolean:
01035     case CK_AtomicToNonAtomic:
01036     case CK_AddressSpaceConversion:
01037       needsCast = true;
01038       break;
01039 
01040     case CK_Dependent:
01041     case CK_BitCast:
01042     case CK_LValueBitCast:
01043     case CK_BaseToDerived:
01044     case CK_DerivedToBase:
01045     case CK_UncheckedDerivedToBase:
01046     case CK_Dynamic:
01047     case CK_ToUnion:
01048     case CK_ArrayToPointerDecay:
01049     case CK_FunctionToPointerDecay:
01050     case CK_NullToPointer:
01051     case CK_NullToMemberPointer:
01052     case CK_BaseToDerivedMemberPointer:
01053     case CK_DerivedToBaseMemberPointer:
01054     case CK_MemberPointerToBoolean:
01055     case CK_ReinterpretMemberPointer:
01056     case CK_ConstructorConversion:
01057     case CK_IntegralToPointer:
01058     case CK_PointerToIntegral:
01059     case CK_ToVoid:
01060     case CK_VectorSplat:
01061     case CK_CPointerToObjCPointerCast:
01062     case CK_BlockPointerToObjCPointerCast:
01063     case CK_AnyPointerToBlockPointerCast:
01064     case CK_ObjCObjectLValueCast:
01065     case CK_FloatingRealToComplex:
01066     case CK_FloatingComplexCast:
01067     case CK_FloatingComplexToIntegralComplex:
01068     case CK_IntegralRealToComplex:
01069     case CK_IntegralComplexCast:
01070     case CK_IntegralComplexToFloatingComplex:
01071     case CK_ARCProduceObject:
01072     case CK_ARCConsumeObject:
01073     case CK_ARCReclaimReturnedObject:
01074     case CK_ARCExtendBlockObject:
01075     case CK_NonAtomicToAtomic:
01076     case CK_CopyAndAutoreleaseBlockObject:
01077     case CK_BuiltinFnToFnPtr:
01078     case CK_ZeroToOCLEvent:
01079       return false;
01080     }
01081   }
01082 
01083   if (needsCast) {
01084     DiagnosticsEngine &Diags = Ctx.getDiagnostics(); 
01085     // FIXME: Use a custom category name to distinguish migration diagnostics.
01086     unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
01087                        "converting to boxing syntax requires casting %0 to %1");
01088     Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
01089         << Msg->getSourceRange();
01090     return false;
01091   }
01092 
01093   SourceRange ArgRange = OrigArg->getSourceRange();
01094   commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
01095 
01096   if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
01097     commit.insertBefore(ArgRange.getBegin(), "@");
01098   else
01099     commit.insertWrap("@(", ArgRange, ")");
01100 
01101   return true;
01102 }
01103 
01104 //===----------------------------------------------------------------------===//
01105 // rewriteToStringBoxedExpression.
01106 //===----------------------------------------------------------------------===//
01107 
01108 static bool doRewriteToUTF8StringBoxedExpressionHelper(
01109                                               const ObjCMessageExpr *Msg,
01110                                               const NSAPI &NS, Commit &commit) {
01111   const Expr *Arg = Msg->getArg(0);
01112   if (Arg->isTypeDependent())
01113     return false;
01114 
01115   ASTContext &Ctx = NS.getASTContext();
01116 
01117   const Expr *OrigArg = Arg->IgnoreImpCasts();
01118   QualType OrigTy = OrigArg->getType();
01119   if (OrigTy->isArrayType())
01120     OrigTy = Ctx.getArrayDecayedType(OrigTy);
01121 
01122   if (const StringLiteral *
01123         StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
01124     commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
01125     commit.insert(StrE->getLocStart(), "@");
01126     return true;
01127   }
01128 
01129   if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
01130     QualType PointeeType = PT->getPointeeType();
01131     if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
01132       SourceRange ArgRange = OrigArg->getSourceRange();
01133       commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
01134 
01135       if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
01136         commit.insertBefore(ArgRange.getBegin(), "@");
01137       else
01138         commit.insertWrap("@(", ArgRange, ")");
01139       
01140       return true;
01141     }
01142   }
01143 
01144   return false;
01145 }
01146 
01147 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
01148                                            const NSAPI &NS, Commit &commit) {
01149   Selector Sel = Msg->getSelector();
01150 
01151   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
01152       Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString) ||
01153       Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)) {
01154     if (Msg->getNumArgs() != 1)
01155       return false;
01156     return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
01157   }
01158 
01159   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
01160     if (Msg->getNumArgs() != 2)
01161       return false;
01162 
01163     const Expr *encodingArg = Msg->getArg(1);
01164     if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
01165         NS.isNSASCIIStringEncodingConstant(encodingArg))
01166       return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
01167   }
01168 
01169   return false;
01170 }