Clang Project

clang_source_code/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
1//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// removeZeroOutPropsInDealloc:
10//
11// Removes zero'ing out "strong" @synthesized properties in a -dealloc method.
12//
13//===----------------------------------------------------------------------===//
14
15#include "Transforms.h"
16#include "Internals.h"
17#include "clang/AST/ASTContext.h"
18
19using namespace clang;
20using namespace arcmt;
21using namespace trans;
22
23namespace {
24
25class ZeroOutInDeallocRemover :
26                           public RecursiveASTVisitor<ZeroOutInDeallocRemover> {
27  typedef RecursiveASTVisitor<ZeroOutInDeallocRemoverbase;
28
29  MigrationPass &Pass;
30
31  llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;
32  ImplicitParamDecl *SelfD;
33  ExprSet Removables;
34  Selector FinalizeSel;
35
36public:
37  ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(nullptr) {
38    FinalizeSel =
39        Pass.Ctx.Selectors.getNullarySelector(&Pass.Ctx.Idents.get("finalize"));
40  }
41
42  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
43    ASTContext &Ctx = Pass.Ctx;
44    TransformActions &TA = Pass.TA;
45
46    if (ME->getReceiverKind() != ObjCMessageExpr::Instance)
47      return true;
48    Expr *receiver = ME->getInstanceReceiver();
49    if (!receiver)
50      return true;
51
52    DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());
53    if (!refE || refE->getDecl() != SelfD)
54      return true;
55
56    bool BackedBySynthesizeSetter = false;
57    for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
58         P = SynthesizedProperties.begin(),
59         E = SynthesizedProperties.end(); P != E; ++P) {
60      ObjCPropertyDecl *PropDecl = P->first;
61      if (PropDecl->getSetterName() == ME->getSelector()) {
62        BackedBySynthesizeSetter = true;
63        break;
64      }
65    }
66    if (!BackedBySynthesizeSetter)
67      return true;
68
69    // Remove the setter message if RHS is null
70    Transaction Trans(TA);
71    Expr *RHS = ME->getArg(0);
72    bool RHSIsNull =
73      RHS->isNullPointerConstant(Ctx,
74                                 Expr::NPC_ValueDependentIsNull);
75    if (RHSIsNull && isRemovable(ME))
76      TA.removeStmt(ME);
77
78    return true;
79  }
80
81  bool VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
82    if (isZeroingPropIvar(POE) && isRemovable(POE)) {
83      Transaction Trans(Pass.TA);
84      Pass.TA.removeStmt(POE);
85    }
86
87    return true;
88  }
89
90  bool VisitBinaryOperator(BinaryOperator *BOE) {
91    if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
92      Transaction Trans(Pass.TA);
93      Pass.TA.removeStmt(BOE);
94    }
95
96    return true;
97  }
98
99  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
100    if (D->getMethodFamily() != OMF_dealloc &&
101        !(D->isInstanceMethod() && D->getSelector() == FinalizeSel))
102      return true;
103    if (!D->hasBody())
104      return true;
105
106    ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());
107    if (!IMD)
108      return true;
109
110    SelfD = D->getSelfDecl();
111    collectRemovables(D->getBody(), Removables);
112
113    // For a 'dealloc' method use, find all property implementations in
114    // this class implementation.
115    for (auto *PID : IMD->property_impls()) {
116      if (PID->getPropertyImplementation() ==
117          ObjCPropertyImplDecl::Synthesize) {
118        ObjCPropertyDecl *PD = PID->getPropertyDecl();
119        ObjCMethodDecl *setterM = PD->getSetterMethodDecl();
120        if (!(setterM && setterM->isDefined())) {
121          ObjCPropertyDecl::PropertyAttributeKind AttrKind =
122            PD->getPropertyAttributes();
123            if (AttrKind &
124                (ObjCPropertyDecl::OBJC_PR_retain |
125                  ObjCPropertyDecl::OBJC_PR_copy   |
126                  ObjCPropertyDecl::OBJC_PR_strong))
127              SynthesizedProperties[PD] = PID;
128        }
129      }
130    }
131
132    // Now, remove all zeroing of ivars etc.
133    base::TraverseObjCMethodDecl(D);
134
135    // clear out for next method.
136    SynthesizedProperties.clear();
137    SelfD = nullptr;
138    Removables.clear();
139    return true;
140  }
141
142  bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
143  bool TraverseBlockDecl(BlockDecl *block) { return true; }
144  bool TraverseBlockExpr(BlockExpr *block) { return true; }
145
146private:
147  bool isRemovable(Expr *Econst {
148    return Removables.count(E);
149  }
150
151  bool isZeroingPropIvar(Expr *E) {
152    E = E->IgnoreParens();
153    if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
154      return isZeroingPropIvar(BO);
155    if (PseudoObjectExpr *PO = dyn_cast<PseudoObjectExpr>(E))
156      return isZeroingPropIvar(PO);
157    return false;
158  }
159
160  bool isZeroingPropIvar(BinaryOperator *BOE) {
161    if (BOE->getOpcode() == BO_Comma)
162      return isZeroingPropIvar(BOE->getLHS()) &&
163             isZeroingPropIvar(BOE->getRHS());
164
165    if (BOE->getOpcode() != BO_Assign)
166      return false;
167
168    Expr *LHS = BOE->getLHS();
169    if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
170      ObjCIvarDecl *IVDecl = IV->getDecl();
171      if (!IVDecl->getType()->isObjCObjectPointerType())
172        return false;
173      bool IvarBacksPropertySynthesis = false;
174      for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
175           P = SynthesizedProperties.begin(),
176           E = SynthesizedProperties.end(); P != E; ++P) {
177        ObjCPropertyImplDecl *PropImpDecl = P->second;
178        if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {
179          IvarBacksPropertySynthesis = true;
180          break;
181        }
182      }
183      if (!IvarBacksPropertySynthesis)
184        return false;
185    }
186    else
187        return false;
188
189    return isZero(BOE->getRHS());
190  }
191
192  bool isZeroingPropIvar(PseudoObjectExpr *PO) {
193    BinaryOperator *BO = dyn_cast<BinaryOperator>(PO->getSyntacticForm());
194    if (!BOreturn false;
195    if (BO->getOpcode() != BO_Assignreturn false;
196
197    ObjCPropertyRefExpr *PropRefExp =
198      dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParens());
199    if (!PropRefExpreturn false;
200
201    // TODO: Using implicit property decl.
202    if (PropRefExp->isImplicitProperty())
203      return false;
204
205    if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
206      if (!SynthesizedProperties.count(PDecl))
207        return false;
208    }
209
210    return isZero(cast<OpaqueValueExpr>(BO->getRHS())->getSourceExpr());
211  }
212
213  bool isZero(Expr *E) {
214    if (E->isNullPointerConstant(Pass.CtxExpr::NPC_ValueDependentIsNull))
215      return true;
216
217    return isZeroingPropIvar(E);
218  }
219};
220
221// anonymous namespace
222
223void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass &pass) {
224  ZeroOutInDeallocRemover trans(pass);
225  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
226}
227