blob: 218ef2274f37861b7b651e70b5b9d9188bda9fe8 [file] [log] [blame]
Ted Kremenekf7639e12012-03-06 20:06:33 +00001//===--- 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
21using namespace clang;
22using namespace edit;
23
24static 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
44bool 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
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +000080static bool subscriptOperatorNeedsParens(const Expr *FullExpr);
81
Ted Kremenekf7639e12012-03-06 20:06:33 +000082static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +000083 if (subscriptOperatorNeedsParens(Receiver)) {
Ted Kremenekf7639e12012-03-06 20:06:33 +000084 SourceRange RecRange = Receiver->getSourceRange();
85 commit.insertWrap("(", RecRange, ")");
86 }
87}
88
89static bool rewriteToSubscriptGet(const ObjCMessageExpr *Msg, Commit &commit) {
90 if (Msg->getNumArgs() != 1)
91 return false;
92 const Expr *Rec = Msg->getInstanceReceiver();
93 if (!Rec)
94 return false;
95
96 SourceRange MsgRange = Msg->getSourceRange();
97 SourceRange RecRange = Rec->getSourceRange();
98 SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
99
100 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
101 ArgRange.getBegin()),
102 CharSourceRange::getTokenRange(RecRange));
103 commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
104 ArgRange);
105 commit.insertWrap("[", ArgRange, "]");
106 maybePutParensOnReceiver(Rec, commit);
107 return true;
108}
109
110static bool rewriteToArraySubscriptSet(const ObjCMessageExpr *Msg,
111 Commit &commit) {
112 if (Msg->getNumArgs() != 2)
113 return false;
114 const Expr *Rec = Msg->getInstanceReceiver();
115 if (!Rec)
116 return false;
117
118 SourceRange MsgRange = Msg->getSourceRange();
119 SourceRange RecRange = Rec->getSourceRange();
120 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
121 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
122
123 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
124 Arg0Range.getBegin()),
125 CharSourceRange::getTokenRange(RecRange));
126 commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
127 Arg1Range.getBegin()),
128 CharSourceRange::getTokenRange(Arg0Range));
129 commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
130 Arg1Range);
131 commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
132 Arg1Range.getBegin()),
133 "] = ");
134 maybePutParensOnReceiver(Rec, commit);
135 return true;
136}
137
138static bool rewriteToDictionarySubscriptSet(const ObjCMessageExpr *Msg,
139 Commit &commit) {
140 if (Msg->getNumArgs() != 2)
141 return false;
142 const Expr *Rec = Msg->getInstanceReceiver();
143 if (!Rec)
144 return false;
145
146 SourceRange MsgRange = Msg->getSourceRange();
147 SourceRange RecRange = Rec->getSourceRange();
148 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
149 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
150
151 SourceLocation LocBeforeVal = Arg0Range.getBegin();
152 commit.insertBefore(LocBeforeVal, "] = ");
153 commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
154 /*beforePreviousInsertions=*/true);
155 commit.insertBefore(LocBeforeVal, "[");
156 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
157 Arg0Range.getBegin()),
158 CharSourceRange::getTokenRange(RecRange));
159 commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
160 Arg0Range);
161 maybePutParensOnReceiver(Rec, commit);
162 return true;
163}
164
165bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
166 const NSAPI &NS, Commit &commit) {
167 if (!Msg || Msg->isImplicit() ||
168 Msg->getReceiverKind() != ObjCMessageExpr::Instance)
169 return false;
170 const ObjCMethodDecl *Method = Msg->getMethodDecl();
171 if (!Method)
172 return false;
173
174 const ObjCInterfaceDecl *
175 IFace = NS.getASTContext().getObjContainingInterface(
176 const_cast<ObjCMethodDecl *>(Method));
177 if (!IFace)
178 return false;
179 IdentifierInfo *II = IFace->getIdentifier();
180 Selector Sel = Msg->getSelector();
181
182 if ((II == NS.getNSClassId(NSAPI::ClassId_NSArray) &&
183 Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex)) ||
184 (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary) &&
185 Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey)))
186 return rewriteToSubscriptGet(Msg, commit);
187
188 if (Msg->getNumArgs() != 2)
189 return false;
190
191 if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableArray) &&
192 Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
193 return rewriteToArraySubscriptSet(Msg, commit);
194
195 if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableDictionary) &&
196 Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
197 return rewriteToDictionarySubscriptSet(Msg, commit);
198
199 return false;
200}
201
202//===----------------------------------------------------------------------===//
203// rewriteToObjCLiteralSyntax.
204//===----------------------------------------------------------------------===//
205
206static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
207 const NSAPI &NS, Commit &commit);
208static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
209 const NSAPI &NS, Commit &commit);
210static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
211 const NSAPI &NS, Commit &commit);
212
213bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
214 const NSAPI &NS, Commit &commit) {
215 IdentifierInfo *II = 0;
216 if (!checkForLiteralCreation(Msg, II))
217 return false;
218
219 if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
220 return rewriteToArrayLiteral(Msg, NS, commit);
221 if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
222 return rewriteToDictionaryLiteral(Msg, NS, commit);
223 if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
224 return rewriteToNumberLiteral(Msg, NS, commit);
225
226 return false;
227}
228
229//===----------------------------------------------------------------------===//
230// rewriteToArrayLiteral.
231//===----------------------------------------------------------------------===//
232
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000233/// \brief Adds an explicit cast to 'id' if the type is not objc object.
234static void objectifyExpr(const Expr *E, Commit &commit);
235
Ted Kremenekf7639e12012-03-06 20:06:33 +0000236static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
237 const NSAPI &NS, Commit &commit) {
238 Selector Sel = Msg->getSelector();
239 SourceRange MsgRange = Msg->getSourceRange();
240
241 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
242 if (Msg->getNumArgs() != 0)
243 return false;
244 commit.replace(MsgRange, "@[]");
245 return true;
246 }
247
248 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
249 if (Msg->getNumArgs() != 1)
250 return false;
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000251 objectifyExpr(Msg->getArg(0), commit);
Ted Kremenekf7639e12012-03-06 20:06:33 +0000252 SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
253 commit.replaceWithInner(MsgRange, ArgRange);
254 commit.insertWrap("@[", ArgRange, "]");
255 return true;
256 }
257
258 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) {
259 if (Msg->getNumArgs() == 0)
260 return false;
261 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
262 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
263 return false;
264
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000265 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
266 objectifyExpr(Msg->getArg(i), commit);
267
Ted Kremenekf7639e12012-03-06 20:06:33 +0000268 if (Msg->getNumArgs() == 1) {
269 commit.replace(MsgRange, "@[]");
270 return true;
271 }
272 SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
273 Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
274 commit.replaceWithInner(MsgRange, ArgRange);
275 commit.insertWrap("@[", ArgRange, "]");
276 return true;
277 }
278
279 return false;
280}
281
282//===----------------------------------------------------------------------===//
283// rewriteToDictionaryLiteral.
284//===----------------------------------------------------------------------===//
285
286static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
287 const NSAPI &NS, Commit &commit) {
288 Selector Sel = Msg->getSelector();
289 SourceRange MsgRange = Msg->getSourceRange();
290
291 if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
292 if (Msg->getNumArgs() != 0)
293 return false;
294 commit.replace(MsgRange, "@{}");
295 return true;
296 }
297
298 if (Sel == NS.getNSDictionarySelector(
299 NSAPI::NSDict_dictionaryWithObjectForKey)) {
300 if (Msg->getNumArgs() != 2)
301 return false;
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000302
303 objectifyExpr(Msg->getArg(0), commit);
304 objectifyExpr(Msg->getArg(1), commit);
305
Ted Kremenekf7639e12012-03-06 20:06:33 +0000306 SourceRange ValRange = Msg->getArg(0)->getSourceRange();
307 SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
308 // Insert key before the value.
309 commit.insertBefore(ValRange.getBegin(), ": ");
310 commit.insertFromRange(ValRange.getBegin(),
311 CharSourceRange::getTokenRange(KeyRange),
312 /*afterToken=*/false, /*beforePreviousInsertions=*/true);
313 commit.insertBefore(ValRange.getBegin(), "@{");
314 commit.insertAfterToken(ValRange.getEnd(), "}");
315 commit.replaceWithInner(MsgRange, ValRange);
316 return true;
317 }
318
319 if (Sel == NS.getNSDictionarySelector(
320 NSAPI::NSDict_dictionaryWithObjectsAndKeys)) {
321 if (Msg->getNumArgs() % 2 != 1)
322 return false;
323 unsigned SentinelIdx = Msg->getNumArgs() - 1;
324 const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
325 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
326 return false;
327
328 if (Msg->getNumArgs() == 1) {
329 commit.replace(MsgRange, "@{}");
330 return true;
331 }
332
333 for (unsigned i = 0; i < SentinelIdx; i += 2) {
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000334 objectifyExpr(Msg->getArg(i), commit);
335 objectifyExpr(Msg->getArg(i+1), commit);
336
Ted Kremenekf7639e12012-03-06 20:06:33 +0000337 SourceRange ValRange = Msg->getArg(i)->getSourceRange();
338 SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
339 // Insert value after key.
340 commit.insertAfterToken(KeyRange.getEnd(), ": ");
341 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
342 commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
343 KeyRange.getBegin()));
344 }
345 // Range of arguments up until and including the last key.
346 // The sentinel and first value are cut off, the value will move after the
347 // key.
348 SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
349 Msg->getArg(SentinelIdx-1)->getLocEnd());
350 commit.insertWrap("@{", ArgRange, "}");
351 commit.replaceWithInner(MsgRange, ArgRange);
352 return true;
353 }
354
355 return false;
356}
357
358//===----------------------------------------------------------------------===//
359// rewriteToNumberLiteral.
360//===----------------------------------------------------------------------===//
361
362static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
363 const CharacterLiteral *Arg,
364 const NSAPI &NS, Commit &commit) {
365 if (Arg->getKind() != CharacterLiteral::Ascii)
366 return false;
367 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
368 Msg->getSelector())) {
369 SourceRange ArgRange = Arg->getSourceRange();
370 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
371 commit.insert(ArgRange.getBegin(), "@");
372 return true;
373 }
374
375 return false;
376}
377
378static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
379 const Expr *Arg,
380 const NSAPI &NS, Commit &commit) {
381 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
382 Msg->getSelector())) {
383 SourceRange ArgRange = Arg->getSourceRange();
384 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
385 commit.insert(ArgRange.getBegin(), "@");
386 return true;
387 }
388
389 return false;
390}
391
392namespace {
393
394struct LiteralInfo {
395 bool Hex, Octal;
396 StringRef U, F, L, LL;
397 CharSourceRange WithoutSuffRange;
398};
399
400}
401
402static bool getLiteralInfo(SourceRange literalRange,
403 bool isFloat, bool isIntZero,
404 ASTContext &Ctx, LiteralInfo &Info) {
405 if (literalRange.getBegin().isMacroID() ||
406 literalRange.getEnd().isMacroID())
407 return false;
408 StringRef text = Lexer::getSourceText(
409 CharSourceRange::getTokenRange(literalRange),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000410 Ctx.getSourceManager(), Ctx.getLangOpts());
Ted Kremenekf7639e12012-03-06 20:06:33 +0000411 if (text.empty())
412 return false;
413
414 llvm::Optional<bool> UpperU, UpperL;
415 bool UpperF = false;
416
417 struct Suff {
418 static bool has(StringRef suff, StringRef &text) {
419 if (text.endswith(suff)) {
420 text = text.substr(0, text.size()-suff.size());
421 return true;
422 }
423 return false;
424 }
425 };
426
427 while (1) {
428 if (Suff::has("u", text)) {
429 UpperU = false;
430 } else if (Suff::has("U", text)) {
431 UpperU = true;
432 } else if (Suff::has("ll", text)) {
433 UpperL = false;
434 } else if (Suff::has("LL", text)) {
435 UpperL = true;
436 } else if (Suff::has("l", text)) {
437 UpperL = false;
438 } else if (Suff::has("L", text)) {
439 UpperL = true;
440 } else if (isFloat && Suff::has("f", text)) {
441 UpperF = false;
442 } else if (isFloat && Suff::has("F", text)) {
443 UpperF = true;
444 } else
445 break;
446 }
447
448 if (!UpperU.hasValue() && !UpperL.hasValue())
449 UpperU = UpperL = true;
450 else if (UpperU.hasValue() && !UpperL.hasValue())
451 UpperL = UpperU;
452 else if (UpperL.hasValue() && !UpperU.hasValue())
453 UpperU = UpperL;
454
455 Info.U = *UpperU ? "U" : "u";
456 Info.L = *UpperL ? "L" : "l";
457 Info.LL = *UpperL ? "LL" : "ll";
458 Info.F = UpperF ? "F" : "f";
459
460 Info.Hex = Info.Octal = false;
461 if (text.startswith("0x"))
462 Info.Hex = true;
463 else if (!isFloat && !isIntZero && text.startswith("0"))
464 Info.Octal = true;
465
466 SourceLocation B = literalRange.getBegin();
467 Info.WithoutSuffRange =
468 CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
469 return true;
470}
471
472static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
473 const NSAPI &NS, Commit &commit) {
474 if (Msg->getNumArgs() != 1)
475 return false;
476
477 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
478 if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
479 return rewriteToCharLiteral(Msg, CharE, NS, commit);
480 if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
481 return rewriteToBoolLiteral(Msg, BE, NS, commit);
482 if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
483 return rewriteToBoolLiteral(Msg, BE, NS, commit);
484
485 const Expr *literalE = Arg;
486 if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
487 if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
488 literalE = UOE->getSubExpr();
489 }
490
491 // Only integer and floating literals; non-literals or imaginary literal
492 // cannot be rewritten.
493 if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
494 return false;
495
496 ASTContext &Ctx = NS.getASTContext();
497 Selector Sel = Msg->getSelector();
498 llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
499 MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
500 if (!MKOpt)
501 return false;
502 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
503
Benjamin Kramerece209a2012-03-13 17:05:43 +0000504 bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000505 bool CallIsFloating = false, CallIsDouble = false;
506
507 switch (MK) {
508 // We cannot have these calls with int/float literals.
509 case NSAPI::NSNumberWithChar:
510 case NSAPI::NSNumberWithUnsignedChar:
511 case NSAPI::NSNumberWithShort:
512 case NSAPI::NSNumberWithUnsignedShort:
513 case NSAPI::NSNumberWithBool:
514 return false;
515
516 case NSAPI::NSNumberWithUnsignedInt:
517 case NSAPI::NSNumberWithUnsignedInteger:
518 CallIsUnsigned = true;
519 case NSAPI::NSNumberWithInt:
520 case NSAPI::NSNumberWithInteger:
Ted Kremenekf7639e12012-03-06 20:06:33 +0000521 break;
522
523 case NSAPI::NSNumberWithUnsignedLong:
524 CallIsUnsigned = true;
525 case NSAPI::NSNumberWithLong:
Benjamin Kramerece209a2012-03-13 17:05:43 +0000526 CallIsLong = true;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000527 break;
528
529 case NSAPI::NSNumberWithUnsignedLongLong:
530 CallIsUnsigned = true;
531 case NSAPI::NSNumberWithLongLong:
Benjamin Kramerece209a2012-03-13 17:05:43 +0000532 CallIsLongLong = true;
Ted Kremenekf7639e12012-03-06 20:06:33 +0000533 break;
534
535 case NSAPI::NSNumberWithDouble:
536 CallIsDouble = true;
537 case NSAPI::NSNumberWithFloat:
538 CallIsFloating = true;
539 break;
540 }
541
542 SourceRange ArgRange = Arg->getSourceRange();
543 QualType ArgTy = Arg->getType();
544 QualType CallTy = Msg->getArg(0)->getType();
545
546 // Check for the easy case, the literal maps directly to the call.
547 if (Ctx.hasSameType(ArgTy, CallTy)) {
548 commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
549 commit.insert(ArgRange.getBegin(), "@");
550 return true;
551 }
552
553 // We will need to modify the literal suffix to get the same type as the call.
554 // Don't even try if it came from a macro.
555 if (ArgRange.getBegin().isMacroID())
556 return false;
557
558 bool LitIsFloat = ArgTy->isFloatingType();
559 // For a float passed to integer call, don't try rewriting. It is difficult
560 // and a very uncommon case anyway.
561 if (LitIsFloat && !CallIsFloating)
562 return false;
563
564 // Try to modify the literal make it the same type as the method call.
565 // -Modify the suffix, and/or
566 // -Change integer to float
567
568 LiteralInfo LitInfo;
569 bool isIntZero = false;
570 if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
571 isIntZero = !IntE->getValue().getBoolValue();
572 if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
573 return false;
574
575 // Not easy to do int -> float with hex/octal and uncommon anyway.
576 if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
577 return false;
578
579 SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
580 SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
581
582 commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
583 LitInfo.WithoutSuffRange);
584 commit.insert(LitB, "@");
585
586 if (!LitIsFloat && CallIsFloating)
587 commit.insert(LitE, ".0");
588
589 if (CallIsFloating) {
590 if (!CallIsDouble)
591 commit.insert(LitE, LitInfo.F);
592 } else {
593 if (CallIsUnsigned)
594 commit.insert(LitE, LitInfo.U);
595
596 if (CallIsLong)
597 commit.insert(LitE, LitInfo.L);
598 else if (CallIsLongLong)
599 commit.insert(LitE, LitInfo.LL);
600 }
601 return true;
602}
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000603
Argyrios Kyrtzidis0bbe94f2012-05-14 23:33:49 +0000604// FIXME: Make determination of operator precedence more general and
605// make it broadly available.
606static bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
607 const Expr* Expr = FullExpr->IgnoreImpCasts();
608 if (isa<ArraySubscriptExpr>(Expr) ||
609 isa<CallExpr>(Expr) ||
610 isa<DeclRefExpr>(Expr) ||
611 isa<CXXNamedCastExpr>(Expr) ||
612 isa<CXXConstructExpr>(Expr) ||
613 isa<CXXThisExpr>(Expr) ||
614 isa<CXXTypeidExpr>(Expr) ||
615 isa<CXXUnresolvedConstructExpr>(Expr) ||
616 isa<ObjCMessageExpr>(Expr) ||
617 isa<ObjCPropertyRefExpr>(Expr) ||
618 isa<ObjCProtocolExpr>(Expr) ||
619 isa<MemberExpr>(Expr) ||
620 isa<ParenExpr>(FullExpr) ||
621 isa<ParenListExpr>(Expr) ||
622 isa<SizeOfPackExpr>(Expr))
623 return false;
624
625 return true;
626}
Argyrios Kyrtzidisc1dfed62012-05-14 22:01:53 +0000627static bool castOperatorNeedsParens(const Expr *FullExpr) {
628 const Expr* Expr = FullExpr->IgnoreImpCasts();
629 if (isa<ArraySubscriptExpr>(Expr) ||
630 isa<CallExpr>(Expr) ||
631 isa<DeclRefExpr>(Expr) ||
632 isa<CastExpr>(Expr) ||
633 isa<CXXNewExpr>(Expr) ||
634 isa<CXXConstructExpr>(Expr) ||
635 isa<CXXDeleteExpr>(Expr) ||
636 isa<CXXNoexceptExpr>(Expr) ||
637 isa<CXXPseudoDestructorExpr>(Expr) ||
638 isa<CXXScalarValueInitExpr>(Expr) ||
639 isa<CXXThisExpr>(Expr) ||
640 isa<CXXTypeidExpr>(Expr) ||
641 isa<CXXUnresolvedConstructExpr>(Expr) ||
642 isa<ObjCMessageExpr>(Expr) ||
643 isa<ObjCPropertyRefExpr>(Expr) ||
644 isa<ObjCProtocolExpr>(Expr) ||
645 isa<MemberExpr>(Expr) ||
646 isa<ParenExpr>(FullExpr) ||
647 isa<ParenListExpr>(Expr) ||
648 isa<SizeOfPackExpr>(Expr) ||
649 isa<UnaryOperator>(Expr))
650 return false;
651
652 return true;
653}
654
655static void objectifyExpr(const Expr *E, Commit &commit) {
656 if (!E) return;
657
658 QualType T = E->getType();
659 if (T->isObjCObjectPointerType()) {
660 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
661 if (ICE->getCastKind() != CK_CPointerToObjCPointerCast)
662 return;
663 } else {
664 return;
665 }
666 } else if (!T->isPointerType()) {
667 return;
668 }
669
670 SourceRange Range = E->getSourceRange();
671 if (castOperatorNeedsParens(E))
672 commit.insertWrap("(", Range, ")");
673 commit.insertBefore(Range.getBegin(), "(id)");
674}