]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
MFC r244628:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / lib / Edit / RewriteObjCFoundationAPI.cpp
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/Edit/Commit.h"
16 #include "clang/Lex/Lexer.h"
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/ExprObjC.h"
19 #include "clang/AST/ExprCXX.h"
20 #include "clang/AST/NSAPI.h"
21
22 using namespace clang;
23 using namespace edit;
24
25 static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
26                                     IdentifierInfo *&ClassId,
27                                     const LangOptions &LangOpts) {
28   if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
29     return false;
30
31   const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
32   if (!Receiver)
33     return false;
34   ClassId = Receiver->getIdentifier();
35
36   if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
37     return true;
38
39   // When in ARC mode we also convert "[[.. alloc] init]" messages to literals,
40   // since the change from +1 to +0 will be handled fine by ARC.
41   if (LangOpts.ObjCAutoRefCount) {
42     if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) {
43       if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>(
44                            Msg->getInstanceReceiver()->IgnoreParenImpCasts())) {
45         if (Rec->getMethodFamily() == OMF_alloc)
46           return true;
47       }
48     }
49   }
50
51   return false;
52 }
53
54 //===----------------------------------------------------------------------===//
55 // rewriteObjCRedundantCallWithLiteral.
56 //===----------------------------------------------------------------------===//
57
58 bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
59                                               const NSAPI &NS, Commit &commit) {
60   IdentifierInfo *II = 0;
61   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
62     return false;
63   if (Msg->getNumArgs() != 1)
64     return false;
65
66   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
67   Selector Sel = Msg->getSelector();
68
69   if ((isa<ObjCStringLiteral>(Arg) &&
70        NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
71        (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel ||
72         NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel))   ||
73
74       (isa<ObjCArrayLiteral>(Arg) &&
75        NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
76        (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel ||
77         NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel))     ||
78
79       (isa<ObjCDictionaryLiteral>(Arg) &&
80        NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
81        (NS.getNSDictionarySelector(
82                               NSAPI::NSDict_dictionaryWithDictionary) == Sel ||
83         NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) {
84     
85     commit.replaceWithInner(Msg->getSourceRange(),
86                            Msg->getArg(0)->getSourceRange());
87     return true;
88   }
89
90   return false;
91 }
92
93 //===----------------------------------------------------------------------===//
94 // rewriteToObjCSubscriptSyntax.
95 //===----------------------------------------------------------------------===//
96
97 /// \brief Check for classes that accept 'objectForKey:' (or the other selectors
98 /// that the migrator handles) but return their instances as 'id', resulting
99 /// in the compiler resolving 'objectForKey:' as the method from NSDictionary.
100 ///
101 /// When checking if we can convert to subscripting syntax, check whether
102 /// the receiver is a result of a class method from a hardcoded list of
103 /// such classes. In such a case return the specific class as the interface
104 /// of the receiver.
105 ///
106 /// FIXME: Remove this when these classes start using 'instancetype'.
107 static const ObjCInterfaceDecl *
108 maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace,
109                                          const Expr *Receiver,
110                                          ASTContext &Ctx) {
111   assert(IFace && Receiver);
112
113   // If the receiver has type 'id'...
114   if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType()))
115     return IFace;
116
117   const ObjCMessageExpr *
118     InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts());
119   if (!InnerMsg)
120     return IFace;
121
122   QualType ClassRec;
123   switch (InnerMsg->getReceiverKind()) {
124   case ObjCMessageExpr::Instance:
125   case ObjCMessageExpr::SuperInstance:
126     return IFace;
127
128   case ObjCMessageExpr::Class:
129     ClassRec = InnerMsg->getClassReceiver();
130     break;
131   case ObjCMessageExpr::SuperClass:
132     ClassRec = InnerMsg->getSuperType();
133     break;
134   }
135
136   if (ClassRec.isNull())
137     return IFace;
138
139   // ...and it is the result of a class message...
140
141   const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>();
142   if (!ObjTy)
143     return IFace;
144   const ObjCInterfaceDecl *OID = ObjTy->getInterface();
145
146   // ...and the receiving class is NSMapTable or NSLocale, return that
147   // class as the receiving interface.
148   if (OID->getName() == "NSMapTable" ||
149       OID->getName() == "NSLocale")
150     return OID;
151
152   return IFace;
153 }
154
155 static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace,
156                                         const ObjCMessageExpr *Msg,
157                                         ASTContext &Ctx,
158                                         Selector subscriptSel) {
159   const Expr *Rec = Msg->getInstanceReceiver();
160   if (!Rec)
161     return false;
162   IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx);
163
164   if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) {
165     if (!MD->isUnavailable())
166       return true;
167   }
168   return false;
169 }
170
171 static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
172
173 static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
174   if (subscriptOperatorNeedsParens(Receiver)) {
175     SourceRange RecRange = Receiver->getSourceRange();
176     commit.insertWrap("(", RecRange, ")");
177   }
178 }
179
180 static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg,
181                                         Commit &commit) {
182   if (Msg->getNumArgs() != 1)
183     return false;
184   const Expr *Rec = Msg->getInstanceReceiver();
185   if (!Rec)
186     return false;
187
188   SourceRange MsgRange = Msg->getSourceRange();
189   SourceRange RecRange = Rec->getSourceRange();
190   SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
191
192   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
193                                                        ArgRange.getBegin()),
194                          CharSourceRange::getTokenRange(RecRange));
195   commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
196                          ArgRange);
197   commit.insertWrap("[", ArgRange, "]");
198   maybePutParensOnReceiver(Rec, commit);
199   return true;
200 }
201
202 static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace,
203                                        const ObjCMessageExpr *Msg,
204                                        const NSAPI &NS,
205                                        Commit &commit) {
206   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
207                                    NS.getObjectAtIndexedSubscriptSelector()))
208     return false;
209   return rewriteToSubscriptGetCommon(Msg, commit);
210 }
211
212 static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace,
213                                             const ObjCMessageExpr *Msg,
214                                             const NSAPI &NS,
215                                             Commit &commit) {
216   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
217                                   NS.getObjectForKeyedSubscriptSelector()))
218     return false;
219   return rewriteToSubscriptGetCommon(Msg, commit);
220 }
221
222 static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace,
223                                        const ObjCMessageExpr *Msg,
224                                        const NSAPI &NS,
225                                        Commit &commit) {
226   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
227                                    NS.getSetObjectAtIndexedSubscriptSelector()))
228     return false;
229
230   if (Msg->getNumArgs() != 2)
231     return false;
232   const Expr *Rec = Msg->getInstanceReceiver();
233   if (!Rec)
234     return false;
235
236   SourceRange MsgRange = Msg->getSourceRange();
237   SourceRange RecRange = Rec->getSourceRange();
238   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
239   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
240
241   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
242                                                        Arg0Range.getBegin()),
243                          CharSourceRange::getTokenRange(RecRange));
244   commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
245                                                        Arg1Range.getBegin()),
246                          CharSourceRange::getTokenRange(Arg0Range));
247   commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
248                          Arg1Range);
249   commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
250                                                        Arg1Range.getBegin()),
251                     "] = ");
252   maybePutParensOnReceiver(Rec, commit);
253   return true;
254 }
255
256 static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace,
257                                             const ObjCMessageExpr *Msg,
258                                             const NSAPI &NS,
259                                             Commit &commit) {
260   if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(),
261                                    NS.getSetObjectForKeyedSubscriptSelector()))
262     return false;
263
264   if (Msg->getNumArgs() != 2)
265     return false;
266   const Expr *Rec = Msg->getInstanceReceiver();
267   if (!Rec)
268     return false;
269
270   SourceRange MsgRange = Msg->getSourceRange();
271   SourceRange RecRange = Rec->getSourceRange();
272   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
273   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
274
275   SourceLocation LocBeforeVal = Arg0Range.getBegin();
276   commit.insertBefore(LocBeforeVal, "] = ");
277   commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
278                          /*beforePreviousInsertions=*/true);
279   commit.insertBefore(LocBeforeVal, "[");
280   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
281                                                        Arg0Range.getBegin()),
282                          CharSourceRange::getTokenRange(RecRange));
283   commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
284                          Arg0Range);
285   maybePutParensOnReceiver(Rec, commit);
286   return true;
287 }
288
289 bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
290                                         const NSAPI &NS, Commit &commit) {
291   if (!Msg || Msg->isImplicit() ||
292       Msg->getReceiverKind() != ObjCMessageExpr::Instance)
293     return false;
294   const ObjCMethodDecl *Method = Msg->getMethodDecl();
295   if (!Method)
296     return false;
297
298   const ObjCInterfaceDecl *
299     IFace = NS.getASTContext().getObjContainingInterface(
300                                           const_cast<ObjCMethodDecl *>(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 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
330                                   const NSAPI &NS, Commit &commit);
331 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
332                                   const NSAPI &NS, Commit &commit);
333 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
334                                             const NSAPI &NS, Commit &commit);
335 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
336                                            const NSAPI &NS, Commit &commit);
337
338 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
339                                       const NSAPI &NS, Commit &commit) {
340   IdentifierInfo *II = 0;
341   if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
342     return false;
343
344   if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
345     return rewriteToArrayLiteral(Msg, NS, commit);
346   if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
347     return rewriteToDictionaryLiteral(Msg, NS, commit);
348   if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
349     return rewriteToNumberLiteral(Msg, NS, commit);
350   if (II == NS.getNSClassId(NSAPI::ClassId_NSString))
351     return rewriteToStringBoxedExpression(Msg, NS, commit);
352
353   return false;
354 }
355
356 //===----------------------------------------------------------------------===//
357 // rewriteToArrayLiteral.
358 //===----------------------------------------------------------------------===//
359
360 /// \brief Adds an explicit cast to 'id' if the type is not objc object.
361 static void objectifyExpr(const Expr *E, Commit &commit);
362
363 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
364                                   const NSAPI &NS, Commit &commit) {
365   Selector Sel = Msg->getSelector();
366   SourceRange MsgRange = Msg->getSourceRange();
367
368   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
369     if (Msg->getNumArgs() != 0)
370       return false;
371     commit.replace(MsgRange, "@[]");
372     return true;
373   }
374
375   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
376     if (Msg->getNumArgs() != 1)
377       return false;
378     objectifyExpr(Msg->getArg(0), commit);
379     SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
380     commit.replaceWithInner(MsgRange, ArgRange);
381     commit.insertWrap("@[", ArgRange, "]");
382     return true;
383   }
384
385   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
386       Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
387     if (Msg->getNumArgs() == 0)
388       return false;
389     const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
390     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
391       return false;
392
393     for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
394       objectifyExpr(Msg->getArg(i), commit);
395
396     if (Msg->getNumArgs() == 1) {
397       commit.replace(MsgRange, "@[]");
398       return true;
399     }
400     SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
401                          Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
402     commit.replaceWithInner(MsgRange, ArgRange);
403     commit.insertWrap("@[", ArgRange, "]");
404     return true;
405   }
406
407   return false;
408 }
409
410 //===----------------------------------------------------------------------===//
411 // rewriteToDictionaryLiteral.
412 //===----------------------------------------------------------------------===//
413
414 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
415                                        const NSAPI &NS, Commit &commit) {
416   Selector Sel = Msg->getSelector();
417   SourceRange MsgRange = Msg->getSourceRange();
418
419   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
420     if (Msg->getNumArgs() != 0)
421       return false;
422     commit.replace(MsgRange, "@{}");
423     return true;
424   }
425
426   if (Sel == NS.getNSDictionarySelector(
427                                     NSAPI::NSDict_dictionaryWithObjectForKey)) {
428     if (Msg->getNumArgs() != 2)
429       return false;
430
431     objectifyExpr(Msg->getArg(0), commit);
432     objectifyExpr(Msg->getArg(1), commit);
433
434     SourceRange ValRange = Msg->getArg(0)->getSourceRange();
435     SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
436     // Insert key before the value.
437     commit.insertBefore(ValRange.getBegin(), ": ");
438     commit.insertFromRange(ValRange.getBegin(),
439                            CharSourceRange::getTokenRange(KeyRange),
440                        /*afterToken=*/false, /*beforePreviousInsertions=*/true);
441     commit.insertBefore(ValRange.getBegin(), "@{");
442     commit.insertAfterToken(ValRange.getEnd(), "}");
443     commit.replaceWithInner(MsgRange, ValRange);
444     return true;
445   }
446
447   if (Sel == NS.getNSDictionarySelector(
448                                   NSAPI::NSDict_dictionaryWithObjectsAndKeys) ||
449       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) {
450     if (Msg->getNumArgs() % 2 != 1)
451       return false;
452     unsigned SentinelIdx = Msg->getNumArgs() - 1;
453     const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
454     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
455       return false;
456
457     if (Msg->getNumArgs() == 1) {
458       commit.replace(MsgRange, "@{}");
459       return true;
460     }
461
462     for (unsigned i = 0; i < SentinelIdx; i += 2) {
463       objectifyExpr(Msg->getArg(i), commit);
464       objectifyExpr(Msg->getArg(i+1), commit);
465
466       SourceRange ValRange = Msg->getArg(i)->getSourceRange();
467       SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
468       // Insert value after key.
469       commit.insertAfterToken(KeyRange.getEnd(), ": ");
470       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
471       commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
472                                                   KeyRange.getBegin()));
473     }
474     // Range of arguments up until and including the last key.
475     // The sentinel and first value are cut off, the value will move after the
476     // key.
477     SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
478                          Msg->getArg(SentinelIdx-1)->getLocEnd());
479     commit.insertWrap("@{", ArgRange, "}");
480     commit.replaceWithInner(MsgRange, ArgRange);
481     return true;
482   }
483
484   return false;
485 }
486
487 //===----------------------------------------------------------------------===//
488 // rewriteToNumberLiteral.
489 //===----------------------------------------------------------------------===//
490
491 static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
492                                    const CharacterLiteral *Arg,
493                                    const NSAPI &NS, Commit &commit) {
494   if (Arg->getKind() != CharacterLiteral::Ascii)
495     return false;
496   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
497                                    Msg->getSelector())) {
498     SourceRange ArgRange = Arg->getSourceRange();
499     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
500     commit.insert(ArgRange.getBegin(), "@");
501     return true;
502   }
503
504   return rewriteToNumericBoxedExpression(Msg, NS, commit);
505 }
506
507 static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
508                                    const Expr *Arg,
509                                    const NSAPI &NS, Commit &commit) {
510   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
511                                    Msg->getSelector())) {
512     SourceRange ArgRange = Arg->getSourceRange();
513     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
514     commit.insert(ArgRange.getBegin(), "@");
515     return true;
516   }
517
518   return rewriteToNumericBoxedExpression(Msg, NS, commit);
519 }
520
521 namespace {
522
523 struct LiteralInfo {
524   bool Hex, Octal;
525   StringRef U, F, L, LL;
526   CharSourceRange WithoutSuffRange;
527 };
528
529 }
530
531 static bool getLiteralInfo(SourceRange literalRange,
532                            bool isFloat, bool isIntZero,
533                           ASTContext &Ctx, LiteralInfo &Info) {
534   if (literalRange.getBegin().isMacroID() ||
535       literalRange.getEnd().isMacroID())
536     return false;
537   StringRef text = Lexer::getSourceText(
538                                   CharSourceRange::getTokenRange(literalRange),
539                                   Ctx.getSourceManager(), Ctx.getLangOpts());
540   if (text.empty())
541     return false;
542
543   llvm::Optional<bool> UpperU, UpperL; 
544   bool UpperF = false;
545
546   struct Suff {
547     static bool has(StringRef suff, StringRef &text) {
548       if (text.endswith(suff)) {
549         text = text.substr(0, text.size()-suff.size());
550         return true;
551       }
552       return false;
553     }
554   };
555
556   while (1) {
557     if (Suff::has("u", text)) {
558       UpperU = false;
559     } else if (Suff::has("U", text)) {
560       UpperU = true;
561     } else if (Suff::has("ll", text)) {
562       UpperL = false;
563     } else if (Suff::has("LL", text)) {
564       UpperL = true;
565     } else if (Suff::has("l", text)) {
566       UpperL = false;
567     } else if (Suff::has("L", text)) {
568       UpperL = true;
569     } else if (isFloat && Suff::has("f", text)) {
570       UpperF = false;
571     } else if (isFloat && Suff::has("F", text)) {
572       UpperF = true;
573     } else
574       break;
575   }
576   
577   if (!UpperU.hasValue() && !UpperL.hasValue())
578     UpperU = UpperL = true;
579   else if (UpperU.hasValue() && !UpperL.hasValue())
580     UpperL = UpperU;
581   else if (UpperL.hasValue() && !UpperU.hasValue())
582     UpperU = UpperL;
583
584   Info.U = *UpperU ? "U" : "u";
585   Info.L = *UpperL ? "L" : "l";
586   Info.LL = *UpperL ? "LL" : "ll";
587   Info.F = UpperF ? "F" : "f";
588   
589   Info.Hex = Info.Octal = false;
590   if (text.startswith("0x"))
591     Info.Hex = true;
592   else if (!isFloat && !isIntZero && text.startswith("0"))
593     Info.Octal = true;
594
595   SourceLocation B = literalRange.getBegin();
596   Info.WithoutSuffRange =
597       CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
598   return true;
599 }
600
601 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
602                                    const NSAPI &NS, Commit &commit) {
603   if (Msg->getNumArgs() != 1)
604     return false;
605
606   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
607   if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
608     return rewriteToCharLiteral(Msg, CharE, NS, commit);
609   if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
610     return rewriteToBoolLiteral(Msg, BE, NS, commit);
611   if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
612     return rewriteToBoolLiteral(Msg, BE, NS, commit);
613
614   const Expr *literalE = Arg;
615   if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
616     if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
617       literalE = UOE->getSubExpr();
618   }
619
620   // Only integer and floating literals, otherwise try to rewrite to boxed
621   // expression.
622   if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
623     return rewriteToNumericBoxedExpression(Msg, NS, commit);
624
625   ASTContext &Ctx = NS.getASTContext();
626   Selector Sel = Msg->getSelector();
627   llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
628     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
629   if (!MKOpt)
630     return false;
631   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
632
633   bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
634   bool CallIsFloating = false, CallIsDouble = false;
635
636   switch (MK) {
637   // We cannot have these calls with int/float literals.
638   case NSAPI::NSNumberWithChar:
639   case NSAPI::NSNumberWithUnsignedChar:
640   case NSAPI::NSNumberWithShort:
641   case NSAPI::NSNumberWithUnsignedShort:
642   case NSAPI::NSNumberWithBool:
643     return rewriteToNumericBoxedExpression(Msg, NS, commit);
644
645   case NSAPI::NSNumberWithUnsignedInt:
646   case NSAPI::NSNumberWithUnsignedInteger:
647     CallIsUnsigned = true;
648   case NSAPI::NSNumberWithInt:
649   case NSAPI::NSNumberWithInteger:
650     break;
651
652   case NSAPI::NSNumberWithUnsignedLong:
653     CallIsUnsigned = true;
654   case NSAPI::NSNumberWithLong:
655     CallIsLong = true;
656     break;
657
658   case NSAPI::NSNumberWithUnsignedLongLong:
659     CallIsUnsigned = true;
660   case NSAPI::NSNumberWithLongLong:
661     CallIsLongLong = true;
662     break;
663
664   case NSAPI::NSNumberWithDouble:
665     CallIsDouble = true;
666   case NSAPI::NSNumberWithFloat:
667     CallIsFloating = true;
668     break;
669   }
670
671   SourceRange ArgRange = Arg->getSourceRange();
672   QualType ArgTy = Arg->getType();
673   QualType CallTy = Msg->getArg(0)->getType();
674
675   // Check for the easy case, the literal maps directly to the call.
676   if (Ctx.hasSameType(ArgTy, CallTy)) {
677     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
678     commit.insert(ArgRange.getBegin(), "@");
679     return true;
680   }
681
682   // We will need to modify the literal suffix to get the same type as the call.
683   // Try with boxed expression if it came from a macro.
684   if (ArgRange.getBegin().isMacroID())
685     return rewriteToNumericBoxedExpression(Msg, NS, commit);
686
687   bool LitIsFloat = ArgTy->isFloatingType();
688   // For a float passed to integer call, don't try rewriting to objc literal.
689   // It is difficult and a very uncommon case anyway.
690   // But try with boxed expression.
691   if (LitIsFloat && !CallIsFloating)
692     return rewriteToNumericBoxedExpression(Msg, NS, commit);
693
694   // Try to modify the literal make it the same type as the method call.
695   // -Modify the suffix, and/or
696   // -Change integer to float
697   
698   LiteralInfo LitInfo;
699   bool isIntZero = false;
700   if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
701     isIntZero = !IntE->getValue().getBoolValue();
702   if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
703     return rewriteToNumericBoxedExpression(Msg, NS, commit);
704
705   // Not easy to do int -> float with hex/octal and uncommon anyway.
706   if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
707     return rewriteToNumericBoxedExpression(Msg, NS, commit);
708   
709   SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
710   SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
711
712   commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
713                          LitInfo.WithoutSuffRange);
714   commit.insert(LitB, "@");
715
716   if (!LitIsFloat && CallIsFloating)
717     commit.insert(LitE, ".0");
718
719   if (CallIsFloating) {
720     if (!CallIsDouble)
721       commit.insert(LitE, LitInfo.F);
722   } else {
723     if (CallIsUnsigned)
724       commit.insert(LitE, LitInfo.U);
725   
726     if (CallIsLong)
727       commit.insert(LitE, LitInfo.L);
728     else if (CallIsLongLong)
729       commit.insert(LitE, LitInfo.LL);
730   }
731   return true;
732 }
733
734 // FIXME: Make determination of operator precedence more general and
735 // make it broadly available.
736 static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
737   const Expr* Expr = FullExpr->IgnoreImpCasts();
738   if (isa<ArraySubscriptExpr>(Expr) ||
739       isa<CallExpr>(Expr) ||
740       isa<DeclRefExpr>(Expr) ||
741       isa<CXXNamedCastExpr>(Expr) ||
742       isa<CXXConstructExpr>(Expr) ||
743       isa<CXXThisExpr>(Expr) ||
744       isa<CXXTypeidExpr>(Expr) ||
745       isa<CXXUnresolvedConstructExpr>(Expr) ||
746       isa<ObjCMessageExpr>(Expr) ||
747       isa<ObjCPropertyRefExpr>(Expr) ||
748       isa<ObjCProtocolExpr>(Expr) ||
749       isa<MemberExpr>(Expr) ||
750       isa<ObjCIvarRefExpr>(Expr) ||
751       isa<ParenExpr>(FullExpr) ||
752       isa<ParenListExpr>(Expr) ||
753       isa<SizeOfPackExpr>(Expr))
754     return false;
755
756   return true;
757 }
758 static bool castOperatorNeedsParens(const Expr *FullExpr) {
759   const Expr* Expr = FullExpr->IgnoreImpCasts();
760   if (isa<ArraySubscriptExpr>(Expr) ||
761       isa<CallExpr>(Expr) ||
762       isa<DeclRefExpr>(Expr) ||
763       isa<CastExpr>(Expr) ||
764       isa<CXXNewExpr>(Expr) ||
765       isa<CXXConstructExpr>(Expr) ||
766       isa<CXXDeleteExpr>(Expr) ||
767       isa<CXXNoexceptExpr>(Expr) ||
768       isa<CXXPseudoDestructorExpr>(Expr) ||
769       isa<CXXScalarValueInitExpr>(Expr) ||
770       isa<CXXThisExpr>(Expr) ||
771       isa<CXXTypeidExpr>(Expr) ||
772       isa<CXXUnresolvedConstructExpr>(Expr) ||
773       isa<ObjCMessageExpr>(Expr) ||
774       isa<ObjCPropertyRefExpr>(Expr) ||
775       isa<ObjCProtocolExpr>(Expr) ||
776       isa<MemberExpr>(Expr) ||
777       isa<ObjCIvarRefExpr>(Expr) ||
778       isa<ParenExpr>(FullExpr) ||
779       isa<ParenListExpr>(Expr) ||
780       isa<SizeOfPackExpr>(Expr) ||
781       isa<UnaryOperator>(Expr))
782     return false;
783
784   return true;
785 }
786
787 static void objectifyExpr(const Expr *E, Commit &commit) {
788   if (!E) return;
789
790   QualType T = E->getType();
791   if (T->isObjCObjectPointerType()) {
792     if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
793       if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
794         return;
795     } else {
796       return;
797     }
798   } else if (!T->isPointerType()) {
799     return;
800   }
801
802   SourceRange Range = E->getSourceRange();
803   if (castOperatorNeedsParens(E))
804     commit.insertWrap("(", Range, ")");
805   commit.insertBefore(Range.getBegin(), "(id)");
806 }
807
808 //===----------------------------------------------------------------------===//
809 // rewriteToNumericBoxedExpression.
810 //===----------------------------------------------------------------------===//
811
812 static bool isEnumConstant(const Expr *E) {
813   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
814     if (const ValueDecl *VD = DRE->getDecl())
815       return isa<EnumConstantDecl>(VD);
816
817   return false;
818 }
819
820 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
821                                             const NSAPI &NS, Commit &commit) {
822   if (Msg->getNumArgs() != 1)
823     return false;
824
825   const Expr *Arg = Msg->getArg(0);
826   if (Arg->isTypeDependent())
827     return false;
828
829   ASTContext &Ctx = NS.getASTContext();
830   Selector Sel = Msg->getSelector();
831   llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
832     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
833   if (!MKOpt)
834     return false;
835   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
836
837   const Expr *OrigArg = Arg->IgnoreImpCasts();
838   QualType FinalTy = Arg->getType();
839   QualType OrigTy = OrigArg->getType();
840   uint64_t FinalTySize = Ctx.getTypeSize(FinalTy);
841   uint64_t OrigTySize = Ctx.getTypeSize(OrigTy);
842
843   bool isTruncated = FinalTySize < OrigTySize; 
844   bool needsCast = false;
845
846   if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
847     switch (ICE->getCastKind()) {
848     case CK_LValueToRValue:
849     case CK_NoOp:
850     case CK_UserDefinedConversion:
851       break;
852
853     case CK_IntegralCast: {
854       if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType())
855         break;
856       // Be more liberal with Integer/UnsignedInteger which are very commonly
857       // used.
858       if ((MK == NSAPI::NSNumberWithInteger ||
859            MK == NSAPI::NSNumberWithUnsignedInteger) &&
860           !isTruncated) {
861         if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg))
862           break;
863         if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() &&
864             OrigTySize >= Ctx.getTypeSize(Ctx.IntTy))
865           break;
866       }
867
868       needsCast = true;
869       break;
870     }
871
872     case CK_PointerToBoolean:
873     case CK_IntegralToBoolean:
874     case CK_IntegralToFloating:
875     case CK_FloatingToIntegral:
876     case CK_FloatingToBoolean:
877     case CK_FloatingCast:
878     case CK_FloatingComplexToReal:
879     case CK_FloatingComplexToBoolean:
880     case CK_IntegralComplexToReal:
881     case CK_IntegralComplexToBoolean:
882     case CK_AtomicToNonAtomic:
883       needsCast = true;
884       break;
885
886     case CK_Dependent:
887     case CK_BitCast:
888     case CK_LValueBitCast:
889     case CK_BaseToDerived:
890     case CK_DerivedToBase:
891     case CK_UncheckedDerivedToBase:
892     case CK_Dynamic:
893     case CK_ToUnion:
894     case CK_ArrayToPointerDecay:
895     case CK_FunctionToPointerDecay:
896     case CK_NullToPointer:
897     case CK_NullToMemberPointer:
898     case CK_BaseToDerivedMemberPointer:
899     case CK_DerivedToBaseMemberPointer:
900     case CK_MemberPointerToBoolean:
901     case CK_ReinterpretMemberPointer:
902     case CK_ConstructorConversion:
903     case CK_IntegralToPointer:
904     case CK_PointerToIntegral:
905     case CK_ToVoid:
906     case CK_VectorSplat:
907     case CK_CPointerToObjCPointerCast:
908     case CK_BlockPointerToObjCPointerCast:
909     case CK_AnyPointerToBlockPointerCast:
910     case CK_ObjCObjectLValueCast:
911     case CK_FloatingRealToComplex:
912     case CK_FloatingComplexCast:
913     case CK_FloatingComplexToIntegralComplex:
914     case CK_IntegralRealToComplex:
915     case CK_IntegralComplexCast:
916     case CK_IntegralComplexToFloatingComplex:
917     case CK_ARCProduceObject:
918     case CK_ARCConsumeObject:
919     case CK_ARCReclaimReturnedObject:
920     case CK_ARCExtendBlockObject:
921     case CK_NonAtomicToAtomic:
922     case CK_CopyAndAutoreleaseBlockObject:
923     case CK_BuiltinFnToFnPtr:
924       return false;
925     }
926   }
927
928   if (needsCast) {
929     DiagnosticsEngine &Diags = Ctx.getDiagnostics(); 
930     // FIXME: Use a custom category name to distinguish migration diagnostics.
931     unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
932                        "converting to boxing syntax requires casting %0 to %1");
933     Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy
934         << Msg->getSourceRange();
935     return false;
936   }
937
938   SourceRange ArgRange = OrigArg->getSourceRange();
939   commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
940
941   if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
942     commit.insertBefore(ArgRange.getBegin(), "@");
943   else
944     commit.insertWrap("@(", ArgRange, ")");
945
946   return true;
947 }
948
949 //===----------------------------------------------------------------------===//
950 // rewriteToStringBoxedExpression.
951 //===----------------------------------------------------------------------===//
952
953 static bool doRewriteToUTF8StringBoxedExpressionHelper(
954                                               const ObjCMessageExpr *Msg,
955                                               const NSAPI &NS, Commit &commit) {
956   const Expr *Arg = Msg->getArg(0);
957   if (Arg->isTypeDependent())
958     return false;
959
960   ASTContext &Ctx = NS.getASTContext();
961
962   const Expr *OrigArg = Arg->IgnoreImpCasts();
963   QualType OrigTy = OrigArg->getType();
964   if (OrigTy->isArrayType())
965     OrigTy = Ctx.getArrayDecayedType(OrigTy);
966
967   if (const StringLiteral *
968         StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) {
969     commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange());
970     commit.insert(StrE->getLocStart(), "@");
971     return true;
972   }
973
974   if (const PointerType *PT = OrigTy->getAs<PointerType>()) {
975     QualType PointeeType = PT->getPointeeType();
976     if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) {
977       SourceRange ArgRange = OrigArg->getSourceRange();
978       commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
979
980       if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg))
981         commit.insertBefore(ArgRange.getBegin(), "@");
982       else
983         commit.insertWrap("@(", ArgRange, ")");
984       
985       return true;
986     }
987   }
988
989   return false;
990 }
991
992 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
993                                            const NSAPI &NS, Commit &commit) {
994   Selector Sel = Msg->getSelector();
995
996   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) ||
997       Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) {
998     if (Msg->getNumArgs() != 1)
999       return false;
1000     return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1001   }
1002
1003   if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) {
1004     if (Msg->getNumArgs() != 2)
1005       return false;
1006
1007     const Expr *encodingArg = Msg->getArg(1);
1008     if (NS.isNSUTF8StringEncodingConstant(encodingArg) ||
1009         NS.isNSASCIIStringEncodingConstant(encodingArg))
1010       return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit);
1011   }
1012
1013   return false;
1014 }