RewriteObjCFoundationAPI.cpp revision 20119a87fbb7719c161d81fc5f721f1ee6ed7e66
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 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 80static bool subscriptOperatorNeedsParens(const Expr *FullExpr); 81 82static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) { 83 if (subscriptOperatorNeedsParens(Receiver)) { 84 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 233/// \brief Adds an explicit cast to 'id' if the type is not objc object. 234static void objectifyExpr(const Expr *E, Commit &commit); 235 236static 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; 251 objectifyExpr(Msg->getArg(0), commit); 252 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 265 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i) 266 objectifyExpr(Msg->getArg(i), commit); 267 268 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; 302 303 objectifyExpr(Msg->getArg(0), commit); 304 objectifyExpr(Msg->getArg(1), commit); 305 306 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) { 334 objectifyExpr(Msg->getArg(i), commit); 335 objectifyExpr(Msg->getArg(i+1), commit); 336 337 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), 410 Ctx.getSourceManager(), Ctx.getLangOpts()); 411 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 504 bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false; 505 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: 521 break; 522 523 case NSAPI::NSNumberWithUnsignedLong: 524 CallIsUnsigned = true; 525 case NSAPI::NSNumberWithLong: 526 CallIsLong = true; 527 break; 528 529 case NSAPI::NSNumberWithUnsignedLongLong: 530 CallIsUnsigned = true; 531 case NSAPI::NSNumberWithLongLong: 532 CallIsLongLong = true; 533 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} 603 604// 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} 627static 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} 675