blob: 8136b31d81246210877b3c1379303702ef12c200 [file] [log] [blame]
Argyrios Kyrtzidis7196d062011-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 Kyrtzidis14c4b442011-07-13 19:22:00 +000010// rewriteProperties:
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000011//
Argyrios Kyrtzidis14c4b442011-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 Kyrtzidis7196d062011-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 Kyrtzidis14c4b442011-07-13 19:22:00 +000038#include <map>
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000039
40using namespace clang;
41using namespace arcmt;
42using namespace trans;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000043
44namespace {
45
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +000046class PropertiesRewriter {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000047 MigrationContext &MigrateCtx;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000048 MigrationPass &Pass;
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000049 ObjCImplementationDecl *CurImplD;
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000050
51 enum PropActionKind {
52 PropAction_None,
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000053 PropAction_RetainRemoved,
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000054 PropAction_AssignRemoved,
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000055 PropAction_AssignRewritten,
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000056 PropAction_MaybeAddWeakOrUnsafe
57 };
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +000058
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000059 struct PropData {
60 ObjCPropertyDecl *PropD;
61 ObjCIvarDecl *IvarD;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +000062 ObjCPropertyImplDecl *ImplD;
63
64 PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000065 };
66
Chris Lattner5f9e2722011-07-23 10:55:15 +000067 typedef SmallVector<PropData, 2> PropsTy;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +000068 typedef std::map<unsigned, PropsTy> AtPropDeclsTy;
69 AtPropDeclsTy AtProps;
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000070 llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000071
72public:
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000073 explicit PropertiesRewriter(MigrationContext &MigrateCtx)
74 : MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000075
Argyrios Kyrtzidis44679012011-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 Kyrtzidis7196d062011-06-21 20:20:39 +000087 void doTransform(ObjCImplementationDecl *D) {
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000088 CurImplD = D;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +000089 ObjCInterfaceDecl *iface = D->getClassInterface();
90 if (!iface)
91 return;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000092
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000093 collectProperties(iface, AtProps);
Argyrios Kyrtzidis7196d062011-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 Kyrtzidis14c4b442011-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 Kyrtzidis7196d062011-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 Kyrtzidis14c4b442011-07-13 19:22:00 +0000118 I->ImplD = implD;
119 break;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000120 }
121 }
122 }
123
Argyrios Kyrtzidis14c4b442011-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 Kyrtzidis1d5fb8f2011-11-06 18:58:07 +0000128 if (!getPropertyType(props)->isObjCRetainableType())
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000129 continue;
Argyrios Kyrtzidisbf8455c2011-11-07 18:40:32 +0000130 if (hasIvarWithExplicitARCOwnership(props))
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000131 continue;
132
133 Transaction Trans(Pass.TA);
134 rewriteProperty(props, atLoc);
135 }
Argyrios Kyrtzidis44679012011-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 Kyrtzidis7196d062011-06-21 20:20:39 +0000151 }
152
153private:
Argyrios Kyrtzidis44679012011-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;
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000164 case PropAction_RetainRemoved:
165 removeAttribute("retain", atLoc);
166 return;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000167 case PropAction_AssignRemoved:
168 return removeAssignForDefaultStrong(props, atLoc);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000169 case PropAction_AssignRewritten:
170 return rewriteAssign(props, atLoc);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000171 case PropAction_MaybeAddWeakOrUnsafe:
172 return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
173 }
174 }
175
176 void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
177 llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
178 I = ActionOnProp.find(props[0].PropD->getIdentifier());
179 if (I == ActionOnProp.end())
180 return;
181
182 doPropAction(I->second, props, atLoc, false);
183 }
184
185 void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000186 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
187
188 if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
189 ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
190 ObjCPropertyDecl::OBJC_PR_strong |
191 ObjCPropertyDecl::OBJC_PR_weak))
192 return;
193
194 if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
Argyrios Kyrtzidis8b08eb32011-11-08 23:09:34 +0000195 // strong is the default.
196 return doPropAction(PropAction_RetainRemoved, props, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000197 }
198
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000199 bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
200
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000201 if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000202 if (HasIvarAssignedAPlusOneObject ||
203 (Pass.isGCMigration() && !hasGCWeak(props, atLoc))) {
204 return doPropAction(PropAction_AssignRemoved, props, atLoc);
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000205 }
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000206 return doPropAction(PropAction_AssignRewritten, props, atLoc);
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000207 }
208
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000209 if (HasIvarAssignedAPlusOneObject ||
210 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
Argyrios Kyrtzidisaf9b5e92011-11-08 22:10:58 +0000211 return; // 'strong' by default.
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000212
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000213 return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000214 }
215
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000216 void removeAssignForDefaultStrong(PropsTy &props,
217 SourceLocation atLoc) const {
218 removeAttribute("retain", atLoc);
219 if (!removeAttribute("assign", atLoc))
220 return;
221
222 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
223 if (I->ImplD)
224 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
225 I->ImplD->getLocation());
226 }
227 }
228
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000229 void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000230 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
231 /*AllowOnUnknownClass=*/Pass.isGCMigration());
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000232
233 bool rewroteAttr = rewriteAttribute("assign",
234 canUseWeak ? "weak" : "unsafe_unretained",
235 atLoc);
236 if (!rewroteAttr)
237 canUseWeak = false;
238
239 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000240 if (isUserDeclared(I->IvarD)) {
241 if (I->IvarD &&
242 I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
243 Pass.TA.insert(I->IvarD->getLocation(),
244 canUseWeak ? "__weak " : "__unsafe_unretained ");
245 }
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000246 if (I->ImplD)
247 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
248 I->ImplD->getLocation());
249 }
250 }
251
252 void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
253 SourceLocation atLoc) const {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000254 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
255 /*AllowOnUnknownClass=*/Pass.isGCMigration());
Argyrios Kyrtzidis8b08eb32011-11-08 23:09:34 +0000256
257 bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
258 atLoc);
259 if (!addedAttr)
260 canUseWeak = false;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000261
262 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000263 if (isUserDeclared(I->IvarD)) {
264 if (I->IvarD &&
265 I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
266 Pass.TA.insert(I->IvarD->getLocation(),
267 canUseWeak ? "__weak " : "__unsafe_unretained ");
268 }
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000269 if (I->ImplD) {
270 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
271 I->ImplD->getLocation());
272 Pass.TA.clearDiagnostic(
273 diag::err_arc_objc_property_default_assign_on_object,
274 I->ImplD->getLocation());
275 }
276 }
277 }
278
Argyrios Kyrtzidis01b2b9b2011-10-17 23:14:16 +0000279 bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
280 return rewriteAttribute(fromAttr, StringRef(), atLoc);
281 }
282
Chris Lattner5f9e2722011-07-23 10:55:15 +0000283 bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000284 SourceLocation atLoc) const {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000285 return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000286 }
287
Chris Lattner5f9e2722011-07-23 10:55:15 +0000288 bool addAttribute(StringRef attr, SourceLocation atLoc) const {
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000289 if (atLoc.isMacroID())
290 return false;
291
292 SourceManager &SM = Pass.Ctx.getSourceManager();
293
294 // Break down the source location.
295 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
296
297 // Try to load the file buffer.
298 bool invalidTemp = false;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000299 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000300 if (invalidTemp)
301 return false;
302
303 const char *tokenBegin = file.data() + locInfo.second;
304
305 // Lex from the start of the given location.
306 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
307 Pass.Ctx.getLangOptions(),
308 file.begin(), tokenBegin, file.end());
309 Token tok;
310 lexer.LexFromRawLexer(tok);
311 if (tok.isNot(tok::at)) return false;
312 lexer.LexFromRawLexer(tok);
313 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000314 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000315 != "property")
316 return false;
317 lexer.LexFromRawLexer(tok);
318
319 if (tok.isNot(tok::l_paren)) {
320 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
321 return true;
322 }
323
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000324 lexer.LexFromRawLexer(tok);
325 if (tok.is(tok::r_paren)) {
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000326 Pass.TA.insert(tok.getLocation(), attr);
327 return true;
328 }
329
330 if (tok.isNot(tok::raw_identifier)) return false;
331
332 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
333 return true;
334 }
335
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000336 class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
337 ObjCIvarDecl *Ivar;
338 public:
339 PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
340
341 bool VisitBinAssign(BinaryOperator *E) {
342 Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
343 if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
344 if (RE->getDecl() != Ivar)
345 return true;
346
Argyrios Kyrtzidis94a90162011-08-10 21:46:48 +0000347 if (ObjCMessageExpr *
348 ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
349 if (ME->getMethodFamily() == OMF_retain)
350 return false;
351
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000352 ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
353 while (implCE && implCE->getCastKind() == CK_BitCast)
354 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
355
John McCall33e56f32011-09-10 06:18:15 +0000356 if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000357 return false;
358 }
359
360 return true;
361 }
362 };
363
364 bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
365 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
366 PlusOneAssign oneAssign(I->IvarD);
367 bool notFound = oneAssign.TraverseDecl(CurImplD);
368 if (!notFound)
369 return true;
370 }
371
372 return false;
373 }
374
Argyrios Kyrtzidisbf8455c2011-11-07 18:40:32 +0000375 bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
376 if (Pass.isGCMigration())
377 return false;
378
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000379 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
380 if (isUserDeclared(I->IvarD)) {
381 if (isa<AttributedType>(I->IvarD->getType()))
382 return true;
383 if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
384 != Qualifiers::OCL_Strong)
385 return true;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000386 }
387 }
388
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000389 return false;
390 }
391
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000392 bool hasAllIvarsBacked(PropsTy &props) const {
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000393 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000394 if (!isUserDeclared(I->IvarD))
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000395 return false;
396
397 return true;
398 }
399
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000400 // \brief Returns true if all declarations in the @property have GC __weak.
401 bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
402 if (!Pass.isGCMigration())
403 return false;
404 if (props.empty())
405 return false;
406 return MigrateCtx.AtPropsWeak.count(atLoc.getRawEncoding());
407 }
408
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000409 bool isUserDeclared(ObjCIvarDecl *ivarD) const {
410 return ivarD && !ivarD->getSynthesize();
411 }
412
413 QualType getPropertyType(PropsTy &props) const {
414 assert(!props.empty());
Argyrios Kyrtzidis1d5fb8f2011-11-06 18:58:07 +0000415 QualType ty = props[0].PropD->getType().getUnqualifiedType();
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000416
417#ifndef NDEBUG
418 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis1d5fb8f2011-11-06 18:58:07 +0000419 assert(ty == I->PropD->getType().getUnqualifiedType());
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000420#endif
421
422 return ty;
423 }
424
425 ObjCPropertyDecl::PropertyAttributeKind
426 getPropertyAttrs(PropsTy &props) const {
427 assert(!props.empty());
428 ObjCPropertyDecl::PropertyAttributeKind
429 attrs = props[0].PropD->getPropertyAttributesAsWritten();
430
431#ifndef NDEBUG
432 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
433 assert(attrs == I->PropD->getPropertyAttributesAsWritten());
434#endif
435
436 return attrs;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000437 }
438};
439
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000440} // anonymous namespace
441
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000442void PropertyRewriteTraverser::traverseObjCImplementation(
443 ObjCImplementationContext &ImplCtx) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000444 PropertiesRewriter(ImplCtx.getMigrationContext())
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000445 .doTransform(ImplCtx.getImplementationDecl());
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000446}