blob: 8f65fc3a8bc00ebabb7ca627f730ea107e5d1b38 [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,
Fariborz Jahanian86f96012012-01-20 19:15:02 +000053 PropAction_RetainReplacedWithStrong,
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 Kyrtzidis0fd4a682012-03-29 01:10:31 +000076 static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
77 AtPropDeclsTy *PrevAtProps = 0) {
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000078 for (ObjCInterfaceDecl::prop_iterator
79 propI = D->prop_begin(),
80 propE = D->prop_end(); propI != propE; ++propI) {
81 if (propI->getAtLoc().isInvalid())
82 continue;
Argyrios Kyrtzidis0fd4a682012-03-29 01:10:31 +000083 unsigned RawLoc = propI->getAtLoc().getRawEncoding();
84 if (PrevAtProps)
85 if (PrevAtProps->find(RawLoc) != PrevAtProps->end())
86 continue;
87 PropsTy &props = AtProps[RawLoc];
David Blaikie262bc182012-04-30 02:36:29 +000088 props.push_back(&*propI);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000089 }
90 }
91
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000092 void doTransform(ObjCImplementationDecl *D) {
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +000093 CurImplD = D;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +000094 ObjCInterfaceDecl *iface = D->getClassInterface();
95 if (!iface)
96 return;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000097
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +000098 collectProperties(iface, AtProps);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000099
100 typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
101 prop_impl_iterator;
102 for (prop_impl_iterator
103 I = prop_impl_iterator(D->decls_begin()),
104 E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
David Blaikie262bc182012-04-30 02:36:29 +0000105 ObjCPropertyImplDecl *implD = &*I;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000106 if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
107 continue;
108 ObjCPropertyDecl *propD = implD->getPropertyDecl();
109 if (!propD || propD->isInvalidDecl())
110 continue;
111 ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
112 if (!ivarD || ivarD->isInvalidDecl())
113 continue;
114 unsigned rawAtLoc = propD->getAtLoc().getRawEncoding();
115 AtPropDeclsTy::iterator findAtLoc = AtProps.find(rawAtLoc);
116 if (findAtLoc == AtProps.end())
117 continue;
118
119 PropsTy &props = findAtLoc->second;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000120 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
121 if (I->PropD == propD) {
122 I->IvarD = ivarD;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000123 I->ImplD = implD;
124 break;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000125 }
126 }
127 }
128
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000129 for (AtPropDeclsTy::iterator
130 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
131 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
132 PropsTy &props = I->second;
Argyrios Kyrtzidis1d5fb8f2011-11-06 18:58:07 +0000133 if (!getPropertyType(props)->isObjCRetainableType())
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000134 continue;
Argyrios Kyrtzidisbf8455c2011-11-07 18:40:32 +0000135 if (hasIvarWithExplicitARCOwnership(props))
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000136 continue;
137
138 Transaction Trans(Pass.TA);
139 rewriteProperty(props, atLoc);
140 }
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000141
142 AtPropDeclsTy AtExtProps;
143 // Look through extensions.
144 for (ObjCCategoryDecl *Cat = iface->getCategoryList();
145 Cat; Cat = Cat->getNextClassCategory())
146 if (Cat->IsClassExtension())
Argyrios Kyrtzidis0fd4a682012-03-29 01:10:31 +0000147 collectProperties(Cat, AtExtProps, &AtProps);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000148
149 for (AtPropDeclsTy::iterator
150 I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
151 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
152 PropsTy &props = I->second;
153 Transaction Trans(Pass.TA);
154 doActionForExtensionProp(props, atLoc);
155 }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000156 }
157
158private:
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000159 void doPropAction(PropActionKind kind,
160 PropsTy &props, SourceLocation atLoc,
161 bool markAction = true) {
162 if (markAction)
163 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
164 ActionOnProp[I->PropD->getIdentifier()] = kind;
165
166 switch (kind) {
167 case PropAction_None:
168 return;
Fariborz Jahanian86f96012012-01-20 19:15:02 +0000169 case PropAction_RetainReplacedWithStrong: {
170 StringRef toAttr = "strong";
171 MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000172 return;
Fariborz Jahanian86f96012012-01-20 19:15:02 +0000173 }
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000174 case PropAction_AssignRemoved:
175 return removeAssignForDefaultStrong(props, atLoc);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000176 case PropAction_AssignRewritten:
177 return rewriteAssign(props, atLoc);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000178 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 Kyrtzidis14c4b442011-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 Kyrtzidis8b08eb32011-11-08 23:09:34 +0000202 // strong is the default.
Fariborz Jahanian86f96012012-01-20 19:15:02 +0000203 return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000204 }
205
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000206 bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
207
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000208 if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
Fariborz Jahanian2f72ec92012-01-21 00:43:53 +0000209 if (HasIvarAssignedAPlusOneObject)
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000210 return doPropAction(PropAction_AssignRemoved, props, atLoc);
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000211 return doPropAction(PropAction_AssignRewritten, props, atLoc);
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000212 }
213
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000214 if (HasIvarAssignedAPlusOneObject ||
215 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
Argyrios Kyrtzidisaf9b5e92011-11-08 22:10:58 +0000216 return; // 'strong' by default.
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000217
Argyrios Kyrtzidis44679012011-10-18 19:49:19 +0000218 return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000219 }
220
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000221 void removeAssignForDefaultStrong(PropsTy &props,
222 SourceLocation atLoc) const {
223 removeAttribute("retain", atLoc);
224 if (!removeAttribute("assign", atLoc))
225 return;
226
227 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
228 if (I->ImplD)
229 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
230 I->ImplD->getLocation());
231 }
232 }
233
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000234 void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000235 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
236 /*AllowOnUnknownClass=*/Pass.isGCMigration());
Fariborz Jahanian2f72ec92012-01-21 00:43:53 +0000237 const char *toWhich =
238 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" :
239 (canUseWeak ? "weak" : "unsafe_unretained");
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000240
Fariborz Jahanian2f72ec92012-01-21 00:43:53 +0000241 bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000242 if (!rewroteAttr)
243 canUseWeak = false;
244
245 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000246 if (isUserDeclared(I->IvarD)) {
247 if (I->IvarD &&
Fariborz Jahanian2f72ec92012-01-21 00:43:53 +0000248 I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) {
249 const char *toWhich =
250 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " :
251 (canUseWeak ? "__weak " : "__unsafe_unretained ");
252 Pass.TA.insert(I->IvarD->getLocation(), toWhich);
253 }
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000254 }
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000255 if (I->ImplD)
256 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
257 I->ImplD->getLocation());
258 }
259 }
260
261 void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
262 SourceLocation atLoc) const {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000263 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
264 /*AllowOnUnknownClass=*/Pass.isGCMigration());
Argyrios Kyrtzidis8b08eb32011-11-08 23:09:34 +0000265
266 bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
267 atLoc);
268 if (!addedAttr)
269 canUseWeak = false;
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000270
271 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
Argyrios Kyrtzidis6d7d16d2011-11-28 00:23:12 +0000272 if (isUserDeclared(I->IvarD)) {
273 if (I->IvarD &&
274 I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
275 Pass.TA.insert(I->IvarD->getLocation(),
276 canUseWeak ? "__weak " : "__unsafe_unretained ");
277 }
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000278 if (I->ImplD) {
279 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
280 I->ImplD->getLocation());
281 Pass.TA.clearDiagnostic(
282 diag::err_arc_objc_property_default_assign_on_object,
283 I->ImplD->getLocation());
284 }
285 }
286 }
287
Argyrios Kyrtzidis01b2b9b2011-10-17 23:14:16 +0000288 bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000289 return MigrateCtx.removePropertyAttribute(fromAttr, atLoc);
Argyrios Kyrtzidis01b2b9b2011-10-17 23:14:16 +0000290 }
291
Chris Lattner5f9e2722011-07-23 10:55:15 +0000292 bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000293 SourceLocation atLoc) const {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000294 return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000295 }
296
Chris Lattner5f9e2722011-07-23 10:55:15 +0000297 bool addAttribute(StringRef attr, SourceLocation atLoc) const {
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000298 return MigrateCtx.addPropertyAttribute(attr, atLoc);
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000299 }
300
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000301 class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
302 ObjCIvarDecl *Ivar;
303 public:
304 PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
305
306 bool VisitBinAssign(BinaryOperator *E) {
307 Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
308 if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
309 if (RE->getDecl() != Ivar)
310 return true;
311
Argyrios Kyrtzidis94a90162011-08-10 21:46:48 +0000312 if (ObjCMessageExpr *
313 ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
314 if (ME->getMethodFamily() == OMF_retain)
315 return false;
316
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000317 ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
318 while (implCE && implCE->getCastKind() == CK_BitCast)
319 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
320
John McCall33e56f32011-09-10 06:18:15 +0000321 if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000322 return false;
323 }
324
325 return true;
326 }
327 };
328
329 bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
330 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
331 PlusOneAssign oneAssign(I->IvarD);
332 bool notFound = oneAssign.TraverseDecl(CurImplD);
333 if (!notFound)
334 return true;
335 }
336
337 return false;
338 }
339
Argyrios Kyrtzidisbf8455c2011-11-07 18:40:32 +0000340 bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
341 if (Pass.isGCMigration())
342 return false;
343
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000344 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
345 if (isUserDeclared(I->IvarD)) {
346 if (isa<AttributedType>(I->IvarD->getType()))
347 return true;
348 if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
349 != Qualifiers::OCL_Strong)
350 return true;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000351 }
352 }
353
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000354 return false;
355 }
356
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000357 bool hasAllIvarsBacked(PropsTy &props) const {
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000358 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000359 if (!isUserDeclared(I->IvarD))
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000360 return false;
361
362 return true;
363 }
364
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000365 // \brief Returns true if all declarations in the @property have GC __weak.
366 bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
367 if (!Pass.isGCMigration())
368 return false;
369 if (props.empty())
370 return false;
371 return MigrateCtx.AtPropsWeak.count(atLoc.getRawEncoding());
372 }
373
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000374 bool isUserDeclared(ObjCIvarDecl *ivarD) const {
375 return ivarD && !ivarD->getSynthesize();
376 }
377
378 QualType getPropertyType(PropsTy &props) const {
379 assert(!props.empty());
Argyrios Kyrtzidis1d5fb8f2011-11-06 18:58:07 +0000380 QualType ty = props[0].PropD->getType().getUnqualifiedType();
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000381
382#ifndef NDEBUG
383 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis1d5fb8f2011-11-06 18:58:07 +0000384 assert(ty == I->PropD->getType().getUnqualifiedType());
Argyrios Kyrtzidis14c4b442011-07-13 19:22:00 +0000385#endif
386
387 return ty;
388 }
389
390 ObjCPropertyDecl::PropertyAttributeKind
391 getPropertyAttrs(PropsTy &props) const {
392 assert(!props.empty());
393 ObjCPropertyDecl::PropertyAttributeKind
394 attrs = props[0].PropD->getPropertyAttributesAsWritten();
395
396#ifndef NDEBUG
397 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
398 assert(attrs == I->PropD->getPropertyAttributesAsWritten());
399#endif
400
401 return attrs;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000402 }
403};
404
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000405} // anonymous namespace
406
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000407void PropertyRewriteTraverser::traverseObjCImplementation(
408 ObjCImplementationContext &ImplCtx) {
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000409 PropertiesRewriter(ImplCtx.getMigrationContext())
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000410 .doTransform(ImplCtx.getImplementationDecl());
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000411}