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