1249423Sdim//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===// 2224135Sdim// 3224135Sdim// The LLVM Compiler Infrastructure 4224135Sdim// 5224135Sdim// This file is distributed under the University of Illinois Open Source 6224135Sdim// License. See LICENSE.TXT for details. 7224135Sdim// 8224135Sdim//===----------------------------------------------------------------------===// 9224135Sdim// 10224135Sdim// removeZeroOutPropsInDealloc: 11224135Sdim// 12224135Sdim// Removes zero'ing out "strong" @synthesized properties in a -dealloc method. 13224135Sdim// 14224135Sdim//===----------------------------------------------------------------------===// 15224135Sdim 16224135Sdim#include "Transforms.h" 17224135Sdim#include "Internals.h" 18239462Sdim#include "clang/AST/ASTContext.h" 19224135Sdim 20224135Sdimusing namespace clang; 21224135Sdimusing namespace arcmt; 22224135Sdimusing namespace trans; 23224135Sdim 24224135Sdimnamespace { 25224135Sdim 26224135Sdimclass ZeroOutInDeallocRemover : 27224135Sdim public RecursiveASTVisitor<ZeroOutInDeallocRemover> { 28224135Sdim typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base; 29224135Sdim 30224135Sdim MigrationPass &Pass; 31224135Sdim 32224135Sdim llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties; 33224135Sdim ImplicitParamDecl *SelfD; 34224135Sdim ExprSet Removables; 35234353Sdim Selector FinalizeSel; 36224135Sdim 37224135Sdimpublic: 38234353Sdim ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { 39234353Sdim FinalizeSel = 40234353Sdim Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); 41234353Sdim } 42224135Sdim 43224135Sdim bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { 44224135Sdim ASTContext &Ctx = Pass.Ctx; 45224135Sdim TransformActions &TA = Pass.TA; 46224135Sdim 47224135Sdim if (ME->getReceiverKind() != ObjCMessageExpr::Instance) 48224135Sdim return true; 49224135Sdim Expr *receiver = ME->getInstanceReceiver(); 50224135Sdim if (!receiver) 51224135Sdim return true; 52224135Sdim 53224135Sdim DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts()); 54224135Sdim if (!refE || refE->getDecl() != SelfD) 55224135Sdim return true; 56224135Sdim 57224135Sdim bool BackedBySynthesizeSetter = false; 58224135Sdim for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 59224135Sdim P = SynthesizedProperties.begin(), 60224135Sdim E = SynthesizedProperties.end(); P != E; ++P) { 61224135Sdim ObjCPropertyDecl *PropDecl = P->first; 62224135Sdim if (PropDecl->getSetterName() == ME->getSelector()) { 63224135Sdim BackedBySynthesizeSetter = true; 64224135Sdim break; 65224135Sdim } 66224135Sdim } 67224135Sdim if (!BackedBySynthesizeSetter) 68224135Sdim return true; 69224135Sdim 70224135Sdim // Remove the setter message if RHS is null 71224135Sdim Transaction Trans(TA); 72224135Sdim Expr *RHS = ME->getArg(0); 73224135Sdim bool RHSIsNull = 74224135Sdim RHS->isNullPointerConstant(Ctx, 75224135Sdim Expr::NPC_ValueDependentIsNull); 76224135Sdim if (RHSIsNull && isRemovable(ME)) 77224135Sdim TA.removeStmt(ME); 78224135Sdim 79224135Sdim return true; 80224135Sdim } 81224135Sdim 82234353Sdim bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) { 83234353Sdim if (isZeroingPropIvar(POE) && isRemovable(POE)) { 84234353Sdim Transaction Trans(Pass.TA); 85234353Sdim Pass.TA.removeStmt(POE); 86234353Sdim } 87234353Sdim 88234353Sdim return true; 89234353Sdim } 90234353Sdim 91224135Sdim bool VisitBinaryOperator(BinaryOperator *BOE) { 92224135Sdim if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { 93224135Sdim Transaction Trans(Pass.TA); 94224135Sdim Pass.TA.removeStmt(BOE); 95224135Sdim } 96224135Sdim 97224135Sdim return true; 98224135Sdim } 99224135Sdim 100224135Sdim bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { 101234353Sdim if (D->getMethodFamily() != OMF_dealloc && 102234353Sdim !(D->isInstanceMethod() && D->getSelector() == FinalizeSel)) 103224135Sdim return true; 104224135Sdim if (!D->hasBody()) 105224135Sdim return true; 106224135Sdim 107224135Sdim ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext()); 108224135Sdim if (!IMD) 109224135Sdim return true; 110224135Sdim 111224135Sdim SelfD = D->getSelfDecl(); 112224135Sdim collectRemovables(D->getBody(), Removables); 113224135Sdim 114224135Sdim // For a 'dealloc' method use, find all property implementations in 115224135Sdim // this class implementation. 116224135Sdim for (ObjCImplDecl::propimpl_iterator 117224135Sdim I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) { 118224135Sdim ObjCPropertyImplDecl *PID = *I; 119224135Sdim if (PID->getPropertyImplementation() == 120224135Sdim ObjCPropertyImplDecl::Synthesize) { 121224135Sdim ObjCPropertyDecl *PD = PID->getPropertyDecl(); 122224135Sdim ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); 123224135Sdim if (!(setterM && setterM->isDefined())) { 124224135Sdim ObjCPropertyDecl::PropertyAttributeKind AttrKind = 125224135Sdim PD->getPropertyAttributes(); 126224135Sdim if (AttrKind & 127224135Sdim (ObjCPropertyDecl::OBJC_PR_retain | 128224135Sdim ObjCPropertyDecl::OBJC_PR_copy | 129224135Sdim ObjCPropertyDecl::OBJC_PR_strong)) 130224135Sdim SynthesizedProperties[PD] = PID; 131224135Sdim } 132224135Sdim } 133224135Sdim } 134224135Sdim 135224135Sdim // Now, remove all zeroing of ivars etc. 136224135Sdim base::TraverseObjCMethodDecl(D); 137224135Sdim 138224135Sdim // clear out for next method. 139224135Sdim SynthesizedProperties.clear(); 140224135Sdim SelfD = 0; 141224135Sdim Removables.clear(); 142224135Sdim return true; 143224135Sdim } 144224135Sdim 145224135Sdim bool TraverseFunctionDecl(FunctionDecl *D) { return true; } 146224135Sdim bool TraverseBlockDecl(BlockDecl *block) { return true; } 147224135Sdim bool TraverseBlockExpr(BlockExpr *block) { return true; } 148224135Sdim 149224135Sdimprivate: 150224135Sdim bool isRemovable(Expr *E) const { 151224135Sdim return Removables.count(E); 152224135Sdim } 153224135Sdim 154224135Sdim bool isZeroingPropIvar(Expr *E) { 155234353Sdim E = E->IgnoreParens(); 156234353Sdim if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) 157234353Sdim return isZeroingPropIvar(BO); 158234353Sdim if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E)) 159234353Sdim return isZeroingPropIvar(PO); 160234353Sdim return false; 161234353Sdim } 162224135Sdim 163234353Sdim bool isZeroingPropIvar(BinaryOperator *BOE) { 164224135Sdim if (BOE->getOpcode() == BO_Comma) 165224135Sdim return isZeroingPropIvar(BOE->getLHS()) && 166224135Sdim isZeroingPropIvar(BOE->getRHS()); 167224135Sdim 168224135Sdim if (BOE->getOpcode() != BO_Assign) 169234353Sdim return false; 170224135Sdim 171224135Sdim Expr *LHS = BOE->getLHS(); 172224135Sdim if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { 173224135Sdim ObjCIvarDecl *IVDecl = IV->getDecl(); 174224135Sdim if (!IVDecl->getType()->isObjCObjectPointerType()) 175224135Sdim return false; 176224135Sdim bool IvarBacksPropertySynthesis = false; 177224135Sdim for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 178224135Sdim P = SynthesizedProperties.begin(), 179224135Sdim E = SynthesizedProperties.end(); P != E; ++P) { 180224135Sdim ObjCPropertyImplDecl *PropImpDecl = P->second; 181224135Sdim if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { 182224135Sdim IvarBacksPropertySynthesis = true; 183224135Sdim break; 184224135Sdim } 185224135Sdim } 186224135Sdim if (!IvarBacksPropertySynthesis) 187224135Sdim return false; 188224135Sdim } 189224135Sdim else 190224135Sdim return false; 191224135Sdim 192234353Sdim return isZero(BOE->getRHS()); 193234353Sdim } 194234353Sdim 195234353Sdim bool isZeroingPropIvar(PseudoObjectExpr *PO) { 196234353Sdim BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm()); 197234353Sdim if (!BO) return false; 198234353Sdim if (BO->getOpcode() != BO_Assign) return false; 199234353Sdim 200234353Sdim ObjCPropertyRefExpr *PropRefExp = 201234353Sdim dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens()); 202234353Sdim if (!PropRefExp) return false; 203234353Sdim 204234353Sdim // TODO: Using implicit property decl. 205234353Sdim if (PropRefExp->isImplicitProperty()) 206234353Sdim return false; 207234353Sdim 208234353Sdim if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { 209234353Sdim if (!SynthesizedProperties.count(PDecl)) 210234353Sdim return false; 211234353Sdim } 212234353Sdim 213234353Sdim return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr()); 214234353Sdim } 215234353Sdim 216234353Sdim bool isZero(Expr *E) { 217234353Sdim if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull)) 218224135Sdim return true; 219224135Sdim 220234353Sdim return isZeroingPropIvar(E); 221224135Sdim } 222224135Sdim}; 223224135Sdim 224224135Sdim} // anonymous namespace 225224135Sdim 226234353Sdimvoid trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) { 227224135Sdim ZeroOutInDeallocRemover trans(pass); 228224135Sdim trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 229224135Sdim} 230