Home | History | Annotate | Download | only in ARCMigrate
      1 //===--- TransZeroOutPropsInDealloc.cpp - Tranformations 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 
     19 using namespace clang;
     20 using namespace arcmt;
     21 using namespace trans;
     22 using llvm::StringRef;
     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 
     36 public:
     37   ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { }
     38 
     39   bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
     40     ASTContext &Ctx = Pass.Ctx;
     41     TransformActions &TA = Pass.TA;
     42 
     43     if (ME->getReceiverKind() != ObjCMessageExpr::Instance)
     44       return true;
     45     Expr *receiver = ME->getInstanceReceiver();
     46     if (!receiver)
     47       return true;
     48 
     49     DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());
     50     if (!refE || refE->getDecl() != SelfD)
     51       return true;
     52 
     53     bool BackedBySynthesizeSetter = false;
     54     for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
     55          P = SynthesizedProperties.begin(),
     56          E = SynthesizedProperties.end(); P != E; ++P) {
     57       ObjCPropertyDecl *PropDecl = P->first;
     58       if (PropDecl->getSetterName() == ME->getSelector()) {
     59         BackedBySynthesizeSetter = true;
     60         break;
     61       }
     62     }
     63     if (!BackedBySynthesizeSetter)
     64       return true;
     65 
     66     // Remove the setter message if RHS is null
     67     Transaction Trans(TA);
     68     Expr *RHS = ME->getArg(0);
     69     bool RHSIsNull =
     70       RHS->isNullPointerConstant(Ctx,
     71                                  Expr::NPC_ValueDependentIsNull);
     72     if (RHSIsNull && isRemovable(ME))
     73       TA.removeStmt(ME);
     74 
     75     return true;
     76   }
     77 
     78   bool VisitBinaryOperator(BinaryOperator *BOE) {
     79     if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
     80       Transaction Trans(Pass.TA);
     81       Pass.TA.removeStmt(BOE);
     82     }
     83 
     84     return true;
     85   }
     86 
     87   bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
     88     if (D->getMethodFamily() != OMF_dealloc)
     89       return true;
     90     if (!D->hasBody())
     91       return true;
     92 
     93     ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());
     94     if (!IMD)
     95       return true;
     96 
     97     SelfD = D->getSelfDecl();
     98     collectRemovables(D->getBody(), Removables);
     99 
    100     // For a 'dealloc' method use, find all property implementations in
    101     // this class implementation.
    102     for (ObjCImplDecl::propimpl_iterator
    103            I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) {
    104         ObjCPropertyImplDecl *PID = *I;
    105         if (PID->getPropertyImplementation() ==
    106             ObjCPropertyImplDecl::Synthesize) {
    107           ObjCPropertyDecl *PD = PID->getPropertyDecl();
    108           ObjCMethodDecl *setterM = PD->getSetterMethodDecl();
    109           if (!(setterM && setterM->isDefined())) {
    110             ObjCPropertyDecl::PropertyAttributeKind AttrKind =
    111               PD->getPropertyAttributes();
    112               if (AttrKind &
    113                   (ObjCPropertyDecl::OBJC_PR_retain |
    114                    ObjCPropertyDecl::OBJC_PR_copy   |
    115                    ObjCPropertyDecl::OBJC_PR_strong))
    116                 SynthesizedProperties[PD] = PID;
    117           }
    118         }
    119     }
    120 
    121     // Now, remove all zeroing of ivars etc.
    122     base::TraverseObjCMethodDecl(D);
    123 
    124     // clear out for next method.
    125     SynthesizedProperties.clear();
    126     SelfD = 0;
    127     Removables.clear();
    128     return true;
    129   }
    130 
    131   bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
    132   bool TraverseBlockDecl(BlockDecl *block) { return true; }
    133   bool TraverseBlockExpr(BlockExpr *block) { return true; }
    134 
    135 private:
    136   bool isRemovable(Expr *E) const {
    137     return Removables.count(E);
    138   }
    139 
    140   bool isZeroingPropIvar(Expr *E) {
    141     BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
    142     if (!BOE) return false;
    143 
    144     if (BOE->getOpcode() == BO_Comma)
    145       return isZeroingPropIvar(BOE->getLHS()) &&
    146              isZeroingPropIvar(BOE->getRHS());
    147 
    148     if (BOE->getOpcode() != BO_Assign)
    149         return false;
    150 
    151     ASTContext &Ctx = Pass.Ctx;
    152 
    153     Expr *LHS = BOE->getLHS();
    154     if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
    155       ObjCIvarDecl *IVDecl = IV->getDecl();
    156       if (!IVDecl->getType()->isObjCObjectPointerType())
    157         return false;
    158       bool IvarBacksPropertySynthesis = false;
    159       for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
    160            P = SynthesizedProperties.begin(),
    161            E = SynthesizedProperties.end(); P != E; ++P) {
    162         ObjCPropertyImplDecl *PropImpDecl = P->second;
    163         if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {
    164           IvarBacksPropertySynthesis = true;
    165           break;
    166         }
    167       }
    168       if (!IvarBacksPropertySynthesis)
    169         return false;
    170     }
    171     else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
    172       // TODO: Using implicit property decl.
    173       if (PropRefExp->isImplicitProperty())
    174         return false;
    175       if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
    176         if (!SynthesizedProperties.count(PDecl))
    177           return false;
    178       }
    179     }
    180     else
    181         return false;
    182 
    183     Expr *RHS = BOE->getRHS();
    184     bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
    185                                                 Expr::NPC_ValueDependentIsNull);
    186     if (RHSIsNull)
    187       return true;
    188 
    189     return isZeroingPropIvar(RHS);
    190   }
    191 };
    192 
    193 } // anonymous namespace
    194 
    195 void trans::removeZeroOutPropsInDealloc(MigrationPass &pass) {
    196   ZeroOutInDeallocRemover trans(pass);
    197   trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
    198 }
    199