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