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