• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ExprObjC.h"
18 #include "clang/AST/ExprCXX.h"
19 #include "clang/AST/NSAPI.h"
20 
21 using namespace clang;
22 using namespace edit;
23 
checkForLiteralCreation(const ObjCMessageExpr * Msg,IdentifierInfo * & ClassId)24 static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
25                                     IdentifierInfo *&ClassId) {
26   if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
27     return false;
28 
29   const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
30   if (!Receiver)
31     return false;
32   ClassId = Receiver->getIdentifier();
33 
34   if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
35     return true;
36 
37   return false;
38 }
39 
40 //===----------------------------------------------------------------------===//
41 // rewriteObjCRedundantCallWithLiteral.
42 //===----------------------------------------------------------------------===//
43 
rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)44 bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
45                                               const NSAPI &NS, Commit &commit) {
46   IdentifierInfo *II = 0;
47   if (!checkForLiteralCreation(Msg, II))
48     return false;
49   if (Msg->getNumArgs() != 1)
50     return false;
51 
52   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
53   Selector Sel = Msg->getSelector();
54 
55   if ((isa<ObjCStringLiteral>(Arg) &&
56        NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
57        NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel)    ||
58 
59       (isa<ObjCArrayLiteral>(Arg) &&
60        NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
61        NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel)      ||
62 
63       (isa<ObjCDictionaryLiteral>(Arg) &&
64        NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
65        NS.getNSDictionarySelector(
66                               NSAPI::NSDict_dictionaryWithDictionary) == Sel)) {
67 
68     commit.replaceWithInner(Msg->getSourceRange(),
69                            Msg->getArg(0)->getSourceRange());
70     return true;
71   }
72 
73   return false;
74 }
75 
76 //===----------------------------------------------------------------------===//
77 // rewriteToObjCSubscriptSyntax.
78 //===----------------------------------------------------------------------===//
79 
maybePutParensOnReceiver(const Expr * Receiver,Commit & commit)80 static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
81   Receiver = Receiver->IgnoreImpCasts();
82   if (isa<BinaryOperator>(Receiver) || isa<UnaryOperator>(Receiver)) {
83     SourceRange RecRange = Receiver->getSourceRange();
84     commit.insertWrap("(", RecRange, ")");
85   }
86 }
87 
rewriteToSubscriptGet(const ObjCMessageExpr * Msg,Commit & commit)88 static bool rewriteToSubscriptGet(const ObjCMessageExpr *Msg, Commit &commit) {
89   if (Msg->getNumArgs() != 1)
90     return false;
91   const Expr *Rec = Msg->getInstanceReceiver();
92   if (!Rec)
93     return false;
94 
95   SourceRange MsgRange = Msg->getSourceRange();
96   SourceRange RecRange = Rec->getSourceRange();
97   SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
98 
99   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
100                                                        ArgRange.getBegin()),
101                          CharSourceRange::getTokenRange(RecRange));
102   commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
103                          ArgRange);
104   commit.insertWrap("[", ArgRange, "]");
105   maybePutParensOnReceiver(Rec, commit);
106   return true;
107 }
108 
rewriteToArraySubscriptSet(const ObjCMessageExpr * Msg,Commit & commit)109 static bool rewriteToArraySubscriptSet(const ObjCMessageExpr *Msg,
110                                        Commit &commit) {
111   if (Msg->getNumArgs() != 2)
112     return false;
113   const Expr *Rec = Msg->getInstanceReceiver();
114   if (!Rec)
115     return false;
116 
117   SourceRange MsgRange = Msg->getSourceRange();
118   SourceRange RecRange = Rec->getSourceRange();
119   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
120   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
121 
122   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
123                                                        Arg0Range.getBegin()),
124                          CharSourceRange::getTokenRange(RecRange));
125   commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
126                                                        Arg1Range.getBegin()),
127                          CharSourceRange::getTokenRange(Arg0Range));
128   commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
129                          Arg1Range);
130   commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
131                                                        Arg1Range.getBegin()),
132                     "] = ");
133   maybePutParensOnReceiver(Rec, commit);
134   return true;
135 }
136 
rewriteToDictionarySubscriptSet(const ObjCMessageExpr * Msg,Commit & commit)137 static bool rewriteToDictionarySubscriptSet(const ObjCMessageExpr *Msg,
138                                             Commit &commit) {
139   if (Msg->getNumArgs() != 2)
140     return false;
141   const Expr *Rec = Msg->getInstanceReceiver();
142   if (!Rec)
143     return false;
144 
145   SourceRange MsgRange = Msg->getSourceRange();
146   SourceRange RecRange = Rec->getSourceRange();
147   SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
148   SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
149 
150   SourceLocation LocBeforeVal = Arg0Range.getBegin();
151   commit.insertBefore(LocBeforeVal, "] = ");
152   commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
153                          /*beforePreviousInsertions=*/true);
154   commit.insertBefore(LocBeforeVal, "[");
155   commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
156                                                        Arg0Range.getBegin()),
157                          CharSourceRange::getTokenRange(RecRange));
158   commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
159                          Arg0Range);
160   maybePutParensOnReceiver(Rec, commit);
161   return true;
162 }
163 
rewriteToObjCSubscriptSyntax(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)164 bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
165                                            const NSAPI &NS, Commit &commit) {
166   if (!Msg || Msg->isImplicit() ||
167       Msg->getReceiverKind() != ObjCMessageExpr::Instance)
168     return false;
169   const ObjCMethodDecl *Method = Msg->getMethodDecl();
170   if (!Method)
171     return false;
172 
173   const ObjCInterfaceDecl *
174     IFace = NS.getASTContext().getObjContainingInterface(
175                                           const_cast<ObjCMethodDecl *>(Method));
176   if (!IFace)
177     return false;
178   IdentifierInfo *II = IFace->getIdentifier();
179   Selector Sel = Msg->getSelector();
180 
181   if ((II == NS.getNSClassId(NSAPI::ClassId_NSArray) &&
182        Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex)) ||
183       (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary) &&
184        Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey)))
185     return rewriteToSubscriptGet(Msg, commit);
186 
187   if (Msg->getNumArgs() != 2)
188     return false;
189 
190   if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableArray) &&
191       Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
192     return rewriteToArraySubscriptSet(Msg, commit);
193 
194   if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableDictionary) &&
195       Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
196     return rewriteToDictionarySubscriptSet(Msg, commit);
197 
198   return false;
199 }
200 
201 //===----------------------------------------------------------------------===//
202 // rewriteToObjCLiteralSyntax.
203 //===----------------------------------------------------------------------===//
204 
205 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
206                                   const NSAPI &NS, Commit &commit);
207 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
208                                   const NSAPI &NS, Commit &commit);
209 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
210                                   const NSAPI &NS, Commit &commit);
211 
rewriteToObjCLiteralSyntax(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)212 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
213                                       const NSAPI &NS, Commit &commit) {
214   IdentifierInfo *II = 0;
215   if (!checkForLiteralCreation(Msg, II))
216     return false;
217 
218   if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
219     return rewriteToArrayLiteral(Msg, NS, commit);
220   if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
221     return rewriteToDictionaryLiteral(Msg, NS, commit);
222   if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
223     return rewriteToNumberLiteral(Msg, NS, commit);
224 
225   return false;
226 }
227 
228 //===----------------------------------------------------------------------===//
229 // rewriteToArrayLiteral.
230 //===----------------------------------------------------------------------===//
231 
rewriteToArrayLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)232 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
233                                   const NSAPI &NS, Commit &commit) {
234   Selector Sel = Msg->getSelector();
235   SourceRange MsgRange = Msg->getSourceRange();
236 
237   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
238     if (Msg->getNumArgs() != 0)
239       return false;
240     commit.replace(MsgRange, "@[]");
241     return true;
242   }
243 
244   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
245     if (Msg->getNumArgs() != 1)
246       return false;
247     SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
248     commit.replaceWithInner(MsgRange, ArgRange);
249     commit.insertWrap("@[", ArgRange, "]");
250     return true;
251   }
252 
253   if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) {
254     if (Msg->getNumArgs() == 0)
255       return false;
256     const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
257     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
258       return false;
259 
260     if (Msg->getNumArgs() == 1) {
261       commit.replace(MsgRange, "@[]");
262       return true;
263     }
264     SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
265                          Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
266     commit.replaceWithInner(MsgRange, ArgRange);
267     commit.insertWrap("@[", ArgRange, "]");
268     return true;
269   }
270 
271   return false;
272 }
273 
274 //===----------------------------------------------------------------------===//
275 // rewriteToDictionaryLiteral.
276 //===----------------------------------------------------------------------===//
277 
rewriteToDictionaryLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)278 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
279                                        const NSAPI &NS, Commit &commit) {
280   Selector Sel = Msg->getSelector();
281   SourceRange MsgRange = Msg->getSourceRange();
282 
283   if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
284     if (Msg->getNumArgs() != 0)
285       return false;
286     commit.replace(MsgRange, "@{}");
287     return true;
288   }
289 
290   if (Sel == NS.getNSDictionarySelector(
291                                     NSAPI::NSDict_dictionaryWithObjectForKey)) {
292     if (Msg->getNumArgs() != 2)
293       return false;
294     SourceRange ValRange = Msg->getArg(0)->getSourceRange();
295     SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
296     // Insert key before the value.
297     commit.insertBefore(ValRange.getBegin(), ": ");
298     commit.insertFromRange(ValRange.getBegin(),
299                            CharSourceRange::getTokenRange(KeyRange),
300                        /*afterToken=*/false, /*beforePreviousInsertions=*/true);
301     commit.insertBefore(ValRange.getBegin(), "@{");
302     commit.insertAfterToken(ValRange.getEnd(), "}");
303     commit.replaceWithInner(MsgRange, ValRange);
304     return true;
305   }
306 
307   if (Sel == NS.getNSDictionarySelector(
308                                   NSAPI::NSDict_dictionaryWithObjectsAndKeys)) {
309     if (Msg->getNumArgs() % 2 != 1)
310       return false;
311     unsigned SentinelIdx = Msg->getNumArgs() - 1;
312     const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
313     if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
314       return false;
315 
316     if (Msg->getNumArgs() == 1) {
317       commit.replace(MsgRange, "@{}");
318       return true;
319     }
320 
321     for (unsigned i = 0; i < SentinelIdx; i += 2) {
322       SourceRange ValRange = Msg->getArg(i)->getSourceRange();
323       SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
324       // Insert value after key.
325       commit.insertAfterToken(KeyRange.getEnd(), ": ");
326       commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
327       commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
328                                                   KeyRange.getBegin()));
329     }
330     // Range of arguments up until and including the last key.
331     // The sentinel and first value are cut off, the value will move after the
332     // key.
333     SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
334                          Msg->getArg(SentinelIdx-1)->getLocEnd());
335     commit.insertWrap("@{", ArgRange, "}");
336     commit.replaceWithInner(MsgRange, ArgRange);
337     return true;
338   }
339 
340   return false;
341 }
342 
343 //===----------------------------------------------------------------------===//
344 // rewriteToNumberLiteral.
345 //===----------------------------------------------------------------------===//
346 
rewriteToCharLiteral(const ObjCMessageExpr * Msg,const CharacterLiteral * Arg,const NSAPI & NS,Commit & commit)347 static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
348                                    const CharacterLiteral *Arg,
349                                    const NSAPI &NS, Commit &commit) {
350   if (Arg->getKind() != CharacterLiteral::Ascii)
351     return false;
352   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
353                                    Msg->getSelector())) {
354     SourceRange ArgRange = Arg->getSourceRange();
355     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
356     commit.insert(ArgRange.getBegin(), "@");
357     return true;
358   }
359 
360   return false;
361 }
362 
rewriteToBoolLiteral(const ObjCMessageExpr * Msg,const Expr * Arg,const NSAPI & NS,Commit & commit)363 static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
364                                    const Expr *Arg,
365                                    const NSAPI &NS, Commit &commit) {
366   if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
367                                    Msg->getSelector())) {
368     SourceRange ArgRange = Arg->getSourceRange();
369     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
370     commit.insert(ArgRange.getBegin(), "@");
371     return true;
372   }
373 
374   return false;
375 }
376 
377 namespace {
378 
379 struct LiteralInfo {
380   bool Hex, Octal;
381   StringRef U, F, L, LL;
382   CharSourceRange WithoutSuffRange;
383 };
384 
385 }
386 
getLiteralInfo(SourceRange literalRange,bool isFloat,bool isIntZero,ASTContext & Ctx,LiteralInfo & Info)387 static bool getLiteralInfo(SourceRange literalRange,
388                            bool isFloat, bool isIntZero,
389                           ASTContext &Ctx, LiteralInfo &Info) {
390   if (literalRange.getBegin().isMacroID() ||
391       literalRange.getEnd().isMacroID())
392     return false;
393   StringRef text = Lexer::getSourceText(
394                                   CharSourceRange::getTokenRange(literalRange),
395                                   Ctx.getSourceManager(), Ctx.getLangOpts());
396   if (text.empty())
397     return false;
398 
399   llvm::Optional<bool> UpperU, UpperL;
400   bool UpperF = false;
401 
402   struct Suff {
403     static bool has(StringRef suff, StringRef &text) {
404       if (text.endswith(suff)) {
405         text = text.substr(0, text.size()-suff.size());
406         return true;
407       }
408       return false;
409     }
410   };
411 
412   while (1) {
413     if (Suff::has("u", text)) {
414       UpperU = false;
415     } else if (Suff::has("U", text)) {
416       UpperU = true;
417     } else if (Suff::has("ll", text)) {
418       UpperL = false;
419     } else if (Suff::has("LL", text)) {
420       UpperL = true;
421     } else if (Suff::has("l", text)) {
422       UpperL = false;
423     } else if (Suff::has("L", text)) {
424       UpperL = true;
425     } else if (isFloat && Suff::has("f", text)) {
426       UpperF = false;
427     } else if (isFloat && Suff::has("F", text)) {
428       UpperF = true;
429     } else
430       break;
431   }
432 
433   if (!UpperU.hasValue() && !UpperL.hasValue())
434     UpperU = UpperL = true;
435   else if (UpperU.hasValue() && !UpperL.hasValue())
436     UpperL = UpperU;
437   else if (UpperL.hasValue() && !UpperU.hasValue())
438     UpperU = UpperL;
439 
440   Info.U = *UpperU ? "U" : "u";
441   Info.L = *UpperL ? "L" : "l";
442   Info.LL = *UpperL ? "LL" : "ll";
443   Info.F = UpperF ? "F" : "f";
444 
445   Info.Hex = Info.Octal = false;
446   if (text.startswith("0x"))
447     Info.Hex = true;
448   else if (!isFloat && !isIntZero && text.startswith("0"))
449     Info.Octal = true;
450 
451   SourceLocation B = literalRange.getBegin();
452   Info.WithoutSuffRange =
453       CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
454   return true;
455 }
456 
rewriteToNumberLiteral(const ObjCMessageExpr * Msg,const NSAPI & NS,Commit & commit)457 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
458                                    const NSAPI &NS, Commit &commit) {
459   if (Msg->getNumArgs() != 1)
460     return false;
461 
462   const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
463   if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
464     return rewriteToCharLiteral(Msg, CharE, NS, commit);
465   if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
466     return rewriteToBoolLiteral(Msg, BE, NS, commit);
467   if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
468     return rewriteToBoolLiteral(Msg, BE, NS, commit);
469 
470   const Expr *literalE = Arg;
471   if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
472     if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
473       literalE = UOE->getSubExpr();
474   }
475 
476   // Only integer and floating literals; non-literals or imaginary literal
477   // cannot be rewritten.
478   if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
479     return false;
480 
481   ASTContext &Ctx = NS.getASTContext();
482   Selector Sel = Msg->getSelector();
483   llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
484     MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
485   if (!MKOpt)
486     return false;
487   NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
488 
489   bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
490   bool CallIsFloating = false, CallIsDouble = false;
491 
492   switch (MK) {
493   // We cannot have these calls with int/float literals.
494   case NSAPI::NSNumberWithChar:
495   case NSAPI::NSNumberWithUnsignedChar:
496   case NSAPI::NSNumberWithShort:
497   case NSAPI::NSNumberWithUnsignedShort:
498   case NSAPI::NSNumberWithBool:
499     return false;
500 
501   case NSAPI::NSNumberWithUnsignedInt:
502   case NSAPI::NSNumberWithUnsignedInteger:
503     CallIsUnsigned = true;
504   case NSAPI::NSNumberWithInt:
505   case NSAPI::NSNumberWithInteger:
506     break;
507 
508   case NSAPI::NSNumberWithUnsignedLong:
509     CallIsUnsigned = true;
510   case NSAPI::NSNumberWithLong:
511     CallIsLong = true;
512     break;
513 
514   case NSAPI::NSNumberWithUnsignedLongLong:
515     CallIsUnsigned = true;
516   case NSAPI::NSNumberWithLongLong:
517     CallIsLongLong = true;
518     break;
519 
520   case NSAPI::NSNumberWithDouble:
521     CallIsDouble = true;
522   case NSAPI::NSNumberWithFloat:
523     CallIsFloating = true;
524     break;
525   }
526 
527   SourceRange ArgRange = Arg->getSourceRange();
528   QualType ArgTy = Arg->getType();
529   QualType CallTy = Msg->getArg(0)->getType();
530 
531   // Check for the easy case, the literal maps directly to the call.
532   if (Ctx.hasSameType(ArgTy, CallTy)) {
533     commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
534     commit.insert(ArgRange.getBegin(), "@");
535     return true;
536   }
537 
538   // We will need to modify the literal suffix to get the same type as the call.
539   // Don't even try if it came from a macro.
540   if (ArgRange.getBegin().isMacroID())
541     return false;
542 
543   bool LitIsFloat = ArgTy->isFloatingType();
544   // For a float passed to integer call, don't try rewriting. It is difficult
545   // and a very uncommon case anyway.
546   if (LitIsFloat && !CallIsFloating)
547     return false;
548 
549   // Try to modify the literal make it the same type as the method call.
550   // -Modify the suffix, and/or
551   // -Change integer to float
552 
553   LiteralInfo LitInfo;
554   bool isIntZero = false;
555   if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
556     isIntZero = !IntE->getValue().getBoolValue();
557   if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
558     return false;
559 
560   // Not easy to do int -> float with hex/octal and uncommon anyway.
561   if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
562     return false;
563 
564   SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
565   SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
566 
567   commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
568                          LitInfo.WithoutSuffRange);
569   commit.insert(LitB, "@");
570 
571   if (!LitIsFloat && CallIsFloating)
572     commit.insert(LitE, ".0");
573 
574   if (CallIsFloating) {
575     if (!CallIsDouble)
576       commit.insert(LitE, LitInfo.F);
577   } else {
578     if (CallIsUnsigned)
579       commit.insert(LitE, LitInfo.U);
580 
581     if (CallIsLong)
582       commit.insert(LitE, LitInfo.L);
583     else if (CallIsLongLong)
584       commit.insert(LitE, LitInfo.LL);
585   }
586   return true;
587 }
588