blob: 2f5fe8be4cf2617f8eddd47b1889f55e82e16e08 [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 Kyrtzidisc8b36192011-07-13 19:22:00 +000049
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000050 struct PropData {
51 ObjCPropertyDecl *PropD;
52 ObjCIvarDecl *IvarD;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000053 ObjCPropertyImplDecl *ImplD;
54
55 PropData(ObjCPropertyDecl *propD) : PropD(propD), IvarD(0), ImplD(0) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000056 };
57
Chris Lattner0e62c1c2011-07-23 10:55:15 +000058 typedef SmallVector<PropData, 2> PropsTy;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000059 typedef std::map<unsigned, PropsTy> AtPropDeclsTy;
60 AtPropDeclsTy AtProps;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000061
62public:
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000063 PropertiesRewriter(MigrationPass &pass) : Pass(pass) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000064
65 void doTransform(ObjCImplementationDecl *D) {
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +000066 CurImplD = D;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000067 ObjCInterfaceDecl *iface = D->getClassInterface();
68 if (!iface)
69 return;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000070
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000071 for (ObjCInterfaceDecl::prop_iterator
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000072 propI = iface->prop_begin(),
73 propE = iface->prop_end(); propI != propE; ++propI) {
74 if (propI->getAtLoc().isInvalid())
75 continue;
76 PropsTy &props = AtProps[propI->getAtLoc().getRawEncoding()];
77 props.push_back(*propI);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000078 }
79
80 typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
81 prop_impl_iterator;
82 for (prop_impl_iterator
83 I = prop_impl_iterator(D->decls_begin()),
84 E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +000085 ObjCPropertyImplDecl *implD = *I;
86 if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
87 continue;
88 ObjCPropertyDecl *propD = implD->getPropertyDecl();
89 if (!propD || propD->isInvalidDecl())
90 continue;
91 ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
92 if (!ivarD || ivarD->isInvalidDecl())
93 continue;
94 unsigned rawAtLoc = propD->getAtLoc().getRawEncoding();
95 AtPropDeclsTy::iterator findAtLoc = AtProps.find(rawAtLoc);
96 if (findAtLoc == AtProps.end())
97 continue;
98
99 PropsTy &props = findAtLoc->second;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000100 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
101 if (I->PropD == propD) {
102 I->IvarD = ivarD;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000103 I->ImplD = implD;
104 break;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000105 }
106 }
107 }
108
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000109 for (AtPropDeclsTy::iterator
110 I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
111 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
112 PropsTy &props = I->second;
113 QualType ty = getPropertyType(props);
114 if (!ty->isObjCRetainableType())
115 continue;
116 if (hasIvarWithExplicitOwnership(props))
117 continue;
118
119 Transaction Trans(Pass.TA);
120 rewriteProperty(props, atLoc);
121 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000122 }
123
124private:
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000125 void rewriteProperty(PropsTy &props, SourceLocation atLoc) const {
126 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
127
128 if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy |
129 ObjCPropertyDecl::OBJC_PR_unsafe_unretained |
130 ObjCPropertyDecl::OBJC_PR_strong |
131 ObjCPropertyDecl::OBJC_PR_weak))
132 return;
133
134 if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) {
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000135 if (propAttrs & ObjCPropertyDecl::OBJC_PR_readonly)
136 rewriteAttribute("retain", "strong", atLoc);
137 else
138 removeAttribute("retain", atLoc); // strong is the default.
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000139 return;
140 }
141
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000142 if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) {
143 if (hasIvarAssignedAPlusOneObject(props)) {
144 rewriteAttribute("assign", "strong", atLoc);
145 return;
146 }
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000147 return rewriteAssign(props, atLoc);
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000148 }
149
150 if (hasIvarAssignedAPlusOneObject(props))
151 return maybeAddStrongAttr(props, atLoc);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000152
153 return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
154 }
155
156 void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
157 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
158
159 bool rewroteAttr = rewriteAttribute("assign",
160 canUseWeak ? "weak" : "unsafe_unretained",
161 atLoc);
162 if (!rewroteAttr)
163 canUseWeak = false;
164
165 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
166 if (isUserDeclared(I->IvarD))
167 Pass.TA.insert(I->IvarD->getLocation(),
168 canUseWeak ? "__weak " : "__unsafe_unretained ");
169 if (I->ImplD)
170 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
171 I->ImplD->getLocation());
172 }
173 }
174
175 void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
176 SourceLocation atLoc) const {
177 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000178
179 bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props));
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000180 if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
181 !hasAllIvarsBacked(props)) {
182 bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
183 atLoc);
184 if (!addedAttr)
185 canUseWeak = false;
186 }
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000187
188 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
189 if (isUserDeclared(I->IvarD))
190 Pass.TA.insert(I->IvarD->getLocation(),
191 canUseWeak ? "__weak " : "__unsafe_unretained ");
192 if (I->ImplD) {
193 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
194 I->ImplD->getLocation());
195 Pass.TA.clearDiagnostic(
196 diag::err_arc_objc_property_default_assign_on_object,
197 I->ImplD->getLocation());
198 }
199 }
200 }
201
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000202 void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const {
203 ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props);
204
205 if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) ||
206 !hasAllIvarsBacked(props)) {
207 addAttribute("strong", atLoc);
208 }
209
210 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
211 if (I->ImplD) {
212 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
213 I->ImplD->getLocation());
214 Pass.TA.clearDiagnostic(
215 diag::err_arc_objc_property_default_assign_on_object,
216 I->ImplD->getLocation());
217 }
218 }
219 }
220
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000221 bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
222 return rewriteAttribute(fromAttr, StringRef(), atLoc);
223 }
224
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000225 bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000226 SourceLocation atLoc) const {
227 if (atLoc.isMacroID())
228 return false;
229
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000230 SourceManager &SM = Pass.Ctx.getSourceManager();
231
232 // Break down the source location.
233 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
234
235 // Try to load the file buffer.
236 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000237 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000238 if (invalidTemp)
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000239 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000240
241 const char *tokenBegin = file.data() + locInfo.second;
242
243 // Lex from the start of the given location.
244 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
245 Pass.Ctx.getLangOptions(),
246 file.begin(), tokenBegin, file.end());
247 Token tok;
248 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000249 if (tok.isNot(tok::at)) return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000250 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000251 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000252 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000253 != "property")
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000254 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000255 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000256 if (tok.isNot(tok::l_paren)) return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000257
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000258 Token BeforeTok = tok;
259 Token AfterTok;
260 AfterTok.startToken();
261 SourceLocation AttrLoc;
262
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000263 lexer.LexFromRawLexer(tok);
264 if (tok.is(tok::r_paren))
265 return false;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000266
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000267 while (1) {
268 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000269 StringRef ident(tok.getRawIdentifierData(), tok.getLength());
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000270 if (ident == fromAttr) {
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000271 if (!toAttr.empty()) {
272 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
273 return true;
274 }
275 // We want to remove the attribute.
276 AttrLoc = tok.getLocation();
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000277 }
278
279 do {
280 lexer.LexFromRawLexer(tok);
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000281 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
282 AfterTok = tok;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000283 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
284 if (tok.is(tok::r_paren))
285 break;
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000286 if (AttrLoc.isInvalid())
287 BeforeTok = tok;
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000288 lexer.LexFromRawLexer(tok);
289 }
290
Argyrios Kyrtzidisffe8b1c2011-10-17 23:14:16 +0000291 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
292 // We want to remove the attribute.
293 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
294 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
295 AfterTok.getLocation()));
296 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
297 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
298 } else {
299 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
300 }
301
302 return true;
303 }
304
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000305 return false;
306 }
307
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000308 bool addAttribute(StringRef attr, SourceLocation atLoc) const {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000309 if (atLoc.isMacroID())
310 return false;
311
312 SourceManager &SM = Pass.Ctx.getSourceManager();
313
314 // Break down the source location.
315 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
316
317 // Try to load the file buffer.
318 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000319 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000320 if (invalidTemp)
321 return false;
322
323 const char *tokenBegin = file.data() + locInfo.second;
324
325 // Lex from the start of the given location.
326 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
327 Pass.Ctx.getLangOptions(),
328 file.begin(), tokenBegin, file.end());
329 Token tok;
330 lexer.LexFromRawLexer(tok);
331 if (tok.isNot(tok::at)) return false;
332 lexer.LexFromRawLexer(tok);
333 if (tok.isNot(tok::raw_identifier)) return false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000334 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000335 != "property")
336 return false;
337 lexer.LexFromRawLexer(tok);
338
339 if (tok.isNot(tok::l_paren)) {
340 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
341 return true;
342 }
343
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000344 lexer.LexFromRawLexer(tok);
345 if (tok.is(tok::r_paren)) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000346 Pass.TA.insert(tok.getLocation(), attr);
347 return true;
348 }
349
350 if (tok.isNot(tok::raw_identifier)) return false;
351
352 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
353 return true;
354 }
355
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000356 class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
357 ObjCIvarDecl *Ivar;
358 public:
359 PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
360
361 bool VisitBinAssign(BinaryOperator *E) {
362 Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
363 if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
364 if (RE->getDecl() != Ivar)
365 return true;
366
Argyrios Kyrtzidis93db2272011-08-10 21:46:48 +0000367 if (ObjCMessageExpr *
368 ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
369 if (ME->getMethodFamily() == OMF_retain)
370 return false;
371
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000372 ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
373 while (implCE && implCE->getCastKind() == CK_BitCast)
374 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
375
John McCall2d637d22011-09-10 06:18:15 +0000376 if (implCE && implCE->getCastKind() == CK_ARCConsumeObject)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000377 return false;
378 }
379
380 return true;
381 }
382 };
383
384 bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
385 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
386 PlusOneAssign oneAssign(I->IvarD);
387 bool notFound = oneAssign.TraverseDecl(CurImplD);
388 if (!notFound)
389 return true;
390 }
391
392 return false;
393 }
394
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000395 bool hasIvarWithExplicitOwnership(PropsTy &props) const {
396 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
397 if (isUserDeclared(I->IvarD)) {
398 if (isa<AttributedType>(I->IvarD->getType()))
399 return true;
400 if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
401 != Qualifiers::OCL_Strong)
402 return true;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000403 }
404 }
405
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000406 return false;
407 }
408
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000409 bool hasAllIvarsBacked(PropsTy &props) const {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000410 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000411 if (!isUserDeclared(I->IvarD))
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000412 return false;
413
414 return true;
415 }
416
417 bool isUserDeclared(ObjCIvarDecl *ivarD) const {
418 return ivarD && !ivarD->getSynthesize();
419 }
420
421 QualType getPropertyType(PropsTy &props) const {
422 assert(!props.empty());
423 QualType ty = props[0].PropD->getType();
424
425#ifndef NDEBUG
426 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
427 assert(ty == I->PropD->getType());
428#endif
429
430 return ty;
431 }
432
433 ObjCPropertyDecl::PropertyAttributeKind
434 getPropertyAttrs(PropsTy &props) const {
435 assert(!props.empty());
436 ObjCPropertyDecl::PropertyAttributeKind
437 attrs = props[0].PropD->getPropertyAttributesAsWritten();
438
439#ifndef NDEBUG
440 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
441 assert(attrs == I->PropD->getPropertyAttributesAsWritten());
442#endif
443
444 return attrs;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000445 }
446};
447
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000448class ImplementationChecker :
449 public RecursiveASTVisitor<ImplementationChecker> {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000450 MigrationPass &Pass;
451
452public:
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000453 ImplementationChecker(MigrationPass &pass) : Pass(pass) { }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000454
455 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000456 PropertiesRewriter(Pass).doTransform(D);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000457 return true;
458 }
459};
460
461} // anonymous namespace
462
Argyrios Kyrtzidisc8b36192011-07-13 19:22:00 +0000463void trans::rewriteProperties(MigrationPass &pass) {
464 ImplementationChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000465}