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