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(nullptr) { 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 (auto *PID : IMD->property_impls()) { 117 if (PID->getPropertyImplementation() == 118 ObjCPropertyImplDecl::Synthesize) { 119 ObjCPropertyDecl *PD = PID->getPropertyDecl(); 120 ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); 121 if (!(setterM && setterM->isDefined())) { 122 ObjCPropertyDecl::PropertyAttributeKind AttrKind = 123 PD->getPropertyAttributes(); 124 if (AttrKind & 125 (ObjCPropertyDecl::OBJC_PR_retain | 126 ObjCPropertyDecl::OBJC_PR_copy | 127 ObjCPropertyDecl::OBJC_PR_strong)) 128 SynthesizedProperties[PD] = PID; 129 } 130 } 131 } 132 133 // Now, remove all zeroing of ivars etc. 134 base::TraverseObjCMethodDecl(D); 135 136 // clear out for next method. 137 SynthesizedProperties.clear(); 138 SelfD = nullptr; 139 Removables.clear(); 140 return true; 141 } 142 143 bool TraverseFunctionDecl(FunctionDecl *D) { return true; } 144 bool TraverseBlockDecl(BlockDecl *block) { return true; } 145 bool TraverseBlockExpr(BlockExpr *block) { return true; } 146 147 private: 148 bool isRemovable(Expr *E) const { 149 return Removables.count(E); 150 } 151 152 bool isZeroingPropIvar(Expr *E) { 153 E = E->IgnoreParens(); 154 if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) 155 return isZeroingPropIvar(BO); 156 if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E)) 157 return isZeroingPropIvar(PO); 158 return false; 159 } 160 161 bool isZeroingPropIvar(BinaryOperator *BOE) { 162 if (BOE->getOpcode() == BO_Comma) 163 return isZeroingPropIvar(BOE->getLHS()) && 164 isZeroingPropIvar(BOE->getRHS()); 165 166 if (BOE->getOpcode() != BO_Assign) 167 return false; 168 169 Expr *LHS = BOE->getLHS(); 170 if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { 171 ObjCIvarDecl *IVDecl = IV->getDecl(); 172 if (!IVDecl->getType()->isObjCObjectPointerType()) 173 return false; 174 bool IvarBacksPropertySynthesis = false; 175 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 176 P = SynthesizedProperties.begin(), 177 E = SynthesizedProperties.end(); P != E; ++P) { 178 ObjCPropertyImplDecl *PropImpDecl = P->second; 179 if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { 180 IvarBacksPropertySynthesis = true; 181 break; 182 } 183 } 184 if (!IvarBacksPropertySynthesis) 185 return false; 186 } 187 else 188 return false; 189 190 return isZero(BOE->getRHS()); 191 } 192 193 bool isZeroingPropIvar(PseudoObjectExpr *PO) { 194 BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm()); 195 if (!BO) return false; 196 if (BO->getOpcode() != BO_Assign) return false; 197 198 ObjCPropertyRefExpr *PropRefExp = 199 dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens()); 200 if (!PropRefExp) return false; 201 202 // TODO: Using implicit property decl. 203 if (PropRefExp->isImplicitProperty()) 204 return false; 205 206 if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { 207 if (!SynthesizedProperties.count(PDecl)) 208 return false; 209 } 210 211 return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr()); 212 } 213 214 bool isZero(Expr *E) { 215 if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull)) 216 return true; 217 218 return isZeroingPropIvar(E); 219 } 220 }; 221 222 } // anonymous namespace 223 224 void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) { 225 ZeroOutInDeallocRemover trans(pass); 226 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 227 } 228