blob: 85eb156935c547b98916ea62657c63b74f8c2efc [file] [log] [blame]
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +00001//===--- TransProperties.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//
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000010// rewriteProperties:
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000011//
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000012// - Adds strong/weak/unsafe_unretained ownership specifier to properties that
13// are missing one.
14// - Migrates properties from (retain) to (strong) and (assign) to
15// (unsafe_unretained/weak).
16// - If a property is synthesized, adds the ownership specifier in the ivar
17// backing the property.
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000018//
19// @interface Foo : NSObject {
20// NSObject *x;
21// }
22// @property (assign) id x;
23// @end
24// ---->
25// @interface Foo : NSObject {
26// NSObject *__weak x;
27// }
28// @property (weak) id x;
29// @end
30//
31//===----------------------------------------------------------------------===//
32
33#include "Transforms.h"
34#include "Internals.h"
35#include "clang/Sema/SemaDiagnostic.h"
36#include "clang/Basic/SourceManager.h"
37#include "clang/Lex/Lexer.h"
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000038#include <map>
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000039
40using namespace clang;
41using namespace arcmt;
42using namespace trans;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000043
44namespace {
45
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000046class PropertiesRewriter {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000047 MigrationPass &Pass;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000048 ObjCImplementationDecl *CurImplD;
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000049
50 enum PropActionKind {
51 PropAction_None,
52 PropAction_RetainToStrong,
53 PropAction_RetainRemoved,
54 PropAction_AssignToStrong,
55 PropAction_AssignRewritten,
56 PropAction_MaybeAddStrong,
57 PropAction_MaybeAddWeakOrUnsafe
58 };
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000059
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000060 struct PropData {
61 ObjCPropertyDecl *PropD;
62 ObjCIvarDecl *IvarD;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000063 ObjCPropertyImplDecl *ImplD;
64
65 PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000066 };
67
Chris Lattner0e62c1c2011-07-23 10:55:15 +000068 typedef SmallVector<PropData, 2> PropsTy;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000069 typedef std::map<unsigned, PropsTy> AtPropDeclsTy;
70 AtPropDeclsTy AtProps;
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000071 llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000072
73public:
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000074 PropertiesRewriter(MigrationPass &pass) : Pass(pass) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000075
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000076 static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps) {
77 for (ObjCInterfaceDecl::prop_iterator
78 propI = D->prop_begin(),
79 propE = D->prop_end(); propI != propE; ++propI) {
80 if (propI->getAtLoc().isInvalid())
81 continue;
82 PropsTy &props = AtProps[propI->getAtLoc().getRawEncoding()];
83 props.push_back(*propI);
84 }
85 }
86
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000087 void doTransform(ObjCImplementationDecl *D) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000088 CurImplD = D;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000089 ObjCInterfaceDecl *iface = D->getClassInterface();
90 if (!iface)
91 return;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000092
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000093 collectProperties(iface, AtProps);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000094
95 typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
96 prop_impl_iterator;
97 for (prop_impl_iterator
98 I = prop_impl_iterator(D->decls_begin()),
99 E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000100 ObjCPropertyImplDecl *implD = *I;
101 if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
102 continue;
103 ObjCPropertyDecl *propD = implD->getPropertyDecl();
104 if (!propD || propD->isInvalidDecl())
105 continue;
106 ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
107 if (!ivarD || ivarD->isInvalidDecl())
108 continue;
109 unsigned rawAtLoc = propD->getAtLoc().getRawEncoding();
110 AtPropDeclsTy::iterator findAtLoc = AtProps.find(rawAtLoc);
111 if (findAtLoc == AtProps.end())
112 continue;
113
114 PropsTy &props = findAtLoc->second;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000115 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
116 if (I->PropD == propD) {
117 I->IvarD = ivarD;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000118 I->ImplD = implD;
119 break;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000120 }
121 }
122 }
123
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000124 for (AtPropDeclsTy::iterator
125 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
126 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
127 PropsTy &props = I->second;
128 QualType ty = getPropertyType(props);
129 if (!ty->isObjCRetainableType())
130 continue;
131 if (hasIvarWithExplicitOwnership(props))
132 continue;
133
134 Transaction Trans(Pass.TA);
135 rewriteProperty(props, atLoc);
136 }
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000137
138 AtPropDeclsTy AtExtProps;
139 // Look through extensions.
140 for (ObjCCategoryDecl *Cat = iface->getCategoryList();
141 Cat; Cat = Cat->getNextClassCategory())
142 if (Cat->IsClassExtension())
143 collectProperties(Cat, AtExtProps);
144
145 for (AtPropDeclsTy::iterator
146 I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
147 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
148 PropsTy &props = I->second;
149 Transaction Trans(Pass.TA);
150 doActionForExtensionProp(props, atLoc);
151 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000152 }
153
154private:
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000155 void doPropAction(PropActionKind kind,
156 PropsTy &props, SourceLocation atLoc,
157 bool markAction = true) {
158 if (markAction)
159 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
160 ActionOnProp[I->PropD->getIdentifier()] = kind;
161
162 switch (kind) {
163 case PropAction_None:
164 return;
165 case PropAction_RetainToStrong:
166 rewriteAttribute("retain", "strong", atLoc);
167 return;
168 case PropAction_RetainRemoved:
169 removeAttribute("retain", atLoc);
170 return;
171 case PropAction_AssignToStrong:
172 rewriteAttribute("assign", "strong", atLoc);
173 return;
174 case PropAction_AssignRewritten:
175 return rewriteAssign(props, atLoc);
176 case PropAction_MaybeAddStrong:
177 return maybeAddStrongAttr(props, atLoc);
178 case PropAction_MaybeAddWeakOrUnsafe:
179 return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
180 }
181 }
182
183 void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
184 llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
185 I = ActionOnProp.find(props[0].PropD->getIdentifier());
186 if (I == ActionOnProp.end())
187 return;
188
189 doPropAction(I->second, props, atLoc, false);
190 }
191
192 void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000193 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
194
195 if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
196 ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
197 ObjCPropertyDecl::OBJC_PR_strong |
198 ObjCPropertyDecl::OBJC_PR_weak))
199 return;
200
201 if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000202 if (propAttrs & ObjCPropertyDecl::OBJC_PR_readonly)
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000203 return doPropAction(PropAction_RetainToStrong, props, atLoc);
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000204 else
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000205 // strong is the default.
206 return doPropAction(PropAction_RetainRemoved, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000207 }
208
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000209 if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
210 if (hasIvarAssignedAPlusOneObject(props)) {
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000211 return doPropAction(PropAction_AssignToStrong, props, atLoc);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000212 }
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000213 return doPropAction(PropAction_AssignRewritten, props, atLoc);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000214 }
215
216 if (hasIvarAssignedAPlusOneObject(props))
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000217 return doPropAction(PropAction_MaybeAddStrong, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000218
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000219 return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000220 }
221
222 void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
223 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
224
225 bool rewroteAttr = rewriteAttribute("assign",
226 canUseWeak ? "weak" : "unsafe_unretained",
227 atLoc);
228 if (!rewroteAttr)
229 canUseWeak = false;
230
231 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
232 if (isUserDeclared(I->IvarD))
233 Pass.TA.insert(I->IvarD->getLocation(),
234 canUseWeak ? "__weak " : "__unsafe_unretained ");
235 if (I->ImplD)
236 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
237 I->ImplD->getLocation());
238 }
239 }
240
241 void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
242 SourceLocation atLoc) const {
243 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000244
245 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000246 if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
247 !hasAllIvarsBacked(props)) {
248 bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
249 atLoc);
250 if (!addedAttr)
251 canUseWeak = false;
252 }
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000253
254 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
255 if (isUserDeclared(I->IvarD))
256 Pass.TA.insert(I->IvarD->getLocation(),
257 canUseWeak ? "__weak " : "__unsafe_unretained ");
258 if (I->ImplD) {
259 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
260 I->ImplD->getLocation());
261 Pass.TA.clearDiagnostic(
262 diag::err_arc_objc_property_default_assign_on_object,
263 I->ImplD->getLocation());
264 }
265 }
266 }
267
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000268 void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const {
269 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
270
271 if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
272 !hasAllIvarsBacked(props)) {
273 addAttribute("strong", atLoc);
274 }
275
276 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
277 if (I->ImplD) {
278 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
279 I->ImplD->getLocation());
280 Pass.TA.clearDiagnostic(
281 diag::err_arc_objc_property_default_assign_on_object,
282 I->ImplD->getLocation());
283 }
284 }
285 }
286
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000287 bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
288 return rewriteAttribute(fromAttr, StringRef(), atLoc);
289 }
290
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000291 bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000292 SourceLocation atLoc) const {
293 if (atLoc.isMacroID())
294 return false;
295
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000296 SourceManager &SM = Pass.Ctx.getSourceManager();
297
298 // Break down the source location.
299 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
300
301 // Try to load the file buffer.
302 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000303 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000304 if (invalidTemp)
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000305 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000306
307 const char *tokenBegin = file.data() + locInfo.second;
308
309 // Lex from the start of the given location.
310 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
311 Pass.Ctx.getLangOptions(),
312 file.begin(), tokenBegin, file.end());
313 Token tok;
314 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000315 if (tok.isNot(tok::at)) return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000316 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000317 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000318 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000319 != "property")
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000320 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000321 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000322 if (tok.isNot(tok::l_paren)) return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000323
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000324 Token BeforeTok = tok;
325 Token AfterTok;
326 AfterTok.startToken();
327 SourceLocation AttrLoc;
328
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000329 lexer.LexFromRawLexer(tok);
330 if (tok.is(tok::r_paren))
331 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000332
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000333 while (1) {
334 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000335 StringRef ident(tok.getRawIdentifierData(), tok.getLength());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000336 if (ident == fromAttr) {
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000337 if (!toAttr.empty()) {
338 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
339 return true;
340 }
341 // We want to remove the attribute.
342 AttrLoc = tok.getLocation();
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000343 }
344
345 do {
346 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000347 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
348 AfterTok = tok;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000349 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
350 if (tok.is(tok::r_paren))
351 break;
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000352 if (AttrLoc.isInvalid())
353 BeforeTok = tok;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000354 lexer.LexFromRawLexer(tok);
355 }
356
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000357 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
358 // We want to remove the attribute.
359 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
360 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
361 AfterTok.getLocation()));
362 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
363 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
364 } else {
365 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
366 }
367
368 return true;
369 }
370
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000371 return false;
372 }
373
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000374 bool addAttribute(StringRef attr, SourceLocation atLoc) const {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000375 if (atLoc.isMacroID())
376 return false;
377
378 SourceManager &SM = Pass.Ctx.getSourceManager();
379
380 // Break down the source location.
381 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
382
383 // Try to load the file buffer.
384 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000385 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000386 if (invalidTemp)
387 return false;
388
389 const char *tokenBegin = file.data() + locInfo.second;
390
391 // Lex from the start of the given location.
392 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
393 Pass.Ctx.getLangOptions(),
394 file.begin(), tokenBegin, file.end());
395 Token tok;
396 lexer.LexFromRawLexer(tok);
397 if (tok.isNot(tok::at)) return false;
398 lexer.LexFromRawLexer(tok);
399 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000400 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000401 != "property")
402 return false;
403 lexer.LexFromRawLexer(tok);
404
405 if (tok.isNot(tok::l_paren)) {
406 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
407 return true;
408 }
409
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000410 lexer.LexFromRawLexer(tok);
411 if (tok.is(tok::r_paren)) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000412 Pass.TA.insert(tok.getLocation(), attr);
413 return true;
414 }
415
416 if (tok.isNot(tok::raw_identifier)) return false;
417
418 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
419 return true;
420 }
421
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000422 class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
423 ObjCIvarDecl *Ivar;
424 public:
425 PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
426
427 bool VisitBinAssign(BinaryOperator *E) {
428 Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
429 if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
430 if (RE->getDecl() != Ivar)
431 return true;
432
Argyrios Kyrtzidis93db2272011-08-10 21:46:48 +0000433 if (ObjCMessageExpr *
434 ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
435 if (ME->getMethodFamily() == OMF_retain)
436 return false;
437
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000438 ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
439 while (implCE && implCE->getCastKind() == CK_BitCast)
440 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
441
John McCall2d637d22011-09-10 06:18:15 +0000442 if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000443 return false;
444 }
445
446 return true;
447 }
448 };
449
450 bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
451 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
452 PlusOneAssign oneAssign(I->IvarD);
453 bool notFound = oneAssign.TraverseDecl(CurImplD);
454 if (!notFound)
455 return true;
456 }
457
458 return false;
459 }
460
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000461 bool hasIvarWithExplicitOwnership(PropsTy &props) const {
462 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
463 if (isUserDeclared(I->IvarD)) {
464 if (isa<AttributedType>(I->IvarD->getType()))
465 return true;
466 if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
467 != Qualifiers::OCL_Strong)
468 return true;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000469 }
470 }
471
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000472 return false;
473 }
474
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000475 bool hasAllIvarsBacked(PropsTy &props) const {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000476 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000477 if (!isUserDeclared(I->IvarD))
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000478 return false;
479
480 return true;
481 }
482
483 bool isUserDeclared(ObjCIvarDecl *ivarD) const {
484 return ivarD && !ivarD->getSynthesize();
485 }
486
487 QualType getPropertyType(PropsTy &props) const {
488 assert(!props.empty());
489 QualType ty = props[0].PropD->getType();
490
491#ifndef NDEBUG
492 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
493 assert(ty == I->PropD->getType());
494#endif
495
496 return ty;
497 }
498
499 ObjCPropertyDecl::PropertyAttributeKind
500 getPropertyAttrs(PropsTy &props) const {
501 assert(!props.empty());
502 ObjCPropertyDecl::PropertyAttributeKind
503 attrs = props[0].PropD->getPropertyAttributesAsWritten();
504
505#ifndef NDEBUG
506 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
507 assert(attrs == I->PropD->getPropertyAttributesAsWritten());
508#endif
509
510 return attrs;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000511 }
512};
513
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000514class ImplementationChecker :
515 public RecursiveASTVisitor<ImplementationChecker> {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000516 MigrationPass &Pass;
517
518public:
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000519 ImplementationChecker(MigrationPass &pass) : Pass(pass) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000520
521 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000522 PropertiesRewriter(Pass).doTransform(D);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000523 return true;
524 }
525};
526
527} // anonymous namespace
528
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000529void PropertyRewriteTraverser::traverseObjCImplementation(
530 ObjCImplementationContext &ImplCtx) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000531 PropertiesRewriter(ImplCtx.getMigrationContext().Pass)
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000532 .doTransform(ImplCtx.getImplementationDecl());
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000533}