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/AST/ASTContext.h" 16 #include "clang/AST/ExprCXX.h" 17 #include "clang/AST/ExprObjC.h" 18 #include "clang/AST/NSAPI.h" 19 #include "clang/AST/ParentMap.h" 20 #include "clang/Edit/Commit.h" 21 #include "clang/Lex/Lexer.h" 22 23 using namespace clang; 24 using namespace edit; 25 26 static bool checkForLiteralCreation(const ObjCMessageExpr *Msg, 27 IdentifierInfo *&ClassId, 28 const LangOptions &LangOpts) { 29 if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl()) 30 return false; 31 32 const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface(); 33 if (!Receiver) 34 return false; 35 ClassId = Receiver->getIdentifier(); 36 37 if (Msg->getReceiverKind() == ObjCMessageExpr::Class) 38 return true; 39 40 // When in ARC mode we also convert "[[.. alloc] init]" messages to literals, 41 // since the change from +1 to +0 will be handled fine by ARC. 42 if (LangOpts.ObjCAutoRefCount) { 43 if (Msg->getReceiverKind() == ObjCMessageExpr::Instance) { 44 if (const ObjCMessageExpr *Rec = dyn_cast<ObjCMessageExpr>( 45 Msg->getInstanceReceiver()->IgnoreParenImpCasts())) { 46 if (Rec->getMethodFamily() == OMF_alloc) 47 return true; 48 } 49 } 50 } 51 52 return false; 53 } 54 55 //===----------------------------------------------------------------------===// 56 // rewriteObjCRedundantCallWithLiteral. 57 //===----------------------------------------------------------------------===// 58 59 bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg, 60 const NSAPI &NS, Commit &commit) { 61 IdentifierInfo *II = 0; 62 if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts())) 63 return false; 64 if (Msg->getNumArgs() != 1) 65 return false; 66 67 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts(); 68 Selector Sel = Msg->getSelector(); 69 70 if ((isa<ObjCStringLiteral>(Arg) && 71 NS.getNSClassId(NSAPI::ClassId_NSString) == II && 72 (NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel || 73 NS.getNSStringSelector(NSAPI::NSStr_initWithString) == Sel)) || 74 75 (isa<ObjCArrayLiteral>(Arg) && 76 NS.getNSClassId(NSAPI::ClassId_NSArray) == II && 77 (NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel || 78 NS.getNSArraySelector(NSAPI::NSArr_initWithArray) == Sel)) || 79 80 (isa<ObjCDictionaryLiteral>(Arg) && 81 NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II && 82 (NS.getNSDictionarySelector( 83 NSAPI::NSDict_dictionaryWithDictionary) == Sel || 84 NS.getNSDictionarySelector(NSAPI::NSDict_initWithDictionary) == Sel))) { 85 86 commit.replaceWithInner(Msg->getSourceRange(), 87 Msg->getArg(0)->getSourceRange()); 88 return true; 89 } 90 91 return false; 92 } 93 94 //===----------------------------------------------------------------------===// 95 // rewriteToObjCSubscriptSyntax. 96 //===----------------------------------------------------------------------===// 97 98 /// \brief Check for classes that accept 'objectForKey:' (or the other selectors 99 /// that the migrator handles) but return their instances as 'id', resulting 100 /// in the compiler resolving 'objectForKey:' as the method from NSDictionary. 101 /// 102 /// When checking if we can convert to subscripting syntax, check whether 103 /// the receiver is a result of a class method from a hardcoded list of 104 /// such classes. In such a case return the specific class as the interface 105 /// of the receiver. 106 /// 107 /// FIXME: Remove this when these classes start using 'instancetype'. 108 static const ObjCInterfaceDecl * 109 maybeAdjustInterfaceForSubscriptingCheck(const ObjCInterfaceDecl *IFace, 110 const Expr *Receiver, 111 ASTContext &Ctx) { 112 assert(IFace && Receiver); 113 114 // If the receiver has type 'id'... 115 if (!Ctx.isObjCIdType(Receiver->getType().getUnqualifiedType())) 116 return IFace; 117 118 const ObjCMessageExpr * 119 InnerMsg = dyn_cast<ObjCMessageExpr>(Receiver->IgnoreParenCasts()); 120 if (!InnerMsg) 121 return IFace; 122 123 QualType ClassRec; 124 switch (InnerMsg->getReceiverKind()) { 125 case ObjCMessageExpr::Instance: 126 case ObjCMessageExpr::SuperInstance: 127 return IFace; 128 129 case ObjCMessageExpr::Class: 130 ClassRec = InnerMsg->getClassReceiver(); 131 break; 132 case ObjCMessageExpr::SuperClass: 133 ClassRec = InnerMsg->getSuperType(); 134 break; 135 } 136 137 if (ClassRec.isNull()) 138 return IFace; 139 140 // ...and it is the result of a class message... 141 142 const ObjCObjectType *ObjTy = ClassRec->getAs<ObjCObjectType>(); 143 if (!ObjTy) 144 return IFace; 145 const ObjCInterfaceDecl *OID = ObjTy->getInterface(); 146 147 // ...and the receiving class is NSMapTable or NSLocale, return that 148 // class as the receiving interface. 149 if (OID->getName() == "NSMapTable" || 150 OID->getName() == "NSLocale") 151 return OID; 152 153 return IFace; 154 } 155 156 static bool canRewriteToSubscriptSyntax(const ObjCInterfaceDecl *&IFace, 157 const ObjCMessageExpr *Msg, 158 ASTContext &Ctx, 159 Selector subscriptSel) { 160 const Expr *Rec = Msg->getInstanceReceiver(); 161 if (!Rec) 162 return false; 163 IFace = maybeAdjustInterfaceForSubscriptingCheck(IFace, Rec, Ctx); 164 165 if (const ObjCMethodDecl *MD = IFace->lookupInstanceMethod(subscriptSel)) { 166 if (!MD->isUnavailable()) 167 return true; 168 } 169 return false; 170 } 171 172 static bool subscriptOperatorNeedsParens(const Expr *FullExpr); 173 174 static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) { 175 if (subscriptOperatorNeedsParens(Receiver)) { 176 SourceRange RecRange = Receiver->getSourceRange(); 177 commit.insertWrap("(", RecRange, ")"); 178 } 179 } 180 181 static bool rewriteToSubscriptGetCommon(const ObjCMessageExpr *Msg, 182 Commit &commit) { 183 if (Msg->getNumArgs() != 1) 184 return false; 185 const Expr *Rec = Msg->getInstanceReceiver(); 186 if (!Rec) 187 return false; 188 189 SourceRange MsgRange = Msg->getSourceRange(); 190 SourceRange RecRange = Rec->getSourceRange(); 191 SourceRange ArgRange = Msg->getArg(0)->getSourceRange(); 192 193 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(), 194 ArgRange.getBegin()), 195 CharSourceRange::getTokenRange(RecRange)); 196 commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()), 197 ArgRange); 198 commit.insertWrap("[", ArgRange, "]"); 199 maybePutParensOnReceiver(Rec, commit); 200 return true; 201 } 202 203 static bool rewriteToArraySubscriptGet(const ObjCInterfaceDecl *IFace, 204 const ObjCMessageExpr *Msg, 205 const NSAPI &NS, 206 Commit &commit) { 207 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(), 208 NS.getObjectAtIndexedSubscriptSelector())) 209 return false; 210 return rewriteToSubscriptGetCommon(Msg, commit); 211 } 212 213 static bool rewriteToDictionarySubscriptGet(const ObjCInterfaceDecl *IFace, 214 const ObjCMessageExpr *Msg, 215 const NSAPI &NS, 216 Commit &commit) { 217 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(), 218 NS.getObjectForKeyedSubscriptSelector())) 219 return false; 220 return rewriteToSubscriptGetCommon(Msg, commit); 221 } 222 223 static bool rewriteToArraySubscriptSet(const ObjCInterfaceDecl *IFace, 224 const ObjCMessageExpr *Msg, 225 const NSAPI &NS, 226 Commit &commit) { 227 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(), 228 NS.getSetObjectAtIndexedSubscriptSelector())) 229 return false; 230 231 if (Msg->getNumArgs() != 2) 232 return false; 233 const Expr *Rec = Msg->getInstanceReceiver(); 234 if (!Rec) 235 return false; 236 237 SourceRange MsgRange = Msg->getSourceRange(); 238 SourceRange RecRange = Rec->getSourceRange(); 239 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange(); 240 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange(); 241 242 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(), 243 Arg0Range.getBegin()), 244 CharSourceRange::getTokenRange(RecRange)); 245 commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(), 246 Arg1Range.getBegin()), 247 CharSourceRange::getTokenRange(Arg0Range)); 248 commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()), 249 Arg1Range); 250 commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(), 251 Arg1Range.getBegin()), 252 "] = "); 253 maybePutParensOnReceiver(Rec, commit); 254 return true; 255 } 256 257 static bool rewriteToDictionarySubscriptSet(const ObjCInterfaceDecl *IFace, 258 const ObjCMessageExpr *Msg, 259 const NSAPI &NS, 260 Commit &commit) { 261 if (!canRewriteToSubscriptSyntax(IFace, Msg, NS.getASTContext(), 262 NS.getSetObjectForKeyedSubscriptSelector())) 263 return false; 264 265 if (Msg->getNumArgs() != 2) 266 return false; 267 const Expr *Rec = Msg->getInstanceReceiver(); 268 if (!Rec) 269 return false; 270 271 SourceRange MsgRange = Msg->getSourceRange(); 272 SourceRange RecRange = Rec->getSourceRange(); 273 SourceRange Arg0Range = Msg->getArg(0)->getSourceRange(); 274 SourceRange Arg1Range = Msg->getArg(1)->getSourceRange(); 275 276 SourceLocation LocBeforeVal = Arg0Range.getBegin(); 277 commit.insertBefore(LocBeforeVal, "] = "); 278 commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false, 279 /*beforePreviousInsertions=*/true); 280 commit.insertBefore(LocBeforeVal, "["); 281 commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(), 282 Arg0Range.getBegin()), 283 CharSourceRange::getTokenRange(RecRange)); 284 commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()), 285 Arg0Range); 286 maybePutParensOnReceiver(Rec, commit); 287 return true; 288 } 289 290 bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, 291 const NSAPI &NS, Commit &commit) { 292 if (!Msg || Msg->isImplicit() || 293 Msg->getReceiverKind() != ObjCMessageExpr::Instance) 294 return false; 295 const ObjCMethodDecl *Method = Msg->getMethodDecl(); 296 if (!Method) 297 return false; 298 299 const ObjCInterfaceDecl *IFace = 300 NS.getASTContext().getObjContainingInterface(Method); 301 if (!IFace) 302 return false; 303 Selector Sel = Msg->getSelector(); 304 305 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex)) 306 return rewriteToArraySubscriptGet(IFace, Msg, NS, commit); 307 308 if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey)) 309 return rewriteToDictionarySubscriptGet(IFace, Msg, NS, commit); 310 311 if (Msg->getNumArgs() != 2) 312 return false; 313 314 if (Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex)) 315 return rewriteToArraySubscriptSet(IFace, Msg, NS, commit); 316 317 if (Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey)) 318 return rewriteToDictionarySubscriptSet(IFace, Msg, NS, commit); 319 320 return false; 321 } 322 323 //===----------------------------------------------------------------------===// 324 // rewriteToObjCLiteralSyntax. 325 //===----------------------------------------------------------------------===// 326 327 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, 328 const NSAPI &NS, Commit &commit, 329 const ParentMap *PMap); 330 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, 331 const NSAPI &NS, Commit &commit); 332 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, 333 const NSAPI &NS, Commit &commit); 334 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, 335 const NSAPI &NS, Commit &commit); 336 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg, 337 const NSAPI &NS, Commit &commit); 338 339 bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, 340 const NSAPI &NS, Commit &commit, 341 const ParentMap *PMap) { 342 IdentifierInfo *II = 0; 343 if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts())) 344 return false; 345 346 if (II == NS.getNSClassId(NSAPI::ClassId_NSArray)) 347 return rewriteToArrayLiteral(Msg, NS, commit, PMap); 348 if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary)) 349 return rewriteToDictionaryLiteral(Msg, NS, commit); 350 if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber)) 351 return rewriteToNumberLiteral(Msg, NS, commit); 352 if (II == NS.getNSClassId(NSAPI::ClassId_NSString)) 353 return rewriteToStringBoxedExpression(Msg, NS, commit); 354 355 return false; 356 } 357 358 bool edit::rewriteToObjCProperty(const ObjCMethodDecl *Getter, 359 const ObjCMethodDecl *Setter, 360 const NSAPI &NS, Commit &commit) { 361 ASTContext &Context = NS.getASTContext(); 362 std::string PropertyString = "@property"; 363 const ParmVarDecl *argDecl = *Setter->param_begin(); 364 QualType ArgType = Context.getCanonicalType(argDecl->getType()); 365 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime(); 366 367 if (ArgType->isObjCRetainableType() && 368 propertyLifetime == Qualifiers::OCL_Strong) { 369 if (const ObjCObjectPointerType *ObjPtrTy = 370 ArgType->getAs<ObjCObjectPointerType>()) { 371 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); 372 if (IDecl && 373 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying"))) 374 PropertyString += "(copy)"; 375 } 376 } 377 else if (propertyLifetime == Qualifiers::OCL_Weak) 378 // TODO. More precise determination of 'weak' attribute requires 379 // looking into setter's implementation for backing weak ivar. 380 PropertyString += "(weak)"; 381 else 382 PropertyString += "(unsafe_unretained)"; 383 384 // strip off any ARC lifetime qualifier. 385 QualType CanResultTy = Context.getCanonicalType(Getter->getResultType()); 386 if (CanResultTy.getQualifiers().hasObjCLifetime()) { 387 Qualifiers Qs = CanResultTy.getQualifiers(); 388 Qs.removeObjCLifetime(); 389 CanResultTy = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); 390 } 391 PropertyString += " "; 392 PropertyString += CanResultTy.getAsString(Context.getPrintingPolicy()); 393 PropertyString += " "; 394 PropertyString += Getter->getNameAsString(); 395 commit.replace(CharSourceRange::getCharRange(Getter->getLocStart(), 396 Getter->getDeclaratorEndLoc()), 397 PropertyString); 398 SourceLocation EndLoc = Setter->getDeclaratorEndLoc(); 399 // Get location past ';' 400 EndLoc = EndLoc.getLocWithOffset(1); 401 commit.remove(CharSourceRange::getCharRange(Setter->getLocStart(), EndLoc)); 402 return true; 403 } 404 405 bool edit::rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, 406 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols, 407 const NSAPI &NS, Commit &commit) { 408 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols(); 409 410 // ASTContext &Context = NS.getASTContext(); 411 std::string ClassString = "@interface "; 412 ClassString += IDecl->getNameAsString(); 413 414 if (IDecl->getSuperClass()) { 415 ClassString += " : "; 416 ClassString += IDecl->getSuperClass()->getNameAsString(); 417 } 418 if (Protocols.empty()) 419 ClassString += '<'; 420 421 for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), 422 E = Protocols.end(); I != E; ++I) { 423 ClassString += (I == Protocols.begin() ? '<' : ','); 424 ClassString += (*I)->getNameAsString(); 425 } 426 if (!Protocols.empty()) 427 ClassString += ','; 428 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) { 429 ClassString += ConformingProtocols[i]->getNameAsString(); 430 if (i != (e-1)) 431 ClassString += ','; 432 } 433 ClassString += "> "; 434 return true; 435 } 436 437 /// \brief Returns true if the immediate message arguments of \c Msg should not 438 /// be rewritten because it will interfere with the rewrite of the parent 439 /// message expression. e.g. 440 /// \code 441 /// [NSDictionary dictionaryWithObjects: 442 /// [NSArray arrayWithObjects:@"1", @"2", nil] 443 /// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]]; 444 /// \endcode 445 /// It will return true for this because we are going to rewrite this directly 446 /// to a dictionary literal without any array literals. 447 static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg, 448 const NSAPI &NS); 449 450 //===----------------------------------------------------------------------===// 451 // rewriteToArrayLiteral. 452 //===----------------------------------------------------------------------===// 453 454 /// \brief Adds an explicit cast to 'id' if the type is not objc object. 455 static void objectifyExpr(const Expr *E, Commit &commit); 456 457 static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg, 458 const NSAPI &NS, Commit &commit, 459 const ParentMap *PMap) { 460 if (PMap) { 461 const ObjCMessageExpr *ParentMsg = 462 dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg)); 463 if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS)) 464 return false; 465 } 466 467 Selector Sel = Msg->getSelector(); 468 SourceRange MsgRange = Msg->getSourceRange(); 469 470 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) { 471 if (Msg->getNumArgs() != 0) 472 return false; 473 commit.replace(MsgRange, "@[]"); 474 return true; 475 } 476 477 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) { 478 if (Msg->getNumArgs() != 1) 479 return false; 480 objectifyExpr(Msg->getArg(0), commit); 481 SourceRange ArgRange = Msg->getArg(0)->getSourceRange(); 482 commit.replaceWithInner(MsgRange, ArgRange); 483 commit.insertWrap("@[", ArgRange, "]"); 484 return true; 485 } 486 487 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) || 488 Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) { 489 if (Msg->getNumArgs() == 0) 490 return false; 491 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1); 492 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) 493 return false; 494 495 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i) 496 objectifyExpr(Msg->getArg(i), commit); 497 498 if (Msg->getNumArgs() == 1) { 499 commit.replace(MsgRange, "@[]"); 500 return true; 501 } 502 SourceRange ArgRange(Msg->getArg(0)->getLocStart(), 503 Msg->getArg(Msg->getNumArgs()-2)->getLocEnd()); 504 commit.replaceWithInner(MsgRange, ArgRange); 505 commit.insertWrap("@[", ArgRange, "]"); 506 return true; 507 } 508 509 return false; 510 } 511 512 //===----------------------------------------------------------------------===// 513 // rewriteToDictionaryLiteral. 514 //===----------------------------------------------------------------------===// 515 516 /// \brief If \c Msg is an NSArray creation message or literal, this gets the 517 /// objects that were used to create it. 518 /// \returns true if it is an NSArray and we got objects, or false otherwise. 519 static bool getNSArrayObjects(const Expr *E, const NSAPI &NS, 520 SmallVectorImpl<const Expr *> &Objs) { 521 if (!E) 522 return false; 523 524 E = E->IgnoreParenCasts(); 525 if (!E) 526 return false; 527 528 if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) { 529 IdentifierInfo *Cls = 0; 530 if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts())) 531 return false; 532 533 if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray)) 534 return false; 535 536 Selector Sel = Msg->getSelector(); 537 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) 538 return true; // empty array. 539 540 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) { 541 if (Msg->getNumArgs() != 1) 542 return false; 543 Objs.push_back(Msg->getArg(0)); 544 return true; 545 } 546 547 if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) || 548 Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) { 549 if (Msg->getNumArgs() == 0) 550 return false; 551 const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1); 552 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) 553 return false; 554 555 for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i) 556 Objs.push_back(Msg->getArg(i)); 557 return true; 558 } 559 560 } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) { 561 for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i) 562 Objs.push_back(ArrLit->getElement(i)); 563 return true; 564 } 565 566 return false; 567 } 568 569 static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg, 570 const NSAPI &NS, Commit &commit) { 571 Selector Sel = Msg->getSelector(); 572 SourceRange MsgRange = Msg->getSourceRange(); 573 574 if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) { 575 if (Msg->getNumArgs() != 0) 576 return false; 577 commit.replace(MsgRange, "@{}"); 578 return true; 579 } 580 581 if (Sel == NS.getNSDictionarySelector( 582 NSAPI::NSDict_dictionaryWithObjectForKey)) { 583 if (Msg->getNumArgs() != 2) 584 return false; 585 586 objectifyExpr(Msg->getArg(0), commit); 587 objectifyExpr(Msg->getArg(1), commit); 588 589 SourceRange ValRange = Msg->getArg(0)->getSourceRange(); 590 SourceRange KeyRange = Msg->getArg(1)->getSourceRange(); 591 // Insert key before the value. 592 commit.insertBefore(ValRange.getBegin(), ": "); 593 commit.insertFromRange(ValRange.getBegin(), 594 CharSourceRange::getTokenRange(KeyRange), 595 /*afterToken=*/false, /*beforePreviousInsertions=*/true); 596 commit.insertBefore(ValRange.getBegin(), "@{"); 597 commit.insertAfterToken(ValRange.getEnd(), "}"); 598 commit.replaceWithInner(MsgRange, ValRange); 599 return true; 600 } 601 602 if (Sel == NS.getNSDictionarySelector( 603 NSAPI::NSDict_dictionaryWithObjectsAndKeys) || 604 Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsAndKeys)) { 605 if (Msg->getNumArgs() % 2 != 1) 606 return false; 607 unsigned SentinelIdx = Msg->getNumArgs() - 1; 608 const Expr *SentinelExpr = Msg->getArg(SentinelIdx); 609 if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr)) 610 return false; 611 612 if (Msg->getNumArgs() == 1) { 613 commit.replace(MsgRange, "@{}"); 614 return true; 615 } 616 617 for (unsigned i = 0; i < SentinelIdx; i += 2) { 618 objectifyExpr(Msg->getArg(i), commit); 619 objectifyExpr(Msg->getArg(i+1), commit); 620 621 SourceRange ValRange = Msg->getArg(i)->getSourceRange(); 622 SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange(); 623 // Insert value after key. 624 commit.insertAfterToken(KeyRange.getEnd(), ": "); 625 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true); 626 commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(), 627 KeyRange.getBegin())); 628 } 629 // Range of arguments up until and including the last key. 630 // The sentinel and first value are cut off, the value will move after the 631 // key. 632 SourceRange ArgRange(Msg->getArg(1)->getLocStart(), 633 Msg->getArg(SentinelIdx-1)->getLocEnd()); 634 commit.insertWrap("@{", ArgRange, "}"); 635 commit.replaceWithInner(MsgRange, ArgRange); 636 return true; 637 } 638 639 if (Sel == NS.getNSDictionarySelector( 640 NSAPI::NSDict_dictionaryWithObjectsForKeys) || 641 Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) { 642 if (Msg->getNumArgs() != 2) 643 return false; 644 645 SmallVector<const Expr *, 8> Vals; 646 if (!getNSArrayObjects(Msg->getArg(0), NS, Vals)) 647 return false; 648 649 SmallVector<const Expr *, 8> Keys; 650 if (!getNSArrayObjects(Msg->getArg(1), NS, Keys)) 651 return false; 652 653 if (Vals.size() != Keys.size()) 654 return false; 655 656 if (Vals.empty()) { 657 commit.replace(MsgRange, "@{}"); 658 return true; 659 } 660 661 for (unsigned i = 0, n = Vals.size(); i < n; ++i) { 662 objectifyExpr(Vals[i], commit); 663 objectifyExpr(Keys[i], commit); 664 665 SourceRange ValRange = Vals[i]->getSourceRange(); 666 SourceRange KeyRange = Keys[i]->getSourceRange(); 667 // Insert value after key. 668 commit.insertAfterToken(KeyRange.getEnd(), ": "); 669 commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true); 670 } 671 // Range of arguments up until and including the last key. 672 // The first value is cut off, the value will move after the key. 673 SourceRange ArgRange(Keys.front()->getLocStart(), 674 Keys.back()->getLocEnd()); 675 commit.insertWrap("@{", ArgRange, "}"); 676 commit.replaceWithInner(MsgRange, ArgRange); 677 return true; 678 } 679 680 return false; 681 } 682 683 static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg, 684 const NSAPI &NS) { 685 if (!Msg) 686 return false; 687 688 IdentifierInfo *II = 0; 689 if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts())) 690 return false; 691 692 if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary)) 693 return false; 694 695 Selector Sel = Msg->getSelector(); 696 if (Sel == NS.getNSDictionarySelector( 697 NSAPI::NSDict_dictionaryWithObjectsForKeys) || 698 Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) { 699 if (Msg->getNumArgs() != 2) 700 return false; 701 702 SmallVector<const Expr *, 8> Vals; 703 if (!getNSArrayObjects(Msg->getArg(0), NS, Vals)) 704 return false; 705 706 SmallVector<const Expr *, 8> Keys; 707 if (!getNSArrayObjects(Msg->getArg(1), NS, Keys)) 708 return false; 709 710 if (Vals.size() != Keys.size()) 711 return false; 712 713 return true; 714 } 715 716 return false; 717 } 718 719 //===----------------------------------------------------------------------===// 720 // rewriteToNumberLiteral. 721 //===----------------------------------------------------------------------===// 722 723 static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg, 724 const CharacterLiteral *Arg, 725 const NSAPI &NS, Commit &commit) { 726 if (Arg->getKind() != CharacterLiteral::Ascii) 727 return false; 728 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar, 729 Msg->getSelector())) { 730 SourceRange ArgRange = Arg->getSourceRange(); 731 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 732 commit.insert(ArgRange.getBegin(), "@"); 733 return true; 734 } 735 736 return rewriteToNumericBoxedExpression(Msg, NS, commit); 737 } 738 739 static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg, 740 const Expr *Arg, 741 const NSAPI &NS, Commit &commit) { 742 if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool, 743 Msg->getSelector())) { 744 SourceRange ArgRange = Arg->getSourceRange(); 745 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 746 commit.insert(ArgRange.getBegin(), "@"); 747 return true; 748 } 749 750 return rewriteToNumericBoxedExpression(Msg, NS, commit); 751 } 752 753 namespace { 754 755 struct LiteralInfo { 756 bool Hex, Octal; 757 StringRef U, F, L, LL; 758 CharSourceRange WithoutSuffRange; 759 }; 760 761 } 762 763 static bool getLiteralInfo(SourceRange literalRange, 764 bool isFloat, bool isIntZero, 765 ASTContext &Ctx, LiteralInfo &Info) { 766 if (literalRange.getBegin().isMacroID() || 767 literalRange.getEnd().isMacroID()) 768 return false; 769 StringRef text = Lexer::getSourceText( 770 CharSourceRange::getTokenRange(literalRange), 771 Ctx.getSourceManager(), Ctx.getLangOpts()); 772 if (text.empty()) 773 return false; 774 775 Optional<bool> UpperU, UpperL; 776 bool UpperF = false; 777 778 struct Suff { 779 static bool has(StringRef suff, StringRef &text) { 780 if (text.endswith(suff)) { 781 text = text.substr(0, text.size()-suff.size()); 782 return true; 783 } 784 return false; 785 } 786 }; 787 788 while (1) { 789 if (Suff::has("u", text)) { 790 UpperU = false; 791 } else if (Suff::has("U", text)) { 792 UpperU = true; 793 } else if (Suff::has("ll", text)) { 794 UpperL = false; 795 } else if (Suff::has("LL", text)) { 796 UpperL = true; 797 } else if (Suff::has("l", text)) { 798 UpperL = false; 799 } else if (Suff::has("L", text)) { 800 UpperL = true; 801 } else if (isFloat && Suff::has("f", text)) { 802 UpperF = false; 803 } else if (isFloat && Suff::has("F", text)) { 804 UpperF = true; 805 } else 806 break; 807 } 808 809 if (!UpperU.hasValue() && !UpperL.hasValue()) 810 UpperU = UpperL = true; 811 else if (UpperU.hasValue() && !UpperL.hasValue()) 812 UpperL = UpperU; 813 else if (UpperL.hasValue() && !UpperU.hasValue()) 814 UpperU = UpperL; 815 816 Info.U = *UpperU ? "U" : "u"; 817 Info.L = *UpperL ? "L" : "l"; 818 Info.LL = *UpperL ? "LL" : "ll"; 819 Info.F = UpperF ? "F" : "f"; 820 821 Info.Hex = Info.Octal = false; 822 if (text.startswith("0x")) 823 Info.Hex = true; 824 else if (!isFloat && !isIntZero && text.startswith("0")) 825 Info.Octal = true; 826 827 SourceLocation B = literalRange.getBegin(); 828 Info.WithoutSuffRange = 829 CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size())); 830 return true; 831 } 832 833 static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg, 834 const NSAPI &NS, Commit &commit) { 835 if (Msg->getNumArgs() != 1) 836 return false; 837 838 const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts(); 839 if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg)) 840 return rewriteToCharLiteral(Msg, CharE, NS, commit); 841 if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg)) 842 return rewriteToBoolLiteral(Msg, BE, NS, commit); 843 if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg)) 844 return rewriteToBoolLiteral(Msg, BE, NS, commit); 845 846 const Expr *literalE = Arg; 847 if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) { 848 if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus) 849 literalE = UOE->getSubExpr(); 850 } 851 852 // Only integer and floating literals, otherwise try to rewrite to boxed 853 // expression. 854 if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE)) 855 return rewriteToNumericBoxedExpression(Msg, NS, commit); 856 857 ASTContext &Ctx = NS.getASTContext(); 858 Selector Sel = Msg->getSelector(); 859 Optional<NSAPI::NSNumberLiteralMethodKind> 860 MKOpt = NS.getNSNumberLiteralMethodKind(Sel); 861 if (!MKOpt) 862 return false; 863 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt; 864 865 bool CallIsUnsigned = false, CallIsLong = false, CallIsLongLong = false; 866 bool CallIsFloating = false, CallIsDouble = false; 867 868 switch (MK) { 869 // We cannot have these calls with int/float literals. 870 case NSAPI::NSNumberWithChar: 871 case NSAPI::NSNumberWithUnsignedChar: 872 case NSAPI::NSNumberWithShort: 873 case NSAPI::NSNumberWithUnsignedShort: 874 case NSAPI::NSNumberWithBool: 875 return rewriteToNumericBoxedExpression(Msg, NS, commit); 876 877 case NSAPI::NSNumberWithUnsignedInt: 878 case NSAPI::NSNumberWithUnsignedInteger: 879 CallIsUnsigned = true; 880 case NSAPI::NSNumberWithInt: 881 case NSAPI::NSNumberWithInteger: 882 break; 883 884 case NSAPI::NSNumberWithUnsignedLong: 885 CallIsUnsigned = true; 886 case NSAPI::NSNumberWithLong: 887 CallIsLong = true; 888 break; 889 890 case NSAPI::NSNumberWithUnsignedLongLong: 891 CallIsUnsigned = true; 892 case NSAPI::NSNumberWithLongLong: 893 CallIsLongLong = true; 894 break; 895 896 case NSAPI::NSNumberWithDouble: 897 CallIsDouble = true; 898 case NSAPI::NSNumberWithFloat: 899 CallIsFloating = true; 900 break; 901 } 902 903 SourceRange ArgRange = Arg->getSourceRange(); 904 QualType ArgTy = Arg->getType(); 905 QualType CallTy = Msg->getArg(0)->getType(); 906 907 // Check for the easy case, the literal maps directly to the call. 908 if (Ctx.hasSameType(ArgTy, CallTy)) { 909 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 910 commit.insert(ArgRange.getBegin(), "@"); 911 return true; 912 } 913 914 // We will need to modify the literal suffix to get the same type as the call. 915 // Try with boxed expression if it came from a macro. 916 if (ArgRange.getBegin().isMacroID()) 917 return rewriteToNumericBoxedExpression(Msg, NS, commit); 918 919 bool LitIsFloat = ArgTy->isFloatingType(); 920 // For a float passed to integer call, don't try rewriting to objc literal. 921 // It is difficult and a very uncommon case anyway. 922 // But try with boxed expression. 923 if (LitIsFloat && !CallIsFloating) 924 return rewriteToNumericBoxedExpression(Msg, NS, commit); 925 926 // Try to modify the literal make it the same type as the method call. 927 // -Modify the suffix, and/or 928 // -Change integer to float 929 930 LiteralInfo LitInfo; 931 bool isIntZero = false; 932 if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE)) 933 isIntZero = !IntE->getValue().getBoolValue(); 934 if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo)) 935 return rewriteToNumericBoxedExpression(Msg, NS, commit); 936 937 // Not easy to do int -> float with hex/octal and uncommon anyway. 938 if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal)) 939 return rewriteToNumericBoxedExpression(Msg, NS, commit); 940 941 SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin(); 942 SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd(); 943 944 commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()), 945 LitInfo.WithoutSuffRange); 946 commit.insert(LitB, "@"); 947 948 if (!LitIsFloat && CallIsFloating) 949 commit.insert(LitE, ".0"); 950 951 if (CallIsFloating) { 952 if (!CallIsDouble) 953 commit.insert(LitE, LitInfo.F); 954 } else { 955 if (CallIsUnsigned) 956 commit.insert(LitE, LitInfo.U); 957 958 if (CallIsLong) 959 commit.insert(LitE, LitInfo.L); 960 else if (CallIsLongLong) 961 commit.insert(LitE, LitInfo.LL); 962 } 963 return true; 964 } 965 966 // FIXME: Make determination of operator precedence more general and 967 // make it broadly available. 968 static bool subscriptOperatorNeedsParens(const Expr *FullExpr) { 969 const Expr* Expr = FullExpr->IgnoreImpCasts(); 970 if (isa<ArraySubscriptExpr>(Expr) || 971 isa<CallExpr>(Expr) || 972 isa<DeclRefExpr>(Expr) || 973 isa<CXXNamedCastExpr>(Expr) || 974 isa<CXXConstructExpr>(Expr) || 975 isa<CXXThisExpr>(Expr) || 976 isa<CXXTypeidExpr>(Expr) || 977 isa<CXXUnresolvedConstructExpr>(Expr) || 978 isa<ObjCMessageExpr>(Expr) || 979 isa<ObjCPropertyRefExpr>(Expr) || 980 isa<ObjCProtocolExpr>(Expr) || 981 isa<MemberExpr>(Expr) || 982 isa<ObjCIvarRefExpr>(Expr) || 983 isa<ParenExpr>(FullExpr) || 984 isa<ParenListExpr>(Expr) || 985 isa<SizeOfPackExpr>(Expr)) 986 return false; 987 988 return true; 989 } 990 static bool castOperatorNeedsParens(const Expr *FullExpr) { 991 const Expr* Expr = FullExpr->IgnoreImpCasts(); 992 if (isa<ArraySubscriptExpr>(Expr) || 993 isa<CallExpr>(Expr) || 994 isa<DeclRefExpr>(Expr) || 995 isa<CastExpr>(Expr) || 996 isa<CXXNewExpr>(Expr) || 997 isa<CXXConstructExpr>(Expr) || 998 isa<CXXDeleteExpr>(Expr) || 999 isa<CXXNoexceptExpr>(Expr) || 1000 isa<CXXPseudoDestructorExpr>(Expr) || 1001 isa<CXXScalarValueInitExpr>(Expr) || 1002 isa<CXXThisExpr>(Expr) || 1003 isa<CXXTypeidExpr>(Expr) || 1004 isa<CXXUnresolvedConstructExpr>(Expr) || 1005 isa<ObjCMessageExpr>(Expr) || 1006 isa<ObjCPropertyRefExpr>(Expr) || 1007 isa<ObjCProtocolExpr>(Expr) || 1008 isa<MemberExpr>(Expr) || 1009 isa<ObjCIvarRefExpr>(Expr) || 1010 isa<ParenExpr>(FullExpr) || 1011 isa<ParenListExpr>(Expr) || 1012 isa<SizeOfPackExpr>(Expr) || 1013 isa<UnaryOperator>(Expr)) 1014 return false; 1015 1016 return true; 1017 } 1018 1019 static void objectifyExpr(const Expr *E, Commit &commit) { 1020 if (!E) return; 1021 1022 QualType T = E->getType(); 1023 if (T->isObjCObjectPointerType()) { 1024 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { 1025 if (ICE->getCastKind() != CK_CPointerToObjCPointerCast) 1026 return; 1027 } else { 1028 return; 1029 } 1030 } else if (!T->isPointerType()) { 1031 return; 1032 } 1033 1034 SourceRange Range = E->getSourceRange(); 1035 if (castOperatorNeedsParens(E)) 1036 commit.insertWrap("(", Range, ")"); 1037 commit.insertBefore(Range.getBegin(), "(id)"); 1038 } 1039 1040 //===----------------------------------------------------------------------===// 1041 // rewriteToNumericBoxedExpression. 1042 //===----------------------------------------------------------------------===// 1043 1044 static bool isEnumConstant(const Expr *E) { 1045 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) 1046 if (const ValueDecl *VD = DRE->getDecl()) 1047 return isa<EnumConstantDecl>(VD); 1048 1049 return false; 1050 } 1051 1052 static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, 1053 const NSAPI &NS, Commit &commit) { 1054 if (Msg->getNumArgs() != 1) 1055 return false; 1056 1057 const Expr *Arg = Msg->getArg(0); 1058 if (Arg->isTypeDependent()) 1059 return false; 1060 1061 ASTContext &Ctx = NS.getASTContext(); 1062 Selector Sel = Msg->getSelector(); 1063 Optional<NSAPI::NSNumberLiteralMethodKind> 1064 MKOpt = NS.getNSNumberLiteralMethodKind(Sel); 1065 if (!MKOpt) 1066 return false; 1067 NSAPI::NSNumberLiteralMethodKind MK = *MKOpt; 1068 1069 const Expr *OrigArg = Arg->IgnoreImpCasts(); 1070 QualType FinalTy = Arg->getType(); 1071 QualType OrigTy = OrigArg->getType(); 1072 uint64_t FinalTySize = Ctx.getTypeSize(FinalTy); 1073 uint64_t OrigTySize = Ctx.getTypeSize(OrigTy); 1074 1075 bool isTruncated = FinalTySize < OrigTySize; 1076 bool needsCast = false; 1077 1078 if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { 1079 switch (ICE->getCastKind()) { 1080 case CK_LValueToRValue: 1081 case CK_NoOp: 1082 case CK_UserDefinedConversion: 1083 break; 1084 1085 case CK_IntegralCast: { 1086 if (MK == NSAPI::NSNumberWithBool && OrigTy->isBooleanType()) 1087 break; 1088 // Be more liberal with Integer/UnsignedInteger which are very commonly 1089 // used. 1090 if ((MK == NSAPI::NSNumberWithInteger || 1091 MK == NSAPI::NSNumberWithUnsignedInteger) && 1092 !isTruncated) { 1093 if (OrigTy->getAs<EnumType>() || isEnumConstant(OrigArg)) 1094 break; 1095 if ((MK==NSAPI::NSNumberWithInteger) == OrigTy->isSignedIntegerType() && 1096 OrigTySize >= Ctx.getTypeSize(Ctx.IntTy)) 1097 break; 1098 } 1099 1100 needsCast = true; 1101 break; 1102 } 1103 1104 case CK_PointerToBoolean: 1105 case CK_IntegralToBoolean: 1106 case CK_IntegralToFloating: 1107 case CK_FloatingToIntegral: 1108 case CK_FloatingToBoolean: 1109 case CK_FloatingCast: 1110 case CK_FloatingComplexToReal: 1111 case CK_FloatingComplexToBoolean: 1112 case CK_IntegralComplexToReal: 1113 case CK_IntegralComplexToBoolean: 1114 case CK_AtomicToNonAtomic: 1115 needsCast = true; 1116 break; 1117 1118 case CK_Dependent: 1119 case CK_BitCast: 1120 case CK_LValueBitCast: 1121 case CK_BaseToDerived: 1122 case CK_DerivedToBase: 1123 case CK_UncheckedDerivedToBase: 1124 case CK_Dynamic: 1125 case CK_ToUnion: 1126 case CK_ArrayToPointerDecay: 1127 case CK_FunctionToPointerDecay: 1128 case CK_NullToPointer: 1129 case CK_NullToMemberPointer: 1130 case CK_BaseToDerivedMemberPointer: 1131 case CK_DerivedToBaseMemberPointer: 1132 case CK_MemberPointerToBoolean: 1133 case CK_ReinterpretMemberPointer: 1134 case CK_ConstructorConversion: 1135 case CK_IntegralToPointer: 1136 case CK_PointerToIntegral: 1137 case CK_ToVoid: 1138 case CK_VectorSplat: 1139 case CK_CPointerToObjCPointerCast: 1140 case CK_BlockPointerToObjCPointerCast: 1141 case CK_AnyPointerToBlockPointerCast: 1142 case CK_ObjCObjectLValueCast: 1143 case CK_FloatingRealToComplex: 1144 case CK_FloatingComplexCast: 1145 case CK_FloatingComplexToIntegralComplex: 1146 case CK_IntegralRealToComplex: 1147 case CK_IntegralComplexCast: 1148 case CK_IntegralComplexToFloatingComplex: 1149 case CK_ARCProduceObject: 1150 case CK_ARCConsumeObject: 1151 case CK_ARCReclaimReturnedObject: 1152 case CK_ARCExtendBlockObject: 1153 case CK_NonAtomicToAtomic: 1154 case CK_CopyAndAutoreleaseBlockObject: 1155 case CK_BuiltinFnToFnPtr: 1156 case CK_ZeroToOCLEvent: 1157 return false; 1158 } 1159 } 1160 1161 if (needsCast) { 1162 DiagnosticsEngine &Diags = Ctx.getDiagnostics(); 1163 // FIXME: Use a custom category name to distinguish migration diagnostics. 1164 unsigned diagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning, 1165 "converting to boxing syntax requires casting %0 to %1"); 1166 Diags.Report(Msg->getExprLoc(), diagID) << OrigTy << FinalTy 1167 << Msg->getSourceRange(); 1168 return false; 1169 } 1170 1171 SourceRange ArgRange = OrigArg->getSourceRange(); 1172 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 1173 1174 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg)) 1175 commit.insertBefore(ArgRange.getBegin(), "@"); 1176 else 1177 commit.insertWrap("@(", ArgRange, ")"); 1178 1179 return true; 1180 } 1181 1182 //===----------------------------------------------------------------------===// 1183 // rewriteToStringBoxedExpression. 1184 //===----------------------------------------------------------------------===// 1185 1186 static bool doRewriteToUTF8StringBoxedExpressionHelper( 1187 const ObjCMessageExpr *Msg, 1188 const NSAPI &NS, Commit &commit) { 1189 const Expr *Arg = Msg->getArg(0); 1190 if (Arg->isTypeDependent()) 1191 return false; 1192 1193 ASTContext &Ctx = NS.getASTContext(); 1194 1195 const Expr *OrigArg = Arg->IgnoreImpCasts(); 1196 QualType OrigTy = OrigArg->getType(); 1197 if (OrigTy->isArrayType()) 1198 OrigTy = Ctx.getArrayDecayedType(OrigTy); 1199 1200 if (const StringLiteral * 1201 StrE = dyn_cast<StringLiteral>(OrigArg->IgnoreParens())) { 1202 commit.replaceWithInner(Msg->getSourceRange(), StrE->getSourceRange()); 1203 commit.insert(StrE->getLocStart(), "@"); 1204 return true; 1205 } 1206 1207 if (const PointerType *PT = OrigTy->getAs<PointerType>()) { 1208 QualType PointeeType = PT->getPointeeType(); 1209 if (Ctx.hasSameUnqualifiedType(PointeeType, Ctx.CharTy)) { 1210 SourceRange ArgRange = OrigArg->getSourceRange(); 1211 commit.replaceWithInner(Msg->getSourceRange(), ArgRange); 1212 1213 if (isa<ParenExpr>(OrigArg) || isa<IntegerLiteral>(OrigArg)) 1214 commit.insertBefore(ArgRange.getBegin(), "@"); 1215 else 1216 commit.insertWrap("@(", ArgRange, ")"); 1217 1218 return true; 1219 } 1220 } 1221 1222 return false; 1223 } 1224 1225 static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg, 1226 const NSAPI &NS, Commit &commit) { 1227 Selector Sel = Msg->getSelector(); 1228 1229 if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithUTF8String) || 1230 Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCString)) { 1231 if (Msg->getNumArgs() != 1) 1232 return false; 1233 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit); 1234 } 1235 1236 if (Sel == NS.getNSStringSelector(NSAPI::NSStr_stringWithCStringEncoding)) { 1237 if (Msg->getNumArgs() != 2) 1238 return false; 1239 1240 const Expr *encodingArg = Msg->getArg(1); 1241 if (NS.isNSUTF8StringEncodingConstant(encodingArg) || 1242 NS.isNSASCIIStringEncodingConstant(encodingArg)) 1243 return doRewriteToUTF8StringBoxedExpressionHelper(Msg, NS, commit); 1244 } 1245 1246 return false; 1247 } 1248