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