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