1 //===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===//
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
7 //===----------------------------------------------------------------------===//
9 // removeZeroOutPropsInDealloc:
11 // Removes zero'ing out "strong" @synthesized properties in a -dealloc method.
13 //===----------------------------------------------------------------------===//
15 #include "Transforms.h"
16 #include "Internals.h"
17 #include "clang/AST/ASTContext.h"
19 using namespace clang
;
20 using namespace arcmt
;
21 using namespace trans
;
25 class ZeroOutInDeallocRemover
:
26 public RecursiveASTVisitor
<ZeroOutInDeallocRemover
> {
27 typedef RecursiveASTVisitor
<ZeroOutInDeallocRemover
> base
;
31 llvm::DenseMap
<ObjCPropertyDecl
*, ObjCPropertyImplDecl
*> SynthesizedProperties
;
32 ImplicitParamDecl
*SelfD
;
37 ZeroOutInDeallocRemover(MigrationPass
&pass
) : Pass(pass
), SelfD(nullptr) {
39 Pass
.Ctx
.Selectors
.getNullarySelector(&Pass
.Ctx
.Idents
.get("finalize"));
42 bool VisitObjCMessageExpr(ObjCMessageExpr
*ME
) {
43 ASTContext
&Ctx
= Pass
.Ctx
;
44 TransformActions
&TA
= Pass
.TA
;
46 if (ME
->getReceiverKind() != ObjCMessageExpr::Instance
)
48 Expr
*receiver
= ME
->getInstanceReceiver();
52 DeclRefExpr
*refE
= dyn_cast
<DeclRefExpr
>(receiver
->IgnoreParenCasts());
53 if (!refE
|| refE
->getDecl() != SelfD
)
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;
66 if (!BackedBySynthesizeSetter
)
69 // Remove the setter message if RHS is null
70 Transaction
Trans(TA
);
71 Expr
*RHS
= ME
->getArg(0);
73 RHS
->isNullPointerConstant(Ctx
,
74 Expr::NPC_ValueDependentIsNull
);
75 if (RHSIsNull
&& isRemovable(ME
))
81 bool VisitPseudoObjectExpr(PseudoObjectExpr
*POE
) {
82 if (isZeroingPropIvar(POE
) && isRemovable(POE
)) {
83 Transaction
Trans(Pass
.TA
);
84 Pass
.TA
.removeStmt(POE
);
90 bool VisitBinaryOperator(BinaryOperator
*BOE
) {
91 if (isZeroingPropIvar(BOE
) && isRemovable(BOE
)) {
92 Transaction
Trans(Pass
.TA
);
93 Pass
.TA
.removeStmt(BOE
);
99 bool TraverseObjCMethodDecl(ObjCMethodDecl
*D
) {
100 if (D
->getMethodFamily() != OMF_dealloc
&&
101 !(D
->isInstanceMethod() && D
->getSelector() == FinalizeSel
))
106 ObjCImplDecl
*IMD
= dyn_cast
<ObjCImplDecl
>(D
->getDeclContext());
110 SelfD
= D
->getSelfDecl();
111 collectRemovables(D
->getBody(), Removables
);
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 ObjCPropertyAttribute::Kind AttrKind
= PD
->getPropertyAttributes();
122 if (AttrKind
& (ObjCPropertyAttribute::kind_retain
|
123 ObjCPropertyAttribute::kind_copy
|
124 ObjCPropertyAttribute::kind_strong
))
125 SynthesizedProperties
[PD
] = PID
;
130 // Now, remove all zeroing of ivars etc.
131 base::TraverseObjCMethodDecl(D
);
133 // clear out for next method.
134 SynthesizedProperties
.clear();
140 bool TraverseFunctionDecl(FunctionDecl
*D
) { return true; }
141 bool TraverseBlockDecl(BlockDecl
*block
) { return true; }
142 bool TraverseBlockExpr(BlockExpr
*block
) { return true; }
145 bool isRemovable(Expr
*E
) const {
146 return Removables
.count(E
);
149 bool isZeroingPropIvar(Expr
*E
) {
150 E
= E
->IgnoreParens();
151 if (BinaryOperator
*BO
= dyn_cast
<BinaryOperator
>(E
))
152 return isZeroingPropIvar(BO
);
153 if (PseudoObjectExpr
*PO
= dyn_cast
<PseudoObjectExpr
>(E
))
154 return isZeroingPropIvar(PO
);
158 bool isZeroingPropIvar(BinaryOperator
*BOE
) {
159 if (BOE
->getOpcode() == BO_Comma
)
160 return isZeroingPropIvar(BOE
->getLHS()) &&
161 isZeroingPropIvar(BOE
->getRHS());
163 if (BOE
->getOpcode() != BO_Assign
)
166 Expr
*LHS
= BOE
->getLHS();
167 if (ObjCIvarRefExpr
*IV
= dyn_cast
<ObjCIvarRefExpr
>(LHS
)) {
168 ObjCIvarDecl
*IVDecl
= IV
->getDecl();
169 if (!IVDecl
->getType()->isObjCObjectPointerType())
171 bool IvarBacksPropertySynthesis
= false;
172 for (llvm::DenseMap
<ObjCPropertyDecl
*, ObjCPropertyImplDecl
*>::iterator
173 P
= SynthesizedProperties
.begin(),
174 E
= SynthesizedProperties
.end(); P
!= E
; ++P
) {
175 ObjCPropertyImplDecl
*PropImpDecl
= P
->second
;
176 if (PropImpDecl
&& PropImpDecl
->getPropertyIvarDecl() == IVDecl
) {
177 IvarBacksPropertySynthesis
= true;
181 if (!IvarBacksPropertySynthesis
)
187 return isZero(BOE
->getRHS());
190 bool isZeroingPropIvar(PseudoObjectExpr
*PO
) {
191 BinaryOperator
*BO
= dyn_cast
<BinaryOperator
>(PO
->getSyntacticForm());
192 if (!BO
) return false;
193 if (BO
->getOpcode() != BO_Assign
) return false;
195 ObjCPropertyRefExpr
*PropRefExp
=
196 dyn_cast
<ObjCPropertyRefExpr
>(BO
->getLHS()->IgnoreParens());
197 if (!PropRefExp
) return false;
199 // TODO: Using implicit property decl.
200 if (PropRefExp
->isImplicitProperty())
203 if (ObjCPropertyDecl
*PDecl
= PropRefExp
->getExplicitProperty()) {
204 if (!SynthesizedProperties
.count(PDecl
))
208 return isZero(cast
<OpaqueValueExpr
>(BO
->getRHS())->getSourceExpr());
211 bool isZero(Expr
*E
) {
212 if (E
->isNullPointerConstant(Pass
.Ctx
, Expr::NPC_ValueDependentIsNull
))
215 return isZeroingPropIvar(E
);
219 } // anonymous namespace
221 void trans::removeZeroOutPropsInDeallocFinalize(MigrationPass
&pass
) {
222 ZeroOutInDeallocRemover
trans(pass
);
223 trans
.TraverseDecl(pass
.Ctx
.getTranslationUnitDecl());