blob: ab128844b45faf03eaf172c88b86c47aeba65c3e [file] [log] [blame]
Benjamin Kramerd81108f2012-11-14 15:08:31 +00001//===--- TransProperties.cpp - Transformations to ARC mode ----------------===//
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +00002//
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"
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000035#include "clang/Basic/SourceManager.h"
36#include "clang/Lex/Lexer.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000037#include "clang/Sema/SemaDiagnostic.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 Kyrtzidis722d21c2011-11-07 18:46:46 +000047 MigrationContext &MigrateCtx;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000048 MigrationPass &Pass;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000049 ObjCImplementationDecl *CurImplD;
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000050
51 enum PropActionKind {
52 PropAction_None,
Fariborz Jahanian9652adf2012-01-20 19:15:02 +000053 PropAction_RetainReplacedWithStrong,
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000054 PropAction_AssignRemoved,
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000055 PropAction_AssignRewritten,
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000056 PropAction_MaybeAddWeakOrUnsafe
57 };
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000058
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000059 struct PropData {
60 ObjCPropertyDecl *PropD;
61 ObjCIvarDecl *IvarD;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000062 ObjCPropertyImplDecl *ImplD;
63
Craig Topper8ae12032014-05-07 06:21:57 +000064 PropData(ObjCPropertyDecl *propD)
65 : PropD(propD), IvarD(nullptr), ImplD(nullptr) {}
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 Kyrtzidis722d21c2011-11-07 18:46:46 +000074 explicit PropertiesRewriter(MigrationContext &MigrateCtx)
75 : MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000076
Argyrios Kyrtzidis28e0a7f2012-03-29 01:10:31 +000077 static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
Craig Topper8ae12032014-05-07 06:21:57 +000078 AtPropDeclsTy *PrevAtProps = nullptr) {
Aaron Ballmand174edf2014-03-13 19:11:50 +000079 for (auto *Prop : D->properties()) {
Aaron Ballmandc4bea42014-03-13 18:47:37 +000080 if (Prop->getAtLoc().isInvalid())
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000081 continue;
Aaron Ballmandc4bea42014-03-13 18:47:37 +000082 unsigned RawLoc = Prop->getAtLoc().getRawEncoding();
Argyrios Kyrtzidis28e0a7f2012-03-29 01:10:31 +000083 if (PrevAtProps)
84 if (PrevAtProps->find(RawLoc) != PrevAtProps->end())
85 continue;
86 PropsTy &props = AtProps[RawLoc];
Aaron Ballmandc4bea42014-03-13 18:47:37 +000087 props.push_back(Prop);
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000088 }
89 }
90
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000091 void doTransform(ObjCImplementationDecl *D) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000092 CurImplD = D;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000093 ObjCInterfaceDecl *iface = D->getClassInterface();
94 if (!iface)
95 return;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000096
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +000097 collectProperties(iface, AtProps);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000098
99 typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
100 prop_impl_iterator;
101 for (prop_impl_iterator
102 I = prop_impl_iterator(D->decls_begin()),
103 E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
David Blaikie40ed2972012-06-06 20:45:41 +0000104 ObjCPropertyImplDecl *implD = *I;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000105 if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
106 continue;
107 ObjCPropertyDecl *propD = implD->getPropertyDecl();
108 if (!propD || propD->isInvalidDecl())
109 continue;
110 ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
111 if (!ivarD || ivarD->isInvalidDecl())
112 continue;
113 unsigned rawAtLoc = propD->getAtLoc().getRawEncoding();
114 AtPropDeclsTy::iterator findAtLoc = AtProps.find(rawAtLoc);
115 if (findAtLoc == AtProps.end())
116 continue;
117
118 PropsTy &props = findAtLoc->second;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000119 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
120 if (I->PropD == propD) {
121 I->IvarD = ivarD;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000122 I->ImplD = implD;
123 break;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000124 }
125 }
126 }
127
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000128 for (AtPropDeclsTy::iterator
129 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
130 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
131 PropsTy &props = I->second;
Argyrios Kyrtzidisaa421ea2011-11-06 18:58:07 +0000132 if (!getPropertyType(props)->isObjCRetainableType())
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000133 continue;
Argyrios Kyrtzidis0dd98a42011-11-07 18:40:32 +0000134 if (hasIvarWithExplicitARCOwnership(props))
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000135 continue;
136
137 Transaction Trans(Pass.TA);
138 rewriteProperty(props, atLoc);
139 }
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000140
141 AtPropDeclsTy AtExtProps;
142 // Look through extensions.
Aaron Ballmanf53d8dd2014-03-13 21:47:07 +0000143 for (auto *Ext : iface->visible_extensions())
144 collectProperties(Ext, AtExtProps, &AtProps);
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000145
146 for (AtPropDeclsTy::iterator
147 I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
148 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
149 PropsTy &props = I->second;
150 Transaction Trans(Pass.TA);
151 doActionForExtensionProp(props, atLoc);
152 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000153 }
154
155private:
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000156 void doPropAction(PropActionKind kind,
157 PropsTy &props, SourceLocation atLoc,
158 bool markAction = true) {
159 if (markAction)
160 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
161 ActionOnProp[I->PropD->getIdentifier()] = kind;
162
163 switch (kind) {
164 case PropAction_None:
165 return;
Fariborz Jahanian9652adf2012-01-20 19:15:02 +0000166 case PropAction_RetainReplacedWithStrong: {
167 StringRef toAttr = "strong";
168 MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc);
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000169 return;
Fariborz Jahanian9652adf2012-01-20 19:15:02 +0000170 }
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000171 case PropAction_AssignRemoved:
172 return removeAssignForDefaultStrong(props, atLoc);
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000173 case PropAction_AssignRewritten:
174 return rewriteAssign(props, atLoc);
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000175 case PropAction_MaybeAddWeakOrUnsafe:
176 return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
177 }
178 }
179
180 void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) {
181 llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I;
182 I = ActionOnProp.find(props[0].PropD->getIdentifier());
183 if (I == ActionOnProp.end())
184 return;
185
186 doPropAction(I->second, props, atLoc, false);
187 }
188
189 void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000190 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
191
192 if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
193 ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
194 ObjCPropertyDecl::OBJC_PR_strong |
195 ObjCPropertyDecl::OBJC_PR_weak))
196 return;
197
198 if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
Argyrios Kyrtzidis485ecee2011-11-08 23:09:34 +0000199 // strong is the default.
Fariborz Jahanian9652adf2012-01-20 19:15:02 +0000200 return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000201 }
202
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000203 bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
204
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000205 if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
Fariborz Jahanian1630c152012-01-21 00:43:53 +0000206 if (HasIvarAssignedAPlusOneObject)
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000207 return doPropAction(PropAction_AssignRemoved, props, atLoc);
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000208 return doPropAction(PropAction_AssignRewritten, props, atLoc);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000209 }
210
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000211 if (HasIvarAssignedAPlusOneObject ||
212 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
Argyrios Kyrtzidise4a38a72011-11-08 22:10:58 +0000213 return; // 'strong' by default.
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000214
Argyrios Kyrtzidis05c65fb2011-10-18 19:49:19 +0000215 return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000216 }
217
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000218 void removeAssignForDefaultStrong(PropsTy &props,
219 SourceLocation atLoc) const {
220 removeAttribute("retain", atLoc);
221 if (!removeAttribute("assign", atLoc))
222 return;
223
224 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
225 if (I->ImplD)
Argyrios Kyrtzidisf5b993f2012-12-12 22:48:25 +0000226 Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
227 diag::err_arc_assign_property_ownership,
228 diag::err_arc_inconsistent_property_ownership,
229 I->IvarD->getLocation());
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000230 }
231 }
232
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000233 void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000234 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
235 /*AllowOnUnknownClass=*/Pass.isGCMigration());
Fariborz Jahanian1630c152012-01-21 00:43:53 +0000236 const char *toWhich =
237 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" :
238 (canUseWeak ? "weak" : "unsafe_unretained");
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000239
Fariborz Jahanian1630c152012-01-21 00:43:53 +0000240 bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000241 if (!rewroteAttr)
242 canUseWeak = false;
243
244 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
Argyrios Kyrtzidis3fc3dcd2011-11-28 00:23:12 +0000245 if (isUserDeclared(I->IvarD)) {
246 if (I->IvarD &&
Fariborz Jahanian1630c152012-01-21 00:43:53 +0000247 I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) {
248 const char *toWhich =
249 (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " :
250 (canUseWeak ? "__weak " : "__unsafe_unretained ");
251 Pass.TA.insert(I->IvarD->getLocation(), toWhich);
252 }
Argyrios Kyrtzidis3fc3dcd2011-11-28 00:23:12 +0000253 }
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000254 if (I->ImplD)
Argyrios Kyrtzidisf5b993f2012-12-12 22:48:25 +0000255 Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
256 diag::err_arc_assign_property_ownership,
257 diag::err_arc_inconsistent_property_ownership,
258 I->IvarD->getLocation());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000259 }
260 }
261
262 void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
263 SourceLocation atLoc) const {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000264 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
265 /*AllowOnUnknownClass=*/Pass.isGCMigration());
Argyrios Kyrtzidis485ecee2011-11-08 23:09:34 +0000266
267 bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
268 atLoc);
269 if (!addedAttr)
270 canUseWeak = false;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000271
272 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
Argyrios Kyrtzidis3fc3dcd2011-11-28 00:23:12 +0000273 if (isUserDeclared(I->IvarD)) {
274 if (I->IvarD &&
275 I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
276 Pass.TA.insert(I->IvarD->getLocation(),
277 canUseWeak ? "__weak " : "__unsafe_unretained ");
278 }
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000279 if (I->ImplD) {
Argyrios Kyrtzidisf5b993f2012-12-12 22:48:25 +0000280 Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
281 diag::err_arc_assign_property_ownership,
282 diag::err_arc_inconsistent_property_ownership,
283 I->IvarD->getLocation());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000284 Pass.TA.clearDiagnostic(
285 diag::err_arc_objc_property_default_assign_on_object,
286 I->ImplD->getLocation());
287 }
288 }
289 }
290
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000291 bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000292 return MigrateCtx.removePropertyAttribute(fromAttr, atLoc);
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000293 }
294
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000295 bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000296 SourceLocation atLoc) const {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000297 return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000298 }
299
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000300 bool addAttribute(StringRef attr, SourceLocation atLoc) const {
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000301 return MigrateCtx.addPropertyAttribute(attr, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000302 }
303
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000304 class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
305 ObjCIvarDecl *Ivar;
306 public:
307 PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
308
309 bool VisitBinAssign(BinaryOperator *E) {
310 Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
311 if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
312 if (RE->getDecl() != Ivar)
313 return true;
314
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +0000315 if (isPlusOneAssign(E))
Argyrios Kyrtzidis93db2272011-08-10 21:46:48 +0000316 return false;
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000317 }
318
319 return true;
320 }
321 };
322
323 bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
324 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
325 PlusOneAssign oneAssign(I->IvarD);
326 bool notFound = oneAssign.TraverseDecl(CurImplD);
327 if (!notFound)
328 return true;
329 }
330
331 return false;
332 }
333
Argyrios Kyrtzidis0dd98a42011-11-07 18:40:32 +0000334 bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
335 if (Pass.isGCMigration())
336 return false;
337
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000338 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
339 if (isUserDeclared(I->IvarD)) {
340 if (isa<AttributedType>(I->IvarD->getType()))
341 return true;
342 if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
343 != Qualifiers::OCL_Strong)
344 return true;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000345 }
346 }
347
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000348 return false;
349 }
350
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000351 // \brief Returns true if all declarations in the @property have GC __weak.
352 bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
353 if (!Pass.isGCMigration())
354 return false;
355 if (props.empty())
356 return false;
357 return MigrateCtx.AtPropsWeak.count(atLoc.getRawEncoding());
358 }
359
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000360 bool isUserDeclared(ObjCIvarDecl *ivarD) const {
361 return ivarD && !ivarD->getSynthesize();
362 }
363
364 QualType getPropertyType(PropsTy &props) const {
365 assert(!props.empty());
Argyrios Kyrtzidisaa421ea2011-11-06 18:58:07 +0000366 QualType ty = props[0].PropD->getType().getUnqualifiedType();
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000367
368#ifndef NDEBUG
369 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidisaa421ea2011-11-06 18:58:07 +0000370 assert(ty == I->PropD->getType().getUnqualifiedType());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000371#endif
372
373 return ty;
374 }
375
376 ObjCPropertyDecl::PropertyAttributeKind
377 getPropertyAttrs(PropsTy &props) const {
378 assert(!props.empty());
379 ObjCPropertyDecl::PropertyAttributeKind
380 attrs = props[0].PropD->getPropertyAttributesAsWritten();
381
382#ifndef NDEBUG
383 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
384 assert(attrs == I->PropD->getPropertyAttributesAsWritten());
385#endif
386
387 return attrs;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000388 }
389};
390
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000391} // anonymous namespace
392
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000393void PropertyRewriteTraverser::traverseObjCImplementation(
394 ObjCImplementationContext &ImplCtx) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000395 PropertiesRewriter(ImplCtx.getMigrationContext())
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000396 .doTransform(ImplCtx.getImplementationDecl());
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000397}