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