1249423Sdim//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===//
2224135Sdim//
3224135Sdim//                     The LLVM Compiler Infrastructure
4224135Sdim//
5224135Sdim// This file is distributed under the University of Illinois Open Source
6224135Sdim// License. See LICENSE.TXT for details.
7224135Sdim//
8224135Sdim//===----------------------------------------------------------------------===//
9224135Sdim//
10224135Sdim// removeZeroOutPropsInDealloc:
11224135Sdim//
12224135Sdim// Removes zero'ing out "strong" @synthesized properties in a -dealloc method.
13224135Sdim//
14224135Sdim//===----------------------------------------------------------------------===//
15224135Sdim
16224135Sdim#include "Transforms.h"
17224135Sdim#include "Internals.h"
18239462Sdim#include "clang/AST/ASTContext.h"
19224135Sdim
20224135Sdimusing namespace clang;
21224135Sdimusing namespace arcmt;
22224135Sdimusing namespace trans;
23224135Sdim
24224135Sdimnamespace {
25224135Sdim
26224135Sdimclass ZeroOutInDeallocRemover :
27224135Sdim                           public RecursiveASTVisitor<ZeroOutInDeallocRemover> {
28224135Sdim  typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base;
29224135Sdim
30224135Sdim  MigrationPass &Pass;
31224135Sdim
32224135Sdim  llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;
33224135Sdim  ImplicitParamDecl *SelfD;
34224135Sdim  ExprSet Removables;
35234353Sdim  Selector FinalizeSel;
36224135Sdim
37224135Sdimpublic:
38234353Sdim  ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) {
39234353Sdim    FinalizeSel =
40234353Sdim        Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
41234353Sdim  }
42224135Sdim
43224135Sdim  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
44224135Sdim    ASTContext &Ctx = Pass.Ctx;
45224135Sdim    TransformActions &TA = Pass.TA;
46224135Sdim
47224135Sdim    if (ME->getReceiverKind() != ObjCMessageExpr::Instance)
48224135Sdim      return true;
49224135Sdim    Expr *receiver = ME->getInstanceReceiver();
50224135Sdim    if (!receiver)
51224135Sdim      return true;
52224135Sdim
53224135Sdim    DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());
54224135Sdim    if (!refE || refE->getDecl() != SelfD)
55224135Sdim      return true;
56224135Sdim
57224135Sdim    bool BackedBySynthesizeSetter = false;
58224135Sdim    for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
59224135Sdim         P = SynthesizedProperties.begin(),
60224135Sdim         E = SynthesizedProperties.end(); P != E; ++P) {
61224135Sdim      ObjCPropertyDecl *PropDecl = P->first;
62224135Sdim      if (PropDecl->getSetterName() == ME->getSelector()) {
63224135Sdim        BackedBySynthesizeSetter = true;
64224135Sdim        break;
65224135Sdim      }
66224135Sdim    }
67224135Sdim    if (!BackedBySynthesizeSetter)
68224135Sdim      return true;
69224135Sdim
70224135Sdim    // Remove the setter message if RHS is null
71224135Sdim    Transaction Trans(TA);
72224135Sdim    Expr *RHS = ME->getArg(0);
73224135Sdim    bool RHSIsNull =
74224135Sdim      RHS->isNullPointerConstant(Ctx,
75224135Sdim                                 Expr::NPC_ValueDependentIsNull);
76224135Sdim    if (RHSIsNull && isRemovable(ME))
77224135Sdim      TA.removeStmt(ME);
78224135Sdim
79224135Sdim    return true;
80224135Sdim  }
81224135Sdim
82234353Sdim  bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
83234353Sdim    if (isZeroingPropIvar(POE) && isRemovable(POE)) {
84234353Sdim      Transaction Trans(Pass.TA);
85234353Sdim      Pass.TA.removeStmt(POE);
86234353Sdim    }
87234353Sdim
88234353Sdim    return true;
89234353Sdim  }
90234353Sdim
91224135Sdim  bool VisitBinaryOperator(BinaryOperator *BOE) {
92224135Sdim    if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
93224135Sdim      Transaction Trans(Pass.TA);
94224135Sdim      Pass.TA.removeStmt(BOE);
95224135Sdim    }
96224135Sdim
97224135Sdim    return true;
98224135Sdim  }
99224135Sdim
100224135Sdim  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
101234353Sdim    if (D->getMethodFamily() != OMF_dealloc &&
102234353Sdim        !(D->isInstanceMethod() && D->getSelector() == FinalizeSel))
103224135Sdim      return true;
104224135Sdim    if (!D->hasBody())
105224135Sdim      return true;
106224135Sdim
107224135Sdim    ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());
108224135Sdim    if (!IMD)
109224135Sdim      return true;
110224135Sdim
111224135Sdim    SelfD = D->getSelfDecl();
112224135Sdim    collectRemovables(D->getBody(), Removables);
113224135Sdim
114224135Sdim    // For a 'dealloc' method use, find all property implementations in
115224135Sdim    // this class implementation.
116224135Sdim    for (ObjCImplDecl::propimpl_iterator
117224135Sdim           I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) {
118224135Sdim        ObjCPropertyImplDecl *PID = *I;
119224135Sdim        if (PID->getPropertyImplementation() ==
120224135Sdim            ObjCPropertyImplDecl::Synthesize) {
121224135Sdim          ObjCPropertyDecl *PD = PID->getPropertyDecl();
122224135Sdim          ObjCMethodDecl *setterM = PD->getSetterMethodDecl();
123224135Sdim          if (!(setterM && setterM->isDefined())) {
124224135Sdim            ObjCPropertyDecl::PropertyAttributeKind AttrKind =
125224135Sdim              PD->getPropertyAttributes();
126224135Sdim              if (AttrKind &
127224135Sdim                  (ObjCPropertyDecl::OBJC_PR_retain |
128224135Sdim                   ObjCPropertyDecl::OBJC_PR_copy   |
129224135Sdim                   ObjCPropertyDecl::OBJC_PR_strong))
130224135Sdim                SynthesizedProperties[PD] = PID;
131224135Sdim          }
132224135Sdim        }
133224135Sdim    }
134224135Sdim
135224135Sdim    // Now, remove all zeroing of ivars etc.
136224135Sdim    base::TraverseObjCMethodDecl(D);
137224135Sdim
138224135Sdim    // clear out for next method.
139224135Sdim    SynthesizedProperties.clear();
140224135Sdim    SelfD = 0;
141224135Sdim    Removables.clear();
142224135Sdim    return true;
143224135Sdim  }
144224135Sdim
145224135Sdim  bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
146224135Sdim  bool TraverseBlockDecl(BlockDecl *block) { return true; }
147224135Sdim  bool TraverseBlockExpr(BlockExpr *block) { return true; }
148224135Sdim
149224135Sdimprivate:
150224135Sdim  bool isRemovable(Expr *E) const {
151224135Sdim    return Removables.count(E);
152224135Sdim  }
153224135Sdim
154224135Sdim  bool isZeroingPropIvar(Expr *E) {
155234353Sdim    E = E->IgnoreParens();
156234353Sdim    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
157234353Sdim      return isZeroingPropIvar(BO);
158234353Sdim    if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))
159234353Sdim      return isZeroingPropIvar(PO);
160234353Sdim    return false;
161234353Sdim  }
162224135Sdim
163234353Sdim  bool isZeroingPropIvar(BinaryOperator *BOE) {
164224135Sdim    if (BOE->getOpcode() == BO_Comma)
165224135Sdim      return isZeroingPropIvar(BOE->getLHS()) &&
166224135Sdim             isZeroingPropIvar(BOE->getRHS());
167224135Sdim
168224135Sdim    if (BOE->getOpcode() != BO_Assign)
169234353Sdim      return false;
170224135Sdim
171224135Sdim    Expr *LHS = BOE->getLHS();
172224135Sdim    if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
173224135Sdim      ObjCIvarDecl *IVDecl = IV->getDecl();
174224135Sdim      if (!IVDecl->getType()->isObjCObjectPointerType())
175224135Sdim        return false;
176224135Sdim      bool IvarBacksPropertySynthesis = false;
177224135Sdim      for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
178224135Sdim           P = SynthesizedProperties.begin(),
179224135Sdim           E = SynthesizedProperties.end(); P != E; ++P) {
180224135Sdim        ObjCPropertyImplDecl *PropImpDecl = P->second;
181224135Sdim        if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {
182224135Sdim          IvarBacksPropertySynthesis = true;
183224135Sdim          break;
184224135Sdim        }
185224135Sdim      }
186224135Sdim      if (!IvarBacksPropertySynthesis)
187224135Sdim        return false;
188224135Sdim    }
189224135Sdim    else
190224135Sdim        return false;
191224135Sdim
192234353Sdim    return isZero(BOE->getRHS());
193234353Sdim  }
194234353Sdim
195234353Sdim  bool isZeroingPropIvar(PseudoObjectExpr *PO) {
196234353Sdim    BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());
197234353Sdim    if (!BO) return false;
198234353Sdim    if (BO->getOpcode() != BO_Assign) return false;
199234353Sdim
200234353Sdim    ObjCPropertyRefExpr *PropRefExp =
201234353Sdim      dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());
202234353Sdim    if (!PropRefExp) return false;
203234353Sdim
204234353Sdim    // TODO: Using implicit property decl.
205234353Sdim    if (PropRefExp->isImplicitProperty())
206234353Sdim      return false;
207234353Sdim
208234353Sdim    if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
209234353Sdim      if (!SynthesizedProperties.count(PDecl))
210234353Sdim        return false;
211234353Sdim    }
212234353Sdim
213234353Sdim    return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());
214234353Sdim  }
215234353Sdim
216234353Sdim  bool isZero(Expr *E) {
217234353Sdim    if (E->isNullPointerConstant(Pass.Ctx, Expr::NPC_ValueDependentIsNull))
218224135Sdim      return true;
219224135Sdim
220234353Sdim    return isZeroingPropIvar(E);
221224135Sdim  }
222224135Sdim};
223224135Sdim
224224135Sdim} // anonymous namespace
225224135Sdim
226234353Sdimvoid trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) {
227224135Sdim  ZeroOutInDeallocRemover trans(pass);
228224135Sdim  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
229224135Sdim}
230