blob: 170b7c8e15af84af8fb556cedb1050b322c7eaa5 [file] [log] [blame]
John McCall8f0e8d22011-06-15 23:25:17 +00001//===--- Tranforms.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//===----------------------------------------------------------------------===//
John McCall8f0e8d22011-06-15 23:25:17 +00009
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000010#include "Transforms.h"
John McCall8f0e8d22011-06-15 23:25:17 +000011#include "Internals.h"
12#include "clang/Sema/SemaDiagnostic.h"
13#include "clang/AST/RecursiveASTVisitor.h"
14#include "clang/AST/StmtVisitor.h"
John McCall8f0e8d22011-06-15 23:25:17 +000015#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
16#include "clang/Lex/Lexer.h"
17#include "clang/Basic/SourceManager.h"
18#include "llvm/ADT/StringSwitch.h"
19#include "llvm/ADT/DenseSet.h"
20#include <map>
21
22using namespace clang;
23using namespace arcmt;
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000024using namespace trans;
John McCall8f0e8d22011-06-15 23:25:17 +000025
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +000026ASTTraverser::~ASTTraverser() { }
27
John McCall8f0e8d22011-06-15 23:25:17 +000028//===----------------------------------------------------------------------===//
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000029// Helpers.
John McCall8f0e8d22011-06-15 23:25:17 +000030//===----------------------------------------------------------------------===//
31
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000032/// \brief True if the class is one that does not support weak.
33static bool isClassInWeakBlacklist(ObjCInterfaceDecl *cls) {
34 if (!cls)
35 return false;
36
37 bool inList = llvm::StringSwitch<bool>(cls->getName())
38 .Case("NSColorSpace", true)
39 .Case("NSFont", true)
40 .Case("NSFontPanel", true)
41 .Case("NSImage", true)
42 .Case("NSLazyBrowserCell", true)
43 .Case("NSWindow", true)
44 .Case("NSWindowController", true)
Argyrios Kyrtzidis263d6672011-11-08 05:56:08 +000045 .Case("NSViewController", true)
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000046 .Case("NSMenuView", true)
47 .Case("NSPersistentUIWindowInfo", true)
48 .Case("NSTableCellView", true)
49 .Case("NSATSTypeSetter", true)
50 .Case("NSATSGlyphStorage", true)
51 .Case("NSLineFragmentRenderingContext", true)
52 .Case("NSAttributeDictionary", true)
53 .Case("NSParagraphStyle", true)
54 .Case("NSTextTab", true)
55 .Case("NSSimpleHorizontalTypesetter", true)
56 .Case("_NSCachedAttributedString", true)
57 .Case("NSStringDrawingTextStorage", true)
58 .Case("NSTextView", true)
59 .Case("NSSubTextStorage", true)
60 .Default(false);
61
62 if (inList)
63 return true;
64
65 return isClassInWeakBlacklist(cls->getSuperClass());
66}
67
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000068bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
69 bool AllowOnUnknownClass) {
David Blaikie4e4d0842012-03-11 07:00:24 +000070 if (!Ctx.getLangOpts().ObjCRuntimeHasWeak)
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000071 return false;
72
73 QualType T = type;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000074 if (T.isNull())
75 return false;
76
Argyrios Kyrtzidis2af504b2012-03-16 00:10:35 +000077 // iOS is always safe to use 'weak'.
78 if (Ctx.getTargetInfo().getTriple().getOS() == llvm::Triple::IOS)
79 AllowOnUnknownClass = true;
80
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000081 while (const PointerType *ptr = T->getAs<PointerType>())
82 T = ptr->getPointeeType();
83 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
84 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000085 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000086 return false; // id/NSObject is not safe for weak.
Douglas Gregor7723fec2011-12-15 20:29:51 +000087 if (!AllowOnUnknownClass && !Class->hasDefinition())
Argyrios Kyrtzidis5363e8d2011-07-12 22:16:25 +000088 return false; // forward classes are not verifiable, therefore not safe.
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000089 if (Class->isArcWeakrefUnavailable())
90 return false;
91 if (isClassInWeakBlacklist(Class))
92 return false;
93 }
94
95 return true;
96}
97
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000098/// \brief 'Loc' is the end of a statement range. This returns the location
99/// immediately after the semicolon following the statement.
100/// If no semicolon is found or the location is inside a macro, the returned
101/// source location will be invalid.
102SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
103 ASTContext &Ctx) {
Argyrios Kyrtzidisaec230d2011-09-01 20:53:18 +0000104 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
105 if (SemiLoc.isInvalid())
106 return SourceLocation();
Argyrios Kyrtzidisa64ccef2011-09-19 20:40:19 +0000107 return SemiLoc.getLocWithOffset(1);
Argyrios Kyrtzidisaec230d2011-09-01 20:53:18 +0000108}
109
110/// \brief \arg Loc is the end of a statement range. This returns the location
111/// of the semicolon following the statement.
112/// If no semicolon is found or the location is inside a macro, the returned
113/// source location will be invalid.
114SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
115 ASTContext &Ctx) {
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000116 SourceManager &SM = Ctx.getSourceManager();
117 if (loc.isMacroID()) {
David Blaikie4e4d0842012-03-11 07:00:24 +0000118 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000119 return SourceLocation();
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000120 }
David Blaikie4e4d0842012-03-11 07:00:24 +0000121 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000122
123 // Break down the source location.
124 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
125
126 // Try to load the file buffer.
127 bool invalidTemp = false;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000128 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000129 if (invalidTemp)
130 return SourceLocation();
131
132 const char *tokenBegin = file.data() + locInfo.second;
133
134 // Lex from the start of the given location.
135 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
David Blaikie4e4d0842012-03-11 07:00:24 +0000136 Ctx.getLangOpts(),
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000137 file.begin(), tokenBegin, file.end());
138 Token tok;
139 lexer.LexFromRawLexer(tok);
140 if (tok.isNot(tok::semi))
141 return SourceLocation();
142
Argyrios Kyrtzidisaec230d2011-09-01 20:53:18 +0000143 return tok.getLocation();
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000144}
145
146bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
147 if (!E || !E->HasSideEffects(Ctx))
148 return false;
149
150 E = E->IgnoreParenCasts();
151 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
152 if (!ME)
153 return true;
154 switch (ME->getMethodFamily()) {
155 case OMF_autorelease:
156 case OMF_dealloc:
157 case OMF_release:
158 case OMF_retain:
159 switch (ME->getReceiverKind()) {
160 case ObjCMessageExpr::SuperInstance:
161 return false;
162 case ObjCMessageExpr::Instance:
163 return hasSideEffects(ME->getInstanceReceiver(), Ctx);
164 default:
165 break;
166 }
167 break;
168 default:
169 break;
170 }
171
172 return true;
173}
174
Argyrios Kyrtzidis2c18ca02011-07-14 23:32:04 +0000175bool trans::isGlobalVar(Expr *E) {
176 E = E->IgnoreParenCasts();
177 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000178 return DRE->getDecl()->getDeclContext()->isFileContext() &&
179 DRE->getDecl()->getLinkage() == ExternalLinkage;
Argyrios Kyrtzidis2c18ca02011-07-14 23:32:04 +0000180 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
181 return isGlobalVar(condOp->getTrueExpr()) &&
182 isGlobalVar(condOp->getFalseExpr());
183
184 return false;
185}
186
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000187StringRef trans::getNilString(ASTContext &Ctx) {
188 if (Ctx.Idents.get("nil").hasMacroDefinition())
189 return "nil";
190 else
191 return "0";
192}
193
John McCall8f0e8d22011-06-15 23:25:17 +0000194namespace {
195
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000196class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
197 ExprSet &Refs;
198public:
199 ReferenceClear(ExprSet &refs) : Refs(refs) { }
200 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000201};
202
203class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
204 ValueDecl *Dcl;
205 ExprSet &Refs;
John McCall8f0e8d22011-06-15 23:25:17 +0000206
207public:
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000208 ReferenceCollector(ValueDecl *D, ExprSet &refs)
209 : Dcl(D), Refs(refs) { }
210
211 bool VisitDeclRefExpr(DeclRefExpr *E) {
212 if (E->getDecl() == Dcl)
213 Refs.insert(E);
214 return true;
215 }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000216};
217
218class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
219 ExprSet &Removables;
220
221public:
222 RemovablesCollector(ExprSet &removables)
John McCall8f0e8d22011-06-15 23:25:17 +0000223 : Removables(removables) { }
224
225 bool shouldWalkTypesOfTypeLocs() const { return false; }
226
227 bool TraverseStmtExpr(StmtExpr *E) {
228 CompoundStmt *S = E->getSubStmt();
229 for (CompoundStmt::body_iterator
230 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
231 if (I != E - 1)
232 mark(*I);
233 TraverseStmt(*I);
234 }
235 return true;
236 }
237
238 bool VisitCompoundStmt(CompoundStmt *S) {
239 for (CompoundStmt::body_iterator
240 I = S->body_begin(), E = S->body_end(); I != E; ++I)
241 mark(*I);
242 return true;
243 }
244
245 bool VisitIfStmt(IfStmt *S) {
246 mark(S->getThen());
247 mark(S->getElse());
248 return true;
249 }
250
251 bool VisitWhileStmt(WhileStmt *S) {
252 mark(S->getBody());
253 return true;
254 }
255
256 bool VisitDoStmt(DoStmt *S) {
257 mark(S->getBody());
258 return true;
259 }
260
261 bool VisitForStmt(ForStmt *S) {
262 mark(S->getInit());
263 mark(S->getInc());
264 mark(S->getBody());
265 return true;
266 }
267
268private:
269 void mark(Stmt *S) {
270 if (!S) return;
271
John McCall7e5e5f42011-07-07 06:58:02 +0000272 while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
273 S = Label->getSubStmt();
274 S = S->IgnoreImplicit();
John McCall8f0e8d22011-06-15 23:25:17 +0000275 if (Expr *E = dyn_cast<Expr>(S))
276 Removables.insert(E);
277 }
278};
279
John McCall8f0e8d22011-06-15 23:25:17 +0000280} // end anonymous namespace
281
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000282void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
283 ReferenceClear(refs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000284}
285
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000286void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
287 ReferenceCollector(D, refs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000288}
289
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000290void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
291 RemovablesCollector(exprs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000292}
293
294//===----------------------------------------------------------------------===//
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000295// MigrationContext
296//===----------------------------------------------------------------------===//
297
298namespace {
299
300class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
301 MigrationContext &MigrateCtx;
Argyrios Kyrtzidisa33849b2011-11-07 18:46:50 +0000302 typedef RecursiveASTVisitor<ASTTransform> base;
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000303
304public:
305 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
306
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000307 bool shouldWalkTypesOfTypeLocs() const { return false; }
308
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000309 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
310 ObjCImplementationContext ImplCtx(MigrateCtx, D);
311 for (MigrationContext::traverser_iterator
312 I = MigrateCtx.traversers_begin(),
313 E = MigrateCtx.traversers_end(); I != E; ++I)
314 (*I)->traverseObjCImplementation(ImplCtx);
315
Argyrios Kyrtzidisa33849b2011-11-07 18:46:50 +0000316 return base::TraverseObjCImplementationDecl(D);
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000317 }
318
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000319 bool TraverseStmt(Stmt *rootS) {
320 if (!rootS)
321 return true;
322
323 BodyContext BodyCtx(MigrateCtx, rootS);
324 for (MigrationContext::traverser_iterator
325 I = MigrateCtx.traversers_begin(),
326 E = MigrateCtx.traversers_end(); I != E; ++I)
327 (*I)->traverseBody(BodyCtx);
328
329 return true;
330 }
331};
332
333}
334
335MigrationContext::~MigrationContext() {
336 for (traverser_iterator
337 I = traversers_begin(), E = traversers_end(); I != E; ++I)
338 delete *I;
339}
340
Argyrios Kyrtzidis1fe42032011-11-04 23:43:03 +0000341bool MigrationContext::isGCOwnedNonObjC(QualType T) {
342 while (!T.isNull()) {
343 if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
344 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
345 return !AttrT->getModifiedType()->isObjCRetainableType();
346 }
347
348 if (T->isArrayType())
349 T = Pass.Ctx.getBaseElementType(T);
350 else if (const PointerType *PT = T->getAs<PointerType>())
351 T = PT->getPointeeType();
352 else if (const ReferenceType *RT = T->getAs<ReferenceType>())
353 T = RT->getPointeeType();
354 else
355 break;
356 }
357
358 return false;
359}
360
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000361bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
362 StringRef toAttr,
363 SourceLocation atLoc) {
364 if (atLoc.isMacroID())
365 return false;
366
367 SourceManager &SM = Pass.Ctx.getSourceManager();
368
369 // Break down the source location.
370 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
371
372 // Try to load the file buffer.
373 bool invalidTemp = false;
374 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
375 if (invalidTemp)
376 return false;
377
378 const char *tokenBegin = file.data() + locInfo.second;
379
380 // Lex from the start of the given location.
381 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
David Blaikie4e4d0842012-03-11 07:00:24 +0000382 Pass.Ctx.getLangOpts(),
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000383 file.begin(), tokenBegin, file.end());
384 Token tok;
385 lexer.LexFromRawLexer(tok);
386 if (tok.isNot(tok::at)) return false;
387 lexer.LexFromRawLexer(tok);
388 if (tok.isNot(tok::raw_identifier)) return false;
389 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
390 != "property")
391 return false;
392 lexer.LexFromRawLexer(tok);
393 if (tok.isNot(tok::l_paren)) return false;
394
395 Token BeforeTok = tok;
396 Token AfterTok;
397 AfterTok.startToken();
398 SourceLocation AttrLoc;
399
400 lexer.LexFromRawLexer(tok);
401 if (tok.is(tok::r_paren))
402 return false;
403
404 while (1) {
405 if (tok.isNot(tok::raw_identifier)) return false;
406 StringRef ident(tok.getRawIdentifierData(), tok.getLength());
407 if (ident == fromAttr) {
408 if (!toAttr.empty()) {
409 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
410 return true;
411 }
412 // We want to remove the attribute.
413 AttrLoc = tok.getLocation();
414 }
415
416 do {
417 lexer.LexFromRawLexer(tok);
418 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
419 AfterTok = tok;
420 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
421 if (tok.is(tok::r_paren))
422 break;
423 if (AttrLoc.isInvalid())
424 BeforeTok = tok;
425 lexer.LexFromRawLexer(tok);
426 }
427
428 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
429 // We want to remove the attribute.
430 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
431 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
432 AfterTok.getLocation()));
433 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
434 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
435 } else {
436 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
437 }
438
439 return true;
440 }
441
442 return false;
443}
444
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000445bool MigrationContext::addPropertyAttribute(StringRef attr,
446 SourceLocation atLoc) {
447 if (atLoc.isMacroID())
448 return false;
449
450 SourceManager &SM = Pass.Ctx.getSourceManager();
451
452 // Break down the source location.
453 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
454
455 // Try to load the file buffer.
456 bool invalidTemp = false;
457 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
458 if (invalidTemp)
459 return false;
460
461 const char *tokenBegin = file.data() + locInfo.second;
462
463 // Lex from the start of the given location.
464 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
David Blaikie4e4d0842012-03-11 07:00:24 +0000465 Pass.Ctx.getLangOpts(),
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000466 file.begin(), tokenBegin, file.end());
467 Token tok;
468 lexer.LexFromRawLexer(tok);
469 if (tok.isNot(tok::at)) return false;
470 lexer.LexFromRawLexer(tok);
471 if (tok.isNot(tok::raw_identifier)) return false;
472 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
473 != "property")
474 return false;
475 lexer.LexFromRawLexer(tok);
476
477 if (tok.isNot(tok::l_paren)) {
478 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
479 return true;
480 }
481
482 lexer.LexFromRawLexer(tok);
483 if (tok.is(tok::r_paren)) {
484 Pass.TA.insert(tok.getLocation(), attr);
485 return true;
486 }
487
488 if (tok.isNot(tok::raw_identifier)) return false;
489
490 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
491 return true;
492}
493
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000494void MigrationContext::traverse(TranslationUnitDecl *TU) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000495 for (traverser_iterator
496 I = traversers_begin(), E = traversers_end(); I != E; ++I)
497 (*I)->traverseTU(*this);
498
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000499 ASTTransform(*this).TraverseDecl(TU);
500}
501
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000502static void GCRewriteFinalize(MigrationPass &pass) {
503 ASTContext &Ctx = pass.Ctx;
504 TransformActions &TA = pass.TA;
505 DeclContext *DC = Ctx.getTranslationUnitDecl();
506 Selector FinalizeSel =
507 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
508
509 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
510 impl_iterator;
511 for (impl_iterator I = impl_iterator(DC->decls_begin()),
512 E = impl_iterator(DC->decls_end()); I != E; ++I) {
513 for (ObjCImplementationDecl::instmeth_iterator
514 MI = (*I)->instmeth_begin(),
515 ME = (*I)->instmeth_end(); MI != ME; ++MI) {
516 ObjCMethodDecl *MD = *MI;
517 if (!MD->hasBody())
518 continue;
519
520 if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
521 ObjCMethodDecl *FinalizeM = MD;
522 Transaction Trans(TA);
523 TA.insert(FinalizeM->getSourceRange().getBegin(),
524 "#if !__has_feature(objc_arc)\n");
525 CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
526 const SourceManager &SM = pass.Ctx.getSourceManager();
David Blaikie4e4d0842012-03-11 07:00:24 +0000527 const LangOptions &LangOpts = pass.Ctx.getLangOpts();
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000528 bool Invalid;
529 std::string str = "\n#endif\n";
530 str += Lexer::getSourceText(
531 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
532 SM, LangOpts, &Invalid);
533 TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
534
535 break;
536 }
537 }
538 }
539}
540
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000541//===----------------------------------------------------------------------===//
John McCall8f0e8d22011-06-15 23:25:17 +0000542// getAllTransformations.
543//===----------------------------------------------------------------------===//
544
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000545static void traverseAST(MigrationPass &pass) {
546 MigrationContext MigrateCtx(pass);
547
548 if (pass.isGCMigration()) {
549 MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000550 MigrateCtx.addTraverser(new GCAttrsTraverser());
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000551 }
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000552 MigrateCtx.addTraverser(new PropertyRewriteTraverser());
Argyrios Kyrtzidis2a278182012-03-05 08:46:24 +0000553 MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000554
555 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
556}
557
John McCall8f0e8d22011-06-15 23:25:17 +0000558static void independentTransforms(MigrationPass &pass) {
559 rewriteAutoreleasePool(pass);
Argyrios Kyrtzidise7ef8552011-11-04 15:58:22 +0000560 removeRetainReleaseDeallocFinalize(pass);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000561 rewriteUnusedInitDelegate(pass);
Argyrios Kyrtzidise7ef8552011-11-04 15:58:22 +0000562 removeZeroOutPropsInDeallocFinalize(pass);
John McCall8f0e8d22011-06-15 23:25:17 +0000563 makeAssignARCSafe(pass);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000564 rewriteUnbridgedCasts(pass);
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +0000565 checkAPIUses(pass);
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000566 traverseAST(pass);
John McCall8f0e8d22011-06-15 23:25:17 +0000567}
568
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000569std::vector<TransformFn> arcmt::getAllTransformations(
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000570 LangOptions::GCMode OrigGCMode,
571 bool NoFinalizeRemoval) {
John McCall8f0e8d22011-06-15 23:25:17 +0000572 std::vector<TransformFn> transforms;
573
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000574 if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval)
575 transforms.push_back(GCRewriteFinalize);
John McCall8f0e8d22011-06-15 23:25:17 +0000576 transforms.push_back(independentTransforms);
Argyrios Kyrtzidisfd3455a2011-06-21 20:20:42 +0000577 // This depends on previous transformations removing various expressions.
Argyrios Kyrtzidise7ef8552011-11-04 15:58:22 +0000578 transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
John McCall8f0e8d22011-06-15 23:25:17 +0000579
580 return transforms;
581}