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