clang API Documentation
00001 //===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // removeZeroOutPropsInDealloc: 00011 // 00012 // Removes zero'ing out "strong" @synthesized properties in a -dealloc method. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "Transforms.h" 00017 #include "Internals.h" 00018 00019 using namespace clang; 00020 using namespace arcmt; 00021 using namespace trans; 00022 00023 namespace { 00024 00025 class ZeroOutInDeallocRemover : 00026 public RecursiveASTVisitor<ZeroOutInDeallocRemover> { 00027 typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base; 00028 00029 MigrationPass &Pass; 00030 00031 llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties; 00032 ImplicitParamDecl *SelfD; 00033 ExprSet Removables; 00034 Selector FinalizeSel; 00035 00036 public: 00037 ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { 00038 FinalizeSel = 00039 Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize")); 00040 } 00041 00042 bool VisitObjCMessageExpr(ObjCMessageExpr *ME) { 00043 ASTContext &Ctx = Pass.Ctx; 00044 TransformActions &TA = Pass.TA; 00045 00046 if (ME->getReceiverKind() != ObjCMessageExpr::Instance) 00047 return true; 00048 Expr *receiver = ME->getInstanceReceiver(); 00049 if (!receiver) 00050 return true; 00051 00052 DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts()); 00053 if (!refE || refE->getDecl() != SelfD) 00054 return true; 00055 00056 bool BackedBySynthesizeSetter = false; 00057 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 00058 P = SynthesizedProperties.begin(), 00059 E = SynthesizedProperties.end(); P != E; ++P) { 00060 ObjCPropertyDecl *PropDecl = P->first; 00061 if (PropDecl->getSetterName() == ME->getSelector()) { 00062 BackedBySynthesizeSetter = true; 00063 break; 00064 } 00065 } 00066 if (!BackedBySynthesizeSetter) 00067 return true; 00068 00069 // Remove the setter message if RHS is null 00070 Transaction Trans(TA); 00071 Expr *RHS = ME->getArg(0); 00072 bool RHSIsNull = 00073 RHS->isNullPointerConstant(Ctx, 00074 Expr::NPC_ValueDependentIsNull); 00075 if (RHSIsNull && isRemovable(ME)) 00076 TA.removeStmt(ME); 00077 00078 return true; 00079 } 00080 00081 bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) { 00082 if (isZeroingPropIvar(POE) && isRemovable(POE)) { 00083 Transaction Trans(Pass.TA); 00084 Pass.TA.removeStmt(POE); 00085 } 00086 00087 return true; 00088 } 00089 00090 bool VisitBinaryOperator(BinaryOperator *BOE) { 00091 if (isZeroingPropIvar(BOE) && isRemovable(BOE)) { 00092 Transaction Trans(Pass.TA); 00093 Pass.TA.removeStmt(BOE); 00094 } 00095 00096 return true; 00097 } 00098 00099 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) { 00100 if (D->getMethodFamily() != OMF_dealloc && 00101 !(D->isInstanceMethod() && D->getSelector() == FinalizeSel)) 00102 return true; 00103 if (!D->hasBody()) 00104 return true; 00105 00106 ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext()); 00107 if (!IMD) 00108 return true; 00109 00110 SelfD = D->getSelfDecl(); 00111 collectRemovables(D->getBody(), Removables); 00112 00113 // For a 'dealloc' method use, find all property implementations in 00114 // this class implementation. 00115 for (ObjCImplDecl::propimpl_iterator 00116 I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) { 00117 ObjCPropertyImplDecl *PID = &*I; 00118 if (PID->getPropertyImplementation() == 00119 ObjCPropertyImplDecl::Synthesize) { 00120 ObjCPropertyDecl *PD = PID->getPropertyDecl(); 00121 ObjCMethodDecl *setterM = PD->getSetterMethodDecl(); 00122 if (!(setterM && setterM->isDefined())) { 00123 ObjCPropertyDecl::PropertyAttributeKind AttrKind = 00124 PD->getPropertyAttributes(); 00125 if (AttrKind & 00126 (ObjCPropertyDecl::OBJC_PR_retain | 00127 ObjCPropertyDecl::OBJC_PR_copy | 00128 ObjCPropertyDecl::OBJC_PR_strong)) 00129 SynthesizedProperties[PD] = PID; 00130 } 00131 } 00132 } 00133 00134 // Now, remove all zeroing of ivars etc. 00135 base::TraverseObjCMethodDecl(D); 00136 00137 // clear out for next method. 00138 SynthesizedProperties.clear(); 00139 SelfD = 0; 00140 Removables.clear(); 00141 return true; 00142 } 00143 00144 bool TraverseFunctionDecl(FunctionDecl *D) { return true; } 00145 bool TraverseBlockDecl(BlockDecl *block) { return true; } 00146 bool TraverseBlockExpr(BlockExpr *block) { return true; } 00147 00148 private: 00149 bool isRemovable(Expr *E) const { 00150 return Removables.count(E); 00151 } 00152 00153 bool isZeroingPropIvar(Expr *E) { 00154 E = E->IgnoreParens(); 00155 if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) 00156 return isZeroingPropIvar(BO); 00157 if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E)) 00158 return isZeroingPropIvar(PO); 00159 return false; 00160 } 00161 00162 bool isZeroingPropIvar(BinaryOperator *BOE) { 00163 if (BOE->getOpcode() == BO_Comma) 00164 return isZeroingPropIvar(BOE->getLHS()) && 00165 isZeroingPropIvar(BOE->getRHS()); 00166 00167 if (BOE->getOpcode() != BO_Assign) 00168 return false; 00169 00170 Expr *LHS = BOE->getLHS(); 00171 if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) { 00172 ObjCIvarDecl *IVDecl = IV->getDecl(); 00173 if (!IVDecl->getType()->isObjCObjectPointerType()) 00174 return false; 00175 bool IvarBacksPropertySynthesis = false; 00176 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator 00177 P = SynthesizedProperties.begin(), 00178 E = SynthesizedProperties.end(); P != E; ++P) { 00179 ObjCPropertyImplDecl *PropImpDecl = P->second; 00180 if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) { 00181 IvarBacksPropertySynthesis = true; 00182 break; 00183 } 00184 } 00185 if (!IvarBacksPropertySynthesis) 00186 return false; 00187 } 00188 else 00189 return false; 00190 00191 return isZero(BOE->getRHS()); 00192 } 00193 00194 bool isZeroingPropIvar(PseudoObjectExpr *PO) { 00195 BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm()); 00196 if (!BO) return false; 00197 if (BO->getOpcode() != BO_Assign) return false; 00198 00199 ObjCPropertyRefExpr *PropRefExp = 00200 dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens()); 00201 if (!PropRefExp) return false; 00202 00203 // TODO: Using implicit property decl. 00204 if (PropRefExp->isImplicitProperty()) 00205 return false; 00206 00207 if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) { 00208 if (!SynthesizedProperties.count(PDecl)) 00209 return false; 00210 } 00211 00212 return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr()); 00213 } 00214 00215 bool isZero(Expr *E) { 00216 if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull)) 00217 return true; 00218 00219 return isZeroingPropIvar(E); 00220 } 00221 }; 00222 00223 } // anonymous namespace 00224 00225 void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) { 00226 ZeroOutInDeallocRemover trans(pass); 00227 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); 00228 }