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