1 //===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Rewrites legacy method calls to modern syntax.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/Edit/Rewriters.h"
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/ExprCXX.h"
17 #include "clang/AST/ExprObjC.h"
18 #include "clang/AST/NSAPI.h"
19 #include "clang/AST/ParentMap.h"
20 #include "clang/Edit/Commit.h"
21 #include "clang/Lex/Lexer.h"
22 
23 using namespace clang;
24 using namespace edit;
25 
26 static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
27                                     IdentifierInfo *&ClassId,
28                                     const LangOptions &LangOpts) {
29   if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
30     return false;
31 
32   const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
33   if (!Receiver)
34     return false;
35   ClassId = Receiver->getIdentifier();
36 
37   if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
38     return true;
39 
40   // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
41   // since the change from +1 to +0 will be handled fine by ARC.
42   if (LangOpts.ObjCAutoRefCount) {
43     if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
44       if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
45                            Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
46         if (Rec->getMethodFamily() == OMF_alloc)
47           return true;
48       }
49     }
50   }
51 
52   return false;
53 }
54 
55 //===----------------------------------------------------------------------===//
56 // rewriteObjCRedundantCallWithLiteral.
57 //===----------------------------------------------------------------------===//
58 
59 bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
60                                               const NSAPI &NS, Commit &commit) {
61   IdentifierInfo *II = 0;
62   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
63     return false;
64   if (Msg->getNumArgs() != 1)
65     return false;
66 
67   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
68   Selector Sel = Msg->getSelector();
69 
70   if ((isa<ObjCStringLiteral>(Arg) &&
71        NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
72        (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
73         NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel))   ||
74 
75       (isa<ObjCArrayLiteral>(Arg) &&
76        NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
77        (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
78         NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel))     ||
79 
80       (isa<ObjCDictionaryLiteral>(Arg) &&
81        NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
82        (NS.getNSDictionarySelector(
83                               NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
84         NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
85 
86     commit.replaceWithInner(Msg->getSourceRange(),
87                            Msg->getArg(0)->getSourceRange());
88     return true;
89   }
90 
91   return false;
92 }
93 
94 //===----------------------------------------------------------------------===//
95 // rewriteToObjCSubscriptSyntax.
96 //===----------------------------------------------------------------------===//
97 
98 /// \brief Check for classes that accept 'objectForKey:' (or the other selectors
99 /// that the migrator handles) but return their instances as 'id', resulting
100 /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
101 ///
102 /// When checking if we can convert to subscripting syntax, check whether
103 /// the receiver is a result of a class method from a hardcoded list of
104 /// such classes. In such a case return the specific class as the interface
105 /// of the receiver.
106 ///
107 /// FIXME: Remove this when these classes start using 'instancetype'.
108 static const ObjCInterfaceDecl *
109 maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
110                                          const Expr *Receiver,
111                                          ASTContext &Ctx) {
112   assert(IFace && Receiver);
113 
114   // If the receiver has type 'id'...
115   if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
116     return IFace;
117 
118   const ObjCMessageExpr *
119     InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
120   if (!InnerMsg)
121     return IFace;
122 
123   QualType ClassRec;
124   switch (InnerMsg->getReceiverKind()) {
125   case ObjCMessageExpr::Instance:
126   case ObjCMessageExpr::SuperInstance:
127     return IFace;
128 
129   case ObjCMessageExpr::Class:
130     ClassRec = InnerMsg->getClassReceiver();
131     break;
132   case ObjCMessageExpr::SuperClass:
133     ClassRec = InnerMsg->getSuperType();
134     break;
135   }
136 
137   if (ClassRec.isNull())
138     return IFace;
139 
140   // ...and it is the result of a class message...
141 
142   const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
143   if (!ObjTy)
144     return IFace;
145   const ObjCInterfaceDecl *OID = ObjTy->getInterface();
146 
147   // ...and the receiving class is NSMapTable or NSLocale, return that
148   // class as the receiving interface.
149   if (OID->getName() == "NSMapTable" ||
150       OID->getName() == "NSLocale")
151     return OID;
152 
153   return IFace;
154 }
155 
156 static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
157                                         const ObjCMessageExpr *Msg,
158                                         ASTContext &Ctx,
159                                         Selector subscriptSel) {
160   const Expr *Rec = Msg->getInstanceReceiver();
161   if (!Rec)
162     return false;
163   IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
164 
165   if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
166     if (!MD->isUnavailable())
167       return true;
168   }
169   return false;
170 }
171 
172 static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
173 
174 static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
175   if (subscriptOperatorNeedsParens(Receiver)) {
176     SourceRange RecRange = Receiver->getSourceRange();
177     commit.insertWrap("(", RecRange, ")");
178   }
179 }
180 
181 static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
182                                         Commit &commit) {
183   if (Msg->getNumArgs() != 1)
184     return false;
185   const Expr *Rec = Msg->getInstanceReceiver();
186   if (!Rec)
187     return false;
188 
189   SourceRange MsgRange = Msg->getSourceRange();
190   SourceRange RecRange = Rec->getSourceRange();
191   SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
192 
193   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
194                                                        ArgRange.getBegin()),
195                          CharSourceRange::getTokenRange(RecRange));
196   commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
197                          ArgRange);
198   commit.insertWrap("[", ArgRange, "]");
199   maybePutParensOnReceiver(Rec, commit);
200   return true;
201 }
202 
203 static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
204                                        const ObjCMessageExpr *Msg,
205                                        const NSAPI &NS,
206                                        Commit &commit) {
207   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
208                                    NS.getObjectAtIndexedSubscriptSelector()))
209     return false;
210   return rewriteToSubscriptGetCommon(Msg, commit);
211 }
212 
213 static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
214                                             const ObjCMessageExpr *Msg,
215                                             const NSAPI &NS,
216                                             Commit &commit) {
217   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
218                                   NS.getObjectForKeyedSubscriptSelector()))
219     return false;
220   return rewriteToSubscriptGetCommon(Msg, commit);
221 }
222 
223 static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
224                                        const ObjCMessageExpr *Msg,
225                                        const NSAPI &NS,
226                                        Commit &commit) {
227   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
228                                    NS.getSetObjectAtIndexedSubscriptSelector()))
229     return false;
230 
231   if (Msg->getNumArgs() != 2)
232     return false;
233   const Expr *Rec = Msg->getInstanceReceiver();
234   if (!Rec)
235     return false;
236 
237   SourceRange MsgRange = Msg->getSourceRange();
238   SourceRange RecRange = Rec->getSourceRange();
239   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
240   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
241 
242   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
243                                                        Arg0Range.getBegin()),
244                          CharSourceRange::getTokenRange(RecRange));
245   commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
246                                                        Arg1Range.getBegin()),
247                          CharSourceRange::getTokenRange(Arg0Range));
248   commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
249                          Arg1Range);
250   commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
251                                                        Arg1Range.getBegin()),
252                     "] = ");
253   maybePutParensOnReceiver(Rec, commit);
254   return true;
255 }
256 
257 static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
258                                             const ObjCMessageExpr *Msg,
259                                             const NSAPI &NS,
260                                             Commit &commit) {
261   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
262                                    NS.getSetObjectForKeyedSubscriptSelector()))
263     return false;
264 
265   if (Msg->getNumArgs() != 2)
266     return false;
267   const Expr *Rec = Msg->getInstanceReceiver();
268   if (!Rec)
269     return false;
270 
271   SourceRange MsgRange = Msg->getSourceRange();
272   SourceRange RecRange = Rec->getSourceRange();
273   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
274   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
275 
276   SourceLocation LocBeforeVal = Arg0Range.getBegin();
277   commit.insertBefore(LocBeforeVal, "] = ");
278   commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
279                          /*beforePreviousInsertions=*/true);
280   commit.insertBefore(LocBeforeVal, "[");
281   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
282                                                        Arg0Range.getBegin()),
283                          CharSourceRange::getTokenRange(RecRange));
284   commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
285                          Arg0Range);
286   maybePutParensOnReceiver(Rec, commit);
287   return true;
288 }
289 
290 bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
291                                         const NSAPI &NS, Commit &commit) {
292   if (!Msg || Msg->isImplicit() ||
293       Msg->getReceiverKind() != ObjCMessageExpr::Instance)
294     return false;
295   const ObjCMethodDecl *Method = Msg->getMethodDecl();
296   if (!Method)
297     return false;
298 
299   const ObjCInterfaceDecl *IFace =
300       NS.getASTContext().getObjContainingInterface(Method);
301   if (!IFace)
302     return false;
303   Selector Sel = Msg->getSelector();
304 
305   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex))
306     return rewriteToArraySubscriptGet(IFace, Msg, NS, commit);
307 
308   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey))
309     return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit);
310 
311   if (Msg->getNumArgs() != 2)
312     return false;
313 
314   if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
315     return rewriteToArraySubscriptSet(IFace, Msg, NS, commit);
316 
317   if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
318     return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit);
319 
320   return false;
321 }
322 
323 //===----------------------------------------------------------------------===//
324 // rewriteToObjCLiteralSyntax.
325 //===----------------------------------------------------------------------===//
326 
327 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
328                                   const NSAPI &NS, Commit &commit,
329                                   const ParentMap *PMap);
330 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
331                                   const NSAPI &NS, Commit &commit);
332 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
333                                   const NSAPI &NS, Commit &commit);
334 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
335                                             const NSAPI &NS, Commit &commit);
336 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
337                                            const NSAPI &NS, Commit &commit);
338 
339 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
340                                       const NSAPI &NS, Commit &commit,
341                                       const ParentMap *PMap) {
342   IdentifierInfo *II = 0;
343   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
344     return false;
345 
346   if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
347     return rewriteToArrayLiteral(Msg, NS, commit, PMap);
348   if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
349     return rewriteToDictionaryLiteral(Msg, NS, commit);
350   if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
351     return rewriteToNumberLiteral(Msg, NS, commit);
352   if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
353     return rewriteToStringBoxedExpression(Msg, NS, commit);
354 
355   return false;
356 }
357 
358 bool edit::rewriteToObjCProperty(const ObjCMethodDecl *Getter,
359                                  const ObjCMethodDecl *Setter,
360                                  const NSAPI &NS, Commit &commit) {
361   ASTContext &Context = NS.getASTContext();
362   std::string PropertyString = "@property";
363   const ParmVarDecl *argDecl = *Setter->param_begin();
364   QualType ArgType = Context.getCanonicalType(argDecl->getType());
365   Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
366 
367   if (ArgType->isObjCRetainableType() &&
368       propertyLifetime == Qualifiers::OCL_Strong) {
369     if (const ObjCObjectPointerType *ObjPtrTy =
370           ArgType->getAs<ObjCObjectPointerType>()) {
371       ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
372       if (IDecl &&
373           IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
374         PropertyString += "(copy)";
375     }
376   }
377   else if (propertyLifetime == Qualifiers::OCL_Weak)
378     // TODO. More precise determination of 'weak' attribute requires
379     // looking into setter's implementation for backing weak ivar.
380     PropertyString += "(weak)";
381   else
382     PropertyString += "(unsafe_unretained)";
383 
384   // strip off any ARC lifetime qualifier.
385   QualType CanResultTy = Context.getCanonicalType(Getter->getResultType());
386   if (CanResultTy.getQualifiers().hasObjCLifetime()) {
387     Qualifiers Qs = CanResultTy.getQualifiers();
388     Qs.removeObjCLifetime();
389     CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
390   }
391   PropertyString += " ";
392   PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy());
393   PropertyString += " ";
394   PropertyString += Getter->getNameAsString();
395   commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(),
396                                                Getter->getDeclaratorEndLoc()),
397                  PropertyString);
398   SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
399   // Get location past ';'
400   EndLoc = EndLoc.getLocWithOffset(1);
401   commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc));
402   return true;
403 }
404 
405 bool edit::rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
406                   llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
407                   const NSAPI &NS, Commit &commit) {
408   const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
409 
410   // ASTContext &Context = NS.getASTContext();
411   std::string ClassString = "@interface ";
412   ClassString += IDecl->getNameAsString();
413 
414   if (IDecl->getSuperClass()) {
415     ClassString += " : ";
416     ClassString += IDecl->getSuperClass()->getNameAsString();
417   }
418   if (Protocols.empty())
419     ClassString += '<';
420 
421   for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
422        E = Protocols.end(); I != E; ++I) {
423     ClassString += (I == Protocols.begin() ? '<' : ',');
424     ClassString += (*I)->getNameAsString();
425   }
426   if (!Protocols.empty())
427     ClassString += ',';
428   for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
429     ClassString += ConformingProtocols[i]->getNameAsString();
430     if (i != (e-1))
431       ClassString += ',';
432   }
433   ClassString += "> ";
434   return true;
435 }
436 
437 /// \brief Returns true if the immediate message arguments of \c Msg should not
438 /// be rewritten because it will interfere with the rewrite of the parent
439 /// message expression. e.g.
440 /// \code
441 ///   [NSDictionary dictionaryWithObjects:
442 ///                                 [NSArray arrayWithObjects:@"1", @"2", nil]
443 ///                         forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
444 /// \endcode
445 /// It will return true for this because we are going to rewrite this directly
446 /// to a dictionary literal without any array literals.
447 static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
448                                                  const NSAPI &NS);
449 
450 //===----------------------------------------------------------------------===//
451 // rewriteToArrayLiteral.
452 //===----------------------------------------------------------------------===//
453 
454 /// \brief Adds an explicit cast to 'id' if the type is not objc object.
455 static void objectifyExpr(const Expr *E, Commit &commit);
456 
457 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
458                                   const NSAPI &NS, Commit &commit,
459                                   const ParentMap *PMap) {
460   if (PMap) {
461     const ObjCMessageExpr *ParentMsg =
462         dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
463     if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
464       return false;
465   }
466 
467   Selector Sel = Msg->getSelector();
468   SourceRange MsgRange = Msg->getSourceRange();
469 
470   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
471     if (Msg->getNumArgs() != 0)
472       return false;
473     commit.replace(MsgRange, "@[]");
474     return true;
475   }
476 
477   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
478     if (Msg->getNumArgs() != 1)
479       return false;
480     objectifyExpr(Msg->getArg(0), commit);
481     SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
482     commit.replaceWithInner(MsgRange, ArgRange);
483     commit.insertWrap("@[", ArgRange, "]");
484     return true;
485   }
486 
487   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
488       Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
489     if (Msg->getNumArgs() == 0)
490       return false;
491     const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
492     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
493       return false;
494 
495     for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
496       objectifyExpr(Msg->getArg(i), commit);
497 
498     if (Msg->getNumArgs() == 1) {
499       commit.replace(MsgRange, "@[]");
500       return true;
501     }
502     SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
503                          Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
504     commit.replaceWithInner(MsgRange, ArgRange);
505     commit.insertWrap("@[", ArgRange, "]");
506     return true;
507   }
508 
509   return false;
510 }
511 
512 //===----------------------------------------------------------------------===//
513 // rewriteToDictionaryLiteral.
514 //===----------------------------------------------------------------------===//
515 
516 /// \brief If \c Msg is an NSArray creation message or literal, this gets the
517 /// objects that were used to create it.
518 /// \returns true if it is an NSArray and we got objects, or false otherwise.
519 static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
520                               SmallVectorImpl<const Expr *> &Objs) {
521   if (!E)
522     return false;
523 
524   E = E->IgnoreParenCasts();
525   if (!E)
526     return false;
527 
528   if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
529     IdentifierInfo *Cls = 0;
530     if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
531       return false;
532 
533     if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
534       return false;
535 
536     Selector Sel = Msg->getSelector();
537     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
538       return true; // empty array.
539 
540     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
541       if (Msg->getNumArgs() != 1)
542         return false;
543       Objs.push_back(Msg->getArg(0));
544       return true;
545     }
546 
547     if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
548         Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
549       if (Msg->getNumArgs() == 0)
550         return false;
551       const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
552       if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
553         return false;
554 
555       for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
556         Objs.push_back(Msg->getArg(i));
557       return true;
558     }
559 
560   } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
561     for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
562       Objs.push_back(ArrLit->getElement(i));
563     return true;
564   }
565 
566   return false;
567 }
568 
569 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
570                                        const NSAPI &NS, Commit &commit) {
571   Selector Sel = Msg->getSelector();
572   SourceRange MsgRange = Msg->getSourceRange();
573 
574   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
575     if (Msg->getNumArgs() != 0)
576       return false;
577     commit.replace(MsgRange, "@{}");
578     return true;
579   }
580 
581   if (Sel == NS.getNSDictionarySelector(
582                                     NSAPI::NSDict_dictionaryWithObjectForKey)) {
583     if (Msg->getNumArgs() != 2)
584       return false;
585 
586     objectifyExpr(Msg->getArg(0), commit);
587     objectifyExpr(Msg->getArg(1), commit);
588 
589     SourceRange ValRange = Msg->getArg(0)->getSourceRange();
590     SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
591     // Insert key before the value.
592     commit.insertBefore(ValRange.getBegin(), ": ");
593     commit.insertFromRange(ValRange.getBegin(),
594                            CharSourceRange::getTokenRange(KeyRange),
595                        /*afterToken=*/false, /*beforePreviousInsertions=*/true);
596     commit.insertBefore(ValRange.getBegin(), "@{");
597     commit.insertAfterToken(ValRange.getEnd(), "}");
598     commit.replaceWithInner(MsgRange, ValRange);
599     return true;
600   }
601 
602   if (Sel == NS.getNSDictionarySelector(
603                                   NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
604       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
605     if (Msg->getNumArgs() % 2 != 1)
606       return false;
607     unsigned SentinelIdx = Msg->getNumArgs() - 1;
608     const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
609     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
610       return false;
611 
612     if (Msg->getNumArgs() == 1) {
613       commit.replace(MsgRange, "@{}");
614       return true;
615     }
616 
617     for (unsigned i = 0; i < SentinelIdx; i += 2) {
618       objectifyExpr(Msg->getArg(i), commit);
619       objectifyExpr(Msg->getArg(i+1), commit);
620 
621       SourceRange ValRange = Msg->getArg(i)->getSourceRange();
622       SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
623       // Insert value after key.
624       commit.insertAfterToken(KeyRange.getEnd(), ": ");
625       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
626       commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
627                                                   KeyRange.getBegin()));
628     }
629     // Range of arguments up until and including the last key.
630     // The sentinel and first value are cut off, the value will move after the
631     // key.
632     SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
633                          Msg->getArg(SentinelIdx-1)->getLocEnd());
634     commit.insertWrap("@{", ArgRange, "}");
635     commit.replaceWithInner(MsgRange, ArgRange);
636     return true;
637   }
638 
639   if (Sel == NS.getNSDictionarySelector(
640                                   NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
641       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
642     if (Msg->getNumArgs() != 2)
643       return false;
644 
645     SmallVector<const Expr *, 8> Vals;
646     if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
647       return false;
648 
649     SmallVector<const Expr *, 8> Keys;
650     if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
651       return false;
652 
653     if (Vals.size() != Keys.size())
654       return false;
655 
656     if (Vals.empty()) {
657       commit.replace(MsgRange, "@{}");
658       return true;
659     }
660 
661     for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
662       objectifyExpr(Vals[i], commit);
663       objectifyExpr(Keys[i], commit);
664 
665       SourceRange ValRange = Vals[i]->getSourceRange();
666       SourceRange KeyRange = Keys[i]->getSourceRange();
667       // Insert value after key.
668       commit.insertAfterToken(KeyRange.getEnd(), ": ");
669       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
670     }
671     // Range of arguments up until and including the last key.
672     // The first value is cut off, the value will move after the key.
673     SourceRange ArgRange(Keys.front()->getLocStart(),
674                          Keys.back()->getLocEnd());
675     commit.insertWrap("@{", ArgRange, "}");
676     commit.replaceWithInner(MsgRange, ArgRange);
677     return true;
678   }
679 
680   return false;
681 }
682 
683 static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
684                                                  const NSAPI &NS) {
685   if (!Msg)
686     return false;
687 
688   IdentifierInfo *II = 0;
689   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
690     return false;
691 
692   if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
693     return false;
694 
695   Selector Sel = Msg->getSelector();
696   if (Sel == NS.getNSDictionarySelector(
697                                   NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
698       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
699     if (Msg->getNumArgs() != 2)
700       return false;
701 
702     SmallVector<const Expr *, 8> Vals;
703     if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
704       return false;
705 
706     SmallVector<const Expr *, 8> Keys;
707     if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
708       return false;
709 
710     if (Vals.size() != Keys.size())
711       return false;
712 
713     return true;
714   }
715 
716   return false;
717 }
718 
719 //===----------------------------------------------------------------------===//
720 // rewriteToNumberLiteral.
721 //===----------------------------------------------------------------------===//
722 
723 static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
724                                    const CharacterLiteral *Arg,
725                                    const NSAPI &NS, Commit &commit) {
726   if (Arg->getKind() != CharacterLiteral::Ascii)
727     return false;
728   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
729                                    Msg->getSelector())) {
730     SourceRange ArgRange = Arg->getSourceRange();
731     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
732     commit.insert(ArgRange.getBegin(), "@");
733     return true;
734   }
735 
736   return rewriteToNumericBoxedExpression(Msg, NS, commit);
737 }
738 
739 static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
740                                    const Expr *Arg,
741                                    const NSAPI &NS, Commit &commit) {
742   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
743                                    Msg->getSelector())) {
744     SourceRange ArgRange = Arg->getSourceRange();
745     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
746     commit.insert(ArgRange.getBegin(), "@");
747     return true;
748   }
749 
750   return rewriteToNumericBoxedExpression(Msg, NS, commit);
751 }
752 
753 namespace {
754 
755 struct LiteralInfo {
756   bool Hex, Octal;
757   StringRef U, F, L, LL;
758   CharSourceRange WithoutSuffRange;
759 };
760 
761 }
762 
763 static bool getLiteralInfo(SourceRange literalRange,
764                            bool isFloat, bool isIntZero,
765                           ASTContext &Ctx, LiteralInfo &Info) {
766   if (literalRange.getBegin().isMacroID() ||
767       literalRange.getEnd().isMacroID())
768     return false;
769   StringRef text = Lexer::getSourceText(
770                                   CharSourceRange::getTokenRange(literalRange),
771                                   Ctx.getSourceManager(), Ctx.getLangOpts());
772   if (text.empty())
773     return false;
774 
775   Optional<bool> UpperU, UpperL;
776   bool UpperF = false;
777 
778   struct Suff {
779     static bool has(StringRef suff, StringRef &text) {
780       if (text.endswith(suff)) {
781         text = text.substr(0, text.size()-suff.size());
782         return true;
783       }
784       return false;
785     }
786   };
787 
788   while (1) {
789     if (Suff::has("u", text)) {
790       UpperU = false;
791     } else if (Suff::has("U", text)) {
792       UpperU = true;
793     } else if (Suff::has("ll", text)) {
794       UpperL = false;
795     } else if (Suff::has("LL", text)) {
796       UpperL = true;
797     } else if (Suff::has("l", text)) {
798       UpperL = false;
799     } else if (Suff::has("L", text)) {
800       UpperL = true;
801     } else if (isFloat && Suff::has("f", text)) {
802       UpperF = false;
803     } else if (isFloat && Suff::has("F", text)) {
804       UpperF = true;
805     } else
806       break;
807   }
808 
809   if (!UpperU.hasValue() && !UpperL.hasValue())
810     UpperU = UpperL = true;
811   else if (UpperU.hasValue() && !UpperL.hasValue())
812     UpperL = UpperU;
813   else if (UpperL.hasValue() && !UpperU.hasValue())
814     UpperU = UpperL;
815 
816   Info.U = *UpperU ? "U" : "u";
817   Info.L = *UpperL ? "L" : "l";
818   Info.LL = *UpperL ? "LL" : "ll";
819   Info.F = UpperF ? "F" : "f";
820 
821   Info.Hex = Info.Octal = false;
822   if (text.startswith("0x"))
823     Info.Hex = true;
824   else if (!isFloat && !isIntZero && text.startswith("0"))
825     Info.Octal = true;
826 
827   SourceLocation B = literalRange.getBegin();
828   Info.WithoutSuffRange =
829       CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
830   return true;
831 }
832 
833 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
834                                    const NSAPI &NS, Commit &commit) {
835   if (Msg->getNumArgs() != 1)
836     return false;
837 
838   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
839   if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
840     return rewriteToCharLiteral(Msg, CharE, NS, commit);
841   if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
842     return rewriteToBoolLiteral(Msg, BE, NS, commit);
843   if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
844     return rewriteToBoolLiteral(Msg, BE, NS, commit);
845 
846   const Expr *literalE = Arg;
847   if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
848     if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
849       literalE = UOE->getSubExpr();
850   }
851 
852   // Only integer and floating literals, otherwise try to rewrite to boxed
853   // expression.
854   if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
855     return rewriteToNumericBoxedExpression(Msg, NS, commit);
856 
857   ASTContext &Ctx = NS.getASTContext();
858   Selector Sel = Msg->getSelector();
859   Optional<NSAPI::NSNumberLiteralMethodKind>
860     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
861   if (!MKOpt)
862     return false;
863   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
864 
865   bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
866   bool CallIsFloating = false, CallIsDouble = false;
867 
868   switch (MK) {
869   // We cannot have these calls with int/float literals.
870   case NSAPI::NSNumberWithChar:
871   case NSAPI::NSNumberWithUnsignedChar:
872   case NSAPI::NSNumberWithShort:
873   case NSAPI::NSNumberWithUnsignedShort:
874   case NSAPI::NSNumberWithBool:
875     return rewriteToNumericBoxedExpression(Msg, NS, commit);
876 
877   case NSAPI::NSNumberWithUnsignedInt:
878   case NSAPI::NSNumberWithUnsignedInteger:
879     CallIsUnsigned = true;
880   case NSAPI::NSNumberWithInt:
881   case NSAPI::NSNumberWithInteger:
882     break;
883 
884   case NSAPI::NSNumberWithUnsignedLong:
885     CallIsUnsigned = true;
886   case NSAPI::NSNumberWithLong:
887     CallIsLong = true;
888     break;
889 
890   case NSAPI::NSNumberWithUnsignedLongLong:
891     CallIsUnsigned = true;
892   case NSAPI::NSNumberWithLongLong:
893     CallIsLongLong = true;
894     break;
895 
896   case NSAPI::NSNumberWithDouble:
897     CallIsDouble = true;
898   case NSAPI::NSNumberWithFloat:
899     CallIsFloating = true;
900     break;
901   }
902 
903   SourceRange ArgRange = Arg->getSourceRange();
904   QualType ArgTy = Arg->getType();
905   QualType CallTy = Msg->getArg(0)->getType();
906 
907   // Check for the easy case, the literal maps directly to the call.
908   if (Ctx.hasSameType(ArgTy, CallTy)) {
909     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
910     commit.insert(ArgRange.getBegin(), "@");
911     return true;
912   }
913 
914   // We will need to modify the literal suffix to get the same type as the call.
915   // Try with boxed expression if it came from a macro.
916   if (ArgRange.getBegin().isMacroID())
917     return rewriteToNumericBoxedExpression(Msg, NS, commit);
918 
919   bool LitIsFloat = ArgTy->isFloatingType();
920   // For a float passed to integer call, don't try rewriting to objc literal.
921   // It is difficult and a very uncommon case anyway.
922   // But try with boxed expression.
923   if (LitIsFloat && !CallIsFloating)
924     return rewriteToNumericBoxedExpression(Msg, NS, commit);
925 
926   // Try to modify the literal make it the same type as the method call.
927   // -Modify the suffix, and/or
928   // -Change integer to float
929 
930   LiteralInfo LitInfo;
931   bool isIntZero = false;
932   if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
933     isIntZero = !IntE->getValue().getBoolValue();
934   if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
935     return rewriteToNumericBoxedExpression(Msg, NS, commit);
936 
937   // Not easy to do int -> float with hex/octal and uncommon anyway.
938   if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
939     return rewriteToNumericBoxedExpression(Msg, NS, commit);
940 
941   SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
942   SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
943 
944   commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
945                          LitInfo.WithoutSuffRange);
946   commit.insert(LitB, "@");
947 
948   if (!LitIsFloat && CallIsFloating)
949     commit.insert(LitE, ".0");
950 
951   if (CallIsFloating) {
952     if (!CallIsDouble)
953       commit.insert(LitE, LitInfo.F);
954   } else {
955     if (CallIsUnsigned)
956       commit.insert(LitE, LitInfo.U);
957 
958     if (CallIsLong)
959       commit.insert(LitE, LitInfo.L);
960     else if (CallIsLongLong)
961       commit.insert(LitE, LitInfo.LL);
962   }
963   return true;
964 }
965 
966 // FIXME: Make determination of operator precedence more general and
967 // make it broadly available.
968 static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
969   const Expr* Expr = FullExpr->IgnoreImpCasts();
970   if (isa<ArraySubscriptExpr>(Expr) ||
971       isa<CallExpr>(Expr) ||
972       isa<DeclRefExpr>(Expr) ||
973       isa<CXXNamedCastExpr>(Expr) ||
974       isa<CXXConstructExpr>(Expr) ||
975       isa<CXXThisExpr>(Expr) ||
976       isa<CXXTypeidExpr>(Expr) ||
977       isa<CXXUnresolvedConstructExpr>(Expr) ||
978       isa<ObjCMessageExpr>(Expr) ||
979       isa<ObjCPropertyRefExpr>(Expr) ||
980       isa<ObjCProtocolExpr>(Expr) ||
981       isa<MemberExpr>(Expr) ||
982       isa<ObjCIvarRefExpr>(Expr) ||
983       isa<ParenExpr>(FullExpr) ||
984       isa<ParenListExpr>(Expr) ||
985       isa<SizeOfPackExpr>(Expr))
986     return false;
987 
988   return true;
989 }
990 static bool castOperatorNeedsParens(const Expr *FullExpr) {
991   const Expr* Expr = FullExpr->IgnoreImpCasts();
992   if (isa<ArraySubscriptExpr>(Expr) ||
993       isa<CallExpr>(Expr) ||
994       isa<DeclRefExpr>(Expr) ||
995       isa<CastExpr>(Expr) ||
996       isa<CXXNewExpr>(Expr) ||
997       isa<CXXConstructExpr>(Expr) ||
998       isa<CXXDeleteExpr>(Expr) ||
999       isa<CXXNoexceptExpr>(Expr) ||
1000       isa<CXXPseudoDestructorExpr>(Expr) ||
1001       isa<CXXScalarValueInitExpr>(Expr) ||
1002       isa<CXXThisExpr>(Expr) ||
1003       isa<CXXTypeidExpr>(Expr) ||
1004       isa<CXXUnresolvedConstructExpr>(Expr) ||
1005       isa<ObjCMessageExpr>(Expr) ||
1006       isa<ObjCPropertyRefExpr>(Expr) ||
1007       isa<ObjCProtocolExpr>(Expr) ||
1008       isa<MemberExpr>(Expr) ||
1009       isa<ObjCIvarRefExpr>(Expr) ||
1010       isa<ParenExpr>(FullExpr) ||
1011       isa<ParenListExpr>(Expr) ||
1012       isa<SizeOfPackExpr>(Expr) ||
1013       isa<UnaryOperator>(Expr))
1014     return false;
1015 
1016   return true;
1017 }
1018 
1019 static void objectifyExpr(const Expr *E, Commit &commit) {
1020   if (!E) return;
1021 
1022   QualType T = E->getType();
1023   if (T->isObjCObjectPointerType()) {
1024     if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
1025       if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
1026         return;
1027     } else {
1028       return;
1029     }
1030   } else if (!T->isPointerType()) {
1031     return;
1032   }
1033 
1034   SourceRange Range = E->getSourceRange();
1035   if (castOperatorNeedsParens(E))
1036     commit.insertWrap("(", Range, ")");
1037   commit.insertBefore(Range.getBegin(), "(id)");
1038 }
1039 
1040 //===----------------------------------------------------------------------===//
1041 // rewriteToNumericBoxedExpression.
1042 //===----------------------------------------------------------------------===//
1043 
1044 static bool isEnumConstant(const Expr *E) {
1045   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
1046     if (const ValueDecl *VD = DRE->getDecl())
1047       return isa<EnumConstantDecl>(VD);
1048 
1049   return false;
1050 }
1051 
1052 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
1053                                             const NSAPI &NS, Commit &commit) {
1054   if (Msg->getNumArgs() != 1)
1055     return false;
1056 
1057   const Expr *Arg = Msg->getArg(0);
1058   if (Arg->isTypeDependent())
1059     return false;
1060 
1061   ASTContext &Ctx = NS.getASTContext();
1062   Selector Sel = Msg->getSelector();
1063   Optional<NSAPI::NSNumberLiteralMethodKind>
1064     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
1065   if (!MKOpt)
1066     return false;
1067   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
1068 
1069   const Expr *OrigArg = Arg->IgnoreImpCasts();
1070   QualType FinalTy = Arg->getType();
1071   QualType OrigTy = OrigArg->getType();
1072   uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
1073   uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
1074 
1075   bool isTruncated = FinalTySize < OrigTySize;
1076   bool needsCast = false;
1077 
1078   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
1079     switch (ICE->getCastKind()) {
1080     case CK_LValueToRValue:
1081     case CK_NoOp:
1082     case CK_UserDefinedConversion:
1083       break;
1084 
1085     case CK_IntegralCast: {
1086       if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
1087         break;
1088       // Be more liberal with Integer/UnsignedInteger which are very commonly
1089       // used.
1090       if ((MK == NSAPI::NSNumberWithInteger ||
1091            MK == NSAPI::NSNumberWithUnsignedInteger) &&
1092           !isTruncated) {
1093         if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
1094           break;
1095         if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
1096             OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
1097           break;
1098       }
1099 
1100       needsCast = true;
1101       break;
1102     }
1103 
1104     case CK_PointerToBoolean:
1105     case CK_IntegralToBoolean:
1106     case CK_IntegralToFloating:
1107     case CK_FloatingToIntegral:
1108     case CK_FloatingToBoolean:
1109     case CK_FloatingCast:
1110     case CK_FloatingComplexToReal:
1111     case CK_FloatingComplexToBoolean:
1112     case CK_IntegralComplexToReal:
1113     case CK_IntegralComplexToBoolean:
1114     case CK_AtomicToNonAtomic:
1115       needsCast = true;
1116       break;
1117 
1118     case CK_Dependent:
1119     case CK_BitCast:
1120     case CK_LValueBitCast:
1121     case CK_BaseToDerived:
1122     case CK_DerivedToBase:
1123     case CK_UncheckedDerivedToBase:
1124     case CK_Dynamic:
1125     case CK_ToUnion:
1126     case CK_ArrayToPointerDecay:
1127     case CK_FunctionToPointerDecay:
1128     case CK_NullToPointer:
1129     case CK_NullToMemberPointer:
1130     case CK_BaseToDerivedMemberPointer:
1131     case CK_DerivedToBaseMemberPointer:
1132     case CK_MemberPointerToBoolean:
1133     case CK_ReinterpretMemberPointer:
1134     case CK_ConstructorConversion:
1135     case CK_IntegralToPointer:
1136     case CK_PointerToIntegral:
1137     case CK_ToVoid:
1138     case CK_VectorSplat:
1139     case CK_CPointerToObjCPointerCast:
1140     case CK_BlockPointerToObjCPointerCast:
1141     case CK_AnyPointerToBlockPointerCast:
1142     case CK_ObjCObjectLValueCast:
1143     case CK_FloatingRealToComplex:
1144     case CK_FloatingComplexCast:
1145     case CK_FloatingComplexToIntegralComplex:
1146     case CK_IntegralRealToComplex:
1147     case CK_IntegralComplexCast:
1148     case CK_IntegralComplexToFloatingComplex:
1149     case CK_ARCProduceObject:
1150     case CK_ARCConsumeObject:
1151     case CK_ARCReclaimReturnedObject:
1152     case CK_ARCExtendBlockObject:
1153     case CK_NonAtomicToAtomic:
1154     case CK_CopyAndAutoreleaseBlockObject:
1155     case CK_BuiltinFnToFnPtr:
1156     case CK_ZeroToOCLEvent:
1157       return false;
1158     }
1159   }
1160 
1161   if (needsCast) {
1162     DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1163     // FIXME: Use a custom category name to distinguish migration diagnostics.
1164     unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
1165                        "converting to boxing syntax requires casting %0 to %1");
1166     Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
1167         << Msg->getSourceRange();
1168     return false;
1169   }
1170 
1171   SourceRange ArgRange = OrigArg->getSourceRange();
1172   commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1173 
1174   if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1175     commit.insertBefore(ArgRange.getBegin(), "@");
1176   else
1177     commit.insertWrap("@(", ArgRange, ")");
1178 
1179   return true;
1180 }
1181 
1182 //===----------------------------------------------------------------------===//
1183 // rewriteToStringBoxedExpression.
1184 //===----------------------------------------------------------------------===//
1185 
1186 static bool doRewriteToUTF8StringBoxedExpressionHelper(
1187                                               const ObjCMessageExpr *Msg,
1188                                               const NSAPI &NS, Commit &commit) {
1189   const Expr *Arg = Msg->getArg(0);
1190   if (Arg->isTypeDependent())
1191     return false;
1192 
1193   ASTContext &Ctx = NS.getASTContext();
1194 
1195   const Expr *OrigArg = Arg->IgnoreImpCasts();
1196   QualType OrigTy = OrigArg->getType();
1197   if (OrigTy->isArrayType())
1198     OrigTy = Ctx.getArrayDecayedType(OrigTy);
1199 
1200   if (const StringLiteral *
1201         StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
1202     commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
1203     commit.insert(StrE->getLocStart(), "@");
1204     return true;
1205   }
1206 
1207   if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
1208     QualType PointeeType = PT->getPointeeType();
1209     if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
1210       SourceRange ArgRange = OrigArg->getSourceRange();
1211       commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
1212 
1213       if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
1214         commit.insertBefore(ArgRange.getBegin(), "@");
1215       else
1216         commit.insertWrap("@(", ArgRange, ")");
1217 
1218       return true;
1219     }
1220   }
1221 
1222   return false;
1223 }
1224 
1225 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
1226                                            const NSAPI &NS, Commit &commit) {
1227   Selector Sel = Msg->getSelector();
1228 
1229   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
1230       Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
1231     if (Msg->getNumArgs() != 1)
1232       return false;
1233     return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1234   }
1235 
1236   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
1237     if (Msg->getNumArgs() != 2)
1238       return false;
1239 
1240     const Expr *encodingArg = Msg->getArg(1);
1241     if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
1242         NS.isNSASCIIStringEncodingConstant(encodingArg))
1243       return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1244   }
1245 
1246   return false;
1247 }
1248