clang API Documentation

TransZeroOutPropsInDealloc.cpp
Go to the documentation of this file.
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 }