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