Home | History | Annotate | Download | only in Edit
      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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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