xref: /openbsd-src/gnu/llvm/clang/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
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