blob: 45a8c989efd3b4b1ac48fb0970edef9b927757b7 [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) {
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000070 if (!Ctx.getLangOptions().ObjCRuntimeHasWeak)
71 return false;
72
73 QualType T = type;
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +000074 if (T.isNull())
75 return false;
76
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000077 while (const PointerType *ptr = T->getAs<PointerType>())
78 T = ptr->getPointeeType();
79 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
80 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
Argyrios Kyrtzidis12192cf2011-11-07 18:40:29 +000081 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000082 return false; // id/NSObject is not safe for weak.
Douglas Gregor7723fec2011-12-15 20:29:51 +000083 if (!AllowOnUnknownClass && !Class->hasDefinition())
Argyrios Kyrtzidis5363e8d2011-07-12 22:16:25 +000084 return false; // forward classes are not verifiable, therefore not safe.
Argyrios Kyrtzidis86625b52011-07-12 22:05:17 +000085 if (Class->isArcWeakrefUnavailable())
86 return false;
87 if (isClassInWeakBlacklist(Class))
88 return false;
89 }
90
91 return true;
92}
93
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +000094/// \brief 'Loc' is the end of a statement range. This returns the location
95/// immediately after the semicolon following the statement.
96/// If no semicolon is found or the location is inside a macro, the returned
97/// source location will be invalid.
98SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
99 ASTContext &Ctx) {
Argyrios Kyrtzidisaec230d2011-09-01 20:53:18 +0000100 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
101 if (SemiLoc.isInvalid())
102 return SourceLocation();
Argyrios Kyrtzidisa64ccef2011-09-19 20:40:19 +0000103 return SemiLoc.getLocWithOffset(1);
Argyrios Kyrtzidisaec230d2011-09-01 20:53:18 +0000104}
105
106/// \brief \arg Loc is the end of a statement range. This returns the location
107/// of the semicolon following the statement.
108/// If no semicolon is found or the location is inside a macro, the returned
109/// source location will be invalid.
110SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
111 ASTContext &Ctx) {
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000112 SourceManager &SM = Ctx.getSourceManager();
113 if (loc.isMacroID()) {
Argyrios Kyrtzidis69bda4c2012-01-19 15:59:08 +0000114 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions(), &loc))
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000115 return SourceLocation();
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000116 }
117 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
118
119 // Break down the source location.
120 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
121
122 // Try to load the file buffer.
123 bool invalidTemp = false;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000124 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000125 if (invalidTemp)
126 return SourceLocation();
127
128 const char *tokenBegin = file.data() + locInfo.second;
129
130 // Lex from the start of the given location.
131 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
132 Ctx.getLangOptions(),
133 file.begin(), tokenBegin, file.end());
134 Token tok;
135 lexer.LexFromRawLexer(tok);
136 if (tok.isNot(tok::semi))
137 return SourceLocation();
138
Argyrios Kyrtzidisaec230d2011-09-01 20:53:18 +0000139 return tok.getLocation();
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000140}
141
142bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
143 if (!E || !E->HasSideEffects(Ctx))
144 return false;
145
146 E = E->IgnoreParenCasts();
147 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
148 if (!ME)
149 return true;
150 switch (ME->getMethodFamily()) {
151 case OMF_autorelease:
152 case OMF_dealloc:
153 case OMF_release:
154 case OMF_retain:
155 switch (ME->getReceiverKind()) {
156 case ObjCMessageExpr::SuperInstance:
157 return false;
158 case ObjCMessageExpr::Instance:
159 return hasSideEffects(ME->getInstanceReceiver(), Ctx);
160 default:
161 break;
162 }
163 break;
164 default:
165 break;
166 }
167
168 return true;
169}
170
Argyrios Kyrtzidis2c18ca02011-07-14 23:32:04 +0000171bool trans::isGlobalVar(Expr *E) {
172 E = E->IgnoreParenCasts();
173 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000174 return DRE->getDecl()->getDeclContext()->isFileContext() &&
175 DRE->getDecl()->getLinkage() == ExternalLinkage;
Argyrios Kyrtzidis2c18ca02011-07-14 23:32:04 +0000176 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
177 return isGlobalVar(condOp->getTrueExpr()) &&
178 isGlobalVar(condOp->getFalseExpr());
179
180 return false;
181}
182
Argyrios Kyrtzidis18fd0c62011-07-27 05:28:18 +0000183StringRef trans::getNilString(ASTContext &Ctx) {
184 if (Ctx.Idents.get("nil").hasMacroDefinition())
185 return "nil";
186 else
187 return "0";
188}
189
John McCall8f0e8d22011-06-15 23:25:17 +0000190namespace {
191
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000192class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
193 ExprSet &Refs;
194public:
195 ReferenceClear(ExprSet &refs) : Refs(refs) { }
196 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000197};
198
199class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
200 ValueDecl *Dcl;
201 ExprSet &Refs;
John McCall8f0e8d22011-06-15 23:25:17 +0000202
203public:
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000204 ReferenceCollector(ValueDecl *D, ExprSet &refs)
205 : Dcl(D), Refs(refs) { }
206
207 bool VisitDeclRefExpr(DeclRefExpr *E) {
208 if (E->getDecl() == Dcl)
209 Refs.insert(E);
210 return true;
211 }
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000212};
213
214class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
215 ExprSet &Removables;
216
217public:
218 RemovablesCollector(ExprSet &removables)
John McCall8f0e8d22011-06-15 23:25:17 +0000219 : Removables(removables) { }
220
221 bool shouldWalkTypesOfTypeLocs() const { return false; }
222
223 bool TraverseStmtExpr(StmtExpr *E) {
224 CompoundStmt *S = E->getSubStmt();
225 for (CompoundStmt::body_iterator
226 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
227 if (I != E - 1)
228 mark(*I);
229 TraverseStmt(*I);
230 }
231 return true;
232 }
233
234 bool VisitCompoundStmt(CompoundStmt *S) {
235 for (CompoundStmt::body_iterator
236 I = S->body_begin(), E = S->body_end(); I != E; ++I)
237 mark(*I);
238 return true;
239 }
240
241 bool VisitIfStmt(IfStmt *S) {
242 mark(S->getThen());
243 mark(S->getElse());
244 return true;
245 }
246
247 bool VisitWhileStmt(WhileStmt *S) {
248 mark(S->getBody());
249 return true;
250 }
251
252 bool VisitDoStmt(DoStmt *S) {
253 mark(S->getBody());
254 return true;
255 }
256
257 bool VisitForStmt(ForStmt *S) {
258 mark(S->getInit());
259 mark(S->getInc());
260 mark(S->getBody());
261 return true;
262 }
263
264private:
265 void mark(Stmt *S) {
266 if (!S) return;
267
John McCall7e5e5f42011-07-07 06:58:02 +0000268 while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
269 S = Label->getSubStmt();
270 S = S->IgnoreImplicit();
John McCall8f0e8d22011-06-15 23:25:17 +0000271 if (Expr *E = dyn_cast<Expr>(S))
272 Removables.insert(E);
273 }
274};
275
John McCall8f0e8d22011-06-15 23:25:17 +0000276} // end anonymous namespace
277
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000278void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
279 ReferenceClear(refs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000280}
281
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000282void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
283 ReferenceCollector(D, refs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000284}
285
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000286void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
287 RemovablesCollector(exprs).TraverseStmt(S);
John McCall8f0e8d22011-06-15 23:25:17 +0000288}
289
290//===----------------------------------------------------------------------===//
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000291// MigrationContext
292//===----------------------------------------------------------------------===//
293
294namespace {
295
296class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
297 MigrationContext &MigrateCtx;
Argyrios Kyrtzidisa33849b2011-11-07 18:46:50 +0000298 typedef RecursiveASTVisitor<ASTTransform> base;
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000299
300public:
301 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
302
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000303 bool shouldWalkTypesOfTypeLocs() const { return false; }
304
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000305 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
306 ObjCImplementationContext ImplCtx(MigrateCtx, D);
307 for (MigrationContext::traverser_iterator
308 I = MigrateCtx.traversers_begin(),
309 E = MigrateCtx.traversers_end(); I != E; ++I)
310 (*I)->traverseObjCImplementation(ImplCtx);
311
Argyrios Kyrtzidisa33849b2011-11-07 18:46:50 +0000312 return base::TraverseObjCImplementationDecl(D);
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000313 }
314
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000315 bool TraverseStmt(Stmt *rootS) {
316 if (!rootS)
317 return true;
318
319 BodyContext BodyCtx(MigrateCtx, rootS);
320 for (MigrationContext::traverser_iterator
321 I = MigrateCtx.traversers_begin(),
322 E = MigrateCtx.traversers_end(); I != E; ++I)
323 (*I)->traverseBody(BodyCtx);
324
325 return true;
326 }
327};
328
329}
330
331MigrationContext::~MigrationContext() {
332 for (traverser_iterator
333 I = traversers_begin(), E = traversers_end(); I != E; ++I)
334 delete *I;
335}
336
Argyrios Kyrtzidis1fe42032011-11-04 23:43:03 +0000337bool MigrationContext::isGCOwnedNonObjC(QualType T) {
338 while (!T.isNull()) {
339 if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
340 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
341 return !AttrT->getModifiedType()->isObjCRetainableType();
342 }
343
344 if (T->isArrayType())
345 T = Pass.Ctx.getBaseElementType(T);
346 else if (const PointerType *PT = T->getAs<PointerType>())
347 T = PT->getPointeeType();
348 else if (const ReferenceType *RT = T->getAs<ReferenceType>())
349 T = RT->getPointeeType();
350 else
351 break;
352 }
353
354 return false;
355}
356
Argyrios Kyrtzidisb0e1e122011-11-07 18:46:46 +0000357bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
358 StringRef toAttr,
359 SourceLocation atLoc) {
360 if (atLoc.isMacroID())
361 return false;
362
363 SourceManager &SM = Pass.Ctx.getSourceManager();
364
365 // Break down the source location.
366 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
367
368 // Try to load the file buffer.
369 bool invalidTemp = false;
370 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
371 if (invalidTemp)
372 return false;
373
374 const char *tokenBegin = file.data() + locInfo.second;
375
376 // Lex from the start of the given location.
377 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
378 Pass.Ctx.getLangOptions(),
379 file.begin(), tokenBegin, file.end());
380 Token tok;
381 lexer.LexFromRawLexer(tok);
382 if (tok.isNot(tok::at)) return false;
383 lexer.LexFromRawLexer(tok);
384 if (tok.isNot(tok::raw_identifier)) return false;
385 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
386 != "property")
387 return false;
388 lexer.LexFromRawLexer(tok);
389 if (tok.isNot(tok::l_paren)) return false;
390
391 Token BeforeTok = tok;
392 Token AfterTok;
393 AfterTok.startToken();
394 SourceLocation AttrLoc;
395
396 lexer.LexFromRawLexer(tok);
397 if (tok.is(tok::r_paren))
398 return false;
399
400 while (1) {
401 if (tok.isNot(tok::raw_identifier)) return false;
402 StringRef ident(tok.getRawIdentifierData(), tok.getLength());
403 if (ident == fromAttr) {
404 if (!toAttr.empty()) {
405 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
406 return true;
407 }
408 // We want to remove the attribute.
409 AttrLoc = tok.getLocation();
410 }
411
412 do {
413 lexer.LexFromRawLexer(tok);
414 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
415 AfterTok = tok;
416 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
417 if (tok.is(tok::r_paren))
418 break;
419 if (AttrLoc.isInvalid())
420 BeforeTok = tok;
421 lexer.LexFromRawLexer(tok);
422 }
423
424 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
425 // We want to remove the attribute.
426 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
427 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
428 AfterTok.getLocation()));
429 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
430 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
431 } else {
432 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
433 }
434
435 return true;
436 }
437
438 return false;
439}
440
Argyrios Kyrtzidis6da42742011-11-28 02:04:36 +0000441bool MigrationContext::addPropertyAttribute(StringRef attr,
442 SourceLocation atLoc) {
443 if (atLoc.isMacroID())
444 return false;
445
446 SourceManager &SM = Pass.Ctx.getSourceManager();
447
448 // Break down the source location.
449 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
450
451 // Try to load the file buffer.
452 bool invalidTemp = false;
453 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
454 if (invalidTemp)
455 return false;
456
457 const char *tokenBegin = file.data() + locInfo.second;
458
459 // Lex from the start of the given location.
460 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
461 Pass.Ctx.getLangOptions(),
462 file.begin(), tokenBegin, file.end());
463 Token tok;
464 lexer.LexFromRawLexer(tok);
465 if (tok.isNot(tok::at)) return false;
466 lexer.LexFromRawLexer(tok);
467 if (tok.isNot(tok::raw_identifier)) return false;
468 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
469 != "property")
470 return false;
471 lexer.LexFromRawLexer(tok);
472
473 if (tok.isNot(tok::l_paren)) {
474 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
475 return true;
476 }
477
478 lexer.LexFromRawLexer(tok);
479 if (tok.is(tok::r_paren)) {
480 Pass.TA.insert(tok.getLocation(), attr);
481 return true;
482 }
483
484 if (tok.isNot(tok::raw_identifier)) return false;
485
486 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
487 return true;
488}
489
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000490void MigrationContext::traverse(TranslationUnitDecl *TU) {
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000491 for (traverser_iterator
492 I = traversers_begin(), E = traversers_end(); I != E; ++I)
493 (*I)->traverseTU(*this);
494
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000495 ASTTransform(*this).TraverseDecl(TU);
496}
497
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000498static void GCRewriteFinalize(MigrationPass &pass) {
499 ASTContext &Ctx = pass.Ctx;
500 TransformActions &TA = pass.TA;
501 DeclContext *DC = Ctx.getTranslationUnitDecl();
502 Selector FinalizeSel =
503 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
504
505 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
506 impl_iterator;
507 for (impl_iterator I = impl_iterator(DC->decls_begin()),
508 E = impl_iterator(DC->decls_end()); I != E; ++I) {
509 for (ObjCImplementationDecl::instmeth_iterator
510 MI = (*I)->instmeth_begin(),
511 ME = (*I)->instmeth_end(); MI != ME; ++MI) {
512 ObjCMethodDecl *MD = *MI;
513 if (!MD->hasBody())
514 continue;
515
516 if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
517 ObjCMethodDecl *FinalizeM = MD;
518 Transaction Trans(TA);
519 TA.insert(FinalizeM->getSourceRange().getBegin(),
520 "#if !__has_feature(objc_arc)\n");
521 CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
522 const SourceManager &SM = pass.Ctx.getSourceManager();
523 const LangOptions &LangOpts = pass.Ctx.getLangOptions();
524 bool Invalid;
525 std::string str = "\n#endif\n";
526 str += Lexer::getSourceText(
527 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
528 SM, LangOpts, &Invalid);
529 TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
530
531 break;
532 }
533 }
534 }
535}
536
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000537//===----------------------------------------------------------------------===//
John McCall8f0e8d22011-06-15 23:25:17 +0000538// getAllTransformations.
539//===----------------------------------------------------------------------===//
540
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000541static void traverseAST(MigrationPass &pass) {
542 MigrationContext MigrateCtx(pass);
543
544 if (pass.isGCMigration()) {
545 MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
Argyrios Kyrtzidisf38fa732011-11-06 18:58:03 +0000546 MigrateCtx.addTraverser(new GCAttrsTraverser());
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000547 }
Argyrios Kyrtzidisb0d5db12011-11-06 18:57:57 +0000548 MigrateCtx.addTraverser(new PropertyRewriteTraverser());
Argyrios Kyrtzidis2a278182012-03-05 08:46:24 +0000549 MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000550
551 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
552}
553
John McCall8f0e8d22011-06-15 23:25:17 +0000554static void independentTransforms(MigrationPass &pass) {
555 rewriteAutoreleasePool(pass);
Argyrios Kyrtzidise7ef8552011-11-04 15:58:22 +0000556 removeRetainReleaseDeallocFinalize(pass);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000557 rewriteUnusedInitDelegate(pass);
Argyrios Kyrtzidise7ef8552011-11-04 15:58:22 +0000558 removeZeroOutPropsInDeallocFinalize(pass);
John McCall8f0e8d22011-06-15 23:25:17 +0000559 makeAssignARCSafe(pass);
Argyrios Kyrtzidis7196d062011-06-21 20:20:39 +0000560 rewriteUnbridgedCasts(pass);
Argyrios Kyrtzidisfd103982011-07-18 07:44:45 +0000561 checkAPIUses(pass);
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000562 traverseAST(pass);
John McCall8f0e8d22011-06-15 23:25:17 +0000563}
564
Argyrios Kyrtzidise0ac7452011-11-04 15:58:08 +0000565std::vector<TransformFn> arcmt::getAllTransformations(
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000566 LangOptions::GCMode OrigGCMode,
567 bool NoFinalizeRemoval) {
John McCall8f0e8d22011-06-15 23:25:17 +0000568 std::vector<TransformFn> transforms;
569
Fariborz Jahanianbbdfad52012-01-26 20:57:58 +0000570 if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval)
571 transforms.push_back(GCRewriteFinalize);
John McCall8f0e8d22011-06-15 23:25:17 +0000572 transforms.push_back(independentTransforms);
Argyrios Kyrtzidisfd3455a2011-06-21 20:20:42 +0000573 // This depends on previous transformations removing various expressions.
Argyrios Kyrtzidise7ef8552011-11-04 15:58:22 +0000574 transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
John McCall8f0e8d22011-06-15 23:25:17 +0000575
576 return transforms;
577}