blob: ab3bc1dbe7ae35256851e6fb4a8c05836f023595 [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//===----------------------------------------------------------------------===//
9// Transformations:
10//===----------------------------------------------------------------------===//
11//
12// castNonObjCToObjC:
13//
14// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
15// is from a file-level variable, objc_unretainedObject function is used to
16// convert it.
17//
18// NSString *str = (NSString *)kUTTypePlainText;
19// str = b ? kUTTypeRTF : kUTTypePlainText;
20// ---->
21// NSString *str = objc_unretainedObject(kUTTypePlainText);
22// str = objc_unretainedObject(b ? kUTTypeRTF : kUTTypePlainText);
23//
24// For a C pointer to ObjC, objc_unretainedPointer is used.
25//
26// void *vp = str; // NSString*
27// ---->
28// void *vp = (void*)objc_unretainedPointer(str);
29//
30//===----------------------------------------------------------------------===//
31//
32// rewriteAllocCopyWithZone:
33//
34// Calls to +allocWithZone/-copyWithZone/-mutableCopyWithZone are changed to
35// +alloc/-copy/-mutableCopy if we can safely remove the given parameter.
36//
37// Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
38// ---->
39// Foo *foo1 = [[Foo alloc] init];
40//
41//===----------------------------------------------------------------------===//
42//
43// rewriteAutoreleasePool:
44//
45// Calls to NSAutoreleasePools will be rewritten as an @autorelease scope.
46//
47// NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
48// ...
49// [pool release];
50// ---->
51// @autorelease {
52// ...
53// }
54//
55// An NSAutoreleasePool will not be touched if:
56// - There is not a corresponding -release/-drain in the same scope
57// - Not all references of the NSAutoreleasePool variable can be removed
58// - There is a variable that is declared inside the intended @autorelease scope
59// which is also used outside it.
60//
61//===----------------------------------------------------------------------===//
62//
63// makeAssignARCSafe:
64//
65// Add '__strong' where appropriate.
66//
67// for (id x in collection) {
68// x = 0;
69// }
70// ---->
71// for (__strong id x in collection) {
72// x = 0;
73// }
74//
75//===----------------------------------------------------------------------===//
76//
77// removeRetainReleaseDealloc:
78//
79// Removes retain/release/autorelease/dealloc messages.
80//
81// return [[foo retain] autorelease];
82// ---->
83// return foo;
84//
85//===----------------------------------------------------------------------===//
86//
87// removeEmptyStatements:
88//
89// Removes empty statements that are leftovers from previous transformations.
90// e.g for
91//
92// [x retain];
93//
94// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
95// will remove.
96//
97//===----------------------------------------------------------------------===//
98//
99// changeIvarsOfAssignProperties:
100//
101// If a property is synthesized with 'assign' attribute and the user didn't
102// set a lifetime attribute, change the property to 'weak' or add
103// __unsafe_unretained if the ARC runtime is not available.
104//
105// @interface Foo : NSObject {
106// NSObject *x;
107// }
108// @property (assign) id x;
109// @end
110// ---->
111// @interface Foo : NSObject {
112// NSObject *__weak x;
113// }
114// @property (weak) id x;
115// @end
116//
117//===----------------------------------------------------------------------===//
118//
119// rewriteUnusedDelegateInit:
120//
121// Rewrites an unused result of calling a delegate initialization, to assigning
122// the result to self.
123// e.g
124// [self init];
125// ---->
126// self = [self init];
127//
128//===----------------------------------------------------------------------===//
129//
130// rewriteBlockObjCVariable:
131//
132// Adding __block to an obj-c variable could be either because the the variable
133// is used for output storage or the user wanted to break a retain cycle.
134// This transformation checks whether a reference of the variable for the block
135// is actually needed (it is assigned to or its address is taken) or not.
136// If the reference is not needed it will assume __block was added to break a
137// cycle so it will remove '__block' and add __weak/__unsafe_unretained.
138// e.g
139//
140// __block Foo *x;
141// bar(^ { [x cake]; });
142// ---->
143// __weak Foo *x;
144// bar(^ { [x cake]; });
145//
146//===----------------------------------------------------------------------===//
147//
148// removeZeroOutIvarsInDealloc:
149//
150// Removes zero'ing out "strong" @synthesized properties in a -dealloc method.
151//
152//===----------------------------------------------------------------------===//
153
154#include "Internals.h"
155#include "clang/Sema/SemaDiagnostic.h"
156#include "clang/AST/RecursiveASTVisitor.h"
157#include "clang/AST/StmtVisitor.h"
158#include "clang/AST/ParentMap.h"
159#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
160#include "clang/Lex/Lexer.h"
161#include "clang/Basic/SourceManager.h"
162#include "llvm/ADT/StringSwitch.h"
163#include "llvm/ADT/DenseSet.h"
164#include <map>
165
166using namespace clang;
167using namespace arcmt;
168using llvm::StringRef;
169
170//===----------------------------------------------------------------------===//
171// Transformations.
172//===----------------------------------------------------------------------===//
173
174namespace {
175
176class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
177 llvm::DenseSet<Expr *> &Removables;
178
179public:
180 RemovablesCollector(llvm::DenseSet<Expr *> &removables)
181 : Removables(removables) { }
182
183 bool shouldWalkTypesOfTypeLocs() const { return false; }
184
185 bool TraverseStmtExpr(StmtExpr *E) {
186 CompoundStmt *S = E->getSubStmt();
187 for (CompoundStmt::body_iterator
188 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
189 if (I != E - 1)
190 mark(*I);
191 TraverseStmt(*I);
192 }
193 return true;
194 }
195
196 bool VisitCompoundStmt(CompoundStmt *S) {
197 for (CompoundStmt::body_iterator
198 I = S->body_begin(), E = S->body_end(); I != E; ++I)
199 mark(*I);
200 return true;
201 }
202
203 bool VisitIfStmt(IfStmt *S) {
204 mark(S->getThen());
205 mark(S->getElse());
206 return true;
207 }
208
209 bool VisitWhileStmt(WhileStmt *S) {
210 mark(S->getBody());
211 return true;
212 }
213
214 bool VisitDoStmt(DoStmt *S) {
215 mark(S->getBody());
216 return true;
217 }
218
219 bool VisitForStmt(ForStmt *S) {
220 mark(S->getInit());
221 mark(S->getInc());
222 mark(S->getBody());
223 return true;
224 }
225
226private:
227 void mark(Stmt *S) {
228 if (!S) return;
229
230 if (LabelStmt *Label = dyn_cast<LabelStmt>(S))
231 return mark(Label->getSubStmt());
232 if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(S))
233 return mark(CE->getSubExpr());
234 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
235 return mark(EWC->getSubExpr());
236 if (Expr *E = dyn_cast<Expr>(S))
237 Removables.insert(E);
238 }
239};
240
241} // end anonymous namespace.
242
243static bool HasSideEffects(Expr *E, ASTContext &Ctx) {
244 if (!E || !E->HasSideEffects(Ctx))
245 return false;
246
247 E = E->IgnoreParenCasts();
248 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
249 if (!ME)
250 return true;
251 switch (ME->getMethodFamily()) {
252 case OMF_autorelease:
253 case OMF_dealloc:
254 case OMF_release:
255 case OMF_retain:
256 switch (ME->getReceiverKind()) {
257 case ObjCMessageExpr::SuperInstance:
258 return false;
259 case ObjCMessageExpr::Instance:
260 return HasSideEffects(ME->getInstanceReceiver(), Ctx);
261 default:
262 break;
263 }
264 break;
265 default:
266 break;
267 }
268
269 return true;
270}
271
272static void removeDeallocMethod(MigrationPass &pass) {
273 ASTContext &Ctx = pass.Ctx;
274 TransformActions &TA = pass.TA;
275 DeclContext *DC = Ctx.getTranslationUnitDecl();
276 ObjCMethodDecl *DeallocMethodDecl = 0;
277 IdentifierInfo *II = &Ctx.Idents.get("dealloc");
278
279 for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
280 I != E; ++I) {
281 Decl *D = *I;
282 if (ObjCImplementationDecl *IMD =
283 dyn_cast<ObjCImplementationDecl>(D)) {
284 DeallocMethodDecl = 0;
285 for (ObjCImplementationDecl::instmeth_iterator I =
286 IMD->instmeth_begin(), E = IMD->instmeth_end();
287 I != E; ++I) {
288 ObjCMethodDecl *OMD = *I;
289 if (OMD->isInstanceMethod() &&
290 OMD->getSelector() == Ctx.Selectors.getSelector(0, &II)) {
291 DeallocMethodDecl = OMD;
292 break;
293 }
294 }
295 if (DeallocMethodDecl &&
296 DeallocMethodDecl->getCompoundBody()->body_empty()) {
297 Transaction Trans(TA);
298 TA.remove(DeallocMethodDecl->getSourceRange());
299 }
300 }
301 }
302}
303
304namespace {
305
306class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
307 llvm::DenseSet<Expr *> &Refs;
308public:
309 ReferenceClear(llvm::DenseSet<Expr *> &refs) : Refs(refs) { }
310 bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
311 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; }
312 void clearRefsIn(Stmt *S) { TraverseStmt(S); }
313 template <typename iterator>
314 void clearRefsIn(iterator begin, iterator end) {
315 for (; begin != end; ++begin)
316 TraverseStmt(*begin);
317 }
318};
319
320class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
321 ValueDecl *Dcl;
322 llvm::DenseSet<Expr *> &Refs;
323
324public:
325 ReferenceCollector(llvm::DenseSet<Expr *> &refs)
326 : Dcl(0), Refs(refs) { }
327
328 void lookFor(ValueDecl *D, Stmt *S) {
329 Dcl = D;
330 TraverseStmt(S);
331 }
332
333 bool VisitDeclRefExpr(DeclRefExpr *E) {
334 if (E->getDecl() == Dcl)
335 Refs.insert(E);
336 return true;
337 }
338
339 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
340 if (E->getDecl() == Dcl)
341 Refs.insert(E);
342 return true;
343 }
344};
345
346class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
347 Decl *Dcl;
348 llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases;
349
350public:
351 ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases)
352 : Dcl(D), Releases(releases) { }
353
354 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
355 if (!E->isInstanceMessage())
356 return true;
357 if (E->getMethodFamily() != OMF_release)
358 return true;
359 Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts();
360 if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
361 if (DE->getDecl() == Dcl)
362 Releases.push_back(E);
363 }
364 return true;
365 }
366};
367
368template <typename BODY_TRANS>
369class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
370 MigrationPass &Pass;
371
372public:
373 BodyTransform(MigrationPass &pass) : Pass(pass) { }
374
375 void handleBody(Decl *D) {
376 Stmt *body = D->getBody();
377 if (body) {
378 BODY_TRANS(D, Pass).transformBody(body);
379 }
380 }
381
382 bool TraverseBlockDecl(BlockDecl *D) {
383 handleBody(D);
384 return true;
385 }
386 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
387 if (D->isThisDeclarationADefinition())
388 handleBody(D);
389 return true;
390 }
391 bool TraverseFunctionDecl(FunctionDecl *D) {
392 if (D->isThisDeclarationADefinition())
393 handleBody(D);
394 return true;
395 }
396};
397
398} // anonymous namespace
399
400//===----------------------------------------------------------------------===//
401// makeAssignARCSafe
402//===----------------------------------------------------------------------===//
403
404namespace {
405
406class ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> {
407 MigrationPass &Pass;
408 llvm::DenseSet<VarDecl *> ModifiedVars;
409
410public:
411 ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
412
413 bool VisitBinaryOperator(BinaryOperator *Exp) {
414 Expr *E = Exp->getLHS();
415 SourceLocation OrigLoc = E->getExprLoc();
416 SourceLocation Loc = OrigLoc;
417 DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
418 if (declRef && isa<VarDecl>(declRef->getDecl())) {
419 ASTContext &Ctx = Pass.Ctx;
420 Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
421 if (IsLV != Expr::MLV_ConstQualified)
422 return true;
423 VarDecl *var = cast<VarDecl>(declRef->getDecl());
424 if (var->getType().getLocalQualifiers().getObjCLifetime()
425 == Qualifiers::OCL_ExplicitNone &&
426 (var->getTypeSourceInfo() &&
427 !var->getTypeSourceInfo()->getType().isConstQualified())) {
428 Transaction Trans(Pass.TA);
429 if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration,
430 Exp->getOperatorLoc())) {
431 if (!ModifiedVars.count(var)) {
432 TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc();
433 Pass.TA.insert(TLoc.getBeginLoc(), "__strong ");
434 ModifiedVars.insert(var);
435 }
436 }
437 }
438 }
439
440 return true;
441 }
442};
443
444} // anonymous namespace
445
446static void makeAssignARCSafe(MigrationPass &pass) {
447 ARCAssignChecker assignCheck(pass);
448 assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
449}
450
451//===----------------------------------------------------------------------===//
452// castNonObjCToObjC
453//===----------------------------------------------------------------------===//
454
455namespace {
456
457class NonObjCToObjCCaster : public RecursiveASTVisitor<NonObjCToObjCCaster> {
458 MigrationPass &Pass;
459public:
460 NonObjCToObjCCaster(MigrationPass &pass) : Pass(pass) { }
461
462 bool VisitCastExpr(CastExpr *E) {
463 if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
464 && E->getCastKind() != CK_BitCast)
465 return true;
466
467 QualType castType = E->getType();
468 Expr *castExpr = E->getSubExpr();
469 QualType castExprType = castExpr->getType();
470
471 if (castType->isObjCObjectPointerType() &&
472 castExprType->isObjCObjectPointerType())
473 return true;
474 if (!castType->isObjCObjectPointerType() &&
475 !castExprType->isObjCObjectPointerType())
476 return true;
477
478 bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
479 bool castRetainable = castType->isObjCIndirectLifetimeType();
480 if (exprRetainable == castRetainable) return true;
481
482 if (castExpr->isNullPointerConstant(Pass.Ctx,
483 Expr::NPC_ValueDependentIsNull))
484 return true;
485
486 SourceLocation loc = castExpr->getExprLoc();
487 if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
488 return true;
489
490 if (castType->isObjCObjectPointerType())
491 transformNonObjCToObjCCast(E);
492 else
493 transformObjCToNonObjCCast(E);
494
495 return true;
496 }
497
498private:
499 void transformNonObjCToObjCCast(CastExpr *E) {
500 if (!E) return;
501
502 // Global vars are assumed that are cast as unretained.
503 if (isGlobalVar(E))
504 if (E->getSubExpr()->getType()->isPointerType()) {
505 castToObjCObject(E, /*retained=*/false);
506 return;
507 }
508
509 // If the cast is directly over the result of a Core Foundation function
510 // try to figure out whether it should be cast as retained or unretained.
511 Expr *inner = E->IgnoreParenCasts();
512 if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
513 if (FunctionDecl *FD = callE->getDirectCallee()) {
514 if (FD->getAttr<CFReturnsRetainedAttr>()) {
515 castToObjCObject(E, /*retained=*/true);
516 return;
517 }
518 if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
519 castToObjCObject(E, /*retained=*/false);
520 return;
521 }
522 if (FD->isGlobal() &&
523 FD->getIdentifier() &&
524 ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
525 FD->getIdentifier()->getName())) {
526 StringRef fname = FD->getIdentifier()->getName();
527 if (fname.endswith("Retain") ||
528 fname.find("Create") != StringRef::npos ||
529 fname.find("Copy") != StringRef::npos) {
530 castToObjCObject(E, /*retained=*/true);
531 return;
532 }
533
534 if (fname.find("Get") != StringRef::npos) {
535 castToObjCObject(E, /*retained=*/false);
536 return;
537 }
538 }
539 }
540 }
541 }
542
543 void castToObjCObject(CastExpr *E, bool retained) {
544 TransformActions &TA = Pass.TA;
545
546 // We will remove the compiler diagnostic.
547 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
548 diag::err_arc_cast_requires_bridge,
549 E->getLocStart()))
550 return;
551
552 Transaction Trans(TA);
553 TA.clearDiagnostic(diag::err_arc_mismatched_cast,
554 diag::err_arc_cast_requires_bridge,
555 E->getLocStart());
556 if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
557 TA.insertAfterToken(CCE->getLParenLoc(), retained ? "__bridge_transfer "
558 : "__bridge ");
559 } else {
560 SourceLocation insertLoc = E->getSubExpr()->getLocStart();
561 llvm::SmallString<128> newCast;
562 newCast += '(';
563 newCast += retained ? "__bridge_transfer " : "__bridge ";
564 newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
565 newCast += ')';
566
567 if (isa<ParenExpr>(E->getSubExpr())) {
568 TA.insert(insertLoc, newCast.str());
569 } else {
570 newCast += '(';
571 TA.insert(insertLoc, newCast.str());
572 TA.insertAfterToken(E->getLocEnd(), ")");
573 }
574 }
575 }
576
577 void transformObjCToNonObjCCast(CastExpr *E) {
578 // FIXME: Handle these casts.
579 return;
580#if 0
581 TransformActions &TA = Pass.TA;
582
583 // We will remove the compiler diagnostic.
584 if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
585 diag::err_arc_cast_requires_bridge,
586 E->getLocStart()))
587 return;
588
589 Transaction Trans(TA);
590 TA.clearDiagnostic(diag::err_arc_mismatched_cast,
591 diag::err_arc_cast_requires_bridge,
592 E->getLocStart());
593
594 assert(!E->getType()->isObjCObjectPointerType());
595
596 bool shouldCast = !isa<CStyleCastExpr>(E) &&
597 !E->getType()->getPointeeType().isConstQualified();
598 SourceLocation loc = E->getSubExpr()->getLocStart();
599 if (isa<ParenExpr>(E->getSubExpr())) {
600 TA.insert(loc, shouldCast ? "(void*)objc_unretainedPointer"
601 : "objc_unretainedPointer");
602 } else {
603 TA.insert(loc, shouldCast ? "(void*)objc_unretainedPointer("
604 : "objc_unretainedPointer(");
605 TA.insertAfterToken(E->getLocEnd(), ")");
606 }
607#endif
608 }
609
610 static bool isGlobalVar(Expr *E) {
611 E = E->IgnoreParenCasts();
612 if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
613 return DRE->getDecl()->getDeclContext()->isFileContext();
614 if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
615 return isGlobalVar(condOp->getTrueExpr()) &&
616 isGlobalVar(condOp->getFalseExpr());
617
618 return false;
619 }
620};
621
622} // end anonymous namespace
623
624static void castNonObjCToObjC(MigrationPass &pass) {
625 NonObjCToObjCCaster trans(pass);
626 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
627}
628
629//===----------------------------------------------------------------------===//
630// rewriteAllocCopyWithZone
631//===----------------------------------------------------------------------===//
632
633namespace {
634
635class AllocCopyWithZoneRewriter :
636 public RecursiveASTVisitor<AllocCopyWithZoneRewriter> {
637 Decl *Dcl;
638 Stmt *Body;
639 MigrationPass &Pass;
640
641 Selector allocWithZoneSel;
642 Selector copyWithZoneSel;
643 Selector mutableCopyWithZoneSel;
644 Selector zoneSel;
645 IdentifierInfo *NSZoneII;
646
647 std::vector<DeclStmt *> NSZoneVars;
648 std::vector<Expr *> Removals;
649
650public:
651 AllocCopyWithZoneRewriter(Decl *D, MigrationPass &pass)
652 : Dcl(D), Body(0), Pass(pass) {
653 SelectorTable &sels = pass.Ctx.Selectors;
654 IdentifierTable &ids = pass.Ctx.Idents;
655 allocWithZoneSel = sels.getUnarySelector(&ids.get("allocWithZone"));
656 copyWithZoneSel = sels.getUnarySelector(&ids.get("copyWithZone"));
657 mutableCopyWithZoneSel = sels.getUnarySelector(
658 &ids.get("mutableCopyWithZone"));
659 zoneSel = sels.getNullarySelector(&ids.get("zone"));
660 NSZoneII = &ids.get("_NSZone");
661 }
662
663 void transformBody(Stmt *body) {
664 Body = body;
665 // Don't change allocWithZone/copyWithZone messages inside
666 // custom implementations of such methods, it can lead to infinite loops.
667 if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Dcl)) {
668 Selector sel = MD->getSelector();
669 if (sel == allocWithZoneSel ||
670 sel == copyWithZoneSel ||
671 sel == mutableCopyWithZoneSel ||
672 sel == zoneSel)
673 return;
674 }
675
676 TraverseStmt(body);
677 }
678
679 ~AllocCopyWithZoneRewriter() {
680 for (std::vector<DeclStmt *>::reverse_iterator
681 I = NSZoneVars.rbegin(), E = NSZoneVars.rend(); I != E; ++I) {
682 DeclStmt *DS = *I;
683 DeclGroupRef group = DS->getDeclGroup();
684 std::vector<Expr *> varRemovals = Removals;
685
686 bool areAllVarsUnused = true;
687 for (std::reverse_iterator<DeclGroupRef::iterator>
688 DI(group.end()), DE(group.begin()); DI != DE; ++DI) {
689 VarDecl *VD = cast<VarDecl>(*DI);
690 if (isNSZoneVarUsed(VD, varRemovals)) {
691 areAllVarsUnused = false;
692 break;
693 }
694 varRemovals.push_back(VD->getInit());
695 }
696
697 if (areAllVarsUnused) {
698 Transaction Trans(Pass.TA);
699 clearUnavailableDiags(DS);
700 Pass.TA.removeStmt(DS);
701 Removals.swap(varRemovals);
702 }
703 }
704 }
705
706 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
707 if (!isAllocCopyWithZoneCall(E))
708 return true;
709 Expr *arg = E->getArg(0);
710 if (paramToAllocWithZoneHasSideEffects(arg))
711 return true;
712
713 Pass.TA.startTransaction();
714
715 clearUnavailableDiags(arg);
716 Pass.TA.clearDiagnostic(diag::err_unavailable_message,
717 E->getReceiverRange().getBegin());
718
719 Pass.TA.remove(SourceRange(E->getSelectorLoc(), arg->getLocEnd()));
720 StringRef rewrite;
721 if (E->getSelector() == allocWithZoneSel)
722 rewrite = "alloc";
723 else if (E->getSelector() == copyWithZoneSel)
724 rewrite = "copy";
725 else {
726 assert(E->getSelector() == mutableCopyWithZoneSel);
727 rewrite = "mutableCopy";
728 }
729 Pass.TA.insert(E->getSelectorLoc(), rewrite);
730
731 bool failed = Pass.TA.commitTransaction();
732 if (!failed)
733 Removals.push_back(arg);
734
735 return true;
736 }
737
738 bool VisitDeclStmt(DeclStmt *DS) {
739 DeclGroupRef group = DS->getDeclGroup();
740 if (group.begin() == group.end())
741 return true;
742 for (DeclGroupRef::iterator
743 DI = group.begin(), DE = group.end(); DI != DE; ++DI)
744 if (!isRemovableNSZoneVar(*DI))
745 return true;
746
747 NSZoneVars.push_back(DS);
748 return true;
749 }
750
751private:
752 bool isRemovableNSZoneVar(Decl *D) {
753 if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
754 if (isNSZone(VD->getType()))
755 return !paramToAllocWithZoneHasSideEffects(VD->getInit());
756 }
757 return false;
758 }
759
760 bool isNSZone(RecordDecl *RD) {
761 return RD && RD->getIdentifier() == NSZoneII;
762 }
763
764 bool isNSZone(QualType Ty) {
765 QualType pointee = Ty->getPointeeType();
766 if (pointee.isNull())
767 return false;
768 if (const RecordType *recT = pointee->getAsStructureType())
769 return isNSZone(recT->getDecl());
770 return false;
771 }
772
773 bool isNSZoneVarUsed(VarDecl *D, std::vector<Expr *> &removals) {
774 llvm::DenseSet<Expr *> refs;
775
776 ReferenceCollector refColl(refs);
777 refColl.lookFor(D, Body);
778
779 ReferenceClear refClear(refs);
780 refClear.clearRefsIn(removals.begin(), removals.end());
781
782 return !refs.empty();
783 }
784
785 bool isAllocCopyWithZoneCall(ObjCMessageExpr *E) {
786 if (E->getNumArgs() == 1 &&
787 E->getSelector() == allocWithZoneSel &&
788 (E->isClassMessage() ||
789 Pass.TA.hasDiagnostic(diag::err_unavailable_message,
790 E->getReceiverRange().getBegin())))
791 return true;
792
793 return E->isInstanceMessage() &&
794 E->getNumArgs() == 1 &&
795 (E->getSelector() == copyWithZoneSel ||
796 E->getSelector() == mutableCopyWithZoneSel);
797 }
798
799 bool isZoneCall(ObjCMessageExpr *E) {
800 return E->isInstanceMessage() &&
801 E->getNumArgs() == 0 &&
802 E->getSelector() == zoneSel;
803 }
804
805 bool paramToAllocWithZoneHasSideEffects(Expr *E) {
806 if (!HasSideEffects(E, Pass.Ctx))
807 return false;
808 E = E->IgnoreParenCasts();
809 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
810 if (!ME)
811 return true;
812 if (!isZoneCall(ME))
813 return true;
814 return HasSideEffects(ME->getInstanceReceiver(), Pass.Ctx);
815 }
816
817 void clearUnavailableDiags(Stmt *S) {
818 if (S)
819 Pass.TA.clearDiagnostic(diag::err_unavailable,
820 diag::err_unavailable_message,
821 S->getSourceRange());
822 }
823};
824
825} // end anonymous namespace
826
827static void rewriteAllocCopyWithZone(MigrationPass &pass) {
828 BodyTransform<AllocCopyWithZoneRewriter> trans(pass);
829 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
830}
831
832//===----------------------------------------------------------------------===//
833// rewriteAutoreleasePool
834//===----------------------------------------------------------------------===//
835
836/// \brief 'Loc' is the end of a statement range. This returns the location
837/// immediately after the semicolon following the statement.
838/// If no semicolon is found or the location is inside a macro, the returned
839/// source location will be invalid.
840static SourceLocation findLocationAfterSemi(ASTContext &Ctx,
841 SourceLocation loc) {
842 SourceManager &SM = Ctx.getSourceManager();
843 if (loc.isMacroID()) {
844 if (!SM.isAtEndOfMacroInstantiation(loc))
845 return SourceLocation();
846 loc = SM.getInstantiationRange(loc).second;
847 }
848 loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
849
850 // Break down the source location.
851 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
852
853 // Try to load the file buffer.
854 bool invalidTemp = false;
855 llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
856 if (invalidTemp)
857 return SourceLocation();
858
859 const char *tokenBegin = file.data() + locInfo.second;
860
861 // Lex from the start of the given location.
862 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
863 Ctx.getLangOptions(),
864 file.begin(), tokenBegin, file.end());
865 Token tok;
866 lexer.LexFromRawLexer(tok);
867 if (tok.isNot(tok::semi))
868 return SourceLocation();
869
870 return tok.getLocation().getFileLocWithOffset(1);
871}
872
873namespace {
874
875class AutoreleasePoolRewriter
876 : public RecursiveASTVisitor<AutoreleasePoolRewriter> {
877public:
878 AutoreleasePoolRewriter(Decl *D, MigrationPass &pass)
879 : Dcl(D), Body(0), Pass(pass) {
880 PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool");
881 DrainSel = pass.Ctx.Selectors.getNullarySelector(
882 &pass.Ctx.Idents.get("drain"));
883 }
884
885 void transformBody(Stmt *body) {
886 Body = body;
887 TraverseStmt(body);
888 }
889
890 ~AutoreleasePoolRewriter() {
891 llvm::SmallVector<VarDecl *, 8> VarsToHandle;
892
893 for (std::map<VarDecl *, PoolVarInfo>::iterator
894 I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
895 VarDecl *var = I->first;
896 PoolVarInfo &info = I->second;
897
898 // Check that we can handle/rewrite all references of the pool.
899
900 ReferenceClear refClear(info.Refs);
901 refClear.clearRefsIn(info.Dcl);
902 for (llvm::SmallVectorImpl<PoolScope>::iterator
903 scpI = info.Scopes.begin(),
904 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
905 PoolScope &scope = *scpI;
906 refClear.clearRefsIn(*scope.Begin);
907 refClear.clearRefsIn(*scope.End);
908 refClear.clearRefsIn(scope.Releases.begin(), scope.Releases.end());
909 }
910
911 // Even if one reference is not handled we will not do anything about that
912 // pool variable.
913 if (info.Refs.empty())
914 VarsToHandle.push_back(var);
915 }
916
917 for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) {
918 PoolVarInfo &info = PoolVars[VarsToHandle[i]];
919
920 Transaction Trans(Pass.TA);
921
922 clearUnavailableDiags(info.Dcl);
923 Pass.TA.removeStmt(info.Dcl);
924
925 // Add "@autoreleasepool { }"
926 for (llvm::SmallVectorImpl<PoolScope>::iterator
927 scpI = info.Scopes.begin(),
928 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
929 PoolScope &scope = *scpI;
930 clearUnavailableDiags(*scope.Begin);
931 clearUnavailableDiags(*scope.End);
932 if (scope.IsFollowedBySimpleReturnStmt) {
933 // Include the return in the scope.
934 Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
935 Pass.TA.removeStmt(*scope.End);
936 Stmt::child_iterator retI = scope.End;
937 ++retI;
938 SourceLocation afterSemi = findLocationAfterSemi(Pass.Ctx,
939 (*retI)->getLocEnd());
940 assert(afterSemi.isValid() &&
941 "Didn't we check before setting IsFollowedBySimpleReturnStmt "
942 "to true?");
943 Pass.TA.insertAfterToken(afterSemi, "\n}");
944 Pass.TA.increaseIndentation(
945 SourceRange(scope.getIndentedRange().getBegin(),
946 (*retI)->getLocEnd()),
947 scope.CompoundParent->getLocStart());
948 } else {
949 Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
950 Pass.TA.replaceStmt(*scope.End, "}");
951 Pass.TA.increaseIndentation(scope.getIndentedRange(),
952 scope.CompoundParent->getLocStart());
953 }
954 }
955
956 // Remove rest of pool var references.
957 for (llvm::SmallVectorImpl<PoolScope>::iterator
958 scpI = info.Scopes.begin(),
959 scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
960 PoolScope &scope = *scpI;
961 for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator
962 relI = scope.Releases.begin(),
963 relE = scope.Releases.end(); relI != relE; ++relI) {
964 clearUnavailableDiags(*relI);
965 Pass.TA.removeStmt(*relI);
966 }
967 }
968 }
969 }
970
971 bool VisitCompoundStmt(CompoundStmt *S) {
972 llvm::SmallVector<PoolScope, 4> Scopes;
973
974 for (Stmt::child_iterator
975 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
976 Stmt *child = getEssential(*I);
977 if (DeclStmt *DclS = dyn_cast<DeclStmt>(child)) {
978 if (DclS->isSingleDecl()) {
979 if (VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) {
980 if (isNSAutoreleasePool(VD->getType())) {
981 PoolVarInfo &info = PoolVars[VD];
982 info.Dcl = DclS;
983 ReferenceCollector refColl(info.Refs);
984 refColl.lookFor(VD, S);
985 // Does this statement follow the pattern:
986 // NSAutoreleasePool * pool = [NSAutoreleasePool new];
987 if (isPoolCreation(VD->getInit())) {
988 Scopes.push_back(PoolScope());
989 Scopes.back().PoolVar = VD;
990 Scopes.back().CompoundParent = S;
991 Scopes.back().Begin = I;
992 }
993 }
994 }
995 }
996 } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) {
997 if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
998 if (VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) {
999 // Does this statement follow the pattern:
1000 // pool = [NSAutoreleasePool new];
1001 if (isNSAutoreleasePool(VD->getType()) &&
1002 isPoolCreation(bop->getRHS())) {
1003 Scopes.push_back(PoolScope());
1004 Scopes.back().PoolVar = VD;
1005 Scopes.back().CompoundParent = S;
1006 Scopes.back().Begin = I;
1007 }
1008 }
1009 }
1010 }
1011
1012 if (Scopes.empty())
1013 continue;
1014
1015 if (isPoolDrain(Scopes.back().PoolVar, child)) {
1016 PoolScope &scope = Scopes.back();
1017 scope.End = I;
1018 handlePoolScope(scope, S);
1019 Scopes.pop_back();
1020 }
1021 }
1022 return true;
1023 }
1024
1025private:
1026 void clearUnavailableDiags(Stmt *S) {
1027 if (S)
1028 Pass.TA.clearDiagnostic(diag::err_unavailable,
1029 diag::err_unavailable_message,
1030 S->getSourceRange());
1031 }
1032
1033 struct PoolScope {
1034 VarDecl *PoolVar;
1035 CompoundStmt *CompoundParent;
1036 Stmt::child_iterator Begin;
1037 Stmt::child_iterator End;
1038 bool IsFollowedBySimpleReturnStmt;
1039 llvm::SmallVector<ObjCMessageExpr *, 4> Releases;
1040
1041 PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(),
1042 IsFollowedBySimpleReturnStmt(false) { }
1043
1044 SourceRange getIndentedRange() const {
1045 Stmt::child_iterator rangeS = Begin;
1046 ++rangeS;
1047 if (rangeS == End)
1048 return SourceRange();
1049 Stmt::child_iterator rangeE = Begin;
1050 for (Stmt::child_iterator I = rangeS; I != End; ++I)
1051 ++rangeE;
1052 return SourceRange((*rangeS)->getLocStart(), (*rangeE)->getLocEnd());
1053 }
1054 };
1055
1056 class NameReferenceChecker : public RecursiveASTVisitor<NameReferenceChecker>{
1057 ASTContext &Ctx;
1058 SourceRange ScopeRange;
1059 SourceLocation &referenceLoc, &declarationLoc;
1060
1061 public:
1062 NameReferenceChecker(ASTContext &ctx, PoolScope &scope,
1063 SourceLocation &referenceLoc,
1064 SourceLocation &declarationLoc)
1065 : Ctx(ctx), referenceLoc(referenceLoc),
1066 declarationLoc(declarationLoc) {
1067 ScopeRange = SourceRange((*scope.Begin)->getLocStart(),
1068 (*scope.End)->getLocStart());
1069 }
1070
1071 bool VisitDeclRefExpr(DeclRefExpr *E) {
1072 return checkRef(E->getLocation(), E->getDecl()->getLocation());
1073 }
1074
1075 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
1076 return checkRef(E->getLocation(), E->getDecl()->getLocation());
1077 }
1078
1079 bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
1080 return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation());
1081 }
1082
1083 bool VisitTagTypeLoc(TagTypeLoc TL) {
1084 return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation());
1085 }
1086
1087 private:
1088 bool checkRef(SourceLocation refLoc, SourceLocation declLoc) {
1089 if (isInScope(declLoc)) {
1090 referenceLoc = refLoc;
1091 declarationLoc = declLoc;
1092 return false;
1093 }
1094 return true;
1095 }
1096
1097 bool isInScope(SourceLocation loc) {
1098 SourceManager &SM = Ctx.getSourceManager();
1099 if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
1100 return false;
1101 return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd());
1102 }
1103 };
1104
1105 void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) {
1106 // Check that all names declared inside the scope are not used
1107 // outside the scope.
1108 {
1109 bool nameUsedOutsideScope = false;
1110 SourceLocation referenceLoc, declarationLoc;
1111 Stmt::child_iterator SI = scope.End, SE = compoundS->body_end();
1112 ++SI;
1113 // Check if the autoreleasepool scope is followed by a simple return
1114 // statement, in which case we will include the return in the scope.
1115 if (SI != SE)
1116 if (ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
1117 if ((retS->getRetValue() == 0 ||
1118 isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
1119 findLocationAfterSemi(Pass.Ctx, retS->getLocEnd()).isValid()) {
1120 scope.IsFollowedBySimpleReturnStmt = true;
1121 ++SI; // the return will be included in scope, don't check it.
1122 }
1123
1124 for (; SI != SE; ++SI) {
1125 nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
1126 referenceLoc,
1127 declarationLoc).TraverseStmt(*SI);
1128 if (nameUsedOutsideScope)
1129 break;
1130 }
1131
1132 // If not all references were cleared it means some variables/typenames/etc
1133 // declared inside the pool scope are used outside of it.
1134 // We won't try to rewrite the pool.
1135 if (nameUsedOutsideScope) {
1136 Pass.TA.reportError("a name is referenced outside the "
1137 "NSAutoreleasePool scope that it was declared in", referenceLoc);
1138 Pass.TA.reportNote("name declared here", declarationLoc);
1139 Pass.TA.reportNote("intended @autoreleasepool scope begins here",
1140 (*scope.Begin)->getLocStart());
1141 Pass.TA.reportNote("intended @autoreleasepool scope ends here",
1142 (*scope.End)->getLocStart());
1143 return;
1144 }
1145 }
1146
1147 // Collect all releases of the pool; they will be removed.
1148 {
1149 ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
1150 Stmt::child_iterator I = scope.Begin;
1151 ++I;
1152 for (; I != scope.End; ++I)
1153 releaseColl.TraverseStmt(*I);
1154 }
1155
1156 PoolVars[scope.PoolVar].Scopes.push_back(scope);
1157 }
1158
1159 bool isPoolCreation(Expr *E) {
1160 if (!E) return false;
1161 E = getEssential(E);
1162 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
1163 if (!ME) return false;
1164 if (ME->getMethodFamily() == OMF_new &&
1165 ME->getReceiverKind() == ObjCMessageExpr::Class &&
1166 isNSAutoreleasePool(ME->getReceiverInterface()))
1167 return true;
1168 if (ME->getReceiverKind() == ObjCMessageExpr::Instance &&
1169 ME->getMethodFamily() == OMF_init) {
1170 Expr *rec = getEssential(ME->getInstanceReceiver());
1171 if (ObjCMessageExpr *recME = dyn_cast_or_null<ObjCMessageExpr>(rec)) {
1172 if (recME->getMethodFamily() == OMF_alloc &&
1173 recME->getReceiverKind() == ObjCMessageExpr::Class &&
1174 isNSAutoreleasePool(recME->getReceiverInterface()))
1175 return true;
1176 }
1177 }
1178
1179 return false;
1180 }
1181
1182 bool isPoolDrain(VarDecl *poolVar, Stmt *S) {
1183 if (!S) return false;
1184 S = getEssential(S);
1185 ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
1186 if (!ME) return false;
1187 if (ME->getReceiverKind() == ObjCMessageExpr::Instance) {
1188 Expr *rec = getEssential(ME->getInstanceReceiver());
1189 if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
1190 if (dref->getDecl() == poolVar)
1191 return ME->getMethodFamily() == OMF_release ||
1192 ME->getSelector() == DrainSel;
1193 }
1194
1195 return false;
1196 }
1197
1198 bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) {
1199 return IDecl && IDecl->getIdentifier() == PoolII;
1200 }
1201
1202 bool isNSAutoreleasePool(QualType Ty) {
1203 QualType pointee = Ty->getPointeeType();
1204 if (pointee.isNull())
1205 return false;
1206 if (const ObjCInterfaceType *interT = pointee->getAs<ObjCInterfaceType>())
1207 return isNSAutoreleasePool(interT->getDecl());
1208 return false;
1209 }
1210
1211 static Expr *getEssential(Expr *E) {
1212 return cast<Expr>(getEssential((Stmt*)E));
1213 }
1214 static Stmt *getEssential(Stmt *S) {
1215 if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
1216 S = EWC->getSubExpr();
1217 if (Expr *E = dyn_cast<Expr>(S))
1218 S = E->IgnoreParenCasts();
1219 return S;
1220 }
1221
1222 Decl *Dcl;
1223 Stmt *Body;
1224 MigrationPass &Pass;
1225
1226 IdentifierInfo *PoolII;
1227 Selector DrainSel;
1228
1229 struct PoolVarInfo {
1230 DeclStmt *Dcl;
1231 llvm::DenseSet<Expr *> Refs;
1232 llvm::SmallVector<PoolScope, 2> Scopes;
1233
1234 PoolVarInfo() : Dcl(0) { }
1235 };
1236
1237 std::map<VarDecl *, PoolVarInfo> PoolVars;
1238};
1239
1240} // anonymous namespace
1241
1242static void rewriteAutoreleasePool(MigrationPass &pass) {
1243 BodyTransform<AutoreleasePoolRewriter> trans(pass);
1244 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1245}
1246
1247//===----------------------------------------------------------------------===//
1248// removeRetainReleaseDealloc
1249//===----------------------------------------------------------------------===//
1250
1251namespace {
1252
1253class RetainReleaseDeallocRemover :
1254 public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
1255 Decl *Dcl;
1256 Stmt *Body;
1257 MigrationPass &Pass;
1258
1259 llvm::DenseSet<Expr *> Removables;
1260 llvm::OwningPtr<ParentMap> StmtMap;
1261
1262public:
1263 RetainReleaseDeallocRemover(Decl *D, MigrationPass &pass)
1264 : Dcl(D), Body(0), Pass(pass) { }
1265
1266 void transformBody(Stmt *body) {
1267 Body = body;
1268 RemovablesCollector(Removables).TraverseStmt(body);
1269 StmtMap.reset(new ParentMap(body));
1270 TraverseStmt(body);
1271 }
1272
1273 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
1274 switch (E->getMethodFamily()) {
1275 default:
1276 return true;
1277 case OMF_retain:
1278 case OMF_release:
1279 case OMF_autorelease:
1280 if (E->getReceiverKind() == ObjCMessageExpr::Instance)
1281 if (Expr *rec = E->getInstanceReceiver()) {
1282 rec = rec->IgnoreParenImpCasts();
1283 if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){
1284 std::string err = "It is not safe to remove '";
1285 err += E->getSelector().getAsString() + "' message on "
1286 "an __unsafe_unretained type";
1287 Pass.TA.reportError(err, rec->getLocStart());
1288 return true;
1289 }
1290 }
1291 case OMF_dealloc:
1292 break;
1293 }
1294
1295 switch (E->getReceiverKind()) {
1296 default:
1297 return true;
1298 case ObjCMessageExpr::SuperInstance: {
1299 Transaction Trans(Pass.TA);
1300 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
1301 diag::err_unavailable,
1302 diag::err_unavailable_message,
1303 E->getSuperLoc());
1304 if (tryRemoving(E))
1305 return true;
1306 Pass.TA.replace(E->getSourceRange(), "self");
1307 return true;
1308 }
1309 case ObjCMessageExpr::Instance:
1310 break;
1311 }
1312
1313 Expr *rec = E->getInstanceReceiver();
1314 if (!rec) return true;
1315
1316 Transaction Trans(Pass.TA);
1317 Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
1318 diag::err_unavailable,
1319 diag::err_unavailable_message,
1320 rec->getExprLoc());
1321 if (!HasSideEffects(E, Pass.Ctx)) {
1322 if (tryRemoving(E))
1323 return true;
1324 }
1325 Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
1326
1327 return true;
1328 }
1329
1330private:
1331 bool isRemovable(Expr *E) const {
1332 return Removables.count(E);
1333 }
1334
1335 bool tryRemoving(Expr *E) const {
1336 if (isRemovable(E)) {
1337 Pass.TA.removeStmt(E);
1338 return true;
1339 }
1340
1341 if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E)))
1342 return tryRemoving(parenE);
1343
1344 if (BinaryOperator *
1345 bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) {
1346 if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
1347 isRemovable(bopE)) {
1348 Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
1349 return true;
1350 }
1351 }
1352
1353 return false;
1354 }
1355
1356};
1357
1358} // anonymous namespace
1359
1360static void removeRetainReleaseDealloc(MigrationPass &pass) {
1361 BodyTransform<RetainReleaseDeallocRemover> trans(pass);
1362 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1363}
1364
1365//===----------------------------------------------------------------------===//
1366// removeEmptyStatements
1367//===----------------------------------------------------------------------===//
1368
1369namespace {
1370
1371class EmptyStatementsRemover :
1372 public RecursiveASTVisitor<EmptyStatementsRemover> {
1373 MigrationPass &Pass;
1374 llvm::DenseSet<unsigned> MacroLocs;
1375
1376public:
1377 EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) {
1378 for (unsigned i = 0, e = Pass.ARCMTMacroLocs.size(); i != e; ++i)
1379 MacroLocs.insert(Pass.ARCMTMacroLocs[i].getRawEncoding());
1380 }
1381
1382 bool TraverseStmtExpr(StmtExpr *E) {
1383 CompoundStmt *S = E->getSubStmt();
1384 for (CompoundStmt::body_iterator
1385 I = S->body_begin(), E = S->body_end(); I != E; ++I) {
1386 if (I != E - 1)
1387 check(*I);
1388 TraverseStmt(*I);
1389 }
1390 return true;
1391 }
1392
1393 bool VisitCompoundStmt(CompoundStmt *S) {
1394 for (CompoundStmt::body_iterator
1395 I = S->body_begin(), E = S->body_end(); I != E; ++I)
1396 check(*I);
1397 return true;
1398 }
1399
1400 bool isMacroLoc(SourceLocation loc) {
1401 if (loc.isInvalid()) return false;
1402 return MacroLocs.count(loc.getRawEncoding());
1403 }
1404
1405 ASTContext &getContext() { return Pass.Ctx; }
1406
1407private:
1408 /// \brief Returns true if the statement became empty due to previous
1409 /// transformations.
1410 class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
1411 EmptyStatementsRemover &Trans;
1412
1413 public:
1414 EmptyChecker(EmptyStatementsRemover &trans) : Trans(trans) { }
1415
1416 bool VisitNullStmt(NullStmt *S) {
1417 return Trans.isMacroLoc(S->getLeadingEmptyMacroLoc());
1418 }
1419 bool VisitCompoundStmt(CompoundStmt *S) {
1420 if (S->body_empty())
1421 return false; // was already empty, not because of transformations.
1422 for (CompoundStmt::body_iterator
1423 I = S->body_begin(), E = S->body_end(); I != E; ++I)
1424 if (!Visit(*I))
1425 return false;
1426 return true;
1427 }
1428 bool VisitIfStmt(IfStmt *S) {
1429 if (S->getConditionVariable())
1430 return false;
1431 Expr *condE = S->getCond();
1432 if (!condE)
1433 return false;
1434 if (HasSideEffects(condE, Trans.getContext()))
1435 return false;
1436 if (!S->getThen() || !Visit(S->getThen()))
1437 return false;
1438 if (S->getElse() && !Visit(S->getElse()))
1439 return false;
1440 return true;
1441 }
1442 bool VisitWhileStmt(WhileStmt *S) {
1443 if (S->getConditionVariable())
1444 return false;
1445 Expr *condE = S->getCond();
1446 if (!condE)
1447 return false;
1448 if (HasSideEffects(condE, Trans.getContext()))
1449 return false;
1450 if (!S->getBody())
1451 return false;
1452 return Visit(S->getBody());
1453 }
1454 bool VisitDoStmt(DoStmt *S) {
1455 Expr *condE = S->getCond();
1456 if (!condE)
1457 return false;
1458 if (HasSideEffects(condE, Trans.getContext()))
1459 return false;
1460 if (!S->getBody())
1461 return false;
1462 return Visit(S->getBody());
1463 }
1464 bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
1465 Expr *Exp = S->getCollection();
1466 if (!Exp)
1467 return false;
1468 if (HasSideEffects(Exp, Trans.getContext()))
1469 return false;
1470 if (!S->getBody())
1471 return false;
1472 return Visit(S->getBody());
1473 }
1474 bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
1475 if (!S->getSubStmt())
1476 return false;
1477 return Visit(S->getSubStmt());
1478 }
1479 };
1480
1481 void check(Stmt *S) {
1482 if (!S) return;
1483 if (EmptyChecker(*this).Visit(S)) {
1484 Transaction Trans(Pass.TA);
1485 Pass.TA.removeStmt(S);
1486 }
1487 }
1488};
1489
1490} // anonymous namespace
1491
1492static void removeEmptyStatements(MigrationPass &pass) {
1493 EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1494
1495 for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
1496 Transaction Trans(pass.TA);
1497 pass.TA.remove(pass.ARCMTMacroLocs[i]);
1498 }
1499}
1500
1501//===----------------------------------------------------------------------===//
1502// changeIvarsOfAssignProperties.
1503//===----------------------------------------------------------------------===//
1504
1505namespace {
1506
1507class AssignPropertiesTrans {
1508 MigrationPass &Pass;
1509 struct PropData {
1510 ObjCPropertyDecl *PropD;
1511 ObjCIvarDecl *IvarD;
1512 bool ShouldChangeToWeak;
1513 SourceLocation ArcPropAssignErrorLoc;
1514 };
1515
1516 typedef llvm::SmallVector<PropData, 2> PropsTy;
1517 typedef llvm::DenseMap<unsigned, PropsTy> PropsMapTy;
1518 PropsMapTy PropsMap;
1519
1520public:
1521 AssignPropertiesTrans(MigrationPass &pass) : Pass(pass) { }
1522
1523 void doTransform(ObjCImplementationDecl *D) {
1524 SourceManager &SM = Pass.Ctx.getSourceManager();
1525
1526 ObjCInterfaceDecl *IFace = D->getClassInterface();
1527 for (ObjCInterfaceDecl::prop_iterator
1528 I = IFace->prop_begin(), E = IFace->prop_end(); I != E; ++I) {
1529 ObjCPropertyDecl *propD = *I;
1530 unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding();
1531 PropsTy &props = PropsMap[loc];
1532 props.push_back(PropData());
1533 props.back().PropD = propD;
1534 props.back().IvarD = 0;
1535 props.back().ShouldChangeToWeak = false;
1536 }
1537
1538 typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
1539 prop_impl_iterator;
1540 for (prop_impl_iterator
1541 I = prop_impl_iterator(D->decls_begin()),
1542 E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
1543 VisitObjCPropertyImplDecl(*I);
1544 }
1545
1546 for (PropsMapTy::iterator
1547 I = PropsMap.begin(), E = PropsMap.end(); I != E; ++I) {
1548 SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
1549 PropsTy &props = I->second;
1550 if (shouldApplyWeakToAllProp(props)) {
1551 if (changeAssignToWeak(atLoc)) {
1552 // Couldn't add the 'weak' property attribute,
1553 // try adding __unsafe_unretained.
1554 applyUnsafeUnretained(props);
1555 } else {
1556 for (PropsTy::iterator
1557 PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
1558 applyWeak(*PI);
1559 }
1560 }
1561 } else {
1562 // We should not add 'weak' attribute since not all properties need it.
1563 // So just add __unsafe_unretained to the ivars.
1564 applyUnsafeUnretained(props);
1565 }
1566 }
1567 }
1568
1569 bool shouldApplyWeakToAllProp(PropsTy &props) {
1570 for (PropsTy::iterator
1571 PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
1572 if (!PI->ShouldChangeToWeak)
1573 return false;
1574 }
1575 return true;
1576 }
1577
1578 void applyWeak(PropData &prop) {
1579 assert(!Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime);
1580
1581 Transaction Trans(Pass.TA);
1582 Pass.TA.insert(prop.IvarD->getLocation(), "__weak ");
1583 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime,
1584 prop.ArcPropAssignErrorLoc);
1585 }
1586
1587 void applyUnsafeUnretained(PropsTy &props) {
1588 for (PropsTy::iterator
1589 PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
1590 if (PI->ShouldChangeToWeak) {
1591 Transaction Trans(Pass.TA);
1592 Pass.TA.insert(PI->IvarD->getLocation(), "__unsafe_unretained ");
1593 Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime,
1594 PI->ArcPropAssignErrorLoc);
1595 }
1596 }
1597 }
1598
1599 bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
1600 SourceManager &SM = Pass.Ctx.getSourceManager();
1601
1602 if (D->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
1603 return true;
1604 ObjCPropertyDecl *propD = D->getPropertyDecl();
1605 if (!propD || propD->isInvalidDecl())
1606 return true;
1607 ObjCIvarDecl *ivarD = D->getPropertyIvarDecl();
1608 if (!ivarD || ivarD->isInvalidDecl())
1609 return true;
1610 if (!(propD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign))
1611 return true;
1612 if (isa<AttributedType>(ivarD->getType().getTypePtr()))
1613 return true;
1614 if (ivarD->getType().getLocalQualifiers().getObjCLifetime()
1615 != Qualifiers::OCL_Strong)
1616 return true;
1617 if (!Pass.TA.hasDiagnostic(
1618 diag::err_arc_assign_property_lifetime, D->getLocation()))
1619 return true;
1620
1621 // There is a "error: existing ivar for assign property must be
1622 // __unsafe_unretained"; fix it.
1623
1624 if (Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime) {
1625 // We will just add __unsafe_unretained to the ivar.
1626 Transaction Trans(Pass.TA);
1627 Pass.TA.insert(ivarD->getLocation(), "__unsafe_unretained ");
1628 Pass.TA.clearDiagnostic(
1629 diag::err_arc_assign_property_lifetime, D->getLocation());
1630 } else {
1631 // Mark that we want the ivar to become weak.
1632 unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding();
1633 PropsTy &props = PropsMap[loc];
1634 for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
1635 if (I->PropD == propD) {
1636 I->IvarD = ivarD;
1637 I->ShouldChangeToWeak = true;
1638 I->ArcPropAssignErrorLoc = D->getLocation();
1639 }
1640 }
1641 }
1642
1643 return true;
1644 }
1645
1646private:
1647 bool changeAssignToWeak(SourceLocation atLoc) {
1648 SourceManager &SM = Pass.Ctx.getSourceManager();
1649
1650 // Break down the source location.
1651 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
1652
1653 // Try to load the file buffer.
1654 bool invalidTemp = false;
1655 llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
1656 if (invalidTemp)
1657 return true;
1658
1659 const char *tokenBegin = file.data() + locInfo.second;
1660
1661 // Lex from the start of the given location.
1662 Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
1663 Pass.Ctx.getLangOptions(),
1664 file.begin(), tokenBegin, file.end());
1665 Token tok;
1666 lexer.LexFromRawLexer(tok);
1667 if (tok.isNot(tok::at)) return true;
1668 lexer.LexFromRawLexer(tok);
1669 if (tok.isNot(tok::raw_identifier)) return true;
1670 if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength())
1671 != "property")
1672 return true;
1673 lexer.LexFromRawLexer(tok);
1674 if (tok.isNot(tok::l_paren)) return true;
1675
1676 SourceLocation LParen = tok.getLocation();
1677 SourceLocation assignLoc;
1678 bool isEmpty = false;
1679
1680 lexer.LexFromRawLexer(tok);
1681 if (tok.is(tok::r_paren)) {
1682 isEmpty = true;
1683 } else {
1684 while (1) {
1685 if (tok.isNot(tok::raw_identifier)) return true;
1686 llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength());
1687 if (ident == "assign")
1688 assignLoc = tok.getLocation();
1689
1690 do {
1691 lexer.LexFromRawLexer(tok);
1692 } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
1693 if (tok.is(tok::r_paren))
1694 break;
1695 lexer.LexFromRawLexer(tok);
1696 }
1697 }
1698
1699 Transaction Trans(Pass.TA);
1700 if (assignLoc.isValid())
1701 Pass.TA.replaceText(assignLoc, "assign", "weak");
1702 else
1703 Pass.TA.insertAfterToken(LParen, isEmpty ? "weak" : "weak, ");
1704 return false;
1705 }
1706};
1707
1708class PropertiesChecker : public RecursiveASTVisitor<PropertiesChecker> {
1709 MigrationPass &Pass;
1710
1711public:
1712 PropertiesChecker(MigrationPass &pass) : Pass(pass) { }
1713
1714 bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
1715 AssignPropertiesTrans(Pass).doTransform(D);
1716 return true;
1717 }
1718};
1719
1720} // anonymous namespace
1721
1722static void changeIvarsOfAssignProperties(MigrationPass &pass) {
1723 PropertiesChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1724}
1725
1726//===----------------------------------------------------------------------===//
1727// rewriteUnusedDelegateInit
1728//===----------------------------------------------------------------------===//
1729
1730namespace {
1731
1732class UnusedInitRewriter : public RecursiveASTVisitor<UnusedInitRewriter> {
1733 Decl *Dcl;
1734 Stmt *Body;
1735 MigrationPass &Pass;
1736
1737 llvm::DenseSet<Expr *> Removables;
1738
1739public:
1740 UnusedInitRewriter(Decl *D, MigrationPass &pass)
1741 : Dcl(D), Body(0), Pass(pass) { }
1742
1743 void transformBody(Stmt *body) {
1744 Body = body;
1745 RemovablesCollector(Removables).TraverseStmt(body);
1746 TraverseStmt(body);
1747 }
1748
1749 bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
1750 if (ME->isDelegateInitCall() &&
1751 isRemovable(ME) &&
1752 Pass.TA.hasDiagnostic(diag::err_arc_unused_init_message,
1753 ME->getExprLoc())) {
1754 Transaction Trans(Pass.TA);
1755 Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message,
1756 ME->getExprLoc());
1757 Pass.TA.insert(ME->getExprLoc(), "self = ");
1758 }
1759 return true;
1760 }
1761
1762private:
1763 bool isRemovable(Expr *E) const {
1764 return Removables.count(E);
1765 }
1766};
1767
1768} // anonymous namespace
1769
1770static void rewriteUnusedDelegateInit(MigrationPass &pass) {
1771 BodyTransform<UnusedInitRewriter> trans(pass);
1772 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1773}
1774
1775//===----------------------------------------------------------------------===//
1776// rewriteBlockObjCVariable
1777//===----------------------------------------------------------------------===//
1778
1779namespace {
1780
1781class RootBlockObjCVarRewriter :
1782 public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
1783 MigrationPass &Pass;
1784 llvm::DenseSet<VarDecl *> CheckedVars;
1785
1786 class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
1787 VarDecl *Var;
1788
1789 typedef RecursiveASTVisitor<BlockVarChecker> base;
1790 public:
1791 BlockVarChecker(VarDecl *var) : Var(var) { }
1792
1793 bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
1794 if (BlockDeclRefExpr *
1795 ref = dyn_cast<BlockDeclRefExpr>(castE->getSubExpr())) {
1796 if (ref->getDecl() == Var) {
1797 if (castE->getCastKind() == CK_LValueToRValue)
1798 return true; // Using the value of the variable.
1799 if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
1800 Var->getASTContext().getLangOptions().CPlusPlus)
1801 return true; // Binding to const C++ reference.
1802 }
1803 }
1804
1805 return base::TraverseImplicitCastExpr(castE);
1806 }
1807
1808 bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
1809 if (E->getDecl() == Var)
1810 return false; // The reference of the variable, and not just its value,
1811 // is needed.
1812 return true;
1813 }
1814 };
1815
1816public:
1817 RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
1818
1819 bool VisitBlockDecl(BlockDecl *block) {
1820 llvm::SmallVector<VarDecl *, 4> BlockVars;
1821
1822 for (BlockDecl::capture_iterator
1823 I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
1824 VarDecl *var = I->getVariable();
1825 if (I->isByRef() &&
1826 !isAlreadyChecked(var) &&
1827 var->getType()->isObjCObjectPointerType() &&
1828 isImplicitStrong(var->getType())) {
1829 BlockVars.push_back(var);
1830 }
1831 }
1832
1833 for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
1834 VarDecl *var = BlockVars[i];
1835 CheckedVars.insert(var);
1836
1837 BlockVarChecker checker(var);
1838 bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
1839 if (onlyValueOfVarIsNeeded) {
1840 BlocksAttr *attr = var->getAttr<BlocksAttr>();
1841 if(!attr)
1842 continue;
1843 bool hasARCRuntime = !Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime;
1844 SourceManager &SM = Pass.Ctx.getSourceManager();
1845 Transaction Trans(Pass.TA);
1846 Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()),
1847 "__block",
1848 hasARCRuntime ? "__weak" : "__unsafe_unretained");
1849 }
1850
1851 }
1852
1853 return true;
1854 }
1855
1856private:
1857 bool isAlreadyChecked(VarDecl *VD) {
1858 return CheckedVars.count(VD);
1859 }
1860
1861 bool isImplicitStrong(QualType ty) {
1862 if (isa<AttributedType>(ty.getTypePtr()))
1863 return false;
1864 return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
1865 }
1866};
1867
1868class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
1869 MigrationPass &Pass;
1870
1871public:
1872 BlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
1873
1874 bool TraverseBlockDecl(BlockDecl *block) {
1875 RootBlockObjCVarRewriter(Pass).TraverseDecl(block);
1876 return true;
1877 }
1878};
1879
1880} // anonymous namespace
1881
1882static void rewriteBlockObjCVariable(MigrationPass &pass) {
1883 BlockObjCVarRewriter trans(pass);
1884 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
1885}
1886
1887//===----------------------------------------------------------------------===//
1888// removeZeroOutIvarsInDealloc
1889//===----------------------------------------------------------------------===//
1890
1891namespace {
1892
1893class ZeroOutInDeallocRemover :
1894 public RecursiveASTVisitor<ZeroOutInDeallocRemover> {
1895 typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base;
1896
1897 MigrationPass &Pass;
1898
1899 llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;
1900 ImplicitParamDecl *SelfD;
1901 llvm::DenseSet<Expr *> Removables;
1902
1903public:
1904 ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { }
1905
1906 bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
1907 ASTContext &Ctx = Pass.Ctx;
1908 TransformActions &TA = Pass.TA;
1909
1910 if (ME->getReceiverKind() != ObjCMessageExpr::Instance)
1911 return true;
1912 Expr *receiver = ME->getInstanceReceiver();
1913 if (!receiver)
1914 return true;
1915
1916 DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());
1917 if (!refE || refE->getDecl() != SelfD)
1918 return true;
1919
1920 bool BackedBySynthesizeSetter = false;
1921 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
1922 P = SynthesizedProperties.begin(),
1923 E = SynthesizedProperties.end(); P != E; ++P) {
1924 ObjCPropertyDecl *PropDecl = P->first;
1925 if (PropDecl->getSetterName() == ME->getSelector()) {
1926 BackedBySynthesizeSetter = true;
1927 break;
1928 }
1929 }
1930 if (!BackedBySynthesizeSetter)
1931 return true;
1932
1933 // Remove the setter message if RHS is null
1934 Transaction Trans(TA);
1935 Expr *RHS = ME->getArg(0);
1936 bool RHSIsNull =
1937 RHS->isNullPointerConstant(Ctx,
1938 Expr::NPC_ValueDependentIsNull);
1939 if (RHSIsNull && isRemovable(ME))
1940 TA.removeStmt(ME);
1941
1942 return true;
1943 }
1944
1945 bool VisitBinaryOperator(BinaryOperator *BOE) {
1946 if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
1947 Transaction Trans(Pass.TA);
1948 Pass.TA.removeStmt(BOE);
1949 }
1950
1951 return true;
1952 }
1953
1954 bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
1955 if (D->getMethodFamily() != OMF_dealloc)
1956 return true;
1957 if (!D->hasBody())
1958 return true;
1959
1960 ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());
1961 if (!IMD)
1962 return true;
1963
1964 SelfD = D->getSelfDecl();
1965 RemovablesCollector(Removables).TraverseStmt(D->getBody());
1966
1967 // For a 'dealloc' method use, find all property implementations in
1968 // this class implementation.
1969 for (ObjCImplDecl::propimpl_iterator
1970 I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) {
1971 ObjCPropertyImplDecl *PID = *I;
1972 if (PID->getPropertyImplementation() ==
1973 ObjCPropertyImplDecl::Synthesize) {
1974 ObjCPropertyDecl *PD = PID->getPropertyDecl();
1975 ObjCMethodDecl *setterM = PD->getSetterMethodDecl();
1976 if (!(setterM && setterM->isDefined())) {
1977 ObjCPropertyDecl::PropertyAttributeKind AttrKind =
1978 PD->getPropertyAttributes();
1979 if (AttrKind &
1980 (ObjCPropertyDecl::OBJC_PR_retain |
1981 ObjCPropertyDecl::OBJC_PR_copy |
1982 ObjCPropertyDecl::OBJC_PR_strong))
1983 SynthesizedProperties[PD] = PID;
1984 }
1985 }
1986 }
1987
1988 // Now, remove all zeroing of ivars etc.
1989 base::TraverseObjCMethodDecl(D);
1990
1991 // clear out for next method.
1992 SynthesizedProperties.clear();
1993 SelfD = 0;
1994 Removables.clear();
1995 return true;
1996 }
1997
1998 bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
1999 bool TraverseBlockDecl(BlockDecl *block) { return true; }
2000 bool TraverseBlockExpr(BlockExpr *block) { return true; }
2001
2002private:
2003 bool isRemovable(Expr *E) const {
2004 return Removables.count(E);
2005 }
2006
2007 bool isZeroingPropIvar(Expr *E) {
2008 BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
2009 if (!BOE) return false;
2010
2011 if (BOE->getOpcode() == BO_Comma)
2012 return isZeroingPropIvar(BOE->getLHS()) &&
2013 isZeroingPropIvar(BOE->getRHS());
2014
2015 if (BOE->getOpcode() != BO_Assign)
2016 return false;
2017
2018 ASTContext &Ctx = Pass.Ctx;
2019
2020 Expr *LHS = BOE->getLHS();
2021 if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
2022 ObjCIvarDecl *IVDecl = IV->getDecl();
2023 if (!IVDecl->getType()->isObjCObjectPointerType())
2024 return false;
2025 bool IvarBacksPropertySynthesis = false;
2026 for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
2027 P = SynthesizedProperties.begin(),
2028 E = SynthesizedProperties.end(); P != E; ++P) {
2029 ObjCPropertyImplDecl *PropImpDecl = P->second;
2030 if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {
2031 IvarBacksPropertySynthesis = true;
2032 break;
2033 }
2034 }
2035 if (!IvarBacksPropertySynthesis)
2036 return false;
2037 }
2038 else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
2039 // TODO: Using implicit property decl.
2040 if (PropRefExp->isImplicitProperty())
2041 return false;
2042 if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
2043 if (!SynthesizedProperties.count(PDecl))
2044 return false;
2045 }
2046 }
2047 else
2048 return false;
2049
2050 Expr *RHS = BOE->getRHS();
2051 bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
2052 Expr::NPC_ValueDependentIsNull);
2053 if (RHSIsNull)
2054 return true;
2055
2056 return isZeroingPropIvar(RHS);
2057 }
2058};
2059
2060} // anonymous namespace
2061
2062static void removeZeroOutIvarsInDealloc(MigrationPass &pass) {
2063 ZeroOutInDeallocRemover trans(pass);
2064 trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
2065}
2066
2067//===----------------------------------------------------------------------===//
2068// getAllTransformations.
2069//===----------------------------------------------------------------------===//
2070
2071static void independentTransforms(MigrationPass &pass) {
2072 rewriteAutoreleasePool(pass);
2073 changeIvarsOfAssignProperties(pass);
2074 removeRetainReleaseDealloc(pass);
2075 rewriteUnusedDelegateInit(pass);
2076 removeZeroOutIvarsInDealloc(pass);
2077 makeAssignARCSafe(pass);
2078 castNonObjCToObjC(pass);
2079 rewriteBlockObjCVariable(pass);
2080 rewriteAllocCopyWithZone(pass);
2081}
2082
2083std::vector<TransformFn> arcmt::getAllTransformations() {
2084 std::vector<TransformFn> transforms;
2085
2086 // This must come first since rewriteAutoreleasePool depends on -release
2087 // calls being present to determine the @autorelease ending scope.
2088 transforms.push_back(independentTransforms);
2089
2090 transforms.push_back(removeEmptyStatements);
2091 transforms.push_back(removeDeallocMethod);
2092
2093 return transforms;
2094}