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