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