1 //===--- TransZeroOutPropsInDealloc.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 // 10 // removeZeroOutPropsInDealloc: 11 // 12 // Removes zero'ing out "strong" @synthesized properties in a -dealloc method. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "Transforms.h" 17 #include "Internals.h" 18 19 using namespace clang; 20 using namespace arcmt; 21 using namespace trans; 22 23 namespace { 24 25 class ZeroOutInDeallocRemover : 26 public RecursiveASTVisitor<ZeroOutInDeallocRemover> { 27 typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base; 28 29 MigrationPass &Pass; 30 31 llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties; 32 ImplicitParamDecl *SelfD; 33 ExprSet Removables; 34 Selector FinalizeSel; 35 36 public: 37 ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { 38 FinalizeSel = 39 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); 40 } 41 42 bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { 43 ASTContext &Ctx = Pass.Ctx; 44 TransformActions &TA = Pass.TA; 45 46 if (ME->getReceiverKind() != ObjCMessageExpr::Instance) 47 return true; 48 Expr *receiver = ME->getInstanceReceiver(); 49 if (!receiver) 50 return true; 51 52 DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts()); 53 if (!refE || refE->getDecl() != SelfD) 54 return true; 55 56 bool BackedBySynthesizeSetter = false; 57 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 58 P = SynthesizedProperties.begin(), 59 E = SynthesizedProperties.end(); P != E; ++P) { 60 ObjCPropertyDecl *PropDecl = P->first; 61 if (PropDecl->getSetterName() == ME->getSelector()) { 62 BackedBySynthesizeSetter = true; 63 break; 64 } 65 } 66 if (!BackedBySynthesizeSetter) 67 return true; 68 69 // Remove the setter message if RHS is null 70 Transaction Trans(TA); 71 Expr *RHS = ME->getArg(0); 72 bool RHSIsNull = 73 RHS->isNullPointerConstant(Ctx, 74 Expr::NPC_ValueDependentIsNull); 75 if (RHSIsNull && isRemovable(ME)) 76 TA.removeStmt(ME); 77 78 return true; 79 } 80 81 bool VisitBinaryOperator(BinaryOperator *BOE) { 82 if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { 83 Transaction Trans(Pass.TA); 84 Pass.TA.removeStmt(BOE); 85 } 86 87 return true; 88 } 89 90 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { 91 if (D->getMethodFamily() != OMF_dealloc && 92 !(D->isInstanceMethod() && D->getSelector() == FinalizeSel)) 93 return true; 94 if (!D->hasBody()) 95 return true; 96 97 ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext()); 98 if (!IMD) 99 return true; 100 101 SelfD = D->getSelfDecl(); 102 collectRemovables(D->getBody(), Removables); 103 104 // For a 'dealloc' method use, find all property implementations in 105 // this class implementation. 106 for (ObjCImplDecl::propimpl_iterator 107 I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) { 108 ObjCPropertyImplDecl *PID = *I; 109 if (PID->getPropertyImplementation() == 110 ObjCPropertyImplDecl::Synthesize) { 111 ObjCPropertyDecl *PD = PID->getPropertyDecl(); 112 ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); 113 if (!(setterM && setterM->isDefined())) { 114 ObjCPropertyDecl::PropertyAttributeKind AttrKind = 115 PD->getPropertyAttributes(); 116 if (AttrKind & 117 (ObjCPropertyDecl::OBJC_PR_retain | 118 ObjCPropertyDecl::OBJC_PR_copy | 119 ObjCPropertyDecl::OBJC_PR_strong)) 120 SynthesizedProperties[PD] = PID; 121 } 122 } 123 } 124 125 // Now, remove all zeroing of ivars etc. 126 base::TraverseObjCMethodDecl(D); 127 128 // clear out for next method. 129 SynthesizedProperties.clear(); 130 SelfD = 0; 131 Removables.clear(); 132 return true; 133 } 134 135 bool TraverseFunctionDecl(FunctionDecl *D) { return true; } 136 bool TraverseBlockDecl(BlockDecl *block) { return true; } 137 bool TraverseBlockExpr(BlockExpr *block) { return true; } 138 139 private: 140 bool isRemovable(Expr *E) const { 141 return Removables.count(E); 142 } 143 144 bool isZeroingPropIvar(Expr *E) { 145 BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E); 146 if (!BOE) return false; 147 148 if (BOE->getOpcode() == BO_Comma) 149 return isZeroingPropIvar(BOE->getLHS()) && 150 isZeroingPropIvar(BOE->getRHS()); 151 152 if (BOE->getOpcode() != BO_Assign) 153 return false; 154 155 ASTContext &Ctx = Pass.Ctx; 156 157 Expr *LHS = BOE->getLHS(); 158 if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { 159 ObjCIvarDecl *IVDecl = IV->getDecl(); 160 if (!IVDecl->getType()->isObjCObjectPointerType()) 161 return false; 162 bool IvarBacksPropertySynthesis = false; 163 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 164 P = SynthesizedProperties.begin(), 165 E = SynthesizedProperties.end(); P != E; ++P) { 166 ObjCPropertyImplDecl *PropImpDecl = P->second; 167 if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { 168 IvarBacksPropertySynthesis = true; 169 break; 170 } 171 } 172 if (!IvarBacksPropertySynthesis) 173 return false; 174 } 175 else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) { 176 // TODO: Using implicit property decl. 177 if (PropRefExp->isImplicitProperty()) 178 return false; 179 if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { 180 if (!SynthesizedProperties.count(PDecl)) 181 return false; 182 } 183 } 184 else 185 return false; 186 187 Expr *RHS = BOE->getRHS(); 188 bool RHSIsNull = RHS->isNullPointerConstant(Ctx, 189 Expr::NPC_ValueDependentIsNull); 190 if (RHSIsNull) 191 return true; 192 193 return isZeroingPropIvar(RHS); 194 } 195 }; 196 197 } // anonymous namespace 198 199 void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) { 200 ZeroOutInDeallocRemover trans(pass); 201 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 202 } 203