blob: 1512e4e96d38840433b305cec6709365f09c0b12 [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;
Argyrios Kyrtzidisaa421ea2011-11-06 18:58:07 +0000128 if (!getPropertyType(props)->isObjCRetainableType())
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000129 continue;
130 if (hasIvarWithExplicitOwnership(props))
131 continue;
132
133 Transaction Trans(Pass.TA);
134 rewriteProperty(props, atLoc);
135 }
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000136
137 AtPropDeclsTy AtExtProps;
138 // Look through extensions.
139 for (ObjCCategoryDecl *Cat = iface->getCategoryList();
140 Cat; Cat = Cat->getNextClassCategory())
141 if (Cat->IsClassExtension())
142 collectProperties(Cat, AtExtProps);
143
144 for (AtPropDeclsTy::iterator
145 I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
146 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
147 PropsTy &props = I->second;
148 Transaction Trans(Pass.TA);
149 doActionForExtensionProp(props, atLoc);
150 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000151 }
152
153private:
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000154 void doPropAction(PropActionKind kind,
155 PropsTy &props, SourceLocation atLoc,
156 bool markAction = true) {
157 if (markAction)
158 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
159 ActionOnProp[I->PropD->getIdentifier()] = kind;
160
161 switch (kind) {
162 case PropAction_None:
163 return;
164 case PropAction_RetainToStrong:
165 rewriteAttribute("retain", "strong", atLoc);
166 return;
167 case PropAction_RetainRemoved:
168 removeAttribute("retain", atLoc);
169 return;
170 case PropAction_AssignToStrong:
171 rewriteAttribute("assign", "strong", atLoc);
172 return;
173 case PropAction_AssignRewritten:
174 return rewriteAssign(props, atLoc);
175 case PropAction_MaybeAddStrong:
176 return maybeAddStrongAttr(props, atLoc);
177 case PropAction_MaybeAddWeakOrUnsafe:
178 return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
179 }
180 }
181
182 void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
183 llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
184 I = ActionOnProp.find(props[0].PropD->getIdentifier());
185 if (I == ActionOnProp.end())
186 return;
187
188 doPropAction(I->second, props, atLoc, false);
189 }
190
191 void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000192 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
193
194 if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
195 ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
196 ObjCPropertyDecl::OBJC_PR_strong |
197 ObjCPropertyDecl::OBJC_PR_weak))
198 return;
199
200 if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000201 if (propAttrs & ObjCPropertyDecl::OBJC_PR_readonly)
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000202 return doPropAction(PropAction_RetainToStrong, props, atLoc);
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000203 else
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000204 // strong is the default.
205 return doPropAction(PropAction_RetainRemoved, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000206 }
207
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000208 if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
209 if (hasIvarAssignedAPlusOneObject(props)) {
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000210 return doPropAction(PropAction_AssignToStrong, props, atLoc);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000211 }
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000212 return doPropAction(PropAction_AssignRewritten, props, atLoc);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000213 }
214
215 if (hasIvarAssignedAPlusOneObject(props))
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000216 return doPropAction(PropAction_MaybeAddStrong, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000217
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000218 return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000219 }
220
221 void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
222 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
223
224 bool rewroteAttr = rewriteAttribute("assign",
225 canUseWeak ? "weak" : "unsafe_unretained",
226 atLoc);
227 if (!rewroteAttr)
228 canUseWeak = false;
229
230 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
231 if (isUserDeclared(I->IvarD))
232 Pass.TA.insert(I->IvarD->getLocation(),
233 canUseWeak ? "__weak " : "__unsafe_unretained ");
234 if (I->ImplD)
235 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
236 I->ImplD->getLocation());
237 }
238 }
239
240 void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
241 SourceLocation atLoc) const {
242 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000243
244 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000245 if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
246 !hasAllIvarsBacked(props)) {
247 bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
248 atLoc);
249 if (!addedAttr)
250 canUseWeak = false;
251 }
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000252
253 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
254 if (isUserDeclared(I->IvarD))
255 Pass.TA.insert(I->IvarD->getLocation(),
256 canUseWeak ? "__weak " : "__unsafe_unretained ");
257 if (I->ImplD) {
258 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
259 I->ImplD->getLocation());
260 Pass.TA.clearDiagnostic(
261 diag::err_arc_objc_property_default_assign_on_object,
262 I->ImplD->getLocation());
263 }
264 }
265 }
266
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000267 void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const {
268 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
269
270 if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
271 !hasAllIvarsBacked(props)) {
272 addAttribute("strong", atLoc);
273 }
274
275 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
276 if (I->ImplD) {
277 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
278 I->ImplD->getLocation());
279 Pass.TA.clearDiagnostic(
280 diag::err_arc_objc_property_default_assign_on_object,
281 I->ImplD->getLocation());
282 }
283 }
284 }
285
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000286 bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
287 return rewriteAttribute(fromAttr, StringRef(), atLoc);
288 }
289
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000290 bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000291 SourceLocation atLoc) const {
292 if (atLoc.isMacroID())
293 return false;
294
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000295 SourceManager &SM = Pass.Ctx.getSourceManager();
296
297 // Break down the source location.
298 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
299
300 // Try to load the file buffer.
301 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000302 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000303 if (invalidTemp)
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000304 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000305
306 const char *tokenBegin = file.data() + locInfo.second;
307
308 // Lex from the start of the given location.
309 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
310 Pass.Ctx.getLangOptions(),
311 file.begin(), tokenBegin, file.end());
312 Token tok;
313 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000314 if (tok.isNot(tok::at)) return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000315 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000316 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000317 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000318 != "property")
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000319 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000320 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000321 if (tok.isNot(tok::l_paren)) return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000322
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000323 Token BeforeTok = tok;
324 Token AfterTok;
325 AfterTok.startToken();
326 SourceLocation AttrLoc;
327
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000328 lexer.LexFromRawLexer(tok);
329 if (tok.is(tok::r_paren))
330 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000331
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000332 while (1) {
333 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000334 StringRef ident(tok.getRawIdentifierData(), tok.getLength());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000335 if (ident == fromAttr) {
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000336 if (!toAttr.empty()) {
337 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
338 return true;
339 }
340 // We want to remove the attribute.
341 AttrLoc = tok.getLocation();
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000342 }
343
344 do {
345 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000346 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
347 AfterTok = tok;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000348 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
349 if (tok.is(tok::r_paren))
350 break;
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000351 if (AttrLoc.isInvalid())
352 BeforeTok = tok;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000353 lexer.LexFromRawLexer(tok);
354 }
355
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000356 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
357 // We want to remove the attribute.
358 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
359 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
360 AfterTok.getLocation()));
361 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
362 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
363 } else {
364 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
365 }
366
367 return true;
368 }
369
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000370 return false;
371 }
372
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000373 bool addAttribute(StringRef attr, SourceLocation atLoc) const {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000374 if (atLoc.isMacroID())
375 return false;
376
377 SourceManager &SM = Pass.Ctx.getSourceManager();
378
379 // Break down the source location.
380 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
381
382 // Try to load the file buffer.
383 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000384 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000385 if (invalidTemp)
386 return false;
387
388 const char *tokenBegin = file.data() + locInfo.second;
389
390 // Lex from the start of the given location.
391 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
392 Pass.Ctx.getLangOptions(),
393 file.begin(), tokenBegin, file.end());
394 Token tok;
395 lexer.LexFromRawLexer(tok);
396 if (tok.isNot(tok::at)) return false;
397 lexer.LexFromRawLexer(tok);
398 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000399 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000400 != "property")
401 return false;
402 lexer.LexFromRawLexer(tok);
403
404 if (tok.isNot(tok::l_paren)) {
405 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
406 return true;
407 }
408
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000409 lexer.LexFromRawLexer(tok);
410 if (tok.is(tok::r_paren)) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000411 Pass.TA.insert(tok.getLocation(), attr);
412 return true;
413 }
414
415 if (tok.isNot(tok::raw_identifier)) return false;
416
417 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
418 return true;
419 }
420
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000421 class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
422 ObjCIvarDecl *Ivar;
423 public:
424 PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
425
426 bool VisitBinAssign(BinaryOperator *E) {
427 Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
428 if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
429 if (RE->getDecl() != Ivar)
430 return true;
431
Argyrios Kyrtzidis93db2272011-08-10 21:46:48 +0000432 if (ObjCMessageExpr *
433 ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
434 if (ME->getMethodFamily() == OMF_retain)
435 return false;
436
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000437 ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
438 while (implCE && implCE->getCastKind() == CK_BitCast)
439 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
440
John McCall2d637d22011-09-10 06:18:15 +0000441 if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000442 return false;
443 }
444
445 return true;
446 }
447 };
448
449 bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
450 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
451 PlusOneAssign oneAssign(I->IvarD);
452 bool notFound = oneAssign.TraverseDecl(CurImplD);
453 if (!notFound)
454 return true;
455 }
456
457 return false;
458 }
459
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000460 bool hasIvarWithExplicitOwnership(PropsTy &props) const {
461 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
462 if (isUserDeclared(I->IvarD)) {
463 if (isa<AttributedType>(I->IvarD->getType()))
464 return true;
465 if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
466 != Qualifiers::OCL_Strong)
467 return true;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000468 }
469 }
470
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000471 return false;
472 }
473
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000474 bool hasAllIvarsBacked(PropsTy &props) const {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000475 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000476 if (!isUserDeclared(I->IvarD))
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000477 return false;
478
479 return true;
480 }
481
482 bool isUserDeclared(ObjCIvarDecl *ivarD) const {
483 return ivarD && !ivarD->getSynthesize();
484 }
485
486 QualType getPropertyType(PropsTy &props) const {
487 assert(!props.empty());
Argyrios Kyrtzidisaa421ea2011-11-06 18:58:07 +0000488 QualType ty = props[0].PropD->getType().getUnqualifiedType();
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000489
490#ifndef NDEBUG
491 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidisaa421ea2011-11-06 18:58:07 +0000492 assert(ty == I->PropD->getType().getUnqualifiedType());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000493#endif
494
495 return ty;
496 }
497
498 ObjCPropertyDecl::PropertyAttributeKind
499 getPropertyAttrs(PropsTy &props) const {
500 assert(!props.empty());
501 ObjCPropertyDecl::PropertyAttributeKind
502 attrs = props[0].PropD->getPropertyAttributesAsWritten();
503
504#ifndef NDEBUG
505 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
506 assert(attrs == I->PropD->getPropertyAttributesAsWritten());
507#endif
508
509 return attrs;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000510 }
511};
512
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000513class ImplementationChecker :
514 public RecursiveASTVisitor<ImplementationChecker> {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000515 MigrationPass &Pass;
516
517public:
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000518 ImplementationChecker(MigrationPass &pass) : Pass(pass) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000519
520 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000521 PropertiesRewriter(Pass).doTransform(D);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000522 return true;
523 }
524};
525
526} // anonymous namespace
527
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000528void PropertyRewriteTraverser::traverseObjCImplementation(
529 ObjCImplementationContext &ImplCtx) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000530 PropertiesRewriter(ImplCtx.getMigrationContext().Pass)
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000531 .doTransform(ImplCtx.getImplementationDecl());
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000532}