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