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