RewriteObjCFoundationAPI.cpp revision 0d578a6f873697309e6dd027352fa0716e29986f
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); 212static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, 213 const NSAPI &NS, Commit &commit); 214 215bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, 216 const NSAPI &NS, Commit &commit) { 217 IdentifierInfo *II = 0; 218 if (!checkForLiteralCreation(Msg, II)) 219 return false; 220 221 if (II == NS.getNSClassId(NSAPI::ClassId_NSArray)) 222 return rewriteToArrayLiteral(Msg, NS, commit); 223 if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary)) 224 return rewriteToDictionaryLiteral(Msg, NS, commit); 225 if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber)) 226 return rewriteToNumberLiteral(Msg, NS, commit); 227 228 return false; 229} 230 231//===----------------------------------------------------------------------===// 232// rewriteToArrayLiteral. 233//===----------------------------------------------------------------------===// 234 235/// \brief Adds an explicit cast to 'id' if the type is not objc object. 236static void objectifyExpr(const Expr *E, Commit &commit); 237 238static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, 239 const NSAPI &NS, Commit &commit) { 240 Selector Sel = Msg->getSelector(); 241 SourceRange MsgRange = Msg->getSourceRange(); 242 243 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) { 244 if (Msg->getNumArgs() != 0) 245 return false; 246 commit.replace(MsgRange, "@[]"); 247 return true; 248 } 249 250 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) { 251 if (Msg->getNumArgs() != 1) 252 return false; 253 objectifyExpr(Msg->getArg(0), commit); 254 SourceRange ArgRange = Msg->getArg(0)->getSourceRange(); 255 commit.replaceWithInner(MsgRange, ArgRange); 256 commit.insertWrap("@[", ArgRange, "]"); 257 return true; 258 } 259 260 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) { 261 if (Msg->getNumArgs() == 0) 262 return false; 263 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1); 264 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) 265 return false; 266 267 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i) 268 objectifyExpr(Msg->getArg(i), commit); 269 270 if (Msg->getNumArgs() == 1) { 271 commit.replace(MsgRange, "@[]"); 272 return true; 273 } 274 SourceRange ArgRange(Msg->getArg(0)->getLocStart(), 275 Msg->getArg(Msg->getNumArgs()-2)->getLocEnd()); 276 commit.replaceWithInner(MsgRange, ArgRange); 277 commit.insertWrap("@[", ArgRange, "]"); 278 return true; 279 } 280 281 return false; 282} 283 284//===----------------------------------------------------------------------===// 285// rewriteToDictionaryLiteral. 286//===----------------------------------------------------------------------===// 287 288static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, 289 const NSAPI &NS, Commit &commit) { 290 Selector Sel = Msg->getSelector(); 291 SourceRange MsgRange = Msg->getSourceRange(); 292 293 if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) { 294 if (Msg->getNumArgs() != 0) 295 return false; 296 commit.replace(MsgRange, "@{}"); 297 return true; 298 } 299 300 if (Sel == NS.getNSDictionarySelector( 301 NSAPI::NSDict_dictionaryWithObjectForKey)) { 302 if (Msg->getNumArgs() != 2) 303 return false; 304 305 objectifyExpr(Msg->getArg(0), commit); 306 objectifyExpr(Msg->getArg(1), commit); 307 308 SourceRange ValRange = Msg->getArg(0)->getSourceRange(); 309 SourceRange KeyRange = Msg->getArg(1)->getSourceRange(); 310 // Insert key before the value. 311 commit.insertBefore(ValRange.getBegin(), ": "); 312 commit.insertFromRange(ValRange.getBegin(), 313 CharSourceRange::getTokenRange(KeyRange), 314 /*afterToken=*/false, /*beforePreviousInsertions=*/true); 315 commit.insertBefore(ValRange.getBegin(), "@{"); 316 commit.insertAfterToken(ValRange.getEnd(), "}"); 317 commit.replaceWithInner(MsgRange, ValRange); 318 return true; 319 } 320 321 if (Sel == NS.getNSDictionarySelector( 322 NSAPI::NSDict_dictionaryWithObjectsAndKeys)) { 323 if (Msg->getNumArgs() % 2 != 1) 324 return false; 325 unsigned SentinelIdx = Msg->getNumArgs() - 1; 326 const Expr *SentinelExpr = Msg->getArg(SentinelIdx); 327 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) 328 return false; 329 330 if (Msg->getNumArgs() == 1) { 331 commit.replace(MsgRange, "@{}"); 332 return true; 333 } 334 335 for (unsigned i = 0; i < SentinelIdx; i += 2) { 336 objectifyExpr(Msg->getArg(i), commit); 337 objectifyExpr(Msg->getArg(i+1), commit); 338 339 SourceRange ValRange = Msg->getArg(i)->getSourceRange(); 340 SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange(); 341 // Insert value after key. 342 commit.insertAfterToken(KeyRange.getEnd(), ": "); 343 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true); 344 commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(), 345 KeyRange.getBegin())); 346 } 347 // Range of arguments up until and including the last key. 348 // The sentinel and first value are cut off, the value will move after the 349 // key. 350 SourceRange ArgRange(Msg->getArg(1)->getLocStart(), 351 Msg->getArg(SentinelIdx-1)->getLocEnd()); 352 commit.insertWrap("@{", ArgRange, "}"); 353 commit.replaceWithInner(MsgRange, ArgRange); 354 return true; 355 } 356 357 return false; 358} 359 360//===----------------------------------------------------------------------===// 361// rewriteToNumberLiteral. 362//===----------------------------------------------------------------------===// 363 364static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg, 365 const CharacterLiteral *Arg, 366 const NSAPI &NS, Commit &commit) { 367 if (Arg->getKind() != CharacterLiteral::Ascii) 368 return false; 369 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar, 370 Msg->getSelector())) { 371 SourceRange ArgRange = Arg->getSourceRange(); 372 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 373 commit.insert(ArgRange.getBegin(), "@"); 374 return true; 375 } 376 377 return rewriteToNumericBoxedExpression(Msg, NS, commit); 378} 379 380static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg, 381 const Expr *Arg, 382 const NSAPI &NS, Commit &commit) { 383 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool, 384 Msg->getSelector())) { 385 SourceRange ArgRange = Arg->getSourceRange(); 386 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 387 commit.insert(ArgRange.getBegin(), "@"); 388 return true; 389 } 390 391 return rewriteToNumericBoxedExpression(Msg, NS, commit); 392} 393 394namespace { 395 396struct LiteralInfo { 397 bool Hex, Octal; 398 StringRef U, F, L, LL; 399 CharSourceRange WithoutSuffRange; 400}; 401 402} 403 404static bool getLiteralInfo(SourceRange literalRange, 405 bool isFloat, bool isIntZero, 406 ASTContext &Ctx, LiteralInfo &Info) { 407 if (literalRange.getBegin().isMacroID() || 408 literalRange.getEnd().isMacroID()) 409 return false; 410 StringRef text = Lexer::getSourceText( 411 CharSourceRange::getTokenRange(literalRange), 412 Ctx.getSourceManager(), Ctx.getLangOpts()); 413 if (text.empty()) 414 return false; 415 416 llvm::Optional<bool> UpperU, UpperL; 417 bool UpperF = false; 418 419 struct Suff { 420 static bool has(StringRef suff, StringRef &text) { 421 if (text.endswith(suff)) { 422 text = text.substr(0, text.size()-suff.size()); 423 return true; 424 } 425 return false; 426 } 427 }; 428 429 while (1) { 430 if (Suff::has("u", text)) { 431 UpperU = false; 432 } else if (Suff::has("U", text)) { 433 UpperU = true; 434 } else if (Suff::has("ll", text)) { 435 UpperL = false; 436 } else if (Suff::has("LL", text)) { 437 UpperL = true; 438 } else if (Suff::has("l", text)) { 439 UpperL = false; 440 } else if (Suff::has("L", text)) { 441 UpperL = true; 442 } else if (isFloat && Suff::has("f", text)) { 443 UpperF = false; 444 } else if (isFloat && Suff::has("F", text)) { 445 UpperF = true; 446 } else 447 break; 448 } 449 450 if (!UpperU.hasValue() && !UpperL.hasValue()) 451 UpperU = UpperL = true; 452 else if (UpperU.hasValue() && !UpperL.hasValue()) 453 UpperL = UpperU; 454 else if (UpperL.hasValue() && !UpperU.hasValue()) 455 UpperU = UpperL; 456 457 Info.U = *UpperU ? "U" : "u"; 458 Info.L = *UpperL ? "L" : "l"; 459 Info.LL = *UpperL ? "LL" : "ll"; 460 Info.F = UpperF ? "F" : "f"; 461 462 Info.Hex = Info.Octal = false; 463 if (text.startswith("0x")) 464 Info.Hex = true; 465 else if (!isFloat && !isIntZero && text.startswith("0")) 466 Info.Octal = true; 467 468 SourceLocation B = literalRange.getBegin(); 469 Info.WithoutSuffRange = 470 CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size())); 471 return true; 472} 473 474static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, 475 const NSAPI &NS, Commit &commit) { 476 if (Msg->getNumArgs() != 1) 477 return false; 478 479 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts(); 480 if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg)) 481 return rewriteToCharLiteral(Msg, CharE, NS, commit); 482 if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg)) 483 return rewriteToBoolLiteral(Msg, BE, NS, commit); 484 if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg)) 485 return rewriteToBoolLiteral(Msg, BE, NS, commit); 486 487 const Expr *literalE = Arg; 488 if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) { 489 if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus) 490 literalE = UOE->getSubExpr(); 491 } 492 493 // Only integer and floating literals, otherwise try to rewrite to boxed 494 // expression. 495 if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE)) 496 return rewriteToNumericBoxedExpression(Msg, NS, commit); 497 498 ASTContext &Ctx = NS.getASTContext(); 499 Selector Sel = Msg->getSelector(); 500 llvm::Optional<NSAPI::NSNumberLiteralMethodKind> 501 MKOpt = NS.getNSNumberLiteralMethodKind(Sel); 502 if (!MKOpt) 503 return false; 504 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt; 505 506 bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false; 507 bool CallIsFloating = false, CallIsDouble = false; 508 509 switch (MK) { 510 // We cannot have these calls with int/float literals. 511 case NSAPI::NSNumberWithChar: 512 case NSAPI::NSNumberWithUnsignedChar: 513 case NSAPI::NSNumberWithShort: 514 case NSAPI::NSNumberWithUnsignedShort: 515 case NSAPI::NSNumberWithBool: 516 return rewriteToNumericBoxedExpression(Msg, NS, commit); 517 518 case NSAPI::NSNumberWithUnsignedInt: 519 case NSAPI::NSNumberWithUnsignedInteger: 520 CallIsUnsigned = true; 521 case NSAPI::NSNumberWithInt: 522 case NSAPI::NSNumberWithInteger: 523 break; 524 525 case NSAPI::NSNumberWithUnsignedLong: 526 CallIsUnsigned = true; 527 case NSAPI::NSNumberWithLong: 528 CallIsLong = true; 529 break; 530 531 case NSAPI::NSNumberWithUnsignedLongLong: 532 CallIsUnsigned = true; 533 case NSAPI::NSNumberWithLongLong: 534 CallIsLongLong = true; 535 break; 536 537 case NSAPI::NSNumberWithDouble: 538 CallIsDouble = true; 539 case NSAPI::NSNumberWithFloat: 540 CallIsFloating = true; 541 break; 542 } 543 544 SourceRange ArgRange = Arg->getSourceRange(); 545 QualType ArgTy = Arg->getType(); 546 QualType CallTy = Msg->getArg(0)->getType(); 547 548 // Check for the easy case, the literal maps directly to the call. 549 if (Ctx.hasSameType(ArgTy, CallTy)) { 550 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 551 commit.insert(ArgRange.getBegin(), "@"); 552 return true; 553 } 554 555 // We will need to modify the literal suffix to get the same type as the call. 556 // Try with boxed expression if it came from a macro. 557 if (ArgRange.getBegin().isMacroID()) 558 return rewriteToNumericBoxedExpression(Msg, NS, commit); 559 560 bool LitIsFloat = ArgTy->isFloatingType(); 561 // For a float passed to integer call, don't try rewriting to objc literal. 562 // It is difficult and a very uncommon case anyway. 563 // But try with boxed expression. 564 if (LitIsFloat && !CallIsFloating) 565 return rewriteToNumericBoxedExpression(Msg, NS, commit); 566 567 // Try to modify the literal make it the same type as the method call. 568 // -Modify the suffix, and/or 569 // -Change integer to float 570 571 LiteralInfo LitInfo; 572 bool isIntZero = false; 573 if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE)) 574 isIntZero = !IntE->getValue().getBoolValue(); 575 if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo)) 576 return rewriteToNumericBoxedExpression(Msg, NS, commit); 577 578 // Not easy to do int -> float with hex/octal and uncommon anyway. 579 if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal)) 580 return rewriteToNumericBoxedExpression(Msg, NS, commit); 581 582 SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin(); 583 SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd(); 584 585 commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()), 586 LitInfo.WithoutSuffRange); 587 commit.insert(LitB, "@"); 588 589 if (!LitIsFloat && CallIsFloating) 590 commit.insert(LitE, ".0"); 591 592 if (CallIsFloating) { 593 if (!CallIsDouble) 594 commit.insert(LitE, LitInfo.F); 595 } else { 596 if (CallIsUnsigned) 597 commit.insert(LitE, LitInfo.U); 598 599 if (CallIsLong) 600 commit.insert(LitE, LitInfo.L); 601 else if (CallIsLongLong) 602 commit.insert(LitE, LitInfo.LL); 603 } 604 return true; 605} 606 607// FIXME: Make determination of operator precedence more general and 608// make it broadly available. 609static bool subscriptOperatorNeedsParens(const Expr *FullExpr) { 610 const Expr* Expr = FullExpr->IgnoreImpCasts(); 611 if (isa<ArraySubscriptExpr>(Expr) || 612 isa<CallExpr>(Expr) || 613 isa<DeclRefExpr>(Expr) || 614 isa<CXXNamedCastExpr>(Expr) || 615 isa<CXXConstructExpr>(Expr) || 616 isa<CXXThisExpr>(Expr) || 617 isa<CXXTypeidExpr>(Expr) || 618 isa<CXXUnresolvedConstructExpr>(Expr) || 619 isa<ObjCMessageExpr>(Expr) || 620 isa<ObjCPropertyRefExpr>(Expr) || 621 isa<ObjCProtocolExpr>(Expr) || 622 isa<MemberExpr>(Expr) || 623 isa<ParenExpr>(FullExpr) || 624 isa<ParenListExpr>(Expr) || 625 isa<SizeOfPackExpr>(Expr)) 626 return false; 627 628 return true; 629} 630static bool castOperatorNeedsParens(const Expr *FullExpr) { 631 const Expr* Expr = FullExpr->IgnoreImpCasts(); 632 if (isa<ArraySubscriptExpr>(Expr) || 633 isa<CallExpr>(Expr) || 634 isa<DeclRefExpr>(Expr) || 635 isa<CastExpr>(Expr) || 636 isa<CXXNewExpr>(Expr) || 637 isa<CXXConstructExpr>(Expr) || 638 isa<CXXDeleteExpr>(Expr) || 639 isa<CXXNoexceptExpr>(Expr) || 640 isa<CXXPseudoDestructorExpr>(Expr) || 641 isa<CXXScalarValueInitExpr>(Expr) || 642 isa<CXXThisExpr>(Expr) || 643 isa<CXXTypeidExpr>(Expr) || 644 isa<CXXUnresolvedConstructExpr>(Expr) || 645 isa<ObjCMessageExpr>(Expr) || 646 isa<ObjCPropertyRefExpr>(Expr) || 647 isa<ObjCProtocolExpr>(Expr) || 648 isa<MemberExpr>(Expr) || 649 isa<ParenExpr>(FullExpr) || 650 isa<ParenListExpr>(Expr) || 651 isa<SizeOfPackExpr>(Expr) || 652 isa<UnaryOperator>(Expr)) 653 return false; 654 655 return true; 656} 657 658static void objectifyExpr(const Expr *E, Commit &commit) { 659 if (!E) return; 660 661 QualType T = E->getType(); 662 if (T->isObjCObjectPointerType()) { 663 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { 664 if (ICE->getCastKind() != CK_CPointerToObjCPointerCast) 665 return; 666 } else { 667 return; 668 } 669 } else if (!T->isPointerType()) { 670 return; 671 } 672 673 SourceRange Range = E->getSourceRange(); 674 if (castOperatorNeedsParens(E)) 675 commit.insertWrap("(", Range, ")"); 676 commit.insertBefore(Range.getBegin(), "(id)"); 677} 678 679//===----------------------------------------------------------------------===// 680// rewriteToNumericBoxedExpression. 681//===----------------------------------------------------------------------===// 682 683static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, 684 const NSAPI &NS, Commit &commit) { 685 if (Msg->getNumArgs() != 1) 686 return false; 687 688 const Expr *Arg = Msg->getArg(0); 689 if (Arg->isTypeDependent()) 690 return false; 691 692 ASTContext &Ctx = NS.getASTContext(); 693 Selector Sel = Msg->getSelector(); 694 llvm::Optional<NSAPI::NSNumberLiteralMethodKind> 695 MKOpt = NS.getNSNumberLiteralMethodKind(Sel); 696 if (!MKOpt) 697 return false; 698 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt; 699 700 const Expr *OrigArg = Arg->IgnoreImpCasts(); 701 QualType FinalTy = Arg->getType(); 702 QualType OrigTy = OrigArg->getType(); 703 uint64_t FinalTySize = Ctx.getTypeSize(FinalTy); 704 uint64_t OrigTySize = Ctx.getTypeSize(OrigTy); 705 706 bool isTruncated = FinalTySize < OrigTySize; 707 bool needsCast = false; 708 709 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { 710 switch (ICE->getCastKind()) { 711 case CK_LValueToRValue: 712 case CK_NoOp: 713 case CK_UserDefinedConversion: 714 break; 715 716 case CK_IntegralCast: { 717 if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType()) 718 break; 719 // Be more liberal with Integer/UnsignedInteger which are very commonly 720 // used. 721 if ((MK == NSAPI::NSNumberWithInteger || 722 MK == NSAPI::NSNumberWithUnsignedInteger) && 723 !isTruncated) { 724 if (OrigTy->getAs<EnumType>()) 725 break; 726 if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() && 727 OrigTySize >= Ctx.getTypeSize(Ctx.IntTy)) 728 break; 729 } 730 731 needsCast = true; 732 break; 733 } 734 735 case CK_PointerToBoolean: 736 case CK_IntegralToBoolean: 737 case CK_IntegralToFloating: 738 case CK_FloatingToIntegral: 739 case CK_FloatingToBoolean: 740 case CK_FloatingCast: 741 case CK_FloatingComplexToReal: 742 case CK_FloatingComplexToBoolean: 743 case CK_IntegralComplexToReal: 744 case CK_IntegralComplexToBoolean: 745 case CK_AtomicToNonAtomic: 746 needsCast = true; 747 break; 748 749 case CK_Dependent: 750 case CK_BitCast: 751 case CK_LValueBitCast: 752 case CK_BaseToDerived: 753 case CK_DerivedToBase: 754 case CK_UncheckedDerivedToBase: 755 case CK_Dynamic: 756 case CK_ToUnion: 757 case CK_ArrayToPointerDecay: 758 case CK_FunctionToPointerDecay: 759 case CK_NullToPointer: 760 case CK_NullToMemberPointer: 761 case CK_BaseToDerivedMemberPointer: 762 case CK_DerivedToBaseMemberPointer: 763 case CK_MemberPointerToBoolean: 764 case CK_ReinterpretMemberPointer: 765 case CK_ConstructorConversion: 766 case CK_IntegralToPointer: 767 case CK_PointerToIntegral: 768 case CK_ToVoid: 769 case CK_VectorSplat: 770 case CK_CPointerToObjCPointerCast: 771 case CK_BlockPointerToObjCPointerCast: 772 case CK_AnyPointerToBlockPointerCast: 773 case CK_ObjCObjectLValueCast: 774 case CK_FloatingRealToComplex: 775 case CK_FloatingComplexCast: 776 case CK_FloatingComplexToIntegralComplex: 777 case CK_IntegralRealToComplex: 778 case CK_IntegralComplexCast: 779 case CK_IntegralComplexToFloatingComplex: 780 case CK_ARCProduceObject: 781 case CK_ARCConsumeObject: 782 case CK_ARCReclaimReturnedObject: 783 case CK_ARCExtendBlockObject: 784 case CK_NonAtomicToAtomic: 785 case CK_CopyAndAutoreleaseBlockObject: 786 return false; 787 } 788 } 789 790 if (needsCast) 791 return false; 792 793 SourceRange ArgRange = OrigArg->getSourceRange(); 794 commit.replaceWithInner(Msg->getSourceRange(), OrigArg->getSourceRange()); 795 796 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg)) 797 commit.insertBefore(ArgRange.getBegin(), "@"); 798 else 799 commit.insertWrap("@(", ArgRange, ")"); 800 801 return true; 802} 803