xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Edit/RewriteObjCFoundationAPI.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Rewrites legacy method calls to modern syntax.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg 
137330f729Sjoerg #include "clang/Edit/Rewriters.h"
147330f729Sjoerg #include "clang/AST/ASTContext.h"
157330f729Sjoerg #include "clang/AST/ExprCXX.h"
167330f729Sjoerg #include "clang/AST/ExprObjC.h"
177330f729Sjoerg #include "clang/AST/NSAPI.h"
187330f729Sjoerg #include "clang/AST/ParentMap.h"
197330f729Sjoerg #include "clang/Edit/Commit.h"
207330f729Sjoerg #include "clang/Lex/Lexer.h"
217330f729Sjoerg 
227330f729Sjoerg using namespace clang;
237330f729Sjoerg using namespace edit;
247330f729Sjoerg 
checkForLiteralCreation(const ObjCMessageExpr * Msg,IdentifierInfo * & ClassId,const LangOptions & LangOpts)257330f729Sjoerg static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
267330f729Sjoerg                                     IdentifierInfo *&ClassId,
277330f729Sjoerg                                     const LangOptions &LangOpts) {
287330f729Sjoerg   if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
297330f729Sjoerg     return false;
307330f729Sjoerg 
317330f729Sjoerg   const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
327330f729Sjoerg   if (!Receiver)
337330f729Sjoerg     return false;
347330f729Sjoerg   ClassId = Receiver->getIdentifier();
357330f729Sjoerg 
367330f729Sjoerg   if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
377330f729Sjoerg     return true;
387330f729Sjoerg 
397330f729Sjoerg   // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
407330f729Sjoerg   // since the change from +1 to +0 will be handled fine by ARC.
417330f729Sjoerg   if (LangOpts.ObjCAutoRefCount) {
427330f729Sjoerg     if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
437330f729Sjoerg       if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
447330f729Sjoerg                            Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
457330f729Sjoerg         if (Rec->getMethodFamily() == OMF_alloc)
467330f729Sjoerg           return true;
477330f729Sjoerg       }
487330f729Sjoerg     }
497330f729Sjoerg   }
507330f729Sjoerg 
517330f729Sjoerg   return false;
527330f729Sjoerg }
537330f729Sjoerg 
547330f729Sjoerg //===----------------------------------------------------------------------===//
557330f729Sjoerg // rewriteObjCRedundantCallWithLiteral.
567330f729Sjoerg //===----------------------------------------------------------------------===//
577330f729Sjoerg 
rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)587330f729Sjoerg bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
597330f729Sjoerg                                               const NSAPI &NS, Commit &commit) {
607330f729Sjoerg   IdentifierInfo *II = nullptr;
617330f729Sjoerg   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
627330f729Sjoerg     return false;
637330f729Sjoerg   if (Msg->getNumArgs() != 1)
647330f729Sjoerg     return false;
657330f729Sjoerg 
667330f729Sjoerg   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
677330f729Sjoerg   Selector Sel = Msg->getSelector();
687330f729Sjoerg 
697330f729Sjoerg   if ((isa<ObjCStringLiteral>(Arg) &&
707330f729Sjoerg        NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
717330f729Sjoerg        (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
727330f729Sjoerg         NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel))   ||
737330f729Sjoerg 
747330f729Sjoerg       (isa<ObjCArrayLiteral>(Arg) &&
757330f729Sjoerg        NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
767330f729Sjoerg        (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
777330f729Sjoerg         NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel))     ||
787330f729Sjoerg 
797330f729Sjoerg       (isa<ObjCDictionaryLiteral>(Arg) &&
807330f729Sjoerg        NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
817330f729Sjoerg        (NS.getNSDictionarySelector(
827330f729Sjoerg                               NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
837330f729Sjoerg         NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
847330f729Sjoerg 
857330f729Sjoerg     commit.replaceWithInner(Msg->getSourceRange(),
867330f729Sjoerg                            Msg->getArg(0)->getSourceRange());
877330f729Sjoerg     return true;
887330f729Sjoerg   }
897330f729Sjoerg 
907330f729Sjoerg   return false;
917330f729Sjoerg }
927330f729Sjoerg 
937330f729Sjoerg //===----------------------------------------------------------------------===//
947330f729Sjoerg // rewriteToObjCSubscriptSyntax.
957330f729Sjoerg //===----------------------------------------------------------------------===//
967330f729Sjoerg 
977330f729Sjoerg /// Check for classes that accept 'objectForKey:' (or the other selectors
987330f729Sjoerg /// that the migrator handles) but return their instances as 'id', resulting
997330f729Sjoerg /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
1007330f729Sjoerg ///
1017330f729Sjoerg /// When checking if we can convert to subscripting syntax, check whether
1027330f729Sjoerg /// the receiver is a result of a class method from a hardcoded list of
1037330f729Sjoerg /// such classes. In such a case return the specific class as the interface
1047330f729Sjoerg /// of the receiver.
1057330f729Sjoerg ///
1067330f729Sjoerg /// FIXME: Remove this when these classes start using 'instancetype'.
1077330f729Sjoerg static const ObjCInterfaceDecl *
maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl * IFace,const Expr * Receiver,ASTContext & Ctx)1087330f729Sjoerg maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
1097330f729Sjoerg                                          const Expr *Receiver,
1107330f729Sjoerg                                          ASTContext &Ctx) {
1117330f729Sjoerg   assert(IFace && Receiver);
1127330f729Sjoerg 
1137330f729Sjoerg   // If the receiver has type 'id'...
1147330f729Sjoerg   if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
1157330f729Sjoerg     return IFace;
1167330f729Sjoerg 
1177330f729Sjoerg   const ObjCMessageExpr *
1187330f729Sjoerg     InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
1197330f729Sjoerg   if (!InnerMsg)
1207330f729Sjoerg     return IFace;
1217330f729Sjoerg 
1227330f729Sjoerg   QualType ClassRec;
1237330f729Sjoerg   switch (InnerMsg->getReceiverKind()) {
1247330f729Sjoerg   case ObjCMessageExpr::Instance:
1257330f729Sjoerg   case ObjCMessageExpr::SuperInstance:
1267330f729Sjoerg     return IFace;
1277330f729Sjoerg 
1287330f729Sjoerg   case ObjCMessageExpr::Class:
1297330f729Sjoerg     ClassRec = InnerMsg->getClassReceiver();
1307330f729Sjoerg     break;
1317330f729Sjoerg   case ObjCMessageExpr::SuperClass:
1327330f729Sjoerg     ClassRec = InnerMsg->getSuperType();
1337330f729Sjoerg     break;
1347330f729Sjoerg   }
1357330f729Sjoerg 
1367330f729Sjoerg   if (ClassRec.isNull())
1377330f729Sjoerg     return IFace;
1387330f729Sjoerg 
1397330f729Sjoerg   // ...and it is the result of a class message...
1407330f729Sjoerg 
1417330f729Sjoerg   const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
1427330f729Sjoerg   if (!ObjTy)
1437330f729Sjoerg     return IFace;
1447330f729Sjoerg   const ObjCInterfaceDecl *OID = ObjTy->getInterface();
1457330f729Sjoerg 
1467330f729Sjoerg   // ...and the receiving class is NSMapTable or NSLocale, return that
1477330f729Sjoerg   // class as the receiving interface.
1487330f729Sjoerg   if (OID->getName() == "NSMapTable" ||
1497330f729Sjoerg       OID->getName() == "NSLocale")
1507330f729Sjoerg     return OID;
1517330f729Sjoerg 
1527330f729Sjoerg   return IFace;
1537330f729Sjoerg }
1547330f729Sjoerg 
canRewriteToSubscriptSyntax(const ObjCInterfaceDecl * & IFace,const ObjCMessageExpr * Msg,ASTContext & Ctx,Selector subscriptSel)1557330f729Sjoerg static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
1567330f729Sjoerg                                         const ObjCMessageExpr *Msg,
1577330f729Sjoerg                                         ASTContext &Ctx,
1587330f729Sjoerg                                         Selector subscriptSel) {
1597330f729Sjoerg   const Expr *Rec = Msg->getInstanceReceiver();
1607330f729Sjoerg   if (!Rec)
1617330f729Sjoerg     return false;
1627330f729Sjoerg   IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
1637330f729Sjoerg 
1647330f729Sjoerg   if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
1657330f729Sjoerg     if (!MD->isUnavailable())
1667330f729Sjoerg       return true;
1677330f729Sjoerg   }
1687330f729Sjoerg   return false;
1697330f729Sjoerg }
1707330f729Sjoerg 
1717330f729Sjoerg static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
1727330f729Sjoerg 
maybePutParensOnReceiver(const Expr * Receiver,Commit & commit)1737330f729Sjoerg static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
1747330f729Sjoerg   if (subscriptOperatorNeedsParens(Receiver)) {
1757330f729Sjoerg     SourceRange RecRange = Receiver->getSourceRange();
1767330f729Sjoerg     commit.insertWrap("(", RecRange, ")");
1777330f729Sjoerg   }
1787330f729Sjoerg }
1797330f729Sjoerg 
rewriteToSubscriptGetCommon(const ObjCMessageExpr * Msg,Commit & commit)1807330f729Sjoerg static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
1817330f729Sjoerg                                         Commit &commit) {
1827330f729Sjoerg   if (Msg->getNumArgs() != 1)
1837330f729Sjoerg     return false;
1847330f729Sjoerg   const Expr *Rec = Msg->getInstanceReceiver();
1857330f729Sjoerg   if (!Rec)
1867330f729Sjoerg     return false;
1877330f729Sjoerg 
1887330f729Sjoerg   SourceRange MsgRange = Msg->getSourceRange();
1897330f729Sjoerg   SourceRange RecRange = Rec->getSourceRange();
1907330f729Sjoerg   SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
1917330f729Sjoerg 
1927330f729Sjoerg   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
1937330f729Sjoerg                                                        ArgRange.getBegin()),
1947330f729Sjoerg                          CharSourceRange::getTokenRange(RecRange));
1957330f729Sjoerg   commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
1967330f729Sjoerg                          ArgRange);
1977330f729Sjoerg   commit.insertWrap("[", ArgRange, "]");
1987330f729Sjoerg   maybePutParensOnReceiver(Rec, commit);
1997330f729Sjoerg   return true;
2007330f729Sjoerg }
2017330f729Sjoerg 
rewriteToArraySubscriptGet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2027330f729Sjoerg static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
2037330f729Sjoerg                                        const ObjCMessageExpr *Msg,
2047330f729Sjoerg                                        const NSAPI &NS,
2057330f729Sjoerg                                        Commit &commit) {
2067330f729Sjoerg   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
2077330f729Sjoerg                                    NS.getObjectAtIndexedSubscriptSelector()))
2087330f729Sjoerg     return false;
2097330f729Sjoerg   return rewriteToSubscriptGetCommon(Msg, commit);
2107330f729Sjoerg }
2117330f729Sjoerg 
rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2127330f729Sjoerg static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
2137330f729Sjoerg                                             const ObjCMessageExpr *Msg,
2147330f729Sjoerg                                             const NSAPI &NS,
2157330f729Sjoerg                                             Commit &commit) {
2167330f729Sjoerg   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
2177330f729Sjoerg                                   NS.getObjectForKeyedSubscriptSelector()))
2187330f729Sjoerg     return false;
2197330f729Sjoerg   return rewriteToSubscriptGetCommon(Msg, commit);
2207330f729Sjoerg }
2217330f729Sjoerg 
rewriteToArraySubscriptSet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2227330f729Sjoerg static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
2237330f729Sjoerg                                        const ObjCMessageExpr *Msg,
2247330f729Sjoerg                                        const NSAPI &NS,
2257330f729Sjoerg                                        Commit &commit) {
2267330f729Sjoerg   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
2277330f729Sjoerg                                    NS.getSetObjectAtIndexedSubscriptSelector()))
2287330f729Sjoerg     return false;
2297330f729Sjoerg 
2307330f729Sjoerg   if (Msg->getNumArgs() != 2)
2317330f729Sjoerg     return false;
2327330f729Sjoerg   const Expr *Rec = Msg->getInstanceReceiver();
2337330f729Sjoerg   if (!Rec)
2347330f729Sjoerg     return false;
2357330f729Sjoerg 
2367330f729Sjoerg   SourceRange MsgRange = Msg->getSourceRange();
2377330f729Sjoerg   SourceRange RecRange = Rec->getSourceRange();
2387330f729Sjoerg   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
2397330f729Sjoerg   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
2407330f729Sjoerg 
2417330f729Sjoerg   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
2427330f729Sjoerg                                                        Arg0Range.getBegin()),
2437330f729Sjoerg                          CharSourceRange::getTokenRange(RecRange));
2447330f729Sjoerg   commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
2457330f729Sjoerg                                                        Arg1Range.getBegin()),
2467330f729Sjoerg                          CharSourceRange::getTokenRange(Arg0Range));
2477330f729Sjoerg   commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
2487330f729Sjoerg                          Arg1Range);
2497330f729Sjoerg   commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
2507330f729Sjoerg                                                        Arg1Range.getBegin()),
2517330f729Sjoerg                     "] = ");
2527330f729Sjoerg   maybePutParensOnReceiver(Rec, commit);
2537330f729Sjoerg   return true;
2547330f729Sjoerg }
2557330f729Sjoerg 
rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl * IFace,const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2567330f729Sjoerg static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
2577330f729Sjoerg                                             const ObjCMessageExpr *Msg,
2587330f729Sjoerg                                             const NSAPI &NS,
2597330f729Sjoerg                                             Commit &commit) {
2607330f729Sjoerg   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
2617330f729Sjoerg                                    NS.getSetObjectForKeyedSubscriptSelector()))
2627330f729Sjoerg     return false;
2637330f729Sjoerg 
2647330f729Sjoerg   if (Msg->getNumArgs() != 2)
2657330f729Sjoerg     return false;
2667330f729Sjoerg   const Expr *Rec = Msg->getInstanceReceiver();
2677330f729Sjoerg   if (!Rec)
2687330f729Sjoerg     return false;
2697330f729Sjoerg 
2707330f729Sjoerg   SourceRange MsgRange = Msg->getSourceRange();
2717330f729Sjoerg   SourceRange RecRange = Rec->getSourceRange();
2727330f729Sjoerg   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
2737330f729Sjoerg   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
2747330f729Sjoerg 
2757330f729Sjoerg   SourceLocation LocBeforeVal = Arg0Range.getBegin();
2767330f729Sjoerg   commit.insertBefore(LocBeforeVal, "] = ");
2777330f729Sjoerg   commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
2787330f729Sjoerg                          /*beforePreviousInsertions=*/true);
2797330f729Sjoerg   commit.insertBefore(LocBeforeVal, "[");
2807330f729Sjoerg   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
2817330f729Sjoerg                                                        Arg0Range.getBegin()),
2827330f729Sjoerg                          CharSourceRange::getTokenRange(RecRange));
2837330f729Sjoerg   commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
2847330f729Sjoerg                          Arg0Range);
2857330f729Sjoerg   maybePutParensOnReceiver(Rec, commit);
2867330f729Sjoerg   return true;
2877330f729Sjoerg }
2887330f729Sjoerg 
rewriteToObjCSubscriptSyntax(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)2897330f729Sjoerg bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
2907330f729Sjoerg                                         const NSAPI &NS, Commit &commit) {
2917330f729Sjoerg   if (!Msg || Msg->isImplicit() ||
2927330f729Sjoerg       Msg->getReceiverKind() != ObjCMessageExpr::Instance)
2937330f729Sjoerg     return false;
2947330f729Sjoerg   const ObjCMethodDecl *Method = Msg->getMethodDecl();
2957330f729Sjoerg   if (!Method)
2967330f729Sjoerg     return false;
2977330f729Sjoerg 
2987330f729Sjoerg   const ObjCInterfaceDecl *IFace =
2997330f729Sjoerg       NS.getASTContext().getObjContainingInterface(Method);
3007330f729Sjoerg   if (!IFace)
3017330f729Sjoerg     return false;
3027330f729Sjoerg   Selector Sel = Msg->getSelector();
3037330f729Sjoerg 
3047330f729Sjoerg   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
3057330f729Sjoerg     return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
3067330f729Sjoerg 
3077330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
3087330f729Sjoerg     return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
3097330f729Sjoerg 
3107330f729Sjoerg   if (Msg->getNumArgs() != 2)
3117330f729Sjoerg     return false;
3127330f729Sjoerg 
3137330f729Sjoerg   if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
3147330f729Sjoerg     return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
3157330f729Sjoerg 
3167330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
3177330f729Sjoerg     return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
3187330f729Sjoerg 
3197330f729Sjoerg   return false;
3207330f729Sjoerg }
3217330f729Sjoerg 
3227330f729Sjoerg //===----------------------------------------------------------------------===//
3237330f729Sjoerg // rewriteToObjCLiteralSyntax.
3247330f729Sjoerg //===----------------------------------------------------------------------===//
3257330f729Sjoerg 
3267330f729Sjoerg static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
3277330f729Sjoerg                                   const NSAPI &NS, Commit &commit,
3287330f729Sjoerg                                   const ParentMap *PMap);
3297330f729Sjoerg static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
3307330f729Sjoerg                                   const NSAPI &NS, Commit &commit);
3317330f729Sjoerg static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
3327330f729Sjoerg                                   const NSAPI &NS, Commit &commit);
3337330f729Sjoerg static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
3347330f729Sjoerg                                             const NSAPI &NS, Commit &commit);
3357330f729Sjoerg static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
3367330f729Sjoerg                                            const NSAPI &NS, Commit &commit);
3377330f729Sjoerg 
rewriteToObjCLiteralSyntax(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit,const ParentMap * PMap)3387330f729Sjoerg bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
3397330f729Sjoerg                                       const NSAPI &NS, Commit &commit,
3407330f729Sjoerg                                       const ParentMap *PMap) {
3417330f729Sjoerg   IdentifierInfo *II = nullptr;
3427330f729Sjoerg   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
3437330f729Sjoerg     return false;
3447330f729Sjoerg 
3457330f729Sjoerg   if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
3467330f729Sjoerg     return rewriteToArrayLiteral(Msg, NS, commit, PMap);
3477330f729Sjoerg   if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
3487330f729Sjoerg     return rewriteToDictionaryLiteral(Msg, NS, commit);
3497330f729Sjoerg   if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
3507330f729Sjoerg     return rewriteToNumberLiteral(Msg, NS, commit);
3517330f729Sjoerg   if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
3527330f729Sjoerg     return rewriteToStringBoxedExpression(Msg, NS, commit);
3537330f729Sjoerg 
3547330f729Sjoerg   return false;
3557330f729Sjoerg }
3567330f729Sjoerg 
3577330f729Sjoerg /// Returns true if the immediate message arguments of \c Msg should not
3587330f729Sjoerg /// be rewritten because it will interfere with the rewrite of the parent
3597330f729Sjoerg /// message expression. e.g.
3607330f729Sjoerg /// \code
3617330f729Sjoerg ///   [NSDictionary dictionaryWithObjects:
3627330f729Sjoerg ///                                 [NSArray arrayWithObjects:@"1", @"2", nil]
3637330f729Sjoerg ///                         forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
3647330f729Sjoerg /// \endcode
3657330f729Sjoerg /// It will return true for this because we are going to rewrite this directly
3667330f729Sjoerg /// to a dictionary literal without any array literals.
3677330f729Sjoerg static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
3687330f729Sjoerg                                                  const NSAPI &NS);
3697330f729Sjoerg 
3707330f729Sjoerg //===----------------------------------------------------------------------===//
3717330f729Sjoerg // rewriteToArrayLiteral.
3727330f729Sjoerg //===----------------------------------------------------------------------===//
3737330f729Sjoerg 
3747330f729Sjoerg /// Adds an explicit cast to 'id' if the type is not objc object.
3757330f729Sjoerg static void objectifyExpr(const Expr *E, Commit &commit);
3767330f729Sjoerg 
rewriteToArrayLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit,const ParentMap * PMap)3777330f729Sjoerg static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
3787330f729Sjoerg                                   const NSAPI &NS, Commit &commit,
3797330f729Sjoerg                                   const ParentMap *PMap) {
3807330f729Sjoerg   if (PMap) {
3817330f729Sjoerg     const ObjCMessageExpr *ParentMsg =
3827330f729Sjoerg         dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
3837330f729Sjoerg     if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
3847330f729Sjoerg       return false;
3857330f729Sjoerg   }
3867330f729Sjoerg 
3877330f729Sjoerg   Selector Sel = Msg->getSelector();
3887330f729Sjoerg   SourceRange MsgRange = Msg->getSourceRange();
3897330f729Sjoerg 
3907330f729Sjoerg   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
3917330f729Sjoerg     if (Msg->getNumArgs() != 0)
3927330f729Sjoerg       return false;
3937330f729Sjoerg     commit.replace(MsgRange, "@[]");
3947330f729Sjoerg     return true;
3957330f729Sjoerg   }
3967330f729Sjoerg 
3977330f729Sjoerg   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
3987330f729Sjoerg     if (Msg->getNumArgs() != 1)
3997330f729Sjoerg       return false;
4007330f729Sjoerg     objectifyExpr(Msg->getArg(0), commit);
4017330f729Sjoerg     SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
4027330f729Sjoerg     commit.replaceWithInner(MsgRange, ArgRange);
4037330f729Sjoerg     commit.insertWrap("@[", ArgRange, "]");
4047330f729Sjoerg     return true;
4057330f729Sjoerg   }
4067330f729Sjoerg 
4077330f729Sjoerg   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
4087330f729Sjoerg       Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
4097330f729Sjoerg     if (Msg->getNumArgs() == 0)
4107330f729Sjoerg       return false;
4117330f729Sjoerg     const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
4127330f729Sjoerg     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
4137330f729Sjoerg       return false;
4147330f729Sjoerg 
4157330f729Sjoerg     for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
4167330f729Sjoerg       objectifyExpr(Msg->getArg(i), commit);
4177330f729Sjoerg 
4187330f729Sjoerg     if (Msg->getNumArgs() == 1) {
4197330f729Sjoerg       commit.replace(MsgRange, "@[]");
4207330f729Sjoerg       return true;
4217330f729Sjoerg     }
4227330f729Sjoerg     SourceRange ArgRange(Msg->getArg(0)->getBeginLoc(),
4237330f729Sjoerg                          Msg->getArg(Msg->getNumArgs() - 2)->getEndLoc());
4247330f729Sjoerg     commit.replaceWithInner(MsgRange, ArgRange);
4257330f729Sjoerg     commit.insertWrap("@[", ArgRange, "]");
4267330f729Sjoerg     return true;
4277330f729Sjoerg   }
4287330f729Sjoerg 
4297330f729Sjoerg   return false;
4307330f729Sjoerg }
4317330f729Sjoerg 
4327330f729Sjoerg //===----------------------------------------------------------------------===//
4337330f729Sjoerg // rewriteToDictionaryLiteral.
4347330f729Sjoerg //===----------------------------------------------------------------------===//
4357330f729Sjoerg 
4367330f729Sjoerg /// If \c Msg is an NSArray creation message or literal, this gets the
4377330f729Sjoerg /// objects that were used to create it.
4387330f729Sjoerg /// \returns true if it is an NSArray and we got objects, or false otherwise.
getNSArrayObjects(const Expr * E,const NSAPI & NS,SmallVectorImpl<const Expr * > & Objs)4397330f729Sjoerg static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
4407330f729Sjoerg                               SmallVectorImpl<const Expr *> &Objs) {
4417330f729Sjoerg   if (!E)
4427330f729Sjoerg     return false;
4437330f729Sjoerg 
4447330f729Sjoerg   E = E->IgnoreParenCasts();
4457330f729Sjoerg   if (!E)
4467330f729Sjoerg     return false;
4477330f729Sjoerg 
4487330f729Sjoerg   if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
4497330f729Sjoerg     IdentifierInfo *Cls = nullptr;
4507330f729Sjoerg     if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
4517330f729Sjoerg       return false;
4527330f729Sjoerg 
4537330f729Sjoerg     if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
4547330f729Sjoerg       return false;
4557330f729Sjoerg 
4567330f729Sjoerg     Selector Sel = Msg->getSelector();
4577330f729Sjoerg     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
4587330f729Sjoerg       return true; // empty array.
4597330f729Sjoerg 
4607330f729Sjoerg     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
4617330f729Sjoerg       if (Msg->getNumArgs() != 1)
4627330f729Sjoerg         return false;
4637330f729Sjoerg       Objs.push_back(Msg->getArg(0));
4647330f729Sjoerg       return true;
4657330f729Sjoerg     }
4667330f729Sjoerg 
4677330f729Sjoerg     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
4687330f729Sjoerg         Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
4697330f729Sjoerg       if (Msg->getNumArgs() == 0)
4707330f729Sjoerg         return false;
4717330f729Sjoerg       const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
4727330f729Sjoerg       if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
4737330f729Sjoerg         return false;
4747330f729Sjoerg 
4757330f729Sjoerg       for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
4767330f729Sjoerg         Objs.push_back(Msg->getArg(i));
4777330f729Sjoerg       return true;
4787330f729Sjoerg     }
4797330f729Sjoerg 
4807330f729Sjoerg   } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
4817330f729Sjoerg     for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
4827330f729Sjoerg       Objs.push_back(ArrLit->getElement(i));
4837330f729Sjoerg     return true;
4847330f729Sjoerg   }
4857330f729Sjoerg 
4867330f729Sjoerg   return false;
4877330f729Sjoerg }
4887330f729Sjoerg 
rewriteToDictionaryLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)4897330f729Sjoerg static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
4907330f729Sjoerg                                        const NSAPI &NS, Commit &commit) {
4917330f729Sjoerg   Selector Sel = Msg->getSelector();
4927330f729Sjoerg   SourceRange MsgRange = Msg->getSourceRange();
4937330f729Sjoerg 
4947330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
4957330f729Sjoerg     if (Msg->getNumArgs() != 0)
4967330f729Sjoerg       return false;
4977330f729Sjoerg     commit.replace(MsgRange, "@{}");
4987330f729Sjoerg     return true;
4997330f729Sjoerg   }
5007330f729Sjoerg 
5017330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(
5027330f729Sjoerg                                     NSAPI::NSDict_dictionaryWithObjectForKey)) {
5037330f729Sjoerg     if (Msg->getNumArgs() != 2)
5047330f729Sjoerg       return false;
5057330f729Sjoerg 
5067330f729Sjoerg     objectifyExpr(Msg->getArg(0), commit);
5077330f729Sjoerg     objectifyExpr(Msg->getArg(1), commit);
5087330f729Sjoerg 
5097330f729Sjoerg     SourceRange ValRange = Msg->getArg(0)->getSourceRange();
5107330f729Sjoerg     SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
5117330f729Sjoerg     // Insert key before the value.
5127330f729Sjoerg     commit.insertBefore(ValRange.getBegin(), ": ");
5137330f729Sjoerg     commit.insertFromRange(ValRange.getBegin(),
5147330f729Sjoerg                            CharSourceRange::getTokenRange(KeyRange),
5157330f729Sjoerg                        /*afterToken=*/false, /*beforePreviousInsertions=*/true);
5167330f729Sjoerg     commit.insertBefore(ValRange.getBegin(), "@{");
5177330f729Sjoerg     commit.insertAfterToken(ValRange.getEnd(), "}");
5187330f729Sjoerg     commit.replaceWithInner(MsgRange, ValRange);
5197330f729Sjoerg     return true;
5207330f729Sjoerg   }
5217330f729Sjoerg 
5227330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(
5237330f729Sjoerg                                   NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
5247330f729Sjoerg       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
5257330f729Sjoerg     if (Msg->getNumArgs() % 2 != 1)
5267330f729Sjoerg       return false;
5277330f729Sjoerg     unsigned SentinelIdx = Msg->getNumArgs() - 1;
5287330f729Sjoerg     const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
5297330f729Sjoerg     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
5307330f729Sjoerg       return false;
5317330f729Sjoerg 
5327330f729Sjoerg     if (Msg->getNumArgs() == 1) {
5337330f729Sjoerg       commit.replace(MsgRange, "@{}");
5347330f729Sjoerg       return true;
5357330f729Sjoerg     }
5367330f729Sjoerg 
5377330f729Sjoerg     for (unsigned i = 0; i < SentinelIdx; i += 2) {
5387330f729Sjoerg       objectifyExpr(Msg->getArg(i), commit);
5397330f729Sjoerg       objectifyExpr(Msg->getArg(i+1), commit);
5407330f729Sjoerg 
5417330f729Sjoerg       SourceRange ValRange = Msg->getArg(i)->getSourceRange();
5427330f729Sjoerg       SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
5437330f729Sjoerg       // Insert value after key.
5447330f729Sjoerg       commit.insertAfterToken(KeyRange.getEnd(), ": ");
5457330f729Sjoerg       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
5467330f729Sjoerg       commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
5477330f729Sjoerg                                                   KeyRange.getBegin()));
5487330f729Sjoerg     }
5497330f729Sjoerg     // Range of arguments up until and including the last key.
5507330f729Sjoerg     // The sentinel and first value are cut off, the value will move after the
5517330f729Sjoerg     // key.
5527330f729Sjoerg     SourceRange ArgRange(Msg->getArg(1)->getBeginLoc(),
5537330f729Sjoerg                          Msg->getArg(SentinelIdx - 1)->getEndLoc());
5547330f729Sjoerg     commit.insertWrap("@{", ArgRange, "}");
5557330f729Sjoerg     commit.replaceWithInner(MsgRange, ArgRange);
5567330f729Sjoerg     return true;
5577330f729Sjoerg   }
5587330f729Sjoerg 
5597330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(
5607330f729Sjoerg                                   NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
5617330f729Sjoerg       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
5627330f729Sjoerg     if (Msg->getNumArgs() != 2)
5637330f729Sjoerg       return false;
5647330f729Sjoerg 
5657330f729Sjoerg     SmallVector<const Expr *, 8> Vals;
5667330f729Sjoerg     if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
5677330f729Sjoerg       return false;
5687330f729Sjoerg 
5697330f729Sjoerg     SmallVector<const Expr *, 8> Keys;
5707330f729Sjoerg     if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
5717330f729Sjoerg       return false;
5727330f729Sjoerg 
5737330f729Sjoerg     if (Vals.size() != Keys.size())
5747330f729Sjoerg       return false;
5757330f729Sjoerg 
5767330f729Sjoerg     if (Vals.empty()) {
5777330f729Sjoerg       commit.replace(MsgRange, "@{}");
5787330f729Sjoerg       return true;
5797330f729Sjoerg     }
5807330f729Sjoerg 
5817330f729Sjoerg     for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
5827330f729Sjoerg       objectifyExpr(Vals[i], commit);
5837330f729Sjoerg       objectifyExpr(Keys[i], commit);
5847330f729Sjoerg 
5857330f729Sjoerg       SourceRange ValRange = Vals[i]->getSourceRange();
5867330f729Sjoerg       SourceRange KeyRange = Keys[i]->getSourceRange();
5877330f729Sjoerg       // Insert value after key.
5887330f729Sjoerg       commit.insertAfterToken(KeyRange.getEnd(), ": ");
5897330f729Sjoerg       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
5907330f729Sjoerg     }
5917330f729Sjoerg     // Range of arguments up until and including the last key.
5927330f729Sjoerg     // The first value is cut off, the value will move after the key.
5937330f729Sjoerg     SourceRange ArgRange(Keys.front()->getBeginLoc(), Keys.back()->getEndLoc());
5947330f729Sjoerg     commit.insertWrap("@{", ArgRange, "}");
5957330f729Sjoerg     commit.replaceWithInner(MsgRange, ArgRange);
5967330f729Sjoerg     return true;
5977330f729Sjoerg   }
5987330f729Sjoerg 
5997330f729Sjoerg   return false;
6007330f729Sjoerg }
6017330f729Sjoerg 
shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr * Msg,const NSAPI & NS)6027330f729Sjoerg static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
6037330f729Sjoerg                                                  const NSAPI &NS) {
6047330f729Sjoerg   if (!Msg)
6057330f729Sjoerg     return false;
6067330f729Sjoerg 
6077330f729Sjoerg   IdentifierInfo *II = nullptr;
6087330f729Sjoerg   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
6097330f729Sjoerg     return false;
6107330f729Sjoerg 
6117330f729Sjoerg   if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
6127330f729Sjoerg     return false;
6137330f729Sjoerg 
6147330f729Sjoerg   Selector Sel = Msg->getSelector();
6157330f729Sjoerg   if (Sel == NS.getNSDictionarySelector(
6167330f729Sjoerg                                   NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
6177330f729Sjoerg       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
6187330f729Sjoerg     if (Msg->getNumArgs() != 2)
6197330f729Sjoerg       return false;
6207330f729Sjoerg 
6217330f729Sjoerg     SmallVector<const Expr *, 8> Vals;
6227330f729Sjoerg     if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
6237330f729Sjoerg       return false;
6247330f729Sjoerg 
6257330f729Sjoerg     SmallVector<const Expr *, 8> Keys;
6267330f729Sjoerg     if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
6277330f729Sjoerg       return false;
6287330f729Sjoerg 
6297330f729Sjoerg     if (Vals.size() != Keys.size())
6307330f729Sjoerg       return false;
6317330f729Sjoerg 
6327330f729Sjoerg     return true;
6337330f729Sjoerg   }
6347330f729Sjoerg 
6357330f729Sjoerg   return false;
6367330f729Sjoerg }
6377330f729Sjoerg 
6387330f729Sjoerg //===----------------------------------------------------------------------===//
6397330f729Sjoerg // rewriteToNumberLiteral.
6407330f729Sjoerg //===----------------------------------------------------------------------===//
6417330f729Sjoerg 
rewriteToCharLiteral(const ObjCMessageExpr * Msg,const CharacterLiteral * Arg,const NSAPI & NS,Commit & commit)6427330f729Sjoerg static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
6437330f729Sjoerg                                    const CharacterLiteral *Arg,
6447330f729Sjoerg                                    const NSAPI &NS, Commit &commit) {
6457330f729Sjoerg   if (Arg->getKind() != CharacterLiteral::Ascii)
6467330f729Sjoerg     return false;
6477330f729Sjoerg   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
6487330f729Sjoerg                                    Msg->getSelector())) {
6497330f729Sjoerg     SourceRange ArgRange = Arg->getSourceRange();
6507330f729Sjoerg     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
6517330f729Sjoerg     commit.insert(ArgRange.getBegin(), "@");
6527330f729Sjoerg     return true;
6537330f729Sjoerg   }
6547330f729Sjoerg 
6557330f729Sjoerg   return rewriteToNumericBoxedExpression(Msg, NS, commit);
6567330f729Sjoerg }
6577330f729Sjoerg 
rewriteToBoolLiteral(const ObjCMessageExpr * Msg,const Expr * Arg,const NSAPI & NS,Commit & commit)6587330f729Sjoerg static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
6597330f729Sjoerg                                    const Expr *Arg,
6607330f729Sjoerg                                    const NSAPI &NS, Commit &commit) {
6617330f729Sjoerg   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
6627330f729Sjoerg                                    Msg->getSelector())) {
6637330f729Sjoerg     SourceRange ArgRange = Arg->getSourceRange();
6647330f729Sjoerg     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
6657330f729Sjoerg     commit.insert(ArgRange.getBegin(), "@");
6667330f729Sjoerg     return true;
6677330f729Sjoerg   }
6687330f729Sjoerg 
6697330f729Sjoerg   return rewriteToNumericBoxedExpression(Msg, NS, commit);
6707330f729Sjoerg }
6717330f729Sjoerg 
6727330f729Sjoerg namespace {
6737330f729Sjoerg 
6747330f729Sjoerg struct LiteralInfo {
6757330f729Sjoerg   bool Hex, Octal;
6767330f729Sjoerg   StringRef U, F, L, LL;
6777330f729Sjoerg   CharSourceRange WithoutSuffRange;
6787330f729Sjoerg };
6797330f729Sjoerg 
6807330f729Sjoerg }
6817330f729Sjoerg 
getLiteralInfo(SourceRange literalRange,bool isFloat,bool isIntZero,ASTContext & Ctx,LiteralInfo & Info)6827330f729Sjoerg static bool getLiteralInfo(SourceRange literalRange,
6837330f729Sjoerg                            bool isFloat, bool isIntZero,
6847330f729Sjoerg                           ASTContext &Ctx, LiteralInfo &Info) {
6857330f729Sjoerg   if (literalRange.getBegin().isMacroID() ||
6867330f729Sjoerg       literalRange.getEnd().isMacroID())
6877330f729Sjoerg     return false;
6887330f729Sjoerg   StringRef text = Lexer::getSourceText(
6897330f729Sjoerg                                   CharSourceRange::getTokenRange(literalRange),
6907330f729Sjoerg                                   Ctx.getSourceManager(), Ctx.getLangOpts());
6917330f729Sjoerg   if (text.empty())
6927330f729Sjoerg     return false;
6937330f729Sjoerg 
6947330f729Sjoerg   Optional<bool> UpperU, UpperL;
6957330f729Sjoerg   bool UpperF = false;
6967330f729Sjoerg 
6977330f729Sjoerg   struct Suff {
6987330f729Sjoerg     static bool has(StringRef suff, StringRef &text) {
6997330f729Sjoerg       if (text.endswith(suff)) {
7007330f729Sjoerg         text = text.substr(0, text.size()-suff.size());
7017330f729Sjoerg         return true;
7027330f729Sjoerg       }
7037330f729Sjoerg       return false;
7047330f729Sjoerg     }
7057330f729Sjoerg   };
7067330f729Sjoerg 
7077330f729Sjoerg   while (1) {
7087330f729Sjoerg     if (Suff::has("u", text)) {
7097330f729Sjoerg       UpperU = false;
7107330f729Sjoerg     } else if (Suff::has("U", text)) {
7117330f729Sjoerg       UpperU = true;
7127330f729Sjoerg     } else if (Suff::has("ll", text)) {
7137330f729Sjoerg       UpperL = false;
7147330f729Sjoerg     } else if (Suff::has("LL", text)) {
7157330f729Sjoerg       UpperL = true;
7167330f729Sjoerg     } else if (Suff::has("l", text)) {
7177330f729Sjoerg       UpperL = false;
7187330f729Sjoerg     } else if (Suff::has("L", text)) {
7197330f729Sjoerg       UpperL = true;
7207330f729Sjoerg     } else if (isFloat && Suff::has("f", text)) {
7217330f729Sjoerg       UpperF = false;
7227330f729Sjoerg     } else if (isFloat && Suff::has("F", text)) {
7237330f729Sjoerg       UpperF = true;
7247330f729Sjoerg     } else
7257330f729Sjoerg       break;
7267330f729Sjoerg   }
7277330f729Sjoerg 
7287330f729Sjoerg   if (!UpperU.hasValue() && !UpperL.hasValue())
7297330f729Sjoerg     UpperU = UpperL = true;
7307330f729Sjoerg   else if (UpperU.hasValue() && !UpperL.hasValue())
7317330f729Sjoerg     UpperL = UpperU;
7327330f729Sjoerg   else if (UpperL.hasValue() && !UpperU.hasValue())
7337330f729Sjoerg     UpperU = UpperL;
7347330f729Sjoerg 
7357330f729Sjoerg   Info.U = *UpperU ? "U" : "u";
7367330f729Sjoerg   Info.L = *UpperL ? "L" : "l";
7377330f729Sjoerg   Info.LL = *UpperL ? "LL" : "ll";
7387330f729Sjoerg   Info.F = UpperF ? "F" : "f";
7397330f729Sjoerg 
7407330f729Sjoerg   Info.Hex = Info.Octal = false;
7417330f729Sjoerg   if (text.startswith("0x"))
7427330f729Sjoerg     Info.Hex = true;
7437330f729Sjoerg   else if (!isFloat && !isIntZero && text.startswith("0"))
7447330f729Sjoerg     Info.Octal = true;
7457330f729Sjoerg 
7467330f729Sjoerg   SourceLocation B = literalRange.getBegin();
7477330f729Sjoerg   Info.WithoutSuffRange =
7487330f729Sjoerg       CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
7497330f729Sjoerg   return true;
7507330f729Sjoerg }
7517330f729Sjoerg 
rewriteToNumberLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)7527330f729Sjoerg static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
7537330f729Sjoerg                                    const NSAPI &NS, Commit &commit) {
7547330f729Sjoerg   if (Msg->getNumArgs() != 1)
7557330f729Sjoerg     return false;
7567330f729Sjoerg 
7577330f729Sjoerg   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
7587330f729Sjoerg   if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
7597330f729Sjoerg     return rewriteToCharLiteral(Msg, CharE, NS, commit);
7607330f729Sjoerg   if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
7617330f729Sjoerg     return rewriteToBoolLiteral(Msg, BE, NS, commit);
7627330f729Sjoerg   if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
7637330f729Sjoerg     return rewriteToBoolLiteral(Msg, BE, NS, commit);
7647330f729Sjoerg 
7657330f729Sjoerg   const Expr *literalE = Arg;
7667330f729Sjoerg   if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
7677330f729Sjoerg     if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
7687330f729Sjoerg       literalE = UOE->getSubExpr();
7697330f729Sjoerg   }
7707330f729Sjoerg 
7717330f729Sjoerg   // Only integer and floating literals, otherwise try to rewrite to boxed
7727330f729Sjoerg   // expression.
7737330f729Sjoerg   if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
7747330f729Sjoerg     return rewriteToNumericBoxedExpression(Msg, NS, commit);
7757330f729Sjoerg 
7767330f729Sjoerg   ASTContext &Ctx = NS.getASTContext();
7777330f729Sjoerg   Selector Sel = Msg->getSelector();
7787330f729Sjoerg   Optional<NSAPI::NSNumberLiteralMethodKind>
7797330f729Sjoerg     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
7807330f729Sjoerg   if (!MKOpt)
7817330f729Sjoerg     return false;
7827330f729Sjoerg   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
7837330f729Sjoerg 
7847330f729Sjoerg   bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
7857330f729Sjoerg   bool CallIsFloating = false, CallIsDouble = false;
7867330f729Sjoerg 
7877330f729Sjoerg   switch (MK) {
7887330f729Sjoerg   // We cannot have these calls with int/float literals.
7897330f729Sjoerg   case NSAPI::NSNumberWithChar:
7907330f729Sjoerg   case NSAPI::NSNumberWithUnsignedChar:
7917330f729Sjoerg   case NSAPI::NSNumberWithShort:
7927330f729Sjoerg   case NSAPI::NSNumberWithUnsignedShort:
7937330f729Sjoerg   case NSAPI::NSNumberWithBool:
7947330f729Sjoerg     return rewriteToNumericBoxedExpression(Msg, NS, commit);
7957330f729Sjoerg 
7967330f729Sjoerg   case NSAPI::NSNumberWithUnsignedInt:
7977330f729Sjoerg   case NSAPI::NSNumberWithUnsignedInteger:
7987330f729Sjoerg     CallIsUnsigned = true;
7997330f729Sjoerg     LLVM_FALLTHROUGH;
8007330f729Sjoerg   case NSAPI::NSNumberWithInt:
8017330f729Sjoerg   case NSAPI::NSNumberWithInteger:
8027330f729Sjoerg     break;
8037330f729Sjoerg 
8047330f729Sjoerg   case NSAPI::NSNumberWithUnsignedLong:
8057330f729Sjoerg     CallIsUnsigned = true;
8067330f729Sjoerg     LLVM_FALLTHROUGH;
8077330f729Sjoerg   case NSAPI::NSNumberWithLong:
8087330f729Sjoerg     CallIsLong = true;
8097330f729Sjoerg     break;
8107330f729Sjoerg 
8117330f729Sjoerg   case NSAPI::NSNumberWithUnsignedLongLong:
8127330f729Sjoerg     CallIsUnsigned = true;
8137330f729Sjoerg     LLVM_FALLTHROUGH;
8147330f729Sjoerg   case NSAPI::NSNumberWithLongLong:
8157330f729Sjoerg     CallIsLongLong = true;
8167330f729Sjoerg     break;
8177330f729Sjoerg 
8187330f729Sjoerg   case NSAPI::NSNumberWithDouble:
8197330f729Sjoerg     CallIsDouble = true;
8207330f729Sjoerg     LLVM_FALLTHROUGH;
8217330f729Sjoerg   case NSAPI::NSNumberWithFloat:
8227330f729Sjoerg     CallIsFloating = true;
8237330f729Sjoerg     break;
8247330f729Sjoerg   }
8257330f729Sjoerg 
8267330f729Sjoerg   SourceRange ArgRange = Arg->getSourceRange();
8277330f729Sjoerg   QualType ArgTy = Arg->getType();
8287330f729Sjoerg   QualType CallTy = Msg->getArg(0)->getType();
8297330f729Sjoerg 
8307330f729Sjoerg   // Check for the easy case, the literal maps directly to the call.
8317330f729Sjoerg   if (Ctx.hasSameType(ArgTy, CallTy)) {
8327330f729Sjoerg     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
8337330f729Sjoerg     commit.insert(ArgRange.getBegin(), "@");
8347330f729Sjoerg     return true;
8357330f729Sjoerg   }
8367330f729Sjoerg 
8377330f729Sjoerg   // We will need to modify the literal suffix to get the same type as the call.
8387330f729Sjoerg   // Try with boxed expression if it came from a macro.
8397330f729Sjoerg   if (ArgRange.getBegin().isMacroID())
8407330f729Sjoerg     return rewriteToNumericBoxedExpression(Msg, NS, commit);
8417330f729Sjoerg 
8427330f729Sjoerg   bool LitIsFloat = ArgTy->isFloatingType();
8437330f729Sjoerg   // For a float passed to integer call, don't try rewriting to objc literal.
8447330f729Sjoerg   // It is difficult and a very uncommon case anyway.
8457330f729Sjoerg   // But try with boxed expression.
8467330f729Sjoerg   if (LitIsFloat && !CallIsFloating)
8477330f729Sjoerg     return rewriteToNumericBoxedExpression(Msg, NS, commit);
8487330f729Sjoerg 
8497330f729Sjoerg   // Try to modify the literal make it the same type as the method call.
8507330f729Sjoerg   // -Modify the suffix, and/or
8517330f729Sjoerg   // -Change integer to float
8527330f729Sjoerg 
8537330f729Sjoerg   LiteralInfo LitInfo;
8547330f729Sjoerg   bool isIntZero = false;
8557330f729Sjoerg   if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
8567330f729Sjoerg     isIntZero = !IntE->getValue().getBoolValue();
8577330f729Sjoerg   if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
8587330f729Sjoerg     return rewriteToNumericBoxedExpression(Msg, NS, commit);
8597330f729Sjoerg 
8607330f729Sjoerg   // Not easy to do int -> float with hex/octal and uncommon anyway.
8617330f729Sjoerg   if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
8627330f729Sjoerg     return rewriteToNumericBoxedExpression(Msg, NS, commit);
8637330f729Sjoerg 
8647330f729Sjoerg   SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
8657330f729Sjoerg   SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
8667330f729Sjoerg 
8677330f729Sjoerg   commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
8687330f729Sjoerg                          LitInfo.WithoutSuffRange);
8697330f729Sjoerg   commit.insert(LitB, "@");
8707330f729Sjoerg 
8717330f729Sjoerg   if (!LitIsFloat && CallIsFloating)
8727330f729Sjoerg     commit.insert(LitE, ".0");
8737330f729Sjoerg 
8747330f729Sjoerg   if (CallIsFloating) {
8757330f729Sjoerg     if (!CallIsDouble)
8767330f729Sjoerg       commit.insert(LitE, LitInfo.F);
8777330f729Sjoerg   } else {
8787330f729Sjoerg     if (CallIsUnsigned)
8797330f729Sjoerg       commit.insert(LitE, LitInfo.U);
8807330f729Sjoerg 
8817330f729Sjoerg     if (CallIsLong)
8827330f729Sjoerg       commit.insert(LitE, LitInfo.L);
8837330f729Sjoerg     else if (CallIsLongLong)
8847330f729Sjoerg       commit.insert(LitE, LitInfo.LL);
8857330f729Sjoerg   }
8867330f729Sjoerg   return true;
8877330f729Sjoerg }
8887330f729Sjoerg 
8897330f729Sjoerg // FIXME: Make determination of operator precedence more general and
8907330f729Sjoerg // make it broadly available.
subscriptOperatorNeedsParens(const Expr * FullExpr)8917330f729Sjoerg static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
8927330f729Sjoerg   const Expr* Expr = FullExpr->IgnoreImpCasts();
8937330f729Sjoerg   if (isa<ArraySubscriptExpr>(Expr) ||
8947330f729Sjoerg       isa<CallExpr>(Expr) ||
8957330f729Sjoerg       isa<DeclRefExpr>(Expr) ||
8967330f729Sjoerg       isa<CXXNamedCastExpr>(Expr) ||
8977330f729Sjoerg       isa<CXXConstructExpr>(Expr) ||
8987330f729Sjoerg       isa<CXXThisExpr>(Expr) ||
8997330f729Sjoerg       isa<CXXTypeidExpr>(Expr) ||
9007330f729Sjoerg       isa<CXXUnresolvedConstructExpr>(Expr) ||
9017330f729Sjoerg       isa<ObjCMessageExpr>(Expr) ||
9027330f729Sjoerg       isa<ObjCPropertyRefExpr>(Expr) ||
9037330f729Sjoerg       isa<ObjCProtocolExpr>(Expr) ||
9047330f729Sjoerg       isa<MemberExpr>(Expr) ||
9057330f729Sjoerg       isa<ObjCIvarRefExpr>(Expr) ||
9067330f729Sjoerg       isa<ParenExpr>(FullExpr) ||
9077330f729Sjoerg       isa<ParenListExpr>(Expr) ||
9087330f729Sjoerg       isa<SizeOfPackExpr>(Expr))
9097330f729Sjoerg     return false;
9107330f729Sjoerg 
9117330f729Sjoerg   return true;
9127330f729Sjoerg }
castOperatorNeedsParens(const Expr * FullExpr)9137330f729Sjoerg static bool castOperatorNeedsParens(const Expr *FullExpr) {
9147330f729Sjoerg   const Expr* Expr = FullExpr->IgnoreImpCasts();
9157330f729Sjoerg   if (isa<ArraySubscriptExpr>(Expr) ||
9167330f729Sjoerg       isa<CallExpr>(Expr) ||
9177330f729Sjoerg       isa<DeclRefExpr>(Expr) ||
9187330f729Sjoerg       isa<CastExpr>(Expr) ||
9197330f729Sjoerg       isa<CXXNewExpr>(Expr) ||
9207330f729Sjoerg       isa<CXXConstructExpr>(Expr) ||
9217330f729Sjoerg       isa<CXXDeleteExpr>(Expr) ||
9227330f729Sjoerg       isa<CXXNoexceptExpr>(Expr) ||
9237330f729Sjoerg       isa<CXXPseudoDestructorExpr>(Expr) ||
9247330f729Sjoerg       isa<CXXScalarValueInitExpr>(Expr) ||
9257330f729Sjoerg       isa<CXXThisExpr>(Expr) ||
9267330f729Sjoerg       isa<CXXTypeidExpr>(Expr) ||
9277330f729Sjoerg       isa<CXXUnresolvedConstructExpr>(Expr) ||
9287330f729Sjoerg       isa<ObjCMessageExpr>(Expr) ||
9297330f729Sjoerg       isa<ObjCPropertyRefExpr>(Expr) ||
9307330f729Sjoerg       isa<ObjCProtocolExpr>(Expr) ||
9317330f729Sjoerg       isa<MemberExpr>(Expr) ||
9327330f729Sjoerg       isa<ObjCIvarRefExpr>(Expr) ||
9337330f729Sjoerg       isa<ParenExpr>(FullExpr) ||
9347330f729Sjoerg       isa<ParenListExpr>(Expr) ||
9357330f729Sjoerg       isa<SizeOfPackExpr>(Expr) ||
9367330f729Sjoerg       isa<UnaryOperator>(Expr))
9377330f729Sjoerg     return false;
9387330f729Sjoerg 
9397330f729Sjoerg   return true;
9407330f729Sjoerg }
9417330f729Sjoerg 
objectifyExpr(const Expr * E,Commit & commit)9427330f729Sjoerg static void objectifyExpr(const Expr *E, Commit &commit) {
9437330f729Sjoerg   if (!E) return;
9447330f729Sjoerg 
9457330f729Sjoerg   QualType T = E->getType();
9467330f729Sjoerg   if (T->isObjCObjectPointerType()) {
9477330f729Sjoerg     if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
9487330f729Sjoerg       if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
9497330f729Sjoerg         return;
9507330f729Sjoerg     } else {
9517330f729Sjoerg       return;
9527330f729Sjoerg     }
9537330f729Sjoerg   } else if (!T->isPointerType()) {
9547330f729Sjoerg     return;
9557330f729Sjoerg   }
9567330f729Sjoerg 
9577330f729Sjoerg   SourceRange Range = E->getSourceRange();
9587330f729Sjoerg   if (castOperatorNeedsParens(E))
9597330f729Sjoerg     commit.insertWrap("(", Range, ")");
9607330f729Sjoerg   commit.insertBefore(Range.getBegin(), "(id)");
9617330f729Sjoerg }
9627330f729Sjoerg 
9637330f729Sjoerg //===----------------------------------------------------------------------===//
9647330f729Sjoerg // rewriteToNumericBoxedExpression.
9657330f729Sjoerg //===----------------------------------------------------------------------===//
9667330f729Sjoerg 
isEnumConstant(const Expr * E)9677330f729Sjoerg static bool isEnumConstant(const Expr *E) {
9687330f729Sjoerg   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
9697330f729Sjoerg     if (const ValueDecl *VD = DRE->getDecl())
9707330f729Sjoerg       return isa<EnumConstantDecl>(VD);
9717330f729Sjoerg 
9727330f729Sjoerg   return false;
9737330f729Sjoerg }
9747330f729Sjoerg 
rewriteToNumericBoxedExpression(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)9757330f729Sjoerg static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
9767330f729Sjoerg                                             const NSAPI &NS, Commit &commit) {
9777330f729Sjoerg   if (Msg->getNumArgs() != 1)
9787330f729Sjoerg     return false;
9797330f729Sjoerg 
9807330f729Sjoerg   const Expr *Arg = Msg->getArg(0);
9817330f729Sjoerg   if (Arg->isTypeDependent())
9827330f729Sjoerg     return false;
9837330f729Sjoerg 
9847330f729Sjoerg   ASTContext &Ctx = NS.getASTContext();
9857330f729Sjoerg   Selector Sel = Msg->getSelector();
9867330f729Sjoerg   Optional<NSAPI::NSNumberLiteralMethodKind>
9877330f729Sjoerg     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
9887330f729Sjoerg   if (!MKOpt)
9897330f729Sjoerg     return false;
9907330f729Sjoerg   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
9917330f729Sjoerg 
9927330f729Sjoerg   const Expr *OrigArg = Arg->IgnoreImpCasts();
9937330f729Sjoerg   QualType FinalTy = Arg->getType();
9947330f729Sjoerg   QualType OrigTy = OrigArg->getType();
9957330f729Sjoerg   uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
9967330f729Sjoerg   uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
9977330f729Sjoerg 
9987330f729Sjoerg   bool isTruncated = FinalTySize < OrigTySize;
9997330f729Sjoerg   bool needsCast = false;
10007330f729Sjoerg 
10017330f729Sjoerg   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
10027330f729Sjoerg     switch (ICE->getCastKind()) {
10037330f729Sjoerg     case CK_LValueToRValue:
10047330f729Sjoerg     case CK_NoOp:
10057330f729Sjoerg     case CK_UserDefinedConversion:
10067330f729Sjoerg       break;
10077330f729Sjoerg 
10087330f729Sjoerg     case CK_IntegralCast: {
10097330f729Sjoerg       if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
10107330f729Sjoerg         break;
10117330f729Sjoerg       // Be more liberal with Integer/UnsignedInteger which are very commonly
10127330f729Sjoerg       // used.
10137330f729Sjoerg       if ((MK == NSAPI::NSNumberWithInteger ||
10147330f729Sjoerg            MK == NSAPI::NSNumberWithUnsignedInteger) &&
10157330f729Sjoerg           !isTruncated) {
10167330f729Sjoerg         if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
10177330f729Sjoerg           break;
10187330f729Sjoerg         if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
10197330f729Sjoerg             OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
10207330f729Sjoerg           break;
10217330f729Sjoerg       }
10227330f729Sjoerg 
10237330f729Sjoerg       needsCast = true;
10247330f729Sjoerg       break;
10257330f729Sjoerg     }
10267330f729Sjoerg 
10277330f729Sjoerg     case CK_PointerToBoolean:
10287330f729Sjoerg     case CK_IntegralToBoolean:
10297330f729Sjoerg     case CK_IntegralToFloating:
10307330f729Sjoerg     case CK_FloatingToIntegral:
10317330f729Sjoerg     case CK_FloatingToBoolean:
10327330f729Sjoerg     case CK_FloatingCast:
10337330f729Sjoerg     case CK_FloatingComplexToReal:
10347330f729Sjoerg     case CK_FloatingComplexToBoolean:
10357330f729Sjoerg     case CK_IntegralComplexToReal:
10367330f729Sjoerg     case CK_IntegralComplexToBoolean:
10377330f729Sjoerg     case CK_AtomicToNonAtomic:
10387330f729Sjoerg     case CK_AddressSpaceConversion:
10397330f729Sjoerg       needsCast = true;
10407330f729Sjoerg       break;
10417330f729Sjoerg 
10427330f729Sjoerg     case CK_Dependent:
10437330f729Sjoerg     case CK_BitCast:
10447330f729Sjoerg     case CK_LValueBitCast:
10457330f729Sjoerg     case CK_LValueToRValueBitCast:
10467330f729Sjoerg     case CK_BaseToDerived:
10477330f729Sjoerg     case CK_DerivedToBase:
10487330f729Sjoerg     case CK_UncheckedDerivedToBase:
10497330f729Sjoerg     case CK_Dynamic:
10507330f729Sjoerg     case CK_ToUnion:
10517330f729Sjoerg     case CK_ArrayToPointerDecay:
10527330f729Sjoerg     case CK_FunctionToPointerDecay:
10537330f729Sjoerg     case CK_NullToPointer:
10547330f729Sjoerg     case CK_NullToMemberPointer:
10557330f729Sjoerg     case CK_BaseToDerivedMemberPointer:
10567330f729Sjoerg     case CK_DerivedToBaseMemberPointer:
10577330f729Sjoerg     case CK_MemberPointerToBoolean:
10587330f729Sjoerg     case CK_ReinterpretMemberPointer:
10597330f729Sjoerg     case CK_ConstructorConversion:
10607330f729Sjoerg     case CK_IntegralToPointer:
10617330f729Sjoerg     case CK_PointerToIntegral:
10627330f729Sjoerg     case CK_ToVoid:
10637330f729Sjoerg     case CK_VectorSplat:
10647330f729Sjoerg     case CK_CPointerToObjCPointerCast:
10657330f729Sjoerg     case CK_BlockPointerToObjCPointerCast:
10667330f729Sjoerg     case CK_AnyPointerToBlockPointerCast:
10677330f729Sjoerg     case CK_ObjCObjectLValueCast:
10687330f729Sjoerg     case CK_FloatingRealToComplex:
10697330f729Sjoerg     case CK_FloatingComplexCast:
10707330f729Sjoerg     case CK_FloatingComplexToIntegralComplex:
10717330f729Sjoerg     case CK_IntegralRealToComplex:
10727330f729Sjoerg     case CK_IntegralComplexCast:
10737330f729Sjoerg     case CK_IntegralComplexToFloatingComplex:
10747330f729Sjoerg     case CK_ARCProduceObject:
10757330f729Sjoerg     case CK_ARCConsumeObject:
10767330f729Sjoerg     case CK_ARCReclaimReturnedObject:
10777330f729Sjoerg     case CK_ARCExtendBlockObject:
10787330f729Sjoerg     case CK_NonAtomicToAtomic:
10797330f729Sjoerg     case CK_CopyAndAutoreleaseBlockObject:
10807330f729Sjoerg     case CK_BuiltinFnToFnPtr:
10817330f729Sjoerg     case CK_ZeroToOCLOpaqueType:
10827330f729Sjoerg     case CK_IntToOCLSampler:
1083*e038c9c4Sjoerg     case CK_MatrixCast:
10847330f729Sjoerg       return false;
10857330f729Sjoerg 
10867330f729Sjoerg     case CK_BooleanToSignedIntegral:
10877330f729Sjoerg       llvm_unreachable("OpenCL-specific cast in Objective-C?");
10887330f729Sjoerg 
1089*e038c9c4Sjoerg     case CK_FloatingToFixedPoint:
1090*e038c9c4Sjoerg     case CK_FixedPointToFloating:
10917330f729Sjoerg     case CK_FixedPointCast:
10927330f729Sjoerg     case CK_FixedPointToBoolean:
10937330f729Sjoerg     case CK_FixedPointToIntegral:
10947330f729Sjoerg     case CK_IntegralToFixedPoint:
10957330f729Sjoerg       llvm_unreachable("Fixed point types are disabled for Objective-C");
10967330f729Sjoerg     }
10977330f729Sjoerg   }
10987330f729Sjoerg 
10997330f729Sjoerg   if (needsCast) {
11007330f729Sjoerg     DiagnosticsEngine &Diags = Ctx.getDiagnostics();
11017330f729Sjoerg     // FIXME: Use a custom category name to distinguish migration diagnostics.
11027330f729Sjoerg     unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
11037330f729Sjoerg                        "converting to boxing syntax requires casting %0 to %1");
11047330f729Sjoerg     Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
11057330f729Sjoerg         << Msg->getSourceRange();
11067330f729Sjoerg     return false;
11077330f729Sjoerg   }
11087330f729Sjoerg 
11097330f729Sjoerg   SourceRange ArgRange = OrigArg->getSourceRange();
11107330f729Sjoerg   commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
11117330f729Sjoerg 
11127330f729Sjoerg   if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
11137330f729Sjoerg     commit.insertBefore(ArgRange.getBegin(), "@");
11147330f729Sjoerg   else
11157330f729Sjoerg     commit.insertWrap("@(", ArgRange, ")");
11167330f729Sjoerg 
11177330f729Sjoerg   return true;
11187330f729Sjoerg }
11197330f729Sjoerg 
11207330f729Sjoerg //===----------------------------------------------------------------------===//
11217330f729Sjoerg // rewriteToStringBoxedExpression.
11227330f729Sjoerg //===----------------------------------------------------------------------===//
11237330f729Sjoerg 
doRewriteToUTF8StringBoxedExpressionHelper(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)11247330f729Sjoerg static bool doRewriteToUTF8StringBoxedExpressionHelper(
11257330f729Sjoerg                                               const ObjCMessageExpr *Msg,
11267330f729Sjoerg                                               const NSAPI &NS, Commit &commit) {
11277330f729Sjoerg   const Expr *Arg = Msg->getArg(0);
11287330f729Sjoerg   if (Arg->isTypeDependent())
11297330f729Sjoerg     return false;
11307330f729Sjoerg 
11317330f729Sjoerg   ASTContext &Ctx = NS.getASTContext();
11327330f729Sjoerg 
11337330f729Sjoerg   const Expr *OrigArg = Arg->IgnoreImpCasts();
11347330f729Sjoerg   QualType OrigTy = OrigArg->getType();
11357330f729Sjoerg   if (OrigTy->isArrayType())
11367330f729Sjoerg     OrigTy = Ctx.getArrayDecayedType(OrigTy);
11377330f729Sjoerg 
11387330f729Sjoerg   if (const StringLiteral *
11397330f729Sjoerg         StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
11407330f729Sjoerg     commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
11417330f729Sjoerg     commit.insert(StrE->getBeginLoc(), "@");
11427330f729Sjoerg     return true;
11437330f729Sjoerg   }
11447330f729Sjoerg 
11457330f729Sjoerg   if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
11467330f729Sjoerg     QualType PointeeType = PT->getPointeeType();
11477330f729Sjoerg     if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
11487330f729Sjoerg       SourceRange ArgRange = OrigArg->getSourceRange();
11497330f729Sjoerg       commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
11507330f729Sjoerg 
11517330f729Sjoerg       if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
11527330f729Sjoerg         commit.insertBefore(ArgRange.getBegin(), "@");
11537330f729Sjoerg       else
11547330f729Sjoerg         commit.insertWrap("@(", ArgRange, ")");
11557330f729Sjoerg 
11567330f729Sjoerg       return true;
11577330f729Sjoerg     }
11587330f729Sjoerg   }
11597330f729Sjoerg 
11607330f729Sjoerg   return false;
11617330f729Sjoerg }
11627330f729Sjoerg 
rewriteToStringBoxedExpression(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)11637330f729Sjoerg static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
11647330f729Sjoerg                                            const NSAPI &NS, Commit &commit) {
11657330f729Sjoerg   Selector Sel = Msg->getSelector();
11667330f729Sjoerg 
11677330f729Sjoerg   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
11687330f729Sjoerg       Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString) ||
11697330f729Sjoerg       Sel == NS.getNSStringSelector(NSAPI::NSStr_initWithUTF8String)) {
11707330f729Sjoerg     if (Msg->getNumArgs() != 1)
11717330f729Sjoerg       return false;
11727330f729Sjoerg     return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
11737330f729Sjoerg   }
11747330f729Sjoerg 
11757330f729Sjoerg   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
11767330f729Sjoerg     if (Msg->getNumArgs() != 2)
11777330f729Sjoerg       return false;
11787330f729Sjoerg 
11797330f729Sjoerg     const Expr *encodingArg = Msg->getArg(1);
11807330f729Sjoerg     if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
11817330f729Sjoerg         NS.isNSASCIIStringEncodingConstant(encodingArg))
11827330f729Sjoerg       return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
11837330f729Sjoerg   }
11847330f729Sjoerg 
11857330f729Sjoerg   return false;
11867330f729Sjoerg }
1187