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