blob: cb96a547fbac300a7d28da3c18ca6704a85bdaaa [file] [log] [blame]
Benjamin Kramerd81108f2012-11-14 15:08:31 +00001//===--- Transforms.cpp - Transformations to ARC mode ---------------------===//
John McCalld70fb982011-06-15 23:25:17 +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//===----------------------------------------------------------------------===//
John McCalld70fb982011-06-15 23:25:17 +00009
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000010#include "Transforms.h"
John McCalld70fb982011-06-15 23:25:17 +000011#include "Internals.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000012#include "clang/AST/ASTContext.h"
John McCalld70fb982011-06-15 23:25:17 +000013#include "clang/AST/RecursiveASTVisitor.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000014#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
John McCalld70fb982011-06-15 23:25:17 +000015#include "clang/Basic/SourceManager.h"
Benjamin Kramerd7d2b1f2012-12-01 16:35:25 +000016#include "clang/Basic/TargetInfo.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000017#include "clang/Lex/Lexer.h"
Richard Smith20e883e2015-04-29 23:20:19 +000018#include "clang/Lex/Preprocessor.h"
Benjamin Kramer4ab984e2012-07-04 20:19:54 +000019#include "clang/Sema/Sema.h"
John McCalld70fb982011-06-15 23:25:17 +000020
21using namespace clang;
22using namespace arcmt;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000023using namespace trans;
John McCalld70fb982011-06-15 23:25:17 +000024
Angel Garcia Gomez637d1e62015-10-20 13:23:58 +000025ASTTraverser::~ASTTraverser() { }
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +000026
Argyrios Kyrtzidis273c7c42012-06-01 00:10:47 +000027bool MigrationPass::CFBridgingFunctionsDefined() {
28 if (!EnableCFBridgeFns.hasValue())
29 EnableCFBridgeFns = SemaRef.isKnownName("CFBridgingRetain") &&
30 SemaRef.isKnownName("CFBridgingRelease");
31 return *EnableCFBridgeFns;
32}
33
John McCalld70fb982011-06-15 23:25:17 +000034//===----------------------------------------------------------------------===//
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000035// Helpers.
John McCalld70fb982011-06-15 23:25:17 +000036//===----------------------------------------------------------------------===//
37
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000038bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
39 bool AllowOnUnknownClass) {
John McCall460ce582015-10-22 18:38:17 +000040 if (!Ctx.getLangOpts().ObjCWeakRuntime)
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000041 return false;
42
43 QualType T = type;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000044 if (T.isNull())
45 return false;
46
Argyrios Kyrtzidis99282b72012-03-16 00:10:35 +000047 // iOS is always safe to use 'weak'.
Tim Northover756447a2015-10-30 16:30:36 +000048 if (Ctx.getTargetInfo().getTriple().isiOS() ||
49 Ctx.getTargetInfo().getTriple().isWatchOS())
Argyrios Kyrtzidis99282b72012-03-16 00:10:35 +000050 AllowOnUnknownClass = true;
51
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000052 while (const PointerType *ptr = T->getAs<PointerType>())
53 T = ptr->getPointeeType();
54 if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
55 ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl();
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000056 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000057 return false; // id/NSObject is not safe for weak.
Douglas Gregordc9166c2011-12-15 20:29:51 +000058 if (!AllowOnUnknownClass && !Class->hasDefinition())
Argyrios Kyrtzidisa2009732011-07-12 22:16:25 +000059 return false; // forward classes are not verifiable, therefore not safe.
Richard Smith802c4b72012-08-23 06:16:52 +000060 if (Class && Class->isArcWeakrefUnavailable())
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000061 return false;
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000062 }
63
64 return true;
65}
66
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +000067bool trans::isPlusOneAssign(const BinaryOperator *E) {
68 if (E->getOpcode() != BO_Assign)
69 return false;
70
Argyrios Kyrtzidisd12c3322013-01-04 18:30:11 +000071 return isPlusOne(E->getRHS());
72}
73
74bool trans::isPlusOne(const Expr *E) {
75 if (!E)
76 return false;
77 if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
78 E = EWC->getSubExpr();
79
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +000080 if (const ObjCMessageExpr *
Argyrios Kyrtzidisd12c3322013-01-04 18:30:11 +000081 ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +000082 if (ME->getMethodFamily() == OMF_retain)
83 return true;
84
85 if (const CallExpr *
Argyrios Kyrtzidisd12c3322013-01-04 18:30:11 +000086 callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +000087 if (const FunctionDecl *FD = callE->getDirectCallee()) {
Aaron Ballman9ead1242013-12-19 02:39:40 +000088 if (FD->hasAttr<CFReturnsRetainedAttr>())
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +000089 return true;
90
91 if (FD->isGlobal() &&
92 FD->getIdentifier() &&
93 FD->getParent()->isTranslationUnit() &&
Rafael Espindola3ae00052013-05-13 00:12:11 +000094 FD->isExternallyVisible() &&
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +000095 ento::cocoa::isRefType(callE->getType(), "CF",
96 FD->getIdentifier()->getName())) {
97 StringRef fname = FD->getIdentifier()->getName();
98 if (fname.endswith("Retain") ||
99 fname.find("Create") != StringRef::npos ||
100 fname.find("Copy") != StringRef::npos) {
101 return true;
102 }
103 }
104 }
105 }
106
Argyrios Kyrtzidisd12c3322013-01-04 18:30:11 +0000107 const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +0000108 while (implCE && implCE->getCastKind() == CK_BitCast)
109 implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
110
Alexander Kornienkoad988852015-11-06 01:26:37 +0000111 return implCE && implCE->getCastKind() == CK_ARCConsumeObject;
Argyrios Kyrtzidis0b21d822012-05-23 21:50:04 +0000112}
113
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000114/// \brief 'Loc' is the end of a statement range. This returns the location
115/// immediately after the semicolon following the statement.
116/// If no semicolon is found or the location is inside a macro, the returned
117/// source location will be invalid.
118SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
Fariborz Jahanian1d27ffd2013-10-11 17:35:22 +0000119 ASTContext &Ctx, bool IsDecl) {
120 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx, IsDecl);
Argyrios Kyrtzidiscbbc0142011-09-01 20:53:18 +0000121 if (SemiLoc.isInvalid())
122 return SourceLocation();
Argyrios Kyrtzidise6e67de2011-09-19 20:40:19 +0000123 return SemiLoc.getLocWithOffset(1);
Argyrios Kyrtzidiscbbc0142011-09-01 20:53:18 +0000124}
125
126/// \brief \arg Loc is the end of a statement range. This returns the location
127/// of the semicolon following the statement.
128/// If no semicolon is found or the location is inside a macro, the returned
129/// source location will be invalid.
130SourceLocation trans::findSemiAfterLocation(SourceLocation loc,
Fariborz Jahanian1d27ffd2013-10-11 17:35:22 +0000131 ASTContext &Ctx,
132 bool IsDecl) {
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000133 SourceManager &SM = Ctx.getSourceManager();
134 if (loc.isMacroID()) {
David Blaikiebbafb8a2012-03-11 07:00:24 +0000135 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOpts(), &loc))
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000136 return SourceLocation();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000137 }
David Blaikiebbafb8a2012-03-11 07:00:24 +0000138 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOpts());
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000139
140 // Break down the source location.
141 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
142
143 // Try to load the file buffer.
144 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000145 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000146 if (invalidTemp)
147 return SourceLocation();
148
149 const char *tokenBegin = file.data() + locInfo.second;
150
151 // Lex from the start of the given location.
152 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000153 Ctx.getLangOpts(),
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000154 file.begin(), tokenBegin, file.end());
155 Token tok;
156 lexer.LexFromRawLexer(tok);
Fariborz Jahanian1d27ffd2013-10-11 17:35:22 +0000157 if (tok.isNot(tok::semi)) {
158 if (!IsDecl)
159 return SourceLocation();
160 // Declaration may be followed with other tokens; such as an __attribute,
161 // before ending with a semicolon.
162 return findSemiAfterLocation(tok.getLocation(), Ctx, /*IsDecl*/true);
163 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000164
Argyrios Kyrtzidiscbbc0142011-09-01 20:53:18 +0000165 return tok.getLocation();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000166}
167
168bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
169 if (!E || !E->HasSideEffects(Ctx))
170 return false;
171
172 E = E->IgnoreParenCasts();
173 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
174 if (!ME)
175 return true;
176 switch (ME->getMethodFamily()) {
177 case OMF_autorelease:
178 case OMF_dealloc:
179 case OMF_release:
180 case OMF_retain:
181 switch (ME->getReceiverKind()) {
182 case ObjCMessageExpr::SuperInstance:
183 return false;
184 case ObjCMessageExpr::Instance:
185 return hasSideEffects(ME->getInstanceReceiver(), Ctx);
186 default:
187 break;
188 }
189 break;
190 default:
191 break;
192 }
193
194 return true;
195}
196
Argyrios Kyrtzidisf2a27f42011-07-14 23:32:04 +0000197bool trans::isGlobalVar(Expr *E) {
198 E = E->IgnoreParenCasts();
199 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000200 return DRE->getDecl()->getDeclContext()->isFileContext() &&
Rafael Espindola3ae00052013-05-13 00:12:11 +0000201 DRE->getDecl()->isExternallyVisible();
Argyrios Kyrtzidisf2a27f42011-07-14 23:32:04 +0000202 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
203 return isGlobalVar(condOp->getTrueExpr()) &&
204 isGlobalVar(condOp->getFalseExpr());
205
206 return false;
207}
208
Richard Smith20e883e2015-04-29 23:20:19 +0000209StringRef trans::getNilString(MigrationPass &Pass) {
210 return Pass.SemaRef.PP.isMacroDefined("nil") ? "nil" : "0";
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000211}
212
John McCalld70fb982011-06-15 23:25:17 +0000213namespace {
214
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000215class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
216 ExprSet &Refs;
217public:
218 ReferenceClear(ExprSet &refs) : Refs(refs) { }
219 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000220};
221
222class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
223 ValueDecl *Dcl;
224 ExprSet &Refs;
John McCalld70fb982011-06-15 23:25:17 +0000225
226public:
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000227 ReferenceCollector(ValueDecl *D, ExprSet &refs)
228 : Dcl(D), Refs(refs) { }
229
230 bool VisitDeclRefExpr(DeclRefExpr *E) {
231 if (E->getDecl() == Dcl)
232 Refs.insert(E);
233 return true;
234 }
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000235};
236
237class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
238 ExprSet &Removables;
239
240public:
241 RemovablesCollector(ExprSet &removables)
John McCalld70fb982011-06-15 23:25:17 +0000242 : Removables(removables) { }
243
244 bool shouldWalkTypesOfTypeLocs() const { return false; }
245
246 bool TraverseStmtExpr(StmtExpr *E) {
247 CompoundStmt *S = E->getSubStmt();
248 for (CompoundStmt::body_iterator
249 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
250 if (I != E - 1)
251 mark(*I);
252 TraverseStmt(*I);
253 }
254 return true;
255 }
256
257 bool VisitCompoundStmt(CompoundStmt *S) {
Aaron Ballmanc7e4e212014-03-17 14:19:37 +0000258 for (auto *I : S->body())
259 mark(I);
John McCalld70fb982011-06-15 23:25:17 +0000260 return true;
261 }
262
263 bool VisitIfStmt(IfStmt *S) {
264 mark(S->getThen());
265 mark(S->getElse());
266 return true;
267 }
268
269 bool VisitWhileStmt(WhileStmt *S) {
270 mark(S->getBody());
271 return true;
272 }
273
274 bool VisitDoStmt(DoStmt *S) {
275 mark(S->getBody());
276 return true;
277 }
278
279 bool VisitForStmt(ForStmt *S) {
280 mark(S->getInit());
281 mark(S->getInc());
282 mark(S->getBody());
283 return true;
284 }
285
286private:
287 void mark(Stmt *S) {
288 if (!S) return;
289
John McCall4db5c3c2011-07-07 06:58:02 +0000290 while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
291 S = Label->getSubStmt();
292 S = S->IgnoreImplicit();
John McCalld70fb982011-06-15 23:25:17 +0000293 if (Expr *E = dyn_cast<Expr>(S))
294 Removables.insert(E);
295 }
296};
297
John McCalld70fb982011-06-15 23:25:17 +0000298} // end anonymous namespace
299
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000300void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
301 ReferenceClear(refs).TraverseStmt(S);
John McCalld70fb982011-06-15 23:25:17 +0000302}
303
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000304void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
305 ReferenceCollector(D, refs).TraverseStmt(S);
John McCalld70fb982011-06-15 23:25:17 +0000306}
307
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000308void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
309 RemovablesCollector(exprs).TraverseStmt(S);
John McCalld70fb982011-06-15 23:25:17 +0000310}
311
312//===----------------------------------------------------------------------===//
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000313// MigrationContext
314//===----------------------------------------------------------------------===//
315
316namespace {
317
318class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
319 MigrationContext &MigrateCtx;
Argyrios Kyrtzidisd5697912011-11-07 18:46:50 +0000320 typedef RecursiveASTVisitor<ASTTransform> base;
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000321
322public:
323 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
324
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000325 bool shouldWalkTypesOfTypeLocs() const { return false; }
326
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000327 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
328 ObjCImplementationContext ImplCtx(MigrateCtx, D);
329 for (MigrationContext::traverser_iterator
330 I = MigrateCtx.traversers_begin(),
331 E = MigrateCtx.traversers_end(); I != E; ++I)
332 (*I)->traverseObjCImplementation(ImplCtx);
333
Argyrios Kyrtzidisd5697912011-11-07 18:46:50 +0000334 return base::TraverseObjCImplementationDecl(D);
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000335 }
336
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000337 bool TraverseStmt(Stmt *rootS) {
338 if (!rootS)
339 return true;
340
341 BodyContext BodyCtx(MigrateCtx, rootS);
342 for (MigrationContext::traverser_iterator
343 I = MigrateCtx.traversers_begin(),
344 E = MigrateCtx.traversers_end(); I != E; ++I)
345 (*I)->traverseBody(BodyCtx);
346
347 return true;
348 }
349};
350
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000351}
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000352
353MigrationContext::~MigrationContext() {
354 for (traverser_iterator
355 I = traversers_begin(), E = traversers_end(); I != E; ++I)
356 delete *I;
357}
358
Argyrios Kyrtzidis6b2d47d2011-11-04 23:43:03 +0000359bool MigrationContext::isGCOwnedNonObjC(QualType T) {
360 while (!T.isNull()) {
361 if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
362 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
363 return !AttrT->getModifiedType()->isObjCRetainableType();
364 }
365
366 if (T->isArrayType())
367 T = Pass.Ctx.getBaseElementType(T);
368 else if (const PointerType *PT = T->getAs<PointerType>())
369 T = PT->getPointeeType();
370 else if (const ReferenceType *RT = T->getAs<ReferenceType>())
371 T = RT->getPointeeType();
372 else
373 break;
374 }
375
376 return false;
377}
378
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000379bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
380 StringRef toAttr,
381 SourceLocation atLoc) {
382 if (atLoc.isMacroID())
383 return false;
384
385 SourceManager &SM = Pass.Ctx.getSourceManager();
386
387 // Break down the source location.
388 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
389
390 // Try to load the file buffer.
391 bool invalidTemp = false;
392 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
393 if (invalidTemp)
394 return false;
395
396 const char *tokenBegin = file.data() + locInfo.second;
397
398 // Lex from the start of the given location.
399 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000400 Pass.Ctx.getLangOpts(),
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000401 file.begin(), tokenBegin, file.end());
402 Token tok;
403 lexer.LexFromRawLexer(tok);
404 if (tok.isNot(tok::at)) return false;
405 lexer.LexFromRawLexer(tok);
406 if (tok.isNot(tok::raw_identifier)) return false;
Alp Toker2d57cea2014-05-17 04:53:25 +0000407 if (tok.getRawIdentifier() != "property")
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000408 return false;
409 lexer.LexFromRawLexer(tok);
410 if (tok.isNot(tok::l_paren)) return false;
411
412 Token BeforeTok = tok;
413 Token AfterTok;
414 AfterTok.startToken();
415 SourceLocation AttrLoc;
416
417 lexer.LexFromRawLexer(tok);
418 if (tok.is(tok::r_paren))
419 return false;
420
421 while (1) {
422 if (tok.isNot(tok::raw_identifier)) return false;
Alp Toker2d57cea2014-05-17 04:53:25 +0000423 if (tok.getRawIdentifier() == fromAttr) {
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000424 if (!toAttr.empty()) {
425 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
426 return true;
427 }
428 // We want to remove the attribute.
429 AttrLoc = tok.getLocation();
430 }
431
432 do {
433 lexer.LexFromRawLexer(tok);
434 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
435 AfterTok = tok;
436 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
437 if (tok.is(tok::r_paren))
438 break;
439 if (AttrLoc.isInvalid())
440 BeforeTok = tok;
441 lexer.LexFromRawLexer(tok);
442 }
443
444 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
445 // We want to remove the attribute.
446 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
447 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
448 AfterTok.getLocation()));
449 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
450 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
451 } else {
452 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
453 }
454
455 return true;
456 }
457
458 return false;
459}
460
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000461bool MigrationContext::addPropertyAttribute(StringRef attr,
462 SourceLocation atLoc) {
463 if (atLoc.isMacroID())
464 return false;
465
466 SourceManager &SM = Pass.Ctx.getSourceManager();
467
468 // Break down the source location.
469 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
470
471 // Try to load the file buffer.
472 bool invalidTemp = false;
473 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
474 if (invalidTemp)
475 return false;
476
477 const char *tokenBegin = file.data() + locInfo.second;
478
479 // Lex from the start of the given location.
480 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
David Blaikiebbafb8a2012-03-11 07:00:24 +0000481 Pass.Ctx.getLangOpts(),
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000482 file.begin(), tokenBegin, file.end());
483 Token tok;
484 lexer.LexFromRawLexer(tok);
485 if (tok.isNot(tok::at)) return false;
486 lexer.LexFromRawLexer(tok);
487 if (tok.isNot(tok::raw_identifier)) return false;
Alp Toker2d57cea2014-05-17 04:53:25 +0000488 if (tok.getRawIdentifier() != "property")
Argyrios Kyrtzidiseca1f362011-11-28 02:04:36 +0000489 return false;
490 lexer.LexFromRawLexer(tok);
491
492 if (tok.isNot(tok::l_paren)) {
493 Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") ");
494 return true;
495 }
496
497 lexer.LexFromRawLexer(tok);
498 if (tok.is(tok::r_paren)) {
499 Pass.TA.insert(tok.getLocation(), attr);
500 return true;
501 }
502
503 if (tok.isNot(tok::raw_identifier)) return false;
504
505 Pass.TA.insert(tok.getLocation(), std::string(attr) + ", ");
506 return true;
507}
508
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000509void MigrationContext::traverse(TranslationUnitDecl *TU) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000510 for (traverser_iterator
511 I = traversers_begin(), E = traversers_end(); I != E; ++I)
512 (*I)->traverseTU(*this);
513
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000514 ASTTransform(*this).TraverseDecl(TU);
515}
516
Fariborz Jahanian48fd81b2012-01-26 20:57:58 +0000517static void GCRewriteFinalize(MigrationPass &pass) {
518 ASTContext &Ctx = pass.Ctx;
519 TransformActions &TA = pass.TA;
520 DeclContext *DC = Ctx.getTranslationUnitDecl();
521 Selector FinalizeSel =
522 Ctx.Selectors.getNullarySelector(&pass.Ctx.Idents.get("finalize"));
523
524 typedef DeclContext::specific_decl_iterator<ObjCImplementationDecl>
525 impl_iterator;
526 for (impl_iterator I = impl_iterator(DC->decls_begin()),
527 E = impl_iterator(DC->decls_end()); I != E; ++I) {
Aaron Ballmanf26acce2014-03-13 19:50:17 +0000528 for (const auto *MD : I->instance_methods()) {
Fariborz Jahanian48fd81b2012-01-26 20:57:58 +0000529 if (!MD->hasBody())
530 continue;
531
532 if (MD->isInstanceMethod() && MD->getSelector() == FinalizeSel) {
Aaron Ballmanf26acce2014-03-13 19:50:17 +0000533 const ObjCMethodDecl *FinalizeM = MD;
Fariborz Jahanian48fd81b2012-01-26 20:57:58 +0000534 Transaction Trans(TA);
535 TA.insert(FinalizeM->getSourceRange().getBegin(),
536 "#if !__has_feature(objc_arc)\n");
537 CharSourceRange::getTokenRange(FinalizeM->getSourceRange());
538 const SourceManager &SM = pass.Ctx.getSourceManager();
David Blaikiebbafb8a2012-03-11 07:00:24 +0000539 const LangOptions &LangOpts = pass.Ctx.getLangOpts();
Fariborz Jahanian48fd81b2012-01-26 20:57:58 +0000540 bool Invalid;
541 std::string str = "\n#endif\n";
542 str += Lexer::getSourceText(
543 CharSourceRange::getTokenRange(FinalizeM->getSourceRange()),
544 SM, LangOpts, &Invalid);
545 TA.insertAfterToken(FinalizeM->getSourceRange().getEnd(), str);
546
547 break;
548 }
549 }
550 }
551}
552
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000553//===----------------------------------------------------------------------===//
John McCalld70fb982011-06-15 23:25:17 +0000554// getAllTransformations.
555//===----------------------------------------------------------------------===//
556
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000557static void traverseAST(MigrationPass &pass) {
558 MigrationContext MigrateCtx(pass);
559
560 if (pass.isGCMigration()) {
561 MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000562 MigrateCtx.addTraverser(new GCAttrsTraverser());
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000563 }
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000564 MigrateCtx.addTraverser(new PropertyRewriteTraverser());
Argyrios Kyrtzidisafdc66f2012-03-05 08:46:24 +0000565 MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
Argyrios Kyrtzidis03fbe3e2013-01-04 18:30:08 +0000566 MigrateCtx.addTraverser(new ProtectedScopeTraverser());
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000567
568 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
569}
570
John McCalld70fb982011-06-15 23:25:17 +0000571static void independentTransforms(MigrationPass &pass) {
572 rewriteAutoreleasePool(pass);
Argyrios Kyrtzidisd2b91122011-11-04 15:58:22 +0000573 removeRetainReleaseDeallocFinalize(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000574 rewriteUnusedInitDelegate(pass);
Argyrios Kyrtzidisd2b91122011-11-04 15:58:22 +0000575 removeZeroOutPropsInDeallocFinalize(pass);
John McCalld70fb982011-06-15 23:25:17 +0000576 makeAssignARCSafe(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000577 rewriteUnbridgedCasts(pass);
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +0000578 checkAPIUses(pass);
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000579 traverseAST(pass);
John McCalld70fb982011-06-15 23:25:17 +0000580}
581
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000582std::vector<TransformFn> arcmt::getAllTransformations(
Fariborz Jahanian48fd81b2012-01-26 20:57:58 +0000583 LangOptions::GCMode OrigGCMode,
584 bool NoFinalizeRemoval) {
John McCalld70fb982011-06-15 23:25:17 +0000585 std::vector<TransformFn> transforms;
586
Fariborz Jahanian48fd81b2012-01-26 20:57:58 +0000587 if (OrigGCMode == LangOptions::GCOnly && NoFinalizeRemoval)
588 transforms.push_back(GCRewriteFinalize);
John McCalld70fb982011-06-15 23:25:17 +0000589 transforms.push_back(independentTransforms);
Argyrios Kyrtzidise5acb842011-06-21 20:20:42 +0000590 // This depends on previous transformations removing various expressions.
Argyrios Kyrtzidisd2b91122011-11-04 15:58:22 +0000591 transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
John McCalld70fb982011-06-15 23:25:17 +0000592
593 return transforms;
594}