Transforms.cpp revision 7acddacc921cd0b3f813443a8641eeddb82dfbd4
1//===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===// 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// Transformations: 10//===----------------------------------------------------------------------===// 11// 12// castNonObjCToObjC: 13// 14// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer 15// is from a file-level variable, objc_unretainedObject function is used to 16// convert it. 17// 18// NSString *str = (NSString *)kUTTypePlainText; 19// str = b ? kUTTypeRTF : kUTTypePlainText; 20// ----> 21// NSString *str = objc_unretainedObject(kUTTypePlainText); 22// str = objc_unretainedObject(b ? kUTTypeRTF : kUTTypePlainText); 23// 24// For a C pointer to ObjC, objc_unretainedPointer is used. 25// 26// void *vp = str; // NSString* 27// ----> 28// void *vp = (void*)objc_unretainedPointer(str); 29// 30//===----------------------------------------------------------------------===// 31// 32// rewriteAllocCopyWithZone: 33// 34// Calls to +allocWithZone/-copyWithZone/-mutableCopyWithZone are changed to 35// +alloc/-copy/-mutableCopy if we can safely remove the given parameter. 36// 37// Foo *foo1 = [[Foo allocWithZone:[self zone]] init]; 38// ----> 39// Foo *foo1 = [[Foo alloc] init]; 40// 41//===----------------------------------------------------------------------===// 42// 43// rewriteAutoreleasePool: 44// 45// Calls to NSAutoreleasePools will be rewritten as an @autorelease scope. 46// 47// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 48// ... 49// [pool release]; 50// ----> 51// @autorelease { 52// ... 53// } 54// 55// An NSAutoreleasePool will not be touched if: 56// - There is not a corresponding -release/-drain in the same scope 57// - Not all references of the NSAutoreleasePool variable can be removed 58// - There is a variable that is declared inside the intended @autorelease scope 59// which is also used outside it. 60// 61//===----------------------------------------------------------------------===// 62// 63// makeAssignARCSafe: 64// 65// Add '__strong' where appropriate. 66// 67// for (id x in collection) { 68// x = 0; 69// } 70// ----> 71// for (__strong id x in collection) { 72// x = 0; 73// } 74// 75//===----------------------------------------------------------------------===// 76// 77// removeRetainReleaseDealloc: 78// 79// Removes retain/release/autorelease/dealloc messages. 80// 81// return [[foo retain] autorelease]; 82// ----> 83// return foo; 84// 85//===----------------------------------------------------------------------===// 86// 87// removeEmptyStatements: 88// 89// Removes empty statements that are leftovers from previous transformations. 90// e.g for 91// 92// [x retain]; 93// 94// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements 95// will remove. 96// 97//===----------------------------------------------------------------------===// 98// 99// changeIvarsOfAssignProperties: 100// 101// If a property is synthesized with 'assign' attribute and the user didn't 102// set a lifetime attribute, change the property to 'weak' or add 103// __unsafe_unretained if the ARC runtime is not available. 104// 105// @interface Foo : NSObject { 106// NSObject *x; 107// } 108// @property (assign) id x; 109// @end 110// ----> 111// @interface Foo : NSObject { 112// NSObject *__weak x; 113// } 114// @property (weak) id x; 115// @end 116// 117//===----------------------------------------------------------------------===// 118// 119// rewriteUnusedDelegateInit: 120// 121// Rewrites an unused result of calling a delegate initialization, to assigning 122// the result to self. 123// e.g 124// [self init]; 125// ----> 126// self = [self init]; 127// 128//===----------------------------------------------------------------------===// 129// 130// rewriteBlockObjCVariable: 131// 132// Adding __block to an obj-c variable could be either because the the variable 133// is used for output storage or the user wanted to break a retain cycle. 134// This transformation checks whether a reference of the variable for the block 135// is actually needed (it is assigned to or its address is taken) or not. 136// If the reference is not needed it will assume __block was added to break a 137// cycle so it will remove '__block' and add __weak/__unsafe_unretained. 138// e.g 139// 140// __block Foo *x; 141// bar(^ { [x cake]; }); 142// ----> 143// __weak Foo *x; 144// bar(^ { [x cake]; }); 145// 146//===----------------------------------------------------------------------===// 147// 148// removeZeroOutIvarsInDealloc: 149// 150// Removes zero'ing out "strong" @synthesized properties in a -dealloc method. 151// 152//===----------------------------------------------------------------------===// 153 154#include "Internals.h" 155#include "clang/Sema/SemaDiagnostic.h" 156#include "clang/AST/RecursiveASTVisitor.h" 157#include "clang/AST/StmtVisitor.h" 158#include "clang/AST/ParentMap.h" 159#include "clang/Analysis/DomainSpecific/CocoaConventions.h" 160#include "clang/Lex/Lexer.h" 161#include "clang/Basic/SourceManager.h" 162#include "llvm/ADT/StringSwitch.h" 163#include "llvm/ADT/DenseSet.h" 164#include <map> 165 166using namespace clang; 167using namespace arcmt; 168using llvm::StringRef; 169 170//===----------------------------------------------------------------------===// 171// Transformations. 172//===----------------------------------------------------------------------===// 173 174namespace { 175 176class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> { 177 llvm::DenseSet<Expr *> &Removables; 178 179public: 180 RemovablesCollector(llvm::DenseSet<Expr *> &removables) 181 : Removables(removables) { } 182 183 bool shouldWalkTypesOfTypeLocs() const { return false; } 184 185 bool TraverseStmtExpr(StmtExpr *E) { 186 CompoundStmt *S = E->getSubStmt(); 187 for (CompoundStmt::body_iterator 188 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 189 if (I != E - 1) 190 mark(*I); 191 TraverseStmt(*I); 192 } 193 return true; 194 } 195 196 bool VisitCompoundStmt(CompoundStmt *S) { 197 for (CompoundStmt::body_iterator 198 I = S->body_begin(), E = S->body_end(); I != E; ++I) 199 mark(*I); 200 return true; 201 } 202 203 bool VisitIfStmt(IfStmt *S) { 204 mark(S->getThen()); 205 mark(S->getElse()); 206 return true; 207 } 208 209 bool VisitWhileStmt(WhileStmt *S) { 210 mark(S->getBody()); 211 return true; 212 } 213 214 bool VisitDoStmt(DoStmt *S) { 215 mark(S->getBody()); 216 return true; 217 } 218 219 bool VisitForStmt(ForStmt *S) { 220 mark(S->getInit()); 221 mark(S->getInc()); 222 mark(S->getBody()); 223 return true; 224 } 225 226private: 227 void mark(Stmt *S) { 228 if (!S) return; 229 230 if (LabelStmt *Label = dyn_cast<LabelStmt>(S)) 231 return mark(Label->getSubStmt()); 232 if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(S)) 233 return mark(CE->getSubExpr()); 234 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) 235 return mark(EWC->getSubExpr()); 236 if (Expr *E = dyn_cast<Expr>(S)) 237 Removables.insert(E); 238 } 239}; 240 241} // end anonymous namespace. 242 243static bool HasSideEffects(Expr *E, ASTContext &Ctx) { 244 if (!E || !E->HasSideEffects(Ctx)) 245 return false; 246 247 E = E->IgnoreParenCasts(); 248 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 249 if (!ME) 250 return true; 251 switch (ME->getMethodFamily()) { 252 case OMF_autorelease: 253 case OMF_dealloc: 254 case OMF_release: 255 case OMF_retain: 256 switch (ME->getReceiverKind()) { 257 case ObjCMessageExpr::SuperInstance: 258 return false; 259 case ObjCMessageExpr::Instance: 260 return HasSideEffects(ME->getInstanceReceiver(), Ctx); 261 default: 262 break; 263 } 264 break; 265 default: 266 break; 267 } 268 269 return true; 270} 271 272static void removeDeallocMethod(MigrationPass &pass) { 273 ASTContext &Ctx = pass.Ctx; 274 TransformActions &TA = pass.TA; 275 DeclContext *DC = Ctx.getTranslationUnitDecl(); 276 ObjCMethodDecl *DeallocMethodDecl = 0; 277 IdentifierInfo *II = &Ctx.Idents.get("dealloc"); 278 279 for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end(); 280 I != E; ++I) { 281 Decl *D = *I; 282 if (ObjCImplementationDecl *IMD = 283 dyn_cast<ObjCImplementationDecl>(D)) { 284 DeallocMethodDecl = 0; 285 for (ObjCImplementationDecl::instmeth_iterator I = 286 IMD->instmeth_begin(), E = IMD->instmeth_end(); 287 I != E; ++I) { 288 ObjCMethodDecl *OMD = *I; 289 if (OMD->isInstanceMethod() && 290 OMD->getSelector() == Ctx.Selectors.getSelector(0, &II)) { 291 DeallocMethodDecl = OMD; 292 break; 293 } 294 } 295 if (DeallocMethodDecl && 296 DeallocMethodDecl->getCompoundBody()->body_empty()) { 297 Transaction Trans(TA); 298 TA.remove(DeallocMethodDecl->getSourceRange()); 299 } 300 } 301 } 302} 303 304namespace { 305 306class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> { 307 llvm::DenseSet<Expr *> &Refs; 308public: 309 ReferenceClear(llvm::DenseSet<Expr *> &refs) : Refs(refs) { } 310 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; } 311 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; } 312 void clearRefsIn(Stmt *S) { TraverseStmt(S); } 313 template <typename iterator> 314 void clearRefsIn(iterator begin, iterator end) { 315 for (; begin != end; ++begin) 316 TraverseStmt(*begin); 317 } 318}; 319 320class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> { 321 ValueDecl *Dcl; 322 llvm::DenseSet<Expr *> &Refs; 323 324public: 325 ReferenceCollector(llvm::DenseSet<Expr *> &refs) 326 : Dcl(0), Refs(refs) { } 327 328 void lookFor(ValueDecl *D, Stmt *S) { 329 Dcl = D; 330 TraverseStmt(S); 331 } 332 333 bool VisitDeclRefExpr(DeclRefExpr *E) { 334 if (E->getDecl() == Dcl) 335 Refs.insert(E); 336 return true; 337 } 338 339 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 340 if (E->getDecl() == Dcl) 341 Refs.insert(E); 342 return true; 343 } 344}; 345 346class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> { 347 Decl *Dcl; 348 llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases; 349 350public: 351 ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases) 352 : Dcl(D), Releases(releases) { } 353 354 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 355 if (!E->isInstanceMessage()) 356 return true; 357 if (E->getMethodFamily() != OMF_release) 358 return true; 359 Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts(); 360 if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) { 361 if (DE->getDecl() == Dcl) 362 Releases.push_back(E); 363 } 364 return true; 365 } 366}; 367 368template <typename BODY_TRANS> 369class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > { 370 MigrationPass &Pass; 371 372public: 373 BodyTransform(MigrationPass &pass) : Pass(pass) { } 374 375 void handleBody(Decl *D) { 376 Stmt *body = D->getBody(); 377 if (body) { 378 BODY_TRANS(D, Pass).transformBody(body); 379 } 380 } 381 382 bool TraverseBlockDecl(BlockDecl *D) { 383 handleBody(D); 384 return true; 385 } 386 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { 387 if (D->isThisDeclarationADefinition()) 388 handleBody(D); 389 return true; 390 } 391 bool TraverseFunctionDecl(FunctionDecl *D) { 392 if (D->isThisDeclarationADefinition()) 393 handleBody(D); 394 return true; 395 } 396}; 397 398} // anonymous namespace 399 400//===----------------------------------------------------------------------===// 401// makeAssignARCSafe 402//===----------------------------------------------------------------------===// 403 404namespace { 405 406class ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> { 407 MigrationPass &Pass; 408 llvm::DenseSet<VarDecl *> ModifiedVars; 409 410public: 411 ARCAssignChecker(MigrationPass &pass) : Pass(pass) { } 412 413 bool VisitBinaryOperator(BinaryOperator *Exp) { 414 Expr *E = Exp->getLHS(); 415 SourceLocation OrigLoc = E->getExprLoc(); 416 SourceLocation Loc = OrigLoc; 417 DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()); 418 if (declRef && isa<VarDecl>(declRef->getDecl())) { 419 ASTContext &Ctx = Pass.Ctx; 420 Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc); 421 if (IsLV != Expr::MLV_ConstQualified) 422 return true; 423 VarDecl *var = cast<VarDecl>(declRef->getDecl()); 424 if (var->isARCPseudoStrong()) { 425 Transaction Trans(Pass.TA); 426 if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration, 427 Exp->getOperatorLoc())) { 428 if (!ModifiedVars.count(var)) { 429 TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc(); 430 Pass.TA.insert(TLoc.getBeginLoc(), "__strong "); 431 ModifiedVars.insert(var); 432 } 433 } 434 } 435 } 436 437 return true; 438 } 439}; 440 441} // anonymous namespace 442 443static void makeAssignARCSafe(MigrationPass &pass) { 444 ARCAssignChecker assignCheck(pass); 445 assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 446} 447 448//===----------------------------------------------------------------------===// 449// castNonObjCToObjC 450//===----------------------------------------------------------------------===// 451 452namespace { 453 454class NonObjCToObjCCaster : public RecursiveASTVisitor<NonObjCToObjCCaster> { 455 MigrationPass &Pass; 456public: 457 NonObjCToObjCCaster(MigrationPass &pass) : Pass(pass) { } 458 459 bool VisitCastExpr(CastExpr *E) { 460 if (E->getCastKind() != CK_AnyPointerToObjCPointerCast 461 && E->getCastKind() != CK_BitCast) 462 return true; 463 464 QualType castType = E->getType(); 465 Expr *castExpr = E->getSubExpr(); 466 QualType castExprType = castExpr->getType(); 467 468 if (castType->isObjCObjectPointerType() && 469 castExprType->isObjCObjectPointerType()) 470 return true; 471 if (!castType->isObjCObjectPointerType() && 472 !castExprType->isObjCObjectPointerType()) 473 return true; 474 475 bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); 476 bool castRetainable = castType->isObjCIndirectLifetimeType(); 477 if (exprRetainable == castRetainable) return true; 478 479 if (castExpr->isNullPointerConstant(Pass.Ctx, 480 Expr::NPC_ValueDependentIsNull)) 481 return true; 482 483 SourceLocation loc = castExpr->getExprLoc(); 484 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc)) 485 return true; 486 487 if (castType->isObjCObjectPointerType()) 488 transformNonObjCToObjCCast(E); 489 else 490 transformObjCToNonObjCCast(E); 491 492 return true; 493 } 494 495private: 496 void transformNonObjCToObjCCast(CastExpr *E) { 497 if (!E) return; 498 499 // Global vars are assumed that are cast as unretained. 500 if (isGlobalVar(E)) 501 if (E->getSubExpr()->getType()->isPointerType()) { 502 castToObjCObject(E, /*retained=*/false); 503 return; 504 } 505 506 // If the cast is directly over the result of a Core Foundation function 507 // try to figure out whether it should be cast as retained or unretained. 508 Expr *inner = E->IgnoreParenCasts(); 509 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) { 510 if (FunctionDecl *FD = callE->getDirectCallee()) { 511 if (FD->getAttr<CFReturnsRetainedAttr>()) { 512 castToObjCObject(E, /*retained=*/true); 513 return; 514 } 515 if (FD->getAttr<CFReturnsNotRetainedAttr>()) { 516 castToObjCObject(E, /*retained=*/false); 517 return; 518 } 519 if (FD->isGlobal() && 520 FD->getIdentifier() && 521 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", 522 FD->getIdentifier()->getName())) { 523 StringRef fname = FD->getIdentifier()->getName(); 524 if (fname.endswith("Retain") || 525 fname.find("Create") != StringRef::npos || 526 fname.find("Copy") != StringRef::npos) { 527 castToObjCObject(E, /*retained=*/true); 528 return; 529 } 530 531 if (fname.find("Get") != StringRef::npos) { 532 castToObjCObject(E, /*retained=*/false); 533 return; 534 } 535 } 536 } 537 } 538 } 539 540 void castToObjCObject(CastExpr *E, bool retained) { 541 TransformActions &TA = Pass.TA; 542 543 // We will remove the compiler diagnostic. 544 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, 545 diag::err_arc_cast_requires_bridge, 546 E->getLocStart())) 547 return; 548 549 Transaction Trans(TA); 550 TA.clearDiagnostic(diag::err_arc_mismatched_cast, 551 diag::err_arc_cast_requires_bridge, 552 E->getLocStart()); 553 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) { 554 TA.insertAfterToken(CCE->getLParenLoc(), retained ? "__bridge_transfer " 555 : "__bridge "); 556 } else { 557 SourceLocation insertLoc = E->getSubExpr()->getLocStart(); 558 llvm::SmallString<128> newCast; 559 newCast += '('; 560 newCast += retained ? "__bridge_transfer " : "__bridge "; 561 newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy); 562 newCast += ')'; 563 564 if (isa<ParenExpr>(E->getSubExpr())) { 565 TA.insert(insertLoc, newCast.str()); 566 } else { 567 newCast += '('; 568 TA.insert(insertLoc, newCast.str()); 569 TA.insertAfterToken(E->getLocEnd(), ")"); 570 } 571 } 572 } 573 574 void transformObjCToNonObjCCast(CastExpr *E) { 575 // FIXME: Handle these casts. 576 return; 577#if 0 578 TransformActions &TA = Pass.TA; 579 580 // We will remove the compiler diagnostic. 581 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, 582 diag::err_arc_cast_requires_bridge, 583 E->getLocStart())) 584 return; 585 586 Transaction Trans(TA); 587 TA.clearDiagnostic(diag::err_arc_mismatched_cast, 588 diag::err_arc_cast_requires_bridge, 589 E->getLocStart()); 590 591 assert(!E->getType()->isObjCObjectPointerType()); 592 593 bool shouldCast = !isa<CStyleCastExpr>(E) && 594 !E->getType()->getPointeeType().isConstQualified(); 595 SourceLocation loc = E->getSubExpr()->getLocStart(); 596 if (isa<ParenExpr>(E->getSubExpr())) { 597 TA.insert(loc, shouldCast ? "(void*)objc_unretainedPointer" 598 : "objc_unretainedPointer"); 599 } else { 600 TA.insert(loc, shouldCast ? "(void*)objc_unretainedPointer(" 601 : "objc_unretainedPointer("); 602 TA.insertAfterToken(E->getLocEnd(), ")"); 603 } 604#endif 605 } 606 607 static bool isGlobalVar(Expr *E) { 608 E = E->IgnoreParenCasts(); 609 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) 610 return DRE->getDecl()->getDeclContext()->isFileContext(); 611 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E)) 612 return isGlobalVar(condOp->getTrueExpr()) && 613 isGlobalVar(condOp->getFalseExpr()); 614 615 return false; 616 } 617}; 618 619} // end anonymous namespace 620 621static void castNonObjCToObjC(MigrationPass &pass) { 622 NonObjCToObjCCaster trans(pass); 623 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 624} 625 626//===----------------------------------------------------------------------===// 627// rewriteAllocCopyWithZone 628//===----------------------------------------------------------------------===// 629 630namespace { 631 632class AllocCopyWithZoneRewriter : 633 public RecursiveASTVisitor<AllocCopyWithZoneRewriter> { 634 Decl *Dcl; 635 Stmt *Body; 636 MigrationPass &Pass; 637 638 Selector allocWithZoneSel; 639 Selector copyWithZoneSel; 640 Selector mutableCopyWithZoneSel; 641 Selector zoneSel; 642 IdentifierInfo *NSZoneII; 643 644 std::vector<DeclStmt *> NSZoneVars; 645 std::vector<Expr *> Removals; 646 647public: 648 AllocCopyWithZoneRewriter(Decl *D, MigrationPass &pass) 649 : Dcl(D), Body(0), Pass(pass) { 650 SelectorTable &sels = pass.Ctx.Selectors; 651 IdentifierTable &ids = pass.Ctx.Idents; 652 allocWithZoneSel = sels.getUnarySelector(&ids.get("allocWithZone")); 653 copyWithZoneSel = sels.getUnarySelector(&ids.get("copyWithZone")); 654 mutableCopyWithZoneSel = sels.getUnarySelector( 655 &ids.get("mutableCopyWithZone")); 656 zoneSel = sels.getNullarySelector(&ids.get("zone")); 657 NSZoneII = &ids.get("_NSZone"); 658 } 659 660 void transformBody(Stmt *body) { 661 Body = body; 662 // Don't change allocWithZone/copyWithZone messages inside 663 // custom implementations of such methods, it can lead to infinite loops. 664 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Dcl)) { 665 Selector sel = MD->getSelector(); 666 if (sel == allocWithZoneSel || 667 sel == copyWithZoneSel || 668 sel == mutableCopyWithZoneSel || 669 sel == zoneSel) 670 return; 671 } 672 673 TraverseStmt(body); 674 } 675 676 ~AllocCopyWithZoneRewriter() { 677 for (std::vector<DeclStmt *>::reverse_iterator 678 I = NSZoneVars.rbegin(), E = NSZoneVars.rend(); I != E; ++I) { 679 DeclStmt *DS = *I; 680 DeclGroupRef group = DS->getDeclGroup(); 681 std::vector<Expr *> varRemovals = Removals; 682 683 bool areAllVarsUnused = true; 684 for (std::reverse_iterator<DeclGroupRef::iterator> 685 DI(group.end()), DE(group.begin()); DI != DE; ++DI) { 686 VarDecl *VD = cast<VarDecl>(*DI); 687 if (isNSZoneVarUsed(VD, varRemovals)) { 688 areAllVarsUnused = false; 689 break; 690 } 691 varRemovals.push_back(VD->getInit()); 692 } 693 694 if (areAllVarsUnused) { 695 Transaction Trans(Pass.TA); 696 clearUnavailableDiags(DS); 697 Pass.TA.removeStmt(DS); 698 Removals.swap(varRemovals); 699 } 700 } 701 } 702 703 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 704 if (!isAllocCopyWithZoneCall(E)) 705 return true; 706 Expr *arg = E->getArg(0); 707 if (paramToAllocWithZoneHasSideEffects(arg)) 708 return true; 709 710 Pass.TA.startTransaction(); 711 712 clearUnavailableDiags(arg); 713 Pass.TA.clearDiagnostic(diag::err_unavailable_message, 714 E->getReceiverRange().getBegin()); 715 716 Pass.TA.remove(SourceRange(E->getSelectorLoc(), arg->getLocEnd())); 717 StringRef rewrite; 718 if (E->getSelector() == allocWithZoneSel) 719 rewrite = "alloc"; 720 else if (E->getSelector() == copyWithZoneSel) 721 rewrite = "copy"; 722 else { 723 assert(E->getSelector() == mutableCopyWithZoneSel); 724 rewrite = "mutableCopy"; 725 } 726 Pass.TA.insert(E->getSelectorLoc(), rewrite); 727 728 bool failed = Pass.TA.commitTransaction(); 729 if (!failed) 730 Removals.push_back(arg); 731 732 return true; 733 } 734 735 bool VisitDeclStmt(DeclStmt *DS) { 736 DeclGroupRef group = DS->getDeclGroup(); 737 if (group.begin() == group.end()) 738 return true; 739 for (DeclGroupRef::iterator 740 DI = group.begin(), DE = group.end(); DI != DE; ++DI) 741 if (!isRemovableNSZoneVar(*DI)) 742 return true; 743 744 NSZoneVars.push_back(DS); 745 return true; 746 } 747 748private: 749 bool isRemovableNSZoneVar(Decl *D) { 750 if (VarDecl *VD = dyn_cast<VarDecl>(D)) { 751 if (isNSZone(VD->getType())) 752 return !paramToAllocWithZoneHasSideEffects(VD->getInit()); 753 } 754 return false; 755 } 756 757 bool isNSZone(RecordDecl *RD) { 758 return RD && RD->getIdentifier() == NSZoneII; 759 } 760 761 bool isNSZone(QualType Ty) { 762 QualType pointee = Ty->getPointeeType(); 763 if (pointee.isNull()) 764 return false; 765 if (const RecordType *recT = pointee->getAsStructureType()) 766 return isNSZone(recT->getDecl()); 767 return false; 768 } 769 770 bool isNSZoneVarUsed(VarDecl *D, std::vector<Expr *> &removals) { 771 llvm::DenseSet<Expr *> refs; 772 773 ReferenceCollector refColl(refs); 774 refColl.lookFor(D, Body); 775 776 ReferenceClear refClear(refs); 777 refClear.clearRefsIn(removals.begin(), removals.end()); 778 779 return !refs.empty(); 780 } 781 782 bool isAllocCopyWithZoneCall(ObjCMessageExpr *E) { 783 if (E->getNumArgs() == 1 && 784 E->getSelector() == allocWithZoneSel && 785 (E->isClassMessage() || 786 Pass.TA.hasDiagnostic(diag::err_unavailable_message, 787 E->getReceiverRange().getBegin()))) 788 return true; 789 790 return E->isInstanceMessage() && 791 E->getNumArgs() == 1 && 792 (E->getSelector() == copyWithZoneSel || 793 E->getSelector() == mutableCopyWithZoneSel); 794 } 795 796 bool isZoneCall(ObjCMessageExpr *E) { 797 return E->isInstanceMessage() && 798 E->getNumArgs() == 0 && 799 E->getSelector() == zoneSel; 800 } 801 802 bool paramToAllocWithZoneHasSideEffects(Expr *E) { 803 if (!HasSideEffects(E, Pass.Ctx)) 804 return false; 805 E = E->IgnoreParenCasts(); 806 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 807 if (!ME) 808 return true; 809 if (!isZoneCall(ME)) 810 return true; 811 return HasSideEffects(ME->getInstanceReceiver(), Pass.Ctx); 812 } 813 814 void clearUnavailableDiags(Stmt *S) { 815 if (S) 816 Pass.TA.clearDiagnostic(diag::err_unavailable, 817 diag::err_unavailable_message, 818 S->getSourceRange()); 819 } 820}; 821 822} // end anonymous namespace 823 824static void rewriteAllocCopyWithZone(MigrationPass &pass) { 825 BodyTransform<AllocCopyWithZoneRewriter> trans(pass); 826 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 827} 828 829//===----------------------------------------------------------------------===// 830// rewriteAutoreleasePool 831//===----------------------------------------------------------------------===// 832 833/// \brief 'Loc' is the end of a statement range. This returns the location 834/// immediately after the semicolon following the statement. 835/// If no semicolon is found or the location is inside a macro, the returned 836/// source location will be invalid. 837static SourceLocation findLocationAfterSemi(ASTContext &Ctx, 838 SourceLocation loc) { 839 SourceManager &SM = Ctx.getSourceManager(); 840 if (loc.isMacroID()) { 841 if (!SM.isAtEndOfMacroInstantiation(loc)) 842 return SourceLocation(); 843 loc = SM.getInstantiationRange(loc).second; 844 } 845 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions()); 846 847 // Break down the source location. 848 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 849 850 // Try to load the file buffer. 851 bool invalidTemp = false; 852 llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 853 if (invalidTemp) 854 return SourceLocation(); 855 856 const char *tokenBegin = file.data() + locInfo.second; 857 858 // Lex from the start of the given location. 859 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 860 Ctx.getLangOptions(), 861 file.begin(), tokenBegin, file.end()); 862 Token tok; 863 lexer.LexFromRawLexer(tok); 864 if (tok.isNot(tok::semi)) 865 return SourceLocation(); 866 867 return tok.getLocation().getFileLocWithOffset(1); 868} 869 870namespace { 871 872class AutoreleasePoolRewriter 873 : public RecursiveASTVisitor<AutoreleasePoolRewriter> { 874public: 875 AutoreleasePoolRewriter(Decl *D, MigrationPass &pass) 876 : Dcl(D), Body(0), Pass(pass) { 877 PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool"); 878 DrainSel = pass.Ctx.Selectors.getNullarySelector( 879 &pass.Ctx.Idents.get("drain")); 880 } 881 882 void transformBody(Stmt *body) { 883 Body = body; 884 TraverseStmt(body); 885 } 886 887 ~AutoreleasePoolRewriter() { 888 llvm::SmallVector<VarDecl *, 8> VarsToHandle; 889 890 for (std::map<VarDecl *, PoolVarInfo>::iterator 891 I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) { 892 VarDecl *var = I->first; 893 PoolVarInfo &info = I->second; 894 895 // Check that we can handle/rewrite all references of the pool. 896 897 ReferenceClear refClear(info.Refs); 898 refClear.clearRefsIn(info.Dcl); 899 for (llvm::SmallVectorImpl<PoolScope>::iterator 900 scpI = info.Scopes.begin(), 901 scpE = info.Scopes.end(); scpI != scpE; ++scpI) { 902 PoolScope &scope = *scpI; 903 refClear.clearRefsIn(*scope.Begin); 904 refClear.clearRefsIn(*scope.End); 905 refClear.clearRefsIn(scope.Releases.begin(), scope.Releases.end()); 906 } 907 908 // Even if one reference is not handled we will not do anything about that 909 // pool variable. 910 if (info.Refs.empty()) 911 VarsToHandle.push_back(var); 912 } 913 914 for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) { 915 PoolVarInfo &info = PoolVars[VarsToHandle[i]]; 916 917 Transaction Trans(Pass.TA); 918 919 clearUnavailableDiags(info.Dcl); 920 Pass.TA.removeStmt(info.Dcl); 921 922 // Add "@autoreleasepool { }" 923 for (llvm::SmallVectorImpl<PoolScope>::iterator 924 scpI = info.Scopes.begin(), 925 scpE = info.Scopes.end(); scpI != scpE; ++scpI) { 926 PoolScope &scope = *scpI; 927 clearUnavailableDiags(*scope.Begin); 928 clearUnavailableDiags(*scope.End); 929 if (scope.IsFollowedBySimpleReturnStmt) { 930 // Include the return in the scope. 931 Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {"); 932 Pass.TA.removeStmt(*scope.End); 933 Stmt::child_iterator retI = scope.End; 934 ++retI; 935 SourceLocation afterSemi = findLocationAfterSemi(Pass.Ctx, 936 (*retI)->getLocEnd()); 937 assert(afterSemi.isValid() && 938 "Didn't we check before setting IsFollowedBySimpleReturnStmt " 939 "to true?"); 940 Pass.TA.insertAfterToken(afterSemi, "\n}"); 941 Pass.TA.increaseIndentation( 942 SourceRange(scope.getIndentedRange().getBegin(), 943 (*retI)->getLocEnd()), 944 scope.CompoundParent->getLocStart()); 945 } else { 946 Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {"); 947 Pass.TA.replaceStmt(*scope.End, "}"); 948 Pass.TA.increaseIndentation(scope.getIndentedRange(), 949 scope.CompoundParent->getLocStart()); 950 } 951 } 952 953 // Remove rest of pool var references. 954 for (llvm::SmallVectorImpl<PoolScope>::iterator 955 scpI = info.Scopes.begin(), 956 scpE = info.Scopes.end(); scpI != scpE; ++scpI) { 957 PoolScope &scope = *scpI; 958 for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator 959 relI = scope.Releases.begin(), 960 relE = scope.Releases.end(); relI != relE; ++relI) { 961 clearUnavailableDiags(*relI); 962 Pass.TA.removeStmt(*relI); 963 } 964 } 965 } 966 } 967 968 bool VisitCompoundStmt(CompoundStmt *S) { 969 llvm::SmallVector<PoolScope, 4> Scopes; 970 971 for (Stmt::child_iterator 972 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 973 Stmt *child = getEssential(*I); 974 if (DeclStmt *DclS = dyn_cast<DeclStmt>(child)) { 975 if (DclS->isSingleDecl()) { 976 if (VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) { 977 if (isNSAutoreleasePool(VD->getType())) { 978 PoolVarInfo &info = PoolVars[VD]; 979 info.Dcl = DclS; 980 ReferenceCollector refColl(info.Refs); 981 refColl.lookFor(VD, S); 982 // Does this statement follow the pattern: 983 // NSAutoreleasePool * pool = [NSAutoreleasePool new]; 984 if (isPoolCreation(VD->getInit())) { 985 Scopes.push_back(PoolScope()); 986 Scopes.back().PoolVar = VD; 987 Scopes.back().CompoundParent = S; 988 Scopes.back().Begin = I; 989 } 990 } 991 } 992 } 993 } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) { 994 if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) { 995 if (VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) { 996 // Does this statement follow the pattern: 997 // pool = [NSAutoreleasePool new]; 998 if (isNSAutoreleasePool(VD->getType()) && 999 isPoolCreation(bop->getRHS())) { 1000 Scopes.push_back(PoolScope()); 1001 Scopes.back().PoolVar = VD; 1002 Scopes.back().CompoundParent = S; 1003 Scopes.back().Begin = I; 1004 } 1005 } 1006 } 1007 } 1008 1009 if (Scopes.empty()) 1010 continue; 1011 1012 if (isPoolDrain(Scopes.back().PoolVar, child)) { 1013 PoolScope &scope = Scopes.back(); 1014 scope.End = I; 1015 handlePoolScope(scope, S); 1016 Scopes.pop_back(); 1017 } 1018 } 1019 return true; 1020 } 1021 1022private: 1023 void clearUnavailableDiags(Stmt *S) { 1024 if (S) 1025 Pass.TA.clearDiagnostic(diag::err_unavailable, 1026 diag::err_unavailable_message, 1027 S->getSourceRange()); 1028 } 1029 1030 struct PoolScope { 1031 VarDecl *PoolVar; 1032 CompoundStmt *CompoundParent; 1033 Stmt::child_iterator Begin; 1034 Stmt::child_iterator End; 1035 bool IsFollowedBySimpleReturnStmt; 1036 llvm::SmallVector<ObjCMessageExpr *, 4> Releases; 1037 1038 PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(), 1039 IsFollowedBySimpleReturnStmt(false) { } 1040 1041 SourceRange getIndentedRange() const { 1042 Stmt::child_iterator rangeS = Begin; 1043 ++rangeS; 1044 if (rangeS == End) 1045 return SourceRange(); 1046 Stmt::child_iterator rangeE = Begin; 1047 for (Stmt::child_iterator I = rangeS; I != End; ++I) 1048 ++rangeE; 1049 return SourceRange((*rangeS)->getLocStart(), (*rangeE)->getLocEnd()); 1050 } 1051 }; 1052 1053 class NameReferenceChecker : public RecursiveASTVisitor<NameReferenceChecker>{ 1054 ASTContext &Ctx; 1055 SourceRange ScopeRange; 1056 SourceLocation &referenceLoc, &declarationLoc; 1057 1058 public: 1059 NameReferenceChecker(ASTContext &ctx, PoolScope &scope, 1060 SourceLocation &referenceLoc, 1061 SourceLocation &declarationLoc) 1062 : Ctx(ctx), referenceLoc(referenceLoc), 1063 declarationLoc(declarationLoc) { 1064 ScopeRange = SourceRange((*scope.Begin)->getLocStart(), 1065 (*scope.End)->getLocStart()); 1066 } 1067 1068 bool VisitDeclRefExpr(DeclRefExpr *E) { 1069 return checkRef(E->getLocation(), E->getDecl()->getLocation()); 1070 } 1071 1072 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 1073 return checkRef(E->getLocation(), E->getDecl()->getLocation()); 1074 } 1075 1076 bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { 1077 return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation()); 1078 } 1079 1080 bool VisitTagTypeLoc(TagTypeLoc TL) { 1081 return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation()); 1082 } 1083 1084 private: 1085 bool checkRef(SourceLocation refLoc, SourceLocation declLoc) { 1086 if (isInScope(declLoc)) { 1087 referenceLoc = refLoc; 1088 declarationLoc = declLoc; 1089 return false; 1090 } 1091 return true; 1092 } 1093 1094 bool isInScope(SourceLocation loc) { 1095 SourceManager &SM = Ctx.getSourceManager(); 1096 if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin())) 1097 return false; 1098 return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd()); 1099 } 1100 }; 1101 1102 void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) { 1103 // Check that all names declared inside the scope are not used 1104 // outside the scope. 1105 { 1106 bool nameUsedOutsideScope = false; 1107 SourceLocation referenceLoc, declarationLoc; 1108 Stmt::child_iterator SI = scope.End, SE = compoundS->body_end(); 1109 ++SI; 1110 // Check if the autoreleasepool scope is followed by a simple return 1111 // statement, in which case we will include the return in the scope. 1112 if (SI != SE) 1113 if (ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI)) 1114 if ((retS->getRetValue() == 0 || 1115 isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) && 1116 findLocationAfterSemi(Pass.Ctx, retS->getLocEnd()).isValid()) { 1117 scope.IsFollowedBySimpleReturnStmt = true; 1118 ++SI; // the return will be included in scope, don't check it. 1119 } 1120 1121 for (; SI != SE; ++SI) { 1122 nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope, 1123 referenceLoc, 1124 declarationLoc).TraverseStmt(*SI); 1125 if (nameUsedOutsideScope) 1126 break; 1127 } 1128 1129 // If not all references were cleared it means some variables/typenames/etc 1130 // declared inside the pool scope are used outside of it. 1131 // We won't try to rewrite the pool. 1132 if (nameUsedOutsideScope) { 1133 Pass.TA.reportError("a name is referenced outside the " 1134 "NSAutoreleasePool scope that it was declared in", referenceLoc); 1135 Pass.TA.reportNote("name declared here", declarationLoc); 1136 Pass.TA.reportNote("intended @autoreleasepool scope begins here", 1137 (*scope.Begin)->getLocStart()); 1138 Pass.TA.reportNote("intended @autoreleasepool scope ends here", 1139 (*scope.End)->getLocStart()); 1140 return; 1141 } 1142 } 1143 1144 // Collect all releases of the pool; they will be removed. 1145 { 1146 ReleaseCollector releaseColl(scope.PoolVar, scope.Releases); 1147 Stmt::child_iterator I = scope.Begin; 1148 ++I; 1149 for (; I != scope.End; ++I) 1150 releaseColl.TraverseStmt(*I); 1151 } 1152 1153 PoolVars[scope.PoolVar].Scopes.push_back(scope); 1154 } 1155 1156 bool isPoolCreation(Expr *E) { 1157 if (!E) return false; 1158 E = getEssential(E); 1159 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E); 1160 if (!ME) return false; 1161 if (ME->getMethodFamily() == OMF_new && 1162 ME->getReceiverKind() == ObjCMessageExpr::Class && 1163 isNSAutoreleasePool(ME->getReceiverInterface())) 1164 return true; 1165 if (ME->getReceiverKind() == ObjCMessageExpr::Instance && 1166 ME->getMethodFamily() == OMF_init) { 1167 Expr *rec = getEssential(ME->getInstanceReceiver()); 1168 if (ObjCMessageExpr *recME = dyn_cast_or_null<ObjCMessageExpr>(rec)) { 1169 if (recME->getMethodFamily() == OMF_alloc && 1170 recME->getReceiverKind() == ObjCMessageExpr::Class && 1171 isNSAutoreleasePool(recME->getReceiverInterface())) 1172 return true; 1173 } 1174 } 1175 1176 return false; 1177 } 1178 1179 bool isPoolDrain(VarDecl *poolVar, Stmt *S) { 1180 if (!S) return false; 1181 S = getEssential(S); 1182 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S); 1183 if (!ME) return false; 1184 if (ME->getReceiverKind() == ObjCMessageExpr::Instance) { 1185 Expr *rec = getEssential(ME->getInstanceReceiver()); 1186 if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec)) 1187 if (dref->getDecl() == poolVar) 1188 return ME->getMethodFamily() == OMF_release || 1189 ME->getSelector() == DrainSel; 1190 } 1191 1192 return false; 1193 } 1194 1195 bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) { 1196 return IDecl && IDecl->getIdentifier() == PoolII; 1197 } 1198 1199 bool isNSAutoreleasePool(QualType Ty) { 1200 QualType pointee = Ty->getPointeeType(); 1201 if (pointee.isNull()) 1202 return false; 1203 if (const ObjCInterfaceType *interT = pointee->getAs<ObjCInterfaceType>()) 1204 return isNSAutoreleasePool(interT->getDecl()); 1205 return false; 1206 } 1207 1208 static Expr *getEssential(Expr *E) { 1209 return cast<Expr>(getEssential((Stmt*)E)); 1210 } 1211 static Stmt *getEssential(Stmt *S) { 1212 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S)) 1213 S = EWC->getSubExpr(); 1214 if (Expr *E = dyn_cast<Expr>(S)) 1215 S = E->IgnoreParenCasts(); 1216 return S; 1217 } 1218 1219 Decl *Dcl; 1220 Stmt *Body; 1221 MigrationPass &Pass; 1222 1223 IdentifierInfo *PoolII; 1224 Selector DrainSel; 1225 1226 struct PoolVarInfo { 1227 DeclStmt *Dcl; 1228 llvm::DenseSet<Expr *> Refs; 1229 llvm::SmallVector<PoolScope, 2> Scopes; 1230 1231 PoolVarInfo() : Dcl(0) { } 1232 }; 1233 1234 std::map<VarDecl *, PoolVarInfo> PoolVars; 1235}; 1236 1237} // anonymous namespace 1238 1239static void rewriteAutoreleasePool(MigrationPass &pass) { 1240 BodyTransform<AutoreleasePoolRewriter> trans(pass); 1241 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 1242} 1243 1244//===----------------------------------------------------------------------===// 1245// removeRetainReleaseDealloc 1246//===----------------------------------------------------------------------===// 1247 1248namespace { 1249 1250class RetainReleaseDeallocRemover : 1251 public RecursiveASTVisitor<RetainReleaseDeallocRemover> { 1252 Decl *Dcl; 1253 Stmt *Body; 1254 MigrationPass &Pass; 1255 1256 llvm::DenseSet<Expr *> Removables; 1257 llvm::OwningPtr<ParentMap> StmtMap; 1258 1259public: 1260 RetainReleaseDeallocRemover(Decl *D, MigrationPass &pass) 1261 : Dcl(D), Body(0), Pass(pass) { } 1262 1263 void transformBody(Stmt *body) { 1264 Body = body; 1265 RemovablesCollector(Removables).TraverseStmt(body); 1266 StmtMap.reset(new ParentMap(body)); 1267 TraverseStmt(body); 1268 } 1269 1270 bool VisitObjCMessageExpr(ObjCMessageExpr *E) { 1271 switch (E->getMethodFamily()) { 1272 default: 1273 return true; 1274 case OMF_retain: 1275 case OMF_release: 1276 case OMF_autorelease: 1277 if (E->getReceiverKind() == ObjCMessageExpr::Instance) 1278 if (Expr *rec = E->getInstanceReceiver()) { 1279 rec = rec->IgnoreParenImpCasts(); 1280 if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){ 1281 std::string err = "It is not safe to remove '"; 1282 err += E->getSelector().getAsString() + "' message on " 1283 "an __unsafe_unretained type"; 1284 Pass.TA.reportError(err, rec->getLocStart()); 1285 return true; 1286 } 1287 } 1288 case OMF_dealloc: 1289 break; 1290 } 1291 1292 switch (E->getReceiverKind()) { 1293 default: 1294 return true; 1295 case ObjCMessageExpr::SuperInstance: { 1296 Transaction Trans(Pass.TA); 1297 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, 1298 diag::err_unavailable, 1299 diag::err_unavailable_message, 1300 E->getSuperLoc()); 1301 if (tryRemoving(E)) 1302 return true; 1303 Pass.TA.replace(E->getSourceRange(), "self"); 1304 return true; 1305 } 1306 case ObjCMessageExpr::Instance: 1307 break; 1308 } 1309 1310 Expr *rec = E->getInstanceReceiver(); 1311 if (!rec) return true; 1312 1313 Transaction Trans(Pass.TA); 1314 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message, 1315 diag::err_unavailable, 1316 diag::err_unavailable_message, 1317 rec->getExprLoc()); 1318 if (!HasSideEffects(E, Pass.Ctx)) { 1319 if (tryRemoving(E)) 1320 return true; 1321 } 1322 Pass.TA.replace(E->getSourceRange(), rec->getSourceRange()); 1323 1324 return true; 1325 } 1326 1327private: 1328 bool isRemovable(Expr *E) const { 1329 return Removables.count(E); 1330 } 1331 1332 bool tryRemoving(Expr *E) const { 1333 if (isRemovable(E)) { 1334 Pass.TA.removeStmt(E); 1335 return true; 1336 } 1337 1338 if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E))) 1339 return tryRemoving(parenE); 1340 1341 if (BinaryOperator * 1342 bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) { 1343 if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E && 1344 isRemovable(bopE)) { 1345 Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange()); 1346 return true; 1347 } 1348 } 1349 1350 return false; 1351 } 1352 1353}; 1354 1355} // anonymous namespace 1356 1357static void removeRetainReleaseDealloc(MigrationPass &pass) { 1358 BodyTransform<RetainReleaseDeallocRemover> trans(pass); 1359 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 1360} 1361 1362//===----------------------------------------------------------------------===// 1363// removeEmptyStatements 1364//===----------------------------------------------------------------------===// 1365 1366namespace { 1367 1368class EmptyStatementsRemover : 1369 public RecursiveASTVisitor<EmptyStatementsRemover> { 1370 MigrationPass &Pass; 1371 llvm::DenseSet<unsigned> MacroLocs; 1372 1373public: 1374 EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) { 1375 for (unsigned i = 0, e = Pass.ARCMTMacroLocs.size(); i != e; ++i) 1376 MacroLocs.insert(Pass.ARCMTMacroLocs[i].getRawEncoding()); 1377 } 1378 1379 bool TraverseStmtExpr(StmtExpr *E) { 1380 CompoundStmt *S = E->getSubStmt(); 1381 for (CompoundStmt::body_iterator 1382 I = S->body_begin(), E = S->body_end(); I != E; ++I) { 1383 if (I != E - 1) 1384 check(*I); 1385 TraverseStmt(*I); 1386 } 1387 return true; 1388 } 1389 1390 bool VisitCompoundStmt(CompoundStmt *S) { 1391 for (CompoundStmt::body_iterator 1392 I = S->body_begin(), E = S->body_end(); I != E; ++I) 1393 check(*I); 1394 return true; 1395 } 1396 1397 bool isMacroLoc(SourceLocation loc) { 1398 if (loc.isInvalid()) return false; 1399 return MacroLocs.count(loc.getRawEncoding()); 1400 } 1401 1402 ASTContext &getContext() { return Pass.Ctx; } 1403 1404private: 1405 /// \brief Returns true if the statement became empty due to previous 1406 /// transformations. 1407 class EmptyChecker : public StmtVisitor<EmptyChecker, bool> { 1408 EmptyStatementsRemover &Trans; 1409 1410 public: 1411 EmptyChecker(EmptyStatementsRemover &trans) : Trans(trans) { } 1412 1413 bool VisitNullStmt(NullStmt *S) { 1414 return Trans.isMacroLoc(S->getLeadingEmptyMacroLoc()); 1415 } 1416 bool VisitCompoundStmt(CompoundStmt *S) { 1417 if (S->body_empty()) 1418 return false; // was already empty, not because of transformations. 1419 for (CompoundStmt::body_iterator 1420 I = S->body_begin(), E = S->body_end(); I != E; ++I) 1421 if (!Visit(*I)) 1422 return false; 1423 return true; 1424 } 1425 bool VisitIfStmt(IfStmt *S) { 1426 if (S->getConditionVariable()) 1427 return false; 1428 Expr *condE = S->getCond(); 1429 if (!condE) 1430 return false; 1431 if (HasSideEffects(condE, Trans.getContext())) 1432 return false; 1433 if (!S->getThen() || !Visit(S->getThen())) 1434 return false; 1435 if (S->getElse() && !Visit(S->getElse())) 1436 return false; 1437 return true; 1438 } 1439 bool VisitWhileStmt(WhileStmt *S) { 1440 if (S->getConditionVariable()) 1441 return false; 1442 Expr *condE = S->getCond(); 1443 if (!condE) 1444 return false; 1445 if (HasSideEffects(condE, Trans.getContext())) 1446 return false; 1447 if (!S->getBody()) 1448 return false; 1449 return Visit(S->getBody()); 1450 } 1451 bool VisitDoStmt(DoStmt *S) { 1452 Expr *condE = S->getCond(); 1453 if (!condE) 1454 return false; 1455 if (HasSideEffects(condE, Trans.getContext())) 1456 return false; 1457 if (!S->getBody()) 1458 return false; 1459 return Visit(S->getBody()); 1460 } 1461 bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { 1462 Expr *Exp = S->getCollection(); 1463 if (!Exp) 1464 return false; 1465 if (HasSideEffects(Exp, Trans.getContext())) 1466 return false; 1467 if (!S->getBody()) 1468 return false; 1469 return Visit(S->getBody()); 1470 } 1471 bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { 1472 if (!S->getSubStmt()) 1473 return false; 1474 return Visit(S->getSubStmt()); 1475 } 1476 }; 1477 1478 void check(Stmt *S) { 1479 if (!S) return; 1480 if (EmptyChecker(*this).Visit(S)) { 1481 Transaction Trans(Pass.TA); 1482 Pass.TA.removeStmt(S); 1483 } 1484 } 1485}; 1486 1487} // anonymous namespace 1488 1489static void removeEmptyStatements(MigrationPass &pass) { 1490 EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 1491 1492 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) { 1493 Transaction Trans(pass.TA); 1494 pass.TA.remove(pass.ARCMTMacroLocs[i]); 1495 } 1496} 1497 1498//===----------------------------------------------------------------------===// 1499// changeIvarsOfAssignProperties. 1500//===----------------------------------------------------------------------===// 1501 1502namespace { 1503 1504class AssignPropertiesTrans { 1505 MigrationPass &Pass; 1506 struct PropData { 1507 ObjCPropertyDecl *PropD; 1508 ObjCIvarDecl *IvarD; 1509 bool ShouldChangeToWeak; 1510 SourceLocation ArcPropAssignErrorLoc; 1511 }; 1512 1513 typedef llvm::SmallVector<PropData, 2> PropsTy; 1514 typedef llvm::DenseMap<unsigned, PropsTy> PropsMapTy; 1515 PropsMapTy PropsMap; 1516 1517public: 1518 AssignPropertiesTrans(MigrationPass &pass) : Pass(pass) { } 1519 1520 void doTransform(ObjCImplementationDecl *D) { 1521 SourceManager &SM = Pass.Ctx.getSourceManager(); 1522 1523 ObjCInterfaceDecl *IFace = D->getClassInterface(); 1524 for (ObjCInterfaceDecl::prop_iterator 1525 I = IFace->prop_begin(), E = IFace->prop_end(); I != E; ++I) { 1526 ObjCPropertyDecl *propD = *I; 1527 unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding(); 1528 PropsTy &props = PropsMap[loc]; 1529 props.push_back(PropData()); 1530 props.back().PropD = propD; 1531 props.back().IvarD = 0; 1532 props.back().ShouldChangeToWeak = false; 1533 } 1534 1535 typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl> 1536 prop_impl_iterator; 1537 for (prop_impl_iterator 1538 I = prop_impl_iterator(D->decls_begin()), 1539 E = prop_impl_iterator(D->decls_end()); I != E; ++I) { 1540 VisitObjCPropertyImplDecl(*I); 1541 } 1542 1543 for (PropsMapTy::iterator 1544 I = PropsMap.begin(), E = PropsMap.end(); I != E; ++I) { 1545 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first); 1546 PropsTy &props = I->second; 1547 if (shouldApplyWeakToAllProp(props)) { 1548 if (changeAssignToWeak(atLoc)) { 1549 // Couldn't add the 'weak' property attribute, 1550 // try adding __unsafe_unretained. 1551 applyUnsafeUnretained(props); 1552 } else { 1553 for (PropsTy::iterator 1554 PI = props.begin(), PE = props.end(); PI != PE; ++PI) { 1555 applyWeak(*PI); 1556 } 1557 } 1558 } else { 1559 // We should not add 'weak' attribute since not all properties need it. 1560 // So just add __unsafe_unretained to the ivars. 1561 applyUnsafeUnretained(props); 1562 } 1563 } 1564 } 1565 1566 bool shouldApplyWeakToAllProp(PropsTy &props) { 1567 for (PropsTy::iterator 1568 PI = props.begin(), PE = props.end(); PI != PE; ++PI) { 1569 if (!PI->ShouldChangeToWeak) 1570 return false; 1571 } 1572 return true; 1573 } 1574 1575 void applyWeak(PropData &prop) { 1576 assert(!Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime); 1577 1578 Transaction Trans(Pass.TA); 1579 Pass.TA.insert(prop.IvarD->getLocation(), "__weak "); 1580 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime, 1581 prop.ArcPropAssignErrorLoc); 1582 } 1583 1584 void applyUnsafeUnretained(PropsTy &props) { 1585 for (PropsTy::iterator 1586 PI = props.begin(), PE = props.end(); PI != PE; ++PI) { 1587 if (PI->ShouldChangeToWeak) { 1588 Transaction Trans(Pass.TA); 1589 Pass.TA.insert(PI->IvarD->getLocation(), "__unsafe_unretained "); 1590 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime, 1591 PI->ArcPropAssignErrorLoc); 1592 } 1593 } 1594 } 1595 1596 bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { 1597 SourceManager &SM = Pass.Ctx.getSourceManager(); 1598 1599 if (D->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize) 1600 return true; 1601 ObjCPropertyDecl *propD = D->getPropertyDecl(); 1602 if (!propD || propD->isInvalidDecl()) 1603 return true; 1604 ObjCIvarDecl *ivarD = D->getPropertyIvarDecl(); 1605 if (!ivarD || ivarD->isInvalidDecl()) 1606 return true; 1607 if (!(propD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign)) 1608 return true; 1609 if (isa<AttributedType>(ivarD->getType().getTypePtr())) 1610 return true; 1611 if (ivarD->getType().getLocalQualifiers().getObjCLifetime() 1612 != Qualifiers::OCL_Strong) 1613 return true; 1614 if (!Pass.TA.hasDiagnostic( 1615 diag::err_arc_assign_property_lifetime, D->getLocation())) 1616 return true; 1617 1618 // There is a "error: existing ivar for assign property must be 1619 // __unsafe_unretained"; fix it. 1620 1621 if (Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime) { 1622 // We will just add __unsafe_unretained to the ivar. 1623 Transaction Trans(Pass.TA); 1624 Pass.TA.insert(ivarD->getLocation(), "__unsafe_unretained "); 1625 Pass.TA.clearDiagnostic( 1626 diag::err_arc_assign_property_lifetime, D->getLocation()); 1627 } else { 1628 // Mark that we want the ivar to become weak. 1629 unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding(); 1630 PropsTy &props = PropsMap[loc]; 1631 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { 1632 if (I->PropD == propD) { 1633 I->IvarD = ivarD; 1634 I->ShouldChangeToWeak = true; 1635 I->ArcPropAssignErrorLoc = D->getLocation(); 1636 } 1637 } 1638 } 1639 1640 return true; 1641 } 1642 1643private: 1644 bool changeAssignToWeak(SourceLocation atLoc) { 1645 SourceManager &SM = Pass.Ctx.getSourceManager(); 1646 1647 // Break down the source location. 1648 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); 1649 1650 // Try to load the file buffer. 1651 bool invalidTemp = false; 1652 llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 1653 if (invalidTemp) 1654 return true; 1655 1656 const char *tokenBegin = file.data() + locInfo.second; 1657 1658 // Lex from the start of the given location. 1659 Lexer lexer(SM.getLocForStartOfFile(locInfo.first), 1660 Pass.Ctx.getLangOptions(), 1661 file.begin(), tokenBegin, file.end()); 1662 Token tok; 1663 lexer.LexFromRawLexer(tok); 1664 if (tok.isNot(tok::at)) return true; 1665 lexer.LexFromRawLexer(tok); 1666 if (tok.isNot(tok::raw_identifier)) return true; 1667 if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength()) 1668 != "property") 1669 return true; 1670 lexer.LexFromRawLexer(tok); 1671 if (tok.isNot(tok::l_paren)) return true; 1672 1673 SourceLocation LParen = tok.getLocation(); 1674 SourceLocation assignLoc; 1675 bool isEmpty = false; 1676 1677 lexer.LexFromRawLexer(tok); 1678 if (tok.is(tok::r_paren)) { 1679 isEmpty = true; 1680 } else { 1681 while (1) { 1682 if (tok.isNot(tok::raw_identifier)) return true; 1683 llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength()); 1684 if (ident == "assign") 1685 assignLoc = tok.getLocation(); 1686 1687 do { 1688 lexer.LexFromRawLexer(tok); 1689 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); 1690 if (tok.is(tok::r_paren)) 1691 break; 1692 lexer.LexFromRawLexer(tok); 1693 } 1694 } 1695 1696 Transaction Trans(Pass.TA); 1697 if (assignLoc.isValid()) 1698 Pass.TA.replaceText(assignLoc, "assign", "weak"); 1699 else 1700 Pass.TA.insertAfterToken(LParen, isEmpty ? "weak" : "weak, "); 1701 return false; 1702 } 1703}; 1704 1705class PropertiesChecker : public RecursiveASTVisitor<PropertiesChecker> { 1706 MigrationPass &Pass; 1707 1708public: 1709 PropertiesChecker(MigrationPass &pass) : Pass(pass) { } 1710 1711 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { 1712 AssignPropertiesTrans(Pass).doTransform(D); 1713 return true; 1714 } 1715}; 1716 1717} // anonymous namespace 1718 1719static void changeIvarsOfAssignProperties(MigrationPass &pass) { 1720 PropertiesChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 1721} 1722 1723//===----------------------------------------------------------------------===// 1724// rewriteUnusedDelegateInit 1725//===----------------------------------------------------------------------===// 1726 1727namespace { 1728 1729class UnusedInitRewriter : public RecursiveASTVisitor<UnusedInitRewriter> { 1730 Decl *Dcl; 1731 Stmt *Body; 1732 MigrationPass &Pass; 1733 1734 llvm::DenseSet<Expr *> Removables; 1735 1736public: 1737 UnusedInitRewriter(Decl *D, MigrationPass &pass) 1738 : Dcl(D), Body(0), Pass(pass) { } 1739 1740 void transformBody(Stmt *body) { 1741 Body = body; 1742 RemovablesCollector(Removables).TraverseStmt(body); 1743 TraverseStmt(body); 1744 } 1745 1746 bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { 1747 if (ME->isDelegateInitCall() && 1748 isRemovable(ME) && 1749 Pass.TA.hasDiagnostic(diag::err_arc_unused_init_message, 1750 ME->getExprLoc())) { 1751 Transaction Trans(Pass.TA); 1752 Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message, 1753 ME->getExprLoc()); 1754 Pass.TA.insert(ME->getExprLoc(), "self = "); 1755 } 1756 return true; 1757 } 1758 1759private: 1760 bool isRemovable(Expr *E) const { 1761 return Removables.count(E); 1762 } 1763}; 1764 1765} // anonymous namespace 1766 1767static void rewriteUnusedDelegateInit(MigrationPass &pass) { 1768 BodyTransform<UnusedInitRewriter> trans(pass); 1769 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 1770} 1771 1772//===----------------------------------------------------------------------===// 1773// rewriteBlockObjCVariable 1774//===----------------------------------------------------------------------===// 1775 1776namespace { 1777 1778class RootBlockObjCVarRewriter : 1779 public RecursiveASTVisitor<RootBlockObjCVarRewriter> { 1780 MigrationPass &Pass; 1781 llvm::DenseSet<VarDecl *> CheckedVars; 1782 1783 class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> { 1784 VarDecl *Var; 1785 1786 typedef RecursiveASTVisitor<BlockVarChecker> base; 1787 public: 1788 BlockVarChecker(VarDecl *var) : Var(var) { } 1789 1790 bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) { 1791 if (BlockDeclRefExpr * 1792 ref = dyn_cast<BlockDeclRefExpr>(castE->getSubExpr())) { 1793 if (ref->getDecl() == Var) { 1794 if (castE->getCastKind() == CK_LValueToRValue) 1795 return true; // Using the value of the variable. 1796 if (castE->getCastKind() == CK_NoOp && castE->isLValue() && 1797 Var->getASTContext().getLangOptions().CPlusPlus) 1798 return true; // Binding to const C++ reference. 1799 } 1800 } 1801 1802 return base::TraverseImplicitCastExpr(castE); 1803 } 1804 1805 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { 1806 if (E->getDecl() == Var) 1807 return false; // The reference of the variable, and not just its value, 1808 // is needed. 1809 return true; 1810 } 1811 }; 1812 1813public: 1814 RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { } 1815 1816 bool VisitBlockDecl(BlockDecl *block) { 1817 llvm::SmallVector<VarDecl *, 4> BlockVars; 1818 1819 for (BlockDecl::capture_iterator 1820 I = block->capture_begin(), E = block->capture_end(); I != E; ++I) { 1821 VarDecl *var = I->getVariable(); 1822 if (I->isByRef() && 1823 !isAlreadyChecked(var) && 1824 var->getType()->isObjCObjectPointerType() && 1825 isImplicitStrong(var->getType())) { 1826 BlockVars.push_back(var); 1827 } 1828 } 1829 1830 for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) { 1831 VarDecl *var = BlockVars[i]; 1832 CheckedVars.insert(var); 1833 1834 BlockVarChecker checker(var); 1835 bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody()); 1836 if (onlyValueOfVarIsNeeded) { 1837 BlocksAttr *attr = var->getAttr<BlocksAttr>(); 1838 if(!attr) 1839 continue; 1840 bool hasARCRuntime = !Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime; 1841 SourceManager &SM = Pass.Ctx.getSourceManager(); 1842 Transaction Trans(Pass.TA); 1843 Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()), 1844 "__block", 1845 hasARCRuntime ? "__weak" : "__unsafe_unretained"); 1846 } 1847 1848 } 1849 1850 return true; 1851 } 1852 1853private: 1854 bool isAlreadyChecked(VarDecl *VD) { 1855 return CheckedVars.count(VD); 1856 } 1857 1858 bool isImplicitStrong(QualType ty) { 1859 if (isa<AttributedType>(ty.getTypePtr())) 1860 return false; 1861 return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong; 1862 } 1863}; 1864 1865class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> { 1866 MigrationPass &Pass; 1867 1868public: 1869 BlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { } 1870 1871 bool TraverseBlockDecl(BlockDecl *block) { 1872 RootBlockObjCVarRewriter(Pass).TraverseDecl(block); 1873 return true; 1874 } 1875}; 1876 1877} // anonymous namespace 1878 1879static void rewriteBlockObjCVariable(MigrationPass &pass) { 1880 BlockObjCVarRewriter trans(pass); 1881 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 1882} 1883 1884//===----------------------------------------------------------------------===// 1885// removeZeroOutIvarsInDealloc 1886//===----------------------------------------------------------------------===// 1887 1888namespace { 1889 1890class ZeroOutInDeallocRemover : 1891 public RecursiveASTVisitor<ZeroOutInDeallocRemover> { 1892 typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base; 1893 1894 MigrationPass &Pass; 1895 1896 llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties; 1897 ImplicitParamDecl *SelfD; 1898 llvm::DenseSet<Expr *> Removables; 1899 1900public: 1901 ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { } 1902 1903 bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { 1904 ASTContext &Ctx = Pass.Ctx; 1905 TransformActions &TA = Pass.TA; 1906 1907 if (ME->getReceiverKind() != ObjCMessageExpr::Instance) 1908 return true; 1909 Expr *receiver = ME->getInstanceReceiver(); 1910 if (!receiver) 1911 return true; 1912 1913 DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts()); 1914 if (!refE || refE->getDecl() != SelfD) 1915 return true; 1916 1917 bool BackedBySynthesizeSetter = false; 1918 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 1919 P = SynthesizedProperties.begin(), 1920 E = SynthesizedProperties.end(); P != E; ++P) { 1921 ObjCPropertyDecl *PropDecl = P->first; 1922 if (PropDecl->getSetterName() == ME->getSelector()) { 1923 BackedBySynthesizeSetter = true; 1924 break; 1925 } 1926 } 1927 if (!BackedBySynthesizeSetter) 1928 return true; 1929 1930 // Remove the setter message if RHS is null 1931 Transaction Trans(TA); 1932 Expr *RHS = ME->getArg(0); 1933 bool RHSIsNull = 1934 RHS->isNullPointerConstant(Ctx, 1935 Expr::NPC_ValueDependentIsNull); 1936 if (RHSIsNull && isRemovable(ME)) 1937 TA.removeStmt(ME); 1938 1939 return true; 1940 } 1941 1942 bool VisitBinaryOperator(BinaryOperator *BOE) { 1943 if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { 1944 Transaction Trans(Pass.TA); 1945 Pass.TA.removeStmt(BOE); 1946 } 1947 1948 return true; 1949 } 1950 1951 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { 1952 if (D->getMethodFamily() != OMF_dealloc) 1953 return true; 1954 if (!D->hasBody()) 1955 return true; 1956 1957 ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext()); 1958 if (!IMD) 1959 return true; 1960 1961 SelfD = D->getSelfDecl(); 1962 RemovablesCollector(Removables).TraverseStmt(D->getBody()); 1963 1964 // For a 'dealloc' method use, find all property implementations in 1965 // this class implementation. 1966 for (ObjCImplDecl::propimpl_iterator 1967 I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) { 1968 ObjCPropertyImplDecl *PID = *I; 1969 if (PID->getPropertyImplementation() == 1970 ObjCPropertyImplDecl::Synthesize) { 1971 ObjCPropertyDecl *PD = PID->getPropertyDecl(); 1972 ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); 1973 if (!(setterM && setterM->isDefined())) { 1974 ObjCPropertyDecl::PropertyAttributeKind AttrKind = 1975 PD->getPropertyAttributes(); 1976 if (AttrKind & 1977 (ObjCPropertyDecl::OBJC_PR_retain | 1978 ObjCPropertyDecl::OBJC_PR_copy | 1979 ObjCPropertyDecl::OBJC_PR_strong)) 1980 SynthesizedProperties[PD] = PID; 1981 } 1982 } 1983 } 1984 1985 // Now, remove all zeroing of ivars etc. 1986 base::TraverseObjCMethodDecl(D); 1987 1988 // clear out for next method. 1989 SynthesizedProperties.clear(); 1990 SelfD = 0; 1991 Removables.clear(); 1992 return true; 1993 } 1994 1995 bool TraverseFunctionDecl(FunctionDecl *D) { return true; } 1996 bool TraverseBlockDecl(BlockDecl *block) { return true; } 1997 bool TraverseBlockExpr(BlockExpr *block) { return true; } 1998 1999private: 2000 bool isRemovable(Expr *E) const { 2001 return Removables.count(E); 2002 } 2003 2004 bool isZeroingPropIvar(Expr *E) { 2005 BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E); 2006 if (!BOE) return false; 2007 2008 if (BOE->getOpcode() == BO_Comma) 2009 return isZeroingPropIvar(BOE->getLHS()) && 2010 isZeroingPropIvar(BOE->getRHS()); 2011 2012 if (BOE->getOpcode() != BO_Assign) 2013 return false; 2014 2015 ASTContext &Ctx = Pass.Ctx; 2016 2017 Expr *LHS = BOE->getLHS(); 2018 if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { 2019 ObjCIvarDecl *IVDecl = IV->getDecl(); 2020 if (!IVDecl->getType()->isObjCObjectPointerType()) 2021 return false; 2022 bool IvarBacksPropertySynthesis = false; 2023 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 2024 P = SynthesizedProperties.begin(), 2025 E = SynthesizedProperties.end(); P != E; ++P) { 2026 ObjCPropertyImplDecl *PropImpDecl = P->second; 2027 if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { 2028 IvarBacksPropertySynthesis = true; 2029 break; 2030 } 2031 } 2032 if (!IvarBacksPropertySynthesis) 2033 return false; 2034 } 2035 else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) { 2036 // TODO: Using implicit property decl. 2037 if (PropRefExp->isImplicitProperty()) 2038 return false; 2039 if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { 2040 if (!SynthesizedProperties.count(PDecl)) 2041 return false; 2042 } 2043 } 2044 else 2045 return false; 2046 2047 Expr *RHS = BOE->getRHS(); 2048 bool RHSIsNull = RHS->isNullPointerConstant(Ctx, 2049 Expr::NPC_ValueDependentIsNull); 2050 if (RHSIsNull) 2051 return true; 2052 2053 return isZeroingPropIvar(RHS); 2054 } 2055}; 2056 2057} // anonymous namespace 2058 2059static void removeZeroOutIvarsInDealloc(MigrationPass &pass) { 2060 ZeroOutInDeallocRemover trans(pass); 2061 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 2062} 2063 2064//===----------------------------------------------------------------------===// 2065// getAllTransformations. 2066//===----------------------------------------------------------------------===// 2067 2068static void independentTransforms(MigrationPass &pass) { 2069 rewriteAutoreleasePool(pass); 2070 changeIvarsOfAssignProperties(pass); 2071 removeRetainReleaseDealloc(pass); 2072 rewriteUnusedDelegateInit(pass); 2073 removeZeroOutIvarsInDealloc(pass); 2074 makeAssignARCSafe(pass); 2075 castNonObjCToObjC(pass); 2076 rewriteBlockObjCVariable(pass); 2077 rewriteAllocCopyWithZone(pass); 2078} 2079 2080std::vector<TransformFn> arcmt::getAllTransformations() { 2081 std::vector<TransformFn> transforms; 2082 2083 // This must come first since rewriteAutoreleasePool depends on -release 2084 // calls being present to determine the @autorelease ending scope. 2085 transforms.push_back(independentTransforms); 2086 2087 transforms.push_back(removeEmptyStatements); 2088 transforms.push_back(removeDeallocMethod); 2089 2090 return transforms; 2091} 2092