blob: 07ccf70d4dfb76abc453154d9e97c7f464f5c786 [file] [log] [blame]
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +00001//===--- 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
19using namespace clang;
20using namespace arcmt;
21using namespace trans;
22using llvm::StringRef;
23
24namespace {
25
26class 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
36public:
37 ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { }
38
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
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
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
131 bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
132 bool TraverseBlockDecl(BlockDecl *block) { return true; }
133 bool TraverseBlockExpr(BlockExpr *block) { return true; }
134
135private:
136 bool isRemovable(Expr *E) const {
137 return Removables.count(E);
138 }
139
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
195void trans::removeZeroOutPropsInDealloc(MigrationPass &pass) {
196 ZeroOutInDeallocRemover trans(pass);
197 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
198}