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