blob: c1a573c34e9c26c3463f8770da38c82bdd25c527 [file] [log] [blame]
John McCalld70fb982011-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 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"
12#include "clang/Sema/SemaDiagnostic.h"
13#include "clang/AST/RecursiveASTVisitor.h"
14#include "clang/AST/StmtVisitor.h"
John McCalld70fb982011-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 Kyrtzidise5b475c2011-06-21 20:20:39 +000024using namespace trans;
John McCalld70fb982011-06-15 23:25:17 +000025
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +000026ASTTraverser::~ASTTraverser() { }
27
John McCalld70fb982011-06-15 23:25:17 +000028//===----------------------------------------------------------------------===//
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +000029// Helpers.
John McCalld70fb982011-06-15 23:25:17 +000030//===----------------------------------------------------------------------===//
31
Argyrios Kyrtzidisce9b7392011-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 Kyrtzidis3befb8c2011-11-08 05:56:08 +000045 .Case("NSViewController", true)
Argyrios Kyrtzidisce9b7392011-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 Kyrtzidise80d4f22011-11-07 18:40:29 +000068bool trans::canApplyWeak(ASTContext &Ctx, QualType type,
69 bool AllowOnUnknownClass) {
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000070 if (!Ctx.getLangOptions().ObjCRuntimeHasWeak)
71 return false;
72
73 QualType T = type;
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +000074 if (T.isNull())
75 return false;
76
Argyrios Kyrtzidisce9b7392011-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 Kyrtzidise80d4f22011-11-07 18:40:29 +000081 if (!AllowOnUnknownClass && (!Class || Class->getName() == "NSObject"))
Argyrios Kyrtzidisce9b7392011-07-12 22:05:17 +000082 return false; // id/NSObject is not safe for weak.
Argyrios Kyrtzidise80d4f22011-11-07 18:40:29 +000083 if (!AllowOnUnknownClass && Class->isForwardDecl())
Argyrios Kyrtzidisa2009732011-07-12 22:16:25 +000084 return false; // forward classes are not verifiable, therefore not safe.
Argyrios Kyrtzidisce9b7392011-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 Kyrtzidise5b475c2011-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 Kyrtzidiscbbc0142011-09-01 20:53:18 +0000100 SourceLocation SemiLoc = findSemiAfterLocation(loc, Ctx);
101 if (SemiLoc.isInvalid())
102 return SourceLocation();
Argyrios Kyrtzidise6e67de2011-09-19 20:40:19 +0000103 return SemiLoc.getLocWithOffset(1);
Argyrios Kyrtzidiscbbc0142011-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 Kyrtzidise5b475c2011-06-21 20:20:39 +0000112 SourceManager &SM = Ctx.getSourceManager();
113 if (loc.isMacroID()) {
Chandler Carruthe2c09eb2011-07-14 08:20:40 +0000114 if (!Lexer::isAtEndOfMacroExpansion(loc, SM, Ctx.getLangOptions()))
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000115 return SourceLocation();
Chandler Carruth6d28d7f2011-07-25 16:56:02 +0000116 loc = SM.getExpansionRange(loc).second;
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000117 }
118 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
119
120 // Break down the source location.
121 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
122
123 // Try to load the file buffer.
124 bool invalidTemp = false;
Chris Lattner0e62c1c2011-07-23 10:55:15 +0000125 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000126 if (invalidTemp)
127 return SourceLocation();
128
129 const char *tokenBegin = file.data() + locInfo.second;
130
131 // Lex from the start of the given location.
132 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
133 Ctx.getLangOptions(),
134 file.begin(), tokenBegin, file.end());
135 Token tok;
136 lexer.LexFromRawLexer(tok);
137 if (tok.isNot(tok::semi))
138 return SourceLocation();
139
Argyrios Kyrtzidiscbbc0142011-09-01 20:53:18 +0000140 return tok.getLocation();
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000141}
142
143bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
144 if (!E || !E->HasSideEffects(Ctx))
145 return false;
146
147 E = E->IgnoreParenCasts();
148 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
149 if (!ME)
150 return true;
151 switch (ME->getMethodFamily()) {
152 case OMF_autorelease:
153 case OMF_dealloc:
154 case OMF_release:
155 case OMF_retain:
156 switch (ME->getReceiverKind()) {
157 case ObjCMessageExpr::SuperInstance:
158 return false;
159 case ObjCMessageExpr::Instance:
160 return hasSideEffects(ME->getInstanceReceiver(), Ctx);
161 default:
162 break;
163 }
164 break;
165 default:
166 break;
167 }
168
169 return true;
170}
171
Argyrios Kyrtzidisf2a27f42011-07-14 23:32:04 +0000172bool trans::isGlobalVar(Expr *E) {
173 E = E->IgnoreParenCasts();
174 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000175 return DRE->getDecl()->getDeclContext()->isFileContext() &&
176 DRE->getDecl()->getLinkage() == ExternalLinkage;
Argyrios Kyrtzidisf2a27f42011-07-14 23:32:04 +0000177 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
178 return isGlobalVar(condOp->getTrueExpr()) &&
179 isGlobalVar(condOp->getFalseExpr());
180
181 return false;
182}
183
Argyrios Kyrtzidis93907472011-07-27 05:28:18 +0000184StringRef trans::getNilString(ASTContext &Ctx) {
185 if (Ctx.Idents.get("nil").hasMacroDefinition())
186 return "nil";
187 else
188 return "0";
189}
190
John McCalld70fb982011-06-15 23:25:17 +0000191namespace {
192
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000193class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
194 ExprSet &Refs;
195public:
196 ReferenceClear(ExprSet &refs) : Refs(refs) { }
197 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
198 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; }
199};
200
201class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
202 ValueDecl *Dcl;
203 ExprSet &Refs;
John McCalld70fb982011-06-15 23:25:17 +0000204
205public:
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000206 ReferenceCollector(ValueDecl *D, ExprSet &refs)
207 : Dcl(D), Refs(refs) { }
208
209 bool VisitDeclRefExpr(DeclRefExpr *E) {
210 if (E->getDecl() == Dcl)
211 Refs.insert(E);
212 return true;
213 }
214
215 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
216 if (E->getDecl() == Dcl)
217 Refs.insert(E);
218 return true;
219 }
220};
221
222class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
223 ExprSet &Removables;
224
225public:
226 RemovablesCollector(ExprSet &removables)
John McCalld70fb982011-06-15 23:25:17 +0000227 : Removables(removables) { }
228
229 bool shouldWalkTypesOfTypeLocs() const { return false; }
230
231 bool TraverseStmtExpr(StmtExpr *E) {
232 CompoundStmt *S = E->getSubStmt();
233 for (CompoundStmt::body_iterator
234 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
235 if (I != E - 1)
236 mark(*I);
237 TraverseStmt(*I);
238 }
239 return true;
240 }
241
242 bool VisitCompoundStmt(CompoundStmt *S) {
243 for (CompoundStmt::body_iterator
244 I = S->body_begin(), E = S->body_end(); I != E; ++I)
245 mark(*I);
246 return true;
247 }
248
249 bool VisitIfStmt(IfStmt *S) {
250 mark(S->getThen());
251 mark(S->getElse());
252 return true;
253 }
254
255 bool VisitWhileStmt(WhileStmt *S) {
256 mark(S->getBody());
257 return true;
258 }
259
260 bool VisitDoStmt(DoStmt *S) {
261 mark(S->getBody());
262 return true;
263 }
264
265 bool VisitForStmt(ForStmt *S) {
266 mark(S->getInit());
267 mark(S->getInc());
268 mark(S->getBody());
269 return true;
270 }
271
272private:
273 void mark(Stmt *S) {
274 if (!S) return;
275
John McCall4db5c3c2011-07-07 06:58:02 +0000276 while (LabelStmt *Label = dyn_cast<LabelStmt>(S))
277 S = Label->getSubStmt();
278 S = S->IgnoreImplicit();
John McCalld70fb982011-06-15 23:25:17 +0000279 if (Expr *E = dyn_cast<Expr>(S))
280 Removables.insert(E);
281 }
282};
283
John McCalld70fb982011-06-15 23:25:17 +0000284} // end anonymous namespace
285
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000286void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
287 ReferenceClear(refs).TraverseStmt(S);
John McCalld70fb982011-06-15 23:25:17 +0000288}
289
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000290void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
291 ReferenceCollector(D, refs).TraverseStmt(S);
John McCalld70fb982011-06-15 23:25:17 +0000292}
293
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000294void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
295 RemovablesCollector(exprs).TraverseStmt(S);
John McCalld70fb982011-06-15 23:25:17 +0000296}
297
298//===----------------------------------------------------------------------===//
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000299// MigrationContext
300//===----------------------------------------------------------------------===//
301
302namespace {
303
304class ASTTransform : public RecursiveASTVisitor<ASTTransform> {
305 MigrationContext &MigrateCtx;
Argyrios Kyrtzidisd5697912011-11-07 18:46:50 +0000306 typedef RecursiveASTVisitor<ASTTransform> base;
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000307
308public:
309 ASTTransform(MigrationContext &MigrateCtx) : MigrateCtx(MigrateCtx) { }
310
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000311 bool shouldWalkTypesOfTypeLocs() const { return false; }
312
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000313 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
314 ObjCImplementationContext ImplCtx(MigrateCtx, D);
315 for (MigrationContext::traverser_iterator
316 I = MigrateCtx.traversers_begin(),
317 E = MigrateCtx.traversers_end(); I != E; ++I)
318 (*I)->traverseObjCImplementation(ImplCtx);
319
Argyrios Kyrtzidisd5697912011-11-07 18:46:50 +0000320 return base::TraverseObjCImplementationDecl(D);
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000321 }
322
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000323 bool TraverseStmt(Stmt *rootS) {
324 if (!rootS)
325 return true;
326
327 BodyContext BodyCtx(MigrateCtx, rootS);
328 for (MigrationContext::traverser_iterator
329 I = MigrateCtx.traversers_begin(),
330 E = MigrateCtx.traversers_end(); I != E; ++I)
331 (*I)->traverseBody(BodyCtx);
332
333 return true;
334 }
335};
336
337}
338
339MigrationContext::~MigrationContext() {
340 for (traverser_iterator
341 I = traversers_begin(), E = traversers_end(); I != E; ++I)
342 delete *I;
343}
344
Argyrios Kyrtzidis6b2d47d2011-11-04 23:43:03 +0000345bool MigrationContext::isGCOwnedNonObjC(QualType T) {
346 while (!T.isNull()) {
347 if (const AttributedType *AttrT = T->getAs<AttributedType>()) {
348 if (AttrT->getAttrKind() == AttributedType::attr_objc_ownership)
349 return !AttrT->getModifiedType()->isObjCRetainableType();
350 }
351
352 if (T->isArrayType())
353 T = Pass.Ctx.getBaseElementType(T);
354 else if (const PointerType *PT = T->getAs<PointerType>())
355 T = PT->getPointeeType();
356 else if (const ReferenceType *RT = T->getAs<ReferenceType>())
357 T = RT->getPointeeType();
358 else
359 break;
360 }
361
362 return false;
363}
364
Argyrios Kyrtzidis722d21c2011-11-07 18:46:46 +0000365bool MigrationContext::rewritePropertyAttribute(StringRef fromAttr,
366 StringRef toAttr,
367 SourceLocation atLoc) {
368 if (atLoc.isMacroID())
369 return false;
370
371 SourceManager &SM = Pass.Ctx.getSourceManager();
372
373 // Break down the source location.
374 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
375
376 // Try to load the file buffer.
377 bool invalidTemp = false;
378 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
379 if (invalidTemp)
380 return false;
381
382 const char *tokenBegin = file.data() + locInfo.second;
383
384 // Lex from the start of the given location.
385 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
386 Pass.Ctx.getLangOptions(),
387 file.begin(), tokenBegin, file.end());
388 Token tok;
389 lexer.LexFromRawLexer(tok);
390 if (tok.isNot(tok::at)) return false;
391 lexer.LexFromRawLexer(tok);
392 if (tok.isNot(tok::raw_identifier)) return false;
393 if (StringRef(tok.getRawIdentifierData(), tok.getLength())
394 != "property")
395 return false;
396 lexer.LexFromRawLexer(tok);
397 if (tok.isNot(tok::l_paren)) return false;
398
399 Token BeforeTok = tok;
400 Token AfterTok;
401 AfterTok.startToken();
402 SourceLocation AttrLoc;
403
404 lexer.LexFromRawLexer(tok);
405 if (tok.is(tok::r_paren))
406 return false;
407
408 while (1) {
409 if (tok.isNot(tok::raw_identifier)) return false;
410 StringRef ident(tok.getRawIdentifierData(), tok.getLength());
411 if (ident == fromAttr) {
412 if (!toAttr.empty()) {
413 Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr);
414 return true;
415 }
416 // We want to remove the attribute.
417 AttrLoc = tok.getLocation();
418 }
419
420 do {
421 lexer.LexFromRawLexer(tok);
422 if (AttrLoc.isValid() && AfterTok.is(tok::unknown))
423 AfterTok = tok;
424 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
425 if (tok.is(tok::r_paren))
426 break;
427 if (AttrLoc.isInvalid())
428 BeforeTok = tok;
429 lexer.LexFromRawLexer(tok);
430 }
431
432 if (toAttr.empty() && AttrLoc.isValid() && AfterTok.isNot(tok::unknown)) {
433 // We want to remove the attribute.
434 if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::r_paren)) {
435 Pass.TA.remove(SourceRange(BeforeTok.getLocation(),
436 AfterTok.getLocation()));
437 } else if (BeforeTok.is(tok::l_paren) && AfterTok.is(tok::comma)) {
438 Pass.TA.remove(SourceRange(AttrLoc, AfterTok.getLocation()));
439 } else {
440 Pass.TA.remove(SourceRange(BeforeTok.getLocation(), AttrLoc));
441 }
442
443 return true;
444 }
445
446 return false;
447}
448
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000449void MigrationContext::traverse(TranslationUnitDecl *TU) {
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000450 for (traverser_iterator
451 I = traversers_begin(), E = traversers_end(); I != E; ++I)
452 (*I)->traverseTU(*this);
453
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000454 ASTTransform(*this).TraverseDecl(TU);
455}
456
457//===----------------------------------------------------------------------===//
John McCalld70fb982011-06-15 23:25:17 +0000458// getAllTransformations.
459//===----------------------------------------------------------------------===//
460
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000461static void traverseAST(MigrationPass &pass) {
462 MigrationContext MigrateCtx(pass);
463
464 if (pass.isGCMigration()) {
465 MigrateCtx.addTraverser(new GCCollectableCallsTraverser);
Argyrios Kyrtzidise43ae792011-11-06 18:58:03 +0000466 MigrateCtx.addTraverser(new GCAttrsTraverser());
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000467 }
Argyrios Kyrtzidisaaa99962011-11-06 18:57:57 +0000468 MigrateCtx.addTraverser(new PropertyRewriteTraverser());
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000469
470 MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
471}
472
John McCalld70fb982011-06-15 23:25:17 +0000473static void independentTransforms(MigrationPass &pass) {
474 rewriteAutoreleasePool(pass);
Argyrios Kyrtzidisd2b91122011-11-04 15:58:22 +0000475 removeRetainReleaseDeallocFinalize(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000476 rewriteUnusedInitDelegate(pass);
Argyrios Kyrtzidisd2b91122011-11-04 15:58:22 +0000477 removeZeroOutPropsInDeallocFinalize(pass);
John McCalld70fb982011-06-15 23:25:17 +0000478 makeAssignARCSafe(pass);
Argyrios Kyrtzidise5b475c2011-06-21 20:20:39 +0000479 rewriteUnbridgedCasts(pass);
John McCalld70fb982011-06-15 23:25:17 +0000480 rewriteBlockObjCVariable(pass);
Argyrios Kyrtzidis73a0d322011-07-18 07:44:45 +0000481 checkAPIUses(pass);
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000482 traverseAST(pass);
John McCalld70fb982011-06-15 23:25:17 +0000483}
484
Argyrios Kyrtzidisd208ef92011-11-04 15:58:08 +0000485std::vector<TransformFn> arcmt::getAllTransformations(
486 LangOptions::GCMode OrigGCMode) {
John McCalld70fb982011-06-15 23:25:17 +0000487 std::vector<TransformFn> transforms;
488
John McCalld70fb982011-06-15 23:25:17 +0000489 transforms.push_back(independentTransforms);
Argyrios Kyrtzidise5acb842011-06-21 20:20:42 +0000490 // This depends on previous transformations removing various expressions.
Argyrios Kyrtzidisd2b91122011-11-04 15:58:22 +0000491 transforms.push_back(removeEmptyStatementsAndDeallocFinalize);
John McCalld70fb982011-06-15 23:25:17 +0000492
493 return transforms;
494}