]> granicus.if.org Git - clang/commitdiff
[arcmt] Break apart Transforms.cpp.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 21 Jun 2011 20:20:39 +0000 (20:20 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Tue, 21 Jun 2011 20:20:39 +0000 (20:20 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133539 91177308-0d34-0410-b5e6-96231b3b80d8

14 files changed:
lib/ARCMigrate/CMakeLists.txt
lib/ARCMigrate/TransARCAssign.cpp [new file with mode: 0644]
lib/ARCMigrate/TransAllocCopyWithZone.cpp [new file with mode: 0644]
lib/ARCMigrate/TransAutoreleasePool.cpp [new file with mode: 0644]
lib/ARCMigrate/TransBlockObjCVariable.cpp [new file with mode: 0644]
lib/ARCMigrate/TransDeallocMethod.cpp [new file with mode: 0644]
lib/ARCMigrate/TransEmptyStatements.cpp [new file with mode: 0644]
lib/ARCMigrate/TransProperties.cpp [new file with mode: 0644]
lib/ARCMigrate/TransRetainReleaseDealloc.cpp [new file with mode: 0644]
lib/ARCMigrate/TransUnbridgedCasts.cpp [new file with mode: 0644]
lib/ARCMigrate/TransUnusedInitDelegate.cpp [new file with mode: 0644]
lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp [new file with mode: 0644]
lib/ARCMigrate/Transforms.cpp
lib/ARCMigrate/Transforms.h [new file with mode: 0644]

index 0049d2ff37cc2aad95fb720d2cd3532cdfbebf3f..56db384bef2e1699b58d095c4c01d5295b08255f 100644 (file)
@@ -4,8 +4,19 @@ add_clang_library(clangARCMigrate
   ARCMT.cpp
   ARCMTActions.cpp
   FileRemapper.cpp
+  TransAllocCopyWithZone.cpp
+  TransARCAssign.cpp
+  TransAutoreleasePool.cpp
+  TransBlockObjCVariable.cpp
+  TransDeallocMethod.cpp
+  TransEmptyStatements.cpp
   TransformActions.cpp
   Transforms.cpp
+  TransProperties.cpp
+  TransRetainReleaseDealloc.cpp
+  TransUnbridgedCasts.cpp
+  TransUnusedInitDelegate.cpp
+  TransZeroOutPropsInDealloc.cpp
   )
 
 add_dependencies(clangARCMigrate
diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp
new file mode 100644 (file)
index 0000000..8c00df5
--- /dev/null
@@ -0,0 +1,75 @@
+//===--- TransARCAssign.cpp - Tranformations to ARC mode ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// makeAssignARCSafe:
+//
+// Add '__strong' where appropriate.
+//
+//  for (id x in collection) {
+//    x = 0;
+//  }
+// ---->
+//  for (__strong id x in collection) {
+//    x = 0;
+//  }
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> {
+  MigrationPass &Pass;
+  llvm::DenseSet<VarDecl *> ModifiedVars;
+
+public:
+  ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
+
+  bool VisitBinaryOperator(BinaryOperator *Exp) {
+    Expr *E = Exp->getLHS();
+    SourceLocation OrigLoc = E->getExprLoc();
+    SourceLocation Loc = OrigLoc;
+    DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
+    if (declRef && isa<VarDecl>(declRef->getDecl())) {
+      ASTContext &Ctx = Pass.Ctx;
+      Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
+      if (IsLV != Expr::MLV_ConstQualified)
+        return true;
+      VarDecl *var = cast<VarDecl>(declRef->getDecl());
+      if (var->isARCPseudoStrong()) {
+        Transaction Trans(Pass.TA);
+        if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration,
+                                    Exp->getOperatorLoc())) {
+          if (!ModifiedVars.count(var)) {
+            TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc();
+            Pass.TA.insert(TLoc.getBeginLoc(), "__strong ");
+            ModifiedVars.insert(var);
+          }
+        }
+      }
+    }
+    
+    return true;
+  }
+};
+
+} // anonymous namespace
+
+void trans::makeAssignARCSafe(MigrationPass &pass) {
+  ARCAssignChecker assignCheck(pass);
+  assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransAllocCopyWithZone.cpp b/lib/ARCMigrate/TransAllocCopyWithZone.cpp
new file mode 100644 (file)
index 0000000..da7f25d
--- /dev/null
@@ -0,0 +1,223 @@
+//===--- TransAllocCopyWithZone.cpp - Tranformations to ARC mode ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// rewriteAllocCopyWithZone:
+//
+// Calls to +allocWithZone/-copyWithZone/-mutableCopyWithZone are changed to
+// +alloc/-copy/-mutableCopy if we can safely remove the given parameter.
+//
+//  Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
+// ---->
+//  Foo *foo1 = [[Foo alloc] init];
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class AllocCopyWithZoneRewriter :
+                         public RecursiveASTVisitor<AllocCopyWithZoneRewriter> {
+  Decl *Dcl;
+  Stmt *Body;
+  MigrationPass &Pass;
+
+  Selector allocWithZoneSel;
+  Selector copyWithZoneSel;
+  Selector mutableCopyWithZoneSel;
+  Selector zoneSel;
+  IdentifierInfo *NSZoneII;
+
+  std::vector<DeclStmt *> NSZoneVars;
+  std::vector<Expr *> Removals;
+
+public:
+  AllocCopyWithZoneRewriter(Decl *D, MigrationPass &pass)
+    : Dcl(D), Body(0), Pass(pass) {
+    SelectorTable &sels = pass.Ctx.Selectors;
+    IdentifierTable &ids = pass.Ctx.Idents; 
+    allocWithZoneSel = sels.getUnarySelector(&ids.get("allocWithZone"));
+    copyWithZoneSel = sels.getUnarySelector(&ids.get("copyWithZone"));
+    mutableCopyWithZoneSel = sels.getUnarySelector(
+                                               &ids.get("mutableCopyWithZone"));
+    zoneSel = sels.getNullarySelector(&ids.get("zone"));
+    NSZoneII = &ids.get("_NSZone");
+  }
+
+  void transformBody(Stmt *body) {
+    Body = body;
+    // Don't change allocWithZone/copyWithZone messages inside
+    // custom implementations of such methods, it can lead to infinite loops.
+    if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Dcl)) {
+      Selector sel = MD->getSelector();
+      if (sel == allocWithZoneSel ||
+          sel == copyWithZoneSel ||
+          sel == mutableCopyWithZoneSel ||
+          sel == zoneSel)
+        return;
+    }
+
+    TraverseStmt(body);
+  }
+
+  ~AllocCopyWithZoneRewriter() {
+    for (std::vector<DeclStmt *>::reverse_iterator
+           I = NSZoneVars.rbegin(), E = NSZoneVars.rend(); I != E; ++I) {
+      DeclStmt *DS = *I;
+      DeclGroupRef group = DS->getDeclGroup();
+      std::vector<Expr *> varRemovals = Removals;
+
+      bool areAllVarsUnused = true;
+      for (std::reverse_iterator<DeclGroupRef::iterator>
+             DI(group.end()), DE(group.begin()); DI != DE; ++DI) {
+        VarDecl *VD = cast<VarDecl>(*DI);
+        if (isNSZoneVarUsed(VD, varRemovals)) {
+          areAllVarsUnused = false;
+          break;
+        }
+        varRemovals.push_back(VD->getInit());
+      }
+
+      if (areAllVarsUnused) {
+        Transaction Trans(Pass.TA);
+        clearUnavailableDiags(DS);
+        Pass.TA.removeStmt(DS);
+        Removals.swap(varRemovals);
+      }
+    }
+  }
+
+  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+    if (!isAllocCopyWithZoneCall(E))
+      return true;
+    Expr *arg = E->getArg(0);
+    if (paramToAllocWithZoneHasSideEffects(arg))
+      return true;
+
+    Pass.TA.startTransaction();
+
+    clearUnavailableDiags(arg);
+    Pass.TA.clearDiagnostic(diag::err_unavailable_message,
+                            E->getReceiverRange().getBegin());
+
+    Pass.TA.remove(SourceRange(E->getSelectorLoc(), arg->getLocEnd()));
+    StringRef rewrite;
+    if (E->getSelector() == allocWithZoneSel)
+      rewrite = "alloc";
+    else if (E->getSelector() == copyWithZoneSel)
+      rewrite = "copy";
+    else {
+      assert(E->getSelector() == mutableCopyWithZoneSel);
+      rewrite = "mutableCopy";
+    }
+    Pass.TA.insert(E->getSelectorLoc(), rewrite);
+
+    bool failed = Pass.TA.commitTransaction();
+    if (!failed)
+      Removals.push_back(arg);
+
+    return true;
+  }
+
+  bool VisitDeclStmt(DeclStmt *DS) {
+    DeclGroupRef group = DS->getDeclGroup();
+    if (group.begin() == group.end())
+      return true;
+    for (DeclGroupRef::iterator
+           DI = group.begin(), DE = group.end(); DI != DE; ++DI)
+      if (!isRemovableNSZoneVar(*DI))
+        return true;
+
+    NSZoneVars.push_back(DS);
+    return true;
+  }
+
+private:
+  bool isRemovableNSZoneVar(Decl *D) {
+    if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+      if (isNSZone(VD->getType()))
+        return !paramToAllocWithZoneHasSideEffects(VD->getInit());
+    }
+    return false;
+  }
+
+  bool isNSZone(RecordDecl *RD) {
+    return RD && RD->getIdentifier() == NSZoneII;
+  }
+
+  bool isNSZone(QualType Ty) {
+    QualType pointee = Ty->getPointeeType();
+    if (pointee.isNull())
+      return false;
+    if (const RecordType *recT = pointee->getAsStructureType())
+      return isNSZone(recT->getDecl());
+    return false;
+  }
+
+  bool isNSZoneVarUsed(VarDecl *D, std::vector<Expr *> &removals) {
+    ExprSet refs;
+    collectRefs(D, Body, refs);
+    clearRefsIn(removals.begin(), removals.end(), refs);
+
+    return !refs.empty();
+  }
+
+  bool isAllocCopyWithZoneCall(ObjCMessageExpr *E) {
+    if (E->getNumArgs() == 1 &&
+        E->getSelector() == allocWithZoneSel &&
+        (E->isClassMessage() ||
+         Pass.TA.hasDiagnostic(diag::err_unavailable_message,
+                               E->getReceiverRange().getBegin())))
+      return true;
+
+    return E->isInstanceMessage() &&
+           E->getNumArgs() == 1   &&
+           (E->getSelector() == copyWithZoneSel ||
+            E->getSelector() == mutableCopyWithZoneSel);
+  }
+
+  bool isZoneCall(ObjCMessageExpr *E) {
+    return E->isInstanceMessage() &&
+           E->getNumArgs() == 0   &&
+           E->getSelector() == zoneSel;
+  }
+
+  bool paramToAllocWithZoneHasSideEffects(Expr *E) {
+    if (!hasSideEffects(E, Pass.Ctx))
+      return false;
+    E = E->IgnoreParenCasts();
+    ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
+    if (!ME)
+      return true;
+    if (!isZoneCall(ME))
+      return true;
+    return hasSideEffects(ME->getInstanceReceiver(), Pass.Ctx);
+  }
+
+  void clearUnavailableDiags(Stmt *S) {
+    if (S)
+      Pass.TA.clearDiagnostic(diag::err_unavailable,
+                              diag::err_unavailable_message,
+                              S->getSourceRange());
+  }
+};
+
+} // end anonymous namespace
+
+void trans::rewriteAllocCopyWithZone(MigrationPass &pass) {
+  BodyTransform<AllocCopyWithZoneRewriter> trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
new file mode 100644 (file)
index 0000000..602ac0c
--- /dev/null
@@ -0,0 +1,437 @@
+//===--- TransAutoreleasePool.cpp - Tranformations to ARC mode ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// rewriteAutoreleasePool:
+//
+// Calls to NSAutoreleasePools will be rewritten as an @autorelease scope.
+//
+//  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+//  ...
+//  [pool release];
+// ---->
+//  @autorelease {
+//  ...
+//  }
+//
+// An NSAutoreleasePool will not be touched if:
+// - There is not a corresponding -release/-drain in the same scope
+// - Not all references of the NSAutoreleasePool variable can be removed
+// - There is a variable that is declared inside the intended @autorelease scope
+//   which is also used outside it.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include <map>
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
+  Decl *Dcl;
+  llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases;
+
+public:
+  ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases)
+    : Dcl(D), Releases(releases) { }
+
+  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+    if (!E->isInstanceMessage())
+      return true;
+    if (E->getMethodFamily() != OMF_release)
+      return true;
+    Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts();
+    if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
+      if (DE->getDecl() == Dcl)
+        Releases.push_back(E);
+    }
+    return true;
+  }
+};
+
+}
+
+namespace {
+
+class AutoreleasePoolRewriter
+                         : public RecursiveASTVisitor<AutoreleasePoolRewriter> {
+public:
+  AutoreleasePoolRewriter(Decl *D, MigrationPass &pass)
+    : Dcl(D), Body(0), Pass(pass) {
+    PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool");
+    DrainSel = pass.Ctx.Selectors.getNullarySelector(
+                                                 &pass.Ctx.Idents.get("drain"));
+  }
+
+  void transformBody(Stmt *body) {
+    Body = body;
+    TraverseStmt(body);
+  }
+  
+  ~AutoreleasePoolRewriter() {
+    llvm::SmallVector<VarDecl *, 8> VarsToHandle;
+
+    for (std::map<VarDecl *, PoolVarInfo>::iterator
+           I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
+      VarDecl *var = I->first;
+      PoolVarInfo &info = I->second;
+
+      // Check that we can handle/rewrite all references of the pool.
+
+      clearRefsIn(info.Dcl, info.Refs);
+      for (llvm::SmallVectorImpl<PoolScope>::iterator
+             scpI = info.Scopes.begin(),
+             scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
+        PoolScope &scope = *scpI;
+        clearRefsIn(*scope.Begin, info.Refs);
+        clearRefsIn(*scope.End, info.Refs);
+        clearRefsIn(scope.Releases.begin(), scope.Releases.end(), info.Refs);
+      }
+
+      // Even if one reference is not handled we will not do anything about that
+      // pool variable.
+      if (info.Refs.empty())
+        VarsToHandle.push_back(var);
+    }
+
+    for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) {
+      PoolVarInfo &info = PoolVars[VarsToHandle[i]];
+
+      Transaction Trans(Pass.TA);
+
+      clearUnavailableDiags(info.Dcl);
+      Pass.TA.removeStmt(info.Dcl);
+
+      // Add "@autoreleasepool { }"
+      for (llvm::SmallVectorImpl<PoolScope>::iterator
+             scpI = info.Scopes.begin(),
+             scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
+        PoolScope &scope = *scpI;
+        clearUnavailableDiags(*scope.Begin);
+        clearUnavailableDiags(*scope.End);
+        if (scope.IsFollowedBySimpleReturnStmt) {
+          // Include the return in the scope.
+          Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
+          Pass.TA.removeStmt(*scope.End);
+          Stmt::child_iterator retI = scope.End;
+          ++retI;
+          SourceLocation afterSemi = findLocationAfterSemi((*retI)->getLocEnd(),
+                                                           Pass.Ctx);
+          assert(afterSemi.isValid() &&
+                 "Didn't we check before setting IsFollowedBySimpleReturnStmt "
+                 "to true?");
+          Pass.TA.insertAfterToken(afterSemi, "\n}");
+          Pass.TA.increaseIndentation(
+                                SourceRange(scope.getIndentedRange().getBegin(),
+                                            (*retI)->getLocEnd()),
+                                      scope.CompoundParent->getLocStart());
+        } else {
+          Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
+          Pass.TA.replaceStmt(*scope.End, "}");
+          Pass.TA.increaseIndentation(scope.getIndentedRange(),
+                                      scope.CompoundParent->getLocStart());
+        }
+      }
+
+      // Remove rest of pool var references.
+      for (llvm::SmallVectorImpl<PoolScope>::iterator
+             scpI = info.Scopes.begin(),
+             scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
+        PoolScope &scope = *scpI;
+        for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator
+               relI = scope.Releases.begin(),
+               relE = scope.Releases.end(); relI != relE; ++relI) {
+          clearUnavailableDiags(*relI);
+          Pass.TA.removeStmt(*relI);
+        }
+      }
+    }
+  }
+
+  bool VisitCompoundStmt(CompoundStmt *S) {
+    llvm::SmallVector<PoolScope, 4> Scopes;
+
+    for (Stmt::child_iterator
+           I = S->body_begin(), E = S->body_end(); I != E; ++I) {
+      Stmt *child = getEssential(*I);
+      if (DeclStmt *DclS = dyn_cast<DeclStmt>(child)) {
+        if (DclS->isSingleDecl()) {
+          if (VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) {
+            if (isNSAutoreleasePool(VD->getType())) {
+              PoolVarInfo &info = PoolVars[VD];
+              info.Dcl = DclS;
+              collectRefs(VD, S, info.Refs);
+              // Does this statement follow the pattern:  
+              // NSAutoreleasePool * pool = [NSAutoreleasePool  new];
+              if (isPoolCreation(VD->getInit())) {
+                Scopes.push_back(PoolScope());
+                Scopes.back().PoolVar = VD;
+                Scopes.back().CompoundParent = S;
+                Scopes.back().Begin = I;
+              }
+            }
+          }
+        }
+      } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) {
+        if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
+          if (VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) {
+            // Does this statement follow the pattern:  
+            // pool = [NSAutoreleasePool  new];
+            if (isNSAutoreleasePool(VD->getType()) &&
+                isPoolCreation(bop->getRHS())) {
+              Scopes.push_back(PoolScope());
+              Scopes.back().PoolVar = VD;
+              Scopes.back().CompoundParent = S;
+              Scopes.back().Begin = I;
+            }
+          }
+        }
+      }
+
+      if (Scopes.empty())
+        continue;
+
+      if (isPoolDrain(Scopes.back().PoolVar, child)) {
+        PoolScope &scope = Scopes.back();
+        scope.End = I;
+        handlePoolScope(scope, S);
+        Scopes.pop_back();
+      }
+    }
+    return true;
+  }
+
+private:
+  void clearUnavailableDiags(Stmt *S) {
+    if (S)
+      Pass.TA.clearDiagnostic(diag::err_unavailable,
+                              diag::err_unavailable_message,
+                              S->getSourceRange());
+  }
+
+  struct PoolScope {
+    VarDecl *PoolVar;
+    CompoundStmt *CompoundParent;
+    Stmt::child_iterator Begin;
+    Stmt::child_iterator End;
+    bool IsFollowedBySimpleReturnStmt;
+    llvm::SmallVector<ObjCMessageExpr *, 4> Releases;
+
+    PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(),
+                  IsFollowedBySimpleReturnStmt(false) { }
+
+    SourceRange getIndentedRange() const {
+      Stmt::child_iterator rangeS = Begin;
+      ++rangeS;
+      if (rangeS == End)
+        return SourceRange();
+      Stmt::child_iterator rangeE = Begin;
+      for (Stmt::child_iterator I = rangeS; I != End; ++I)
+        ++rangeE;
+      return SourceRange((*rangeS)->getLocStart(), (*rangeE)->getLocEnd());
+    }
+  };
+
+  class NameReferenceChecker : public RecursiveASTVisitor<NameReferenceChecker>{
+    ASTContext &Ctx;
+    SourceRange ScopeRange;
+    SourceLocation &referenceLoc, &declarationLoc;
+
+  public:
+    NameReferenceChecker(ASTContext &ctx, PoolScope &scope,
+                         SourceLocation &referenceLoc,
+                         SourceLocation &declarationLoc)
+      : Ctx(ctx), referenceLoc(referenceLoc),
+        declarationLoc(declarationLoc) {
+      ScopeRange = SourceRange((*scope.Begin)->getLocStart(),
+                               (*scope.End)->getLocStart());
+    }
+
+    bool VisitDeclRefExpr(DeclRefExpr *E) {
+      return checkRef(E->getLocation(), E->getDecl()->getLocation());
+    }
+
+    bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+      return checkRef(E->getLocation(), E->getDecl()->getLocation());
+    }
+
+    bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+      return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation());
+    }
+
+    bool VisitTagTypeLoc(TagTypeLoc TL) {
+      return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation());
+    }
+
+  private:
+    bool checkRef(SourceLocation refLoc, SourceLocation declLoc) {
+      if (isInScope(declLoc)) {
+        referenceLoc = refLoc;
+        declarationLoc = declLoc;
+        return false;
+      }
+      return true;
+    }
+
+    bool isInScope(SourceLocation loc) {
+      SourceManager &SM = Ctx.getSourceManager();
+      if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
+        return false;
+      return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd());
+    }
+  };
+
+  void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) {
+    // Check that all names declared inside the scope are not used
+    // outside the scope.
+    {
+      bool nameUsedOutsideScope = false;
+      SourceLocation referenceLoc, declarationLoc;
+      Stmt::child_iterator SI = scope.End, SE = compoundS->body_end();
+      ++SI;
+      // Check if the autoreleasepool scope is followed by a simple return
+      // statement, in which case we will include the return in the scope.
+      if (SI != SE)
+        if (ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
+          if ((retS->getRetValue() == 0 ||
+               isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
+              findLocationAfterSemi(retS->getLocEnd(), Pass.Ctx).isValid()) {
+            scope.IsFollowedBySimpleReturnStmt = true;
+            ++SI; // the return will be included in scope, don't check it.
+          }
+      
+      for (; SI != SE; ++SI) {
+        nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
+                                                     referenceLoc,
+                                              declarationLoc).TraverseStmt(*SI);
+        if (nameUsedOutsideScope)
+          break;
+      }
+
+      // If not all references were cleared it means some variables/typenames/etc
+      // declared inside the pool scope are used outside of it.
+      // We won't try to rewrite the pool.
+      if (nameUsedOutsideScope) {
+        Pass.TA.reportError("a name is referenced outside the "
+            "NSAutoreleasePool scope that it was declared in", referenceLoc);
+        Pass.TA.reportNote("name declared here", declarationLoc);
+        Pass.TA.reportNote("intended @autoreleasepool scope begins here",
+                           (*scope.Begin)->getLocStart());
+        Pass.TA.reportNote("intended @autoreleasepool scope ends here",
+                           (*scope.End)->getLocStart());
+        return;
+      }
+    }
+
+    // Collect all releases of the pool; they will be removed.
+    {
+      ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
+      Stmt::child_iterator I = scope.Begin;
+      ++I;
+      for (; I != scope.End; ++I)
+        releaseColl.TraverseStmt(*I);
+    }
+
+    PoolVars[scope.PoolVar].Scopes.push_back(scope);
+  }
+
+  bool isPoolCreation(Expr *E) {
+    if (!E) return false;
+    E = getEssential(E);
+    ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
+    if (!ME) return false;
+    if (ME->getMethodFamily() == OMF_new &&
+        ME->getReceiverKind() == ObjCMessageExpr::Class &&
+        isNSAutoreleasePool(ME->getReceiverInterface()))
+      return true;
+    if (ME->getReceiverKind() == ObjCMessageExpr::Instance &&
+        ME->getMethodFamily() == OMF_init) {
+      Expr *rec = getEssential(ME->getInstanceReceiver());
+      if (ObjCMessageExpr *recME = dyn_cast_or_null<ObjCMessageExpr>(rec)) {
+        if (recME->getMethodFamily() == OMF_alloc &&
+            recME->getReceiverKind() == ObjCMessageExpr::Class &&
+            isNSAutoreleasePool(recME->getReceiverInterface()))
+          return true;
+      }
+    }
+
+    return false;
+  }
+
+  bool isPoolDrain(VarDecl *poolVar, Stmt *S) {
+    if (!S) return false;
+    S = getEssential(S);
+    ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
+    if (!ME) return false;
+    if (ME->getReceiverKind() == ObjCMessageExpr::Instance) {
+      Expr *rec = getEssential(ME->getInstanceReceiver());
+      if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
+        if (dref->getDecl() == poolVar)
+          return ME->getMethodFamily() == OMF_release ||
+                 ME->getSelector() == DrainSel;
+    }
+
+    return false;
+  }
+
+  bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) {
+    return IDecl && IDecl->getIdentifier() == PoolII;
+  }
+
+  bool isNSAutoreleasePool(QualType Ty) {
+    QualType pointee = Ty->getPointeeType();
+    if (pointee.isNull())
+      return false;
+    if (const ObjCInterfaceType *interT = pointee->getAs<ObjCInterfaceType>())
+      return isNSAutoreleasePool(interT->getDecl());
+    return false;
+  }
+
+  static Expr *getEssential(Expr *E) {
+    return cast<Expr>(getEssential((Stmt*)E));
+  }
+  static Stmt *getEssential(Stmt *S) {
+    if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
+      S = EWC->getSubExpr();
+    if (Expr *E = dyn_cast<Expr>(S))
+      S = E->IgnoreParenCasts();
+    return S;
+  }
+
+  Decl *Dcl;
+  Stmt *Body;
+  MigrationPass &Pass;
+
+  IdentifierInfo *PoolII;
+  Selector DrainSel;
+  
+  struct PoolVarInfo {
+    DeclStmt *Dcl;
+    ExprSet Refs;
+    llvm::SmallVector<PoolScope, 2> Scopes;
+
+    PoolVarInfo() : Dcl(0) { }
+  };
+
+  std::map<VarDecl *, PoolVarInfo> PoolVars;
+};
+
+} // anonymous namespace
+
+void trans::rewriteAutoreleasePool(MigrationPass &pass) {
+  BodyTransform<AutoreleasePoolRewriter> trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
new file mode 100644 (file)
index 0000000..ba55627
--- /dev/null
@@ -0,0 +1,143 @@
+//===--- TransBlockObjCVariable.cpp - Tranformations to ARC mode ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// rewriteBlockObjCVariable:
+//
+// Adding __block to an obj-c variable could be either because the the variable
+// is used for output storage or the user wanted to break a retain cycle.
+// This transformation checks whether a reference of the variable for the block
+// is actually needed (it is assigned to or its address is taken) or not.
+// If the reference is not needed it will assume __block was added to break a
+// cycle so it will remove '__block' and add __weak/__unsafe_unretained.
+// e.g
+//
+//   __block Foo *x;
+//   bar(^ { [x cake]; });
+// ---->
+//   __weak Foo *x;
+//   bar(^ { [x cake]; });
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class RootBlockObjCVarRewriter :
+                          public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
+  MigrationPass &Pass;
+  llvm::DenseSet<VarDecl *> CheckedVars;
+
+  class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
+    VarDecl *Var;
+  
+    typedef RecursiveASTVisitor<BlockVarChecker> base;
+  public:
+    BlockVarChecker(VarDecl *var) : Var(var) { }
+  
+    bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
+      if (BlockDeclRefExpr *
+            ref = dyn_cast<BlockDeclRefExpr>(castE->getSubExpr())) {
+        if (ref->getDecl() == Var) {
+          if (castE->getCastKind() == CK_LValueToRValue)
+            return true; // Using the value of the variable.
+          if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
+              Var->getASTContext().getLangOptions().CPlusPlus)
+            return true; // Binding to const C++ reference.
+        }
+      }
+
+      return base::TraverseImplicitCastExpr(castE);
+    }
+
+    bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+      if (E->getDecl() == Var)
+        return false; // The reference of the variable, and not just its value,
+                      //  is needed.
+      return true;
+    }
+  };
+
+public:
+  RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
+
+  bool VisitBlockDecl(BlockDecl *block) {
+    llvm::SmallVector<VarDecl *, 4> BlockVars;
+    
+    for (BlockDecl::capture_iterator
+           I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
+      VarDecl *var = I->getVariable();
+      if (I->isByRef() &&
+          !isAlreadyChecked(var) &&
+          var->getType()->isObjCObjectPointerType() &&
+          isImplicitStrong(var->getType())) {
+        BlockVars.push_back(var);
+      }
+    }
+
+    for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
+      VarDecl *var = BlockVars[i];
+      CheckedVars.insert(var);
+
+      BlockVarChecker checker(var);
+      bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
+      if (onlyValueOfVarIsNeeded) {
+        BlocksAttr *attr = var->getAttr<BlocksAttr>();
+        if(!attr)
+          continue;
+        bool hasARCRuntime = !Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime;
+        SourceManager &SM = Pass.Ctx.getSourceManager();
+        Transaction Trans(Pass.TA);
+        Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()),
+                            "__block",
+                            hasARCRuntime ? "__weak" : "__unsafe_unretained");
+      }
+
+    }
+
+    return true;
+  }
+
+private:
+  bool isAlreadyChecked(VarDecl *VD) {
+    return CheckedVars.count(VD);
+  }
+
+  bool isImplicitStrong(QualType ty) {
+    if (isa<AttributedType>(ty.getTypePtr()))
+      return false;
+    return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
+  }
+};
+
+class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
+  MigrationPass &Pass;
+
+public:
+  BlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
+
+  bool TraverseBlockDecl(BlockDecl *block) {
+    RootBlockObjCVarRewriter(Pass).TraverseDecl(block);
+    return true;
+  }
+};
+
+} // anonymous namespace
+
+void trans::rewriteBlockObjCVariable(MigrationPass &pass) {
+  BlockObjCVarRewriter trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransDeallocMethod.cpp b/lib/ARCMigrate/TransDeallocMethod.cpp
new file mode 100644 (file)
index 0000000..a7c3c1e
--- /dev/null
@@ -0,0 +1,47 @@
+//===--- TransDeallocMethod.cpp - Tranformations to ARC mode --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+void trans::removeDeallocMethod(MigrationPass &pass) {
+  ASTContext &Ctx = pass.Ctx;
+  TransformActions &TA = pass.TA;
+  DeclContext *DC = Ctx.getTranslationUnitDecl();
+  ObjCMethodDecl *DeallocMethodDecl = 0;
+  IdentifierInfo *II = &Ctx.Idents.get("dealloc");
+
+  for (DeclContext::decl_iterator
+         I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+    Decl *D = *I;
+    if (ObjCImplementationDecl *IMD = dyn_cast<ObjCImplementationDecl>(D)) {
+      DeallocMethodDecl = 0;
+      for (ObjCImplementationDecl::instmeth_iterator
+             I = IMD->instmeth_begin(), E = IMD->instmeth_end();
+          I != E; ++I) {
+        ObjCMethodDecl *OMD = *I;
+        if (OMD->isInstanceMethod() &&
+            OMD->getSelector() == Ctx.Selectors.getSelector(0, &II)) {
+          DeallocMethodDecl = OMD;
+          break;
+        }
+      }
+      if (DeallocMethodDecl && 
+          DeallocMethodDecl->getCompoundBody()->body_empty()) {
+        Transaction Trans(TA);
+        TA.remove(DeallocMethodDecl->getSourceRange());
+      }
+    }
+  }
+}
diff --git a/lib/ARCMigrate/TransEmptyStatements.cpp b/lib/ARCMigrate/TransEmptyStatements.cpp
new file mode 100644 (file)
index 0000000..1b62bbf
--- /dev/null
@@ -0,0 +1,161 @@
+//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// removeEmptyStatements:
+//
+// Removes empty statements that are leftovers from previous transformations.
+// e.g for
+//
+//  [x retain];
+//
+// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
+// will remove.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class EmptyStatementsRemover :
+                            public RecursiveASTVisitor<EmptyStatementsRemover> {
+  MigrationPass &Pass;
+  llvm::DenseSet<unsigned> MacroLocs;
+
+public:
+  EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) {
+    for (unsigned i = 0, e = Pass.ARCMTMacroLocs.size(); i != e; ++i)
+      MacroLocs.insert(Pass.ARCMTMacroLocs[i].getRawEncoding());
+  }
+
+  bool TraverseStmtExpr(StmtExpr *E) {
+    CompoundStmt *S = E->getSubStmt();
+    for (CompoundStmt::body_iterator
+           I = S->body_begin(), E = S->body_end(); I != E; ++I) {
+      if (I != E - 1)
+        check(*I);
+      TraverseStmt(*I);
+    }
+    return true;
+  }
+
+  bool VisitCompoundStmt(CompoundStmt *S) {
+    for (CompoundStmt::body_iterator
+           I = S->body_begin(), E = S->body_end(); I != E; ++I)
+      check(*I);
+    return true;
+  }
+
+  bool isMacroLoc(SourceLocation loc) {
+    if (loc.isInvalid()) return false;
+    return MacroLocs.count(loc.getRawEncoding());
+  }
+
+  ASTContext &getContext() { return Pass.Ctx; }
+
+private:
+  /// \brief Returns true if the statement became empty due to previous
+  /// transformations.
+  class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
+    EmptyStatementsRemover &Trans;
+
+  public:
+    EmptyChecker(EmptyStatementsRemover &trans) : Trans(trans) { }
+
+    bool VisitNullStmt(NullStmt *S) {
+      return Trans.isMacroLoc(S->getLeadingEmptyMacroLoc());
+    }
+    bool VisitCompoundStmt(CompoundStmt *S) {
+      if (S->body_empty())
+        return false; // was already empty, not because of transformations.
+      for (CompoundStmt::body_iterator
+             I = S->body_begin(), E = S->body_end(); I != E; ++I)
+        if (!Visit(*I))
+          return false;
+      return true;
+    }
+    bool VisitIfStmt(IfStmt *S) {
+      if (S->getConditionVariable())
+        return false;
+      Expr *condE = S->getCond();
+      if (!condE)
+        return false;
+      if (hasSideEffects(condE, Trans.getContext()))
+        return false;
+      if (!S->getThen() || !Visit(S->getThen()))
+        return false;
+      if (S->getElse() && !Visit(S->getElse()))
+        return false;
+      return true;
+    }
+    bool VisitWhileStmt(WhileStmt *S) {
+      if (S->getConditionVariable())
+        return false;
+      Expr *condE = S->getCond();
+      if (!condE)
+        return false;
+      if (hasSideEffects(condE, Trans.getContext()))
+        return false;
+      if (!S->getBody())
+        return false;
+      return Visit(S->getBody());
+    }
+    bool VisitDoStmt(DoStmt *S) {
+      Expr *condE = S->getCond();
+      if (!condE)
+        return false;
+      if (hasSideEffects(condE, Trans.getContext()))
+        return false;
+      if (!S->getBody())
+        return false;
+      return Visit(S->getBody());
+    }
+    bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
+      Expr *Exp = S->getCollection();
+      if (!Exp)
+        return false;
+      if (hasSideEffects(Exp, Trans.getContext()))
+        return false;
+      if (!S->getBody())
+        return false;
+      return Visit(S->getBody());
+    }
+    bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
+      if (!S->getSubStmt())
+        return false;
+      return Visit(S->getSubStmt());
+    }
+  };
+
+  void check(Stmt *S) {
+    if (!S) return;
+    if (EmptyChecker(*this).Visit(S)) {
+      Transaction Trans(Pass.TA);
+      Pass.TA.removeStmt(S);
+    }
+  }
+};
+
+} // anonymous namespace
+
+void trans::removeEmptyStatements(MigrationPass &pass) {
+  EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+
+  for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
+    Transaction Trans(pass.TA);
+    pass.TA.remove(pass.ARCMTMacroLocs[i]);
+  }
+}
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
new file mode 100644 (file)
index 0000000..2122e03
--- /dev/null
@@ -0,0 +1,260 @@
+//===--- TransProperties.cpp - Tranformations to ARC mode -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// changeIvarsOfAssignProperties:
+//
+// If a property is synthesized with 'assign' attribute and the user didn't
+// set a lifetime attribute, change the property to 'weak' or add
+// __unsafe_unretained if the ARC runtime is not available.
+//
+//  @interface Foo : NSObject {
+//      NSObject *x;
+//  }
+//  @property (assign) id x;
+//  @end
+// ---->
+//  @interface Foo : NSObject {
+//      NSObject *__weak x;
+//  }
+//  @property (weak) id x;
+//  @end
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class AssignPropertiesTrans {
+  MigrationPass &Pass;
+  struct PropData {
+    ObjCPropertyDecl *PropD;
+    ObjCIvarDecl *IvarD;
+    bool ShouldChangeToWeak;
+    SourceLocation ArcPropAssignErrorLoc;
+  };
+
+  typedef llvm::SmallVector<PropData, 2> PropsTy; 
+  typedef llvm::DenseMap<unsigned, PropsTy> PropsMapTy;
+  PropsMapTy PropsMap;
+
+public:
+  AssignPropertiesTrans(MigrationPass &pass) : Pass(pass) { }
+
+  void doTransform(ObjCImplementationDecl *D) {
+    SourceManager &SM = Pass.Ctx.getSourceManager();
+
+    ObjCInterfaceDecl *IFace = D->getClassInterface();
+    for (ObjCInterfaceDecl::prop_iterator
+           I = IFace->prop_begin(), E = IFace->prop_end(); I != E; ++I) {
+      ObjCPropertyDecl *propD = *I;
+      unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding();
+      PropsTy &props = PropsMap[loc];
+      props.push_back(PropData());
+      props.back().PropD = propD;
+      props.back().IvarD = 0;
+      props.back().ShouldChangeToWeak = false;
+    }
+
+    typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
+        prop_impl_iterator;
+    for (prop_impl_iterator
+           I = prop_impl_iterator(D->decls_begin()),
+           E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
+      VisitObjCPropertyImplDecl(*I);
+    }
+
+    for (PropsMapTy::iterator
+           I = PropsMap.begin(), E = PropsMap.end(); I != E; ++I) {
+      SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
+      PropsTy &props = I->second;
+      if (shouldApplyWeakToAllProp(props)) {
+        if (changeAssignToWeak(atLoc)) {
+          // Couldn't add the 'weak' property attribute,
+          // try adding __unsafe_unretained.
+          applyUnsafeUnretained(props);
+        } else {
+          for (PropsTy::iterator
+                 PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
+            applyWeak(*PI);
+          }
+        }
+      } else {
+        // We should not add 'weak' attribute since not all properties need it.
+        // So just add __unsafe_unretained to the ivars.
+        applyUnsafeUnretained(props);
+      }
+    }
+  }
+
+  bool shouldApplyWeakToAllProp(PropsTy &props) {
+    for (PropsTy::iterator
+           PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
+      if (!PI->ShouldChangeToWeak)
+        return false;
+    }
+    return true;
+  }
+
+  void applyWeak(PropData &prop) {
+    assert(!Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime);
+
+    Transaction Trans(Pass.TA);
+    Pass.TA.insert(prop.IvarD->getLocation(), "__weak "); 
+    Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime,
+                            prop.ArcPropAssignErrorLoc);
+  }
+
+  void applyUnsafeUnretained(PropsTy &props) {
+    for (PropsTy::iterator
+           PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
+      if (PI->ShouldChangeToWeak) {
+        Transaction Trans(Pass.TA);
+        Pass.TA.insert(PI->IvarD->getLocation(), "__unsafe_unretained ");
+        Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime,
+                                PI->ArcPropAssignErrorLoc);
+      }
+    }
+  }
+
+  bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+    SourceManager &SM = Pass.Ctx.getSourceManager();
+
+    if (D->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
+      return true;
+    ObjCPropertyDecl *propD = D->getPropertyDecl();
+    if (!propD || propD->isInvalidDecl())
+      return true;
+    ObjCIvarDecl *ivarD = D->getPropertyIvarDecl();
+    if (!ivarD || ivarD->isInvalidDecl())
+      return true;
+    if (!(propD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign))
+      return true;
+    if (isa<AttributedType>(ivarD->getType().getTypePtr()))
+      return true;
+    if (ivarD->getType().getLocalQualifiers().getObjCLifetime()
+          != Qualifiers::OCL_Strong)
+      return true;
+    if (!Pass.TA.hasDiagnostic(
+                      diag::err_arc_assign_property_lifetime, D->getLocation()))
+      return true;
+
+    // There is a "error: existing ivar for assign property must be
+    // __unsafe_unretained"; fix it.
+
+    if (Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime) {
+      // We will just add __unsafe_unretained to the ivar.
+      Transaction Trans(Pass.TA);
+      Pass.TA.insert(ivarD->getLocation(), "__unsafe_unretained ");
+      Pass.TA.clearDiagnostic(
+                      diag::err_arc_assign_property_lifetime, D->getLocation());
+    } else {
+      // Mark that we want the ivar to become weak.
+      unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding();
+      PropsTy &props = PropsMap[loc];
+      for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
+        if (I->PropD == propD) {
+          I->IvarD = ivarD;
+          I->ShouldChangeToWeak = true;
+          I->ArcPropAssignErrorLoc = D->getLocation();
+        }
+      }
+    }
+
+    return true;
+  }
+
+private:
+  bool changeAssignToWeak(SourceLocation atLoc) {
+    SourceManager &SM = Pass.Ctx.getSourceManager();
+
+    // Break down the source location.
+    std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
+
+    // Try to load the file buffer.
+    bool invalidTemp = false;
+    llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+    if (invalidTemp)
+      return true;
+
+    const char *tokenBegin = file.data() + locInfo.second;
+
+    // Lex from the start of the given location.
+    Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
+                Pass.Ctx.getLangOptions(),
+                file.begin(), tokenBegin, file.end());
+    Token tok;
+    lexer.LexFromRawLexer(tok);
+    if (tok.isNot(tok::at)) return true;
+    lexer.LexFromRawLexer(tok);
+    if (tok.isNot(tok::raw_identifier)) return true;
+    if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength())
+          != "property")
+      return true;
+    lexer.LexFromRawLexer(tok);
+    if (tok.isNot(tok::l_paren)) return true;
+    
+    SourceLocation LParen = tok.getLocation();
+    SourceLocation assignLoc;
+    bool isEmpty = false;
+
+    lexer.LexFromRawLexer(tok);
+    if (tok.is(tok::r_paren)) {
+      isEmpty = true;
+    } else {
+      while (1) {
+        if (tok.isNot(tok::raw_identifier)) return true;
+        llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength());
+        if (ident == "assign")
+          assignLoc = tok.getLocation();
+  
+        do {
+          lexer.LexFromRawLexer(tok);
+        } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
+        if (tok.is(tok::r_paren))
+          break;
+        lexer.LexFromRawLexer(tok);
+      }
+    }
+
+    Transaction Trans(Pass.TA);
+    if (assignLoc.isValid())
+      Pass.TA.replaceText(assignLoc, "assign", "weak");
+    else 
+      Pass.TA.insertAfterToken(LParen, isEmpty ? "weak" : "weak, ");
+    return false;
+  }
+};
+
+class PropertiesChecker : public RecursiveASTVisitor<PropertiesChecker> {
+  MigrationPass &Pass;
+
+public:
+  PropertiesChecker(MigrationPass &pass) : Pass(pass) { }
+
+  bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
+    AssignPropertiesTrans(Pass).doTransform(D);
+    return true;
+  }
+};
+
+} // anonymous namespace
+
+void trans::changeIvarsOfAssignProperties(MigrationPass &pass) {
+  PropertiesChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
new file mode 100644 (file)
index 0000000..f03ab5a
--- /dev/null
@@ -0,0 +1,142 @@
+//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// removeRetainReleaseDealloc:
+//
+// Removes retain/release/autorelease/dealloc messages.
+//
+//  return [[foo retain] autorelease];
+// ---->
+//  return foo;
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/ParentMap.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class RetainReleaseDeallocRemover :
+                       public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
+  Decl *Dcl;
+  Stmt *Body;
+  MigrationPass &Pass;
+
+  ExprSet Removables;
+  llvm::OwningPtr<ParentMap> StmtMap;
+
+public:
+  RetainReleaseDeallocRemover(Decl *D, MigrationPass &pass)
+    : Dcl(D), Body(0), Pass(pass) { }
+
+  void transformBody(Stmt *body) {
+    Body = body;
+    collectRemovables(body, Removables);
+    StmtMap.reset(new ParentMap(body));
+    TraverseStmt(body);
+  }
+
+  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+    switch (E->getMethodFamily()) {
+    default:
+      return true;
+    case OMF_retain:
+    case OMF_release:
+    case OMF_autorelease:
+      if (E->getReceiverKind() == ObjCMessageExpr::Instance)
+        if (Expr *rec = E->getInstanceReceiver()) {
+          rec = rec->IgnoreParenImpCasts();
+          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){
+            std::string err = "It is not safe to remove '";
+            err += E->getSelector().getAsString() + "' message on "
+                "an __unsafe_unretained type";
+            Pass.TA.reportError(err, rec->getLocStart());
+            return true;
+          }
+        }
+    case OMF_dealloc:
+      break;
+    }
+
+    switch (E->getReceiverKind()) {
+    default:
+      return true;
+    case ObjCMessageExpr::SuperInstance: {
+      Transaction Trans(Pass.TA);
+      Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
+                              diag::err_unavailable,
+                              diag::err_unavailable_message,
+                              E->getSuperLoc());
+      if (tryRemoving(E))
+        return true;
+      Pass.TA.replace(E->getSourceRange(), "self");
+      return true;
+    }
+    case ObjCMessageExpr::Instance:
+      break;
+    }
+
+    Expr *rec = E->getInstanceReceiver();
+    if (!rec) return true;
+
+    Transaction Trans(Pass.TA);
+    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
+                            diag::err_unavailable,
+                            diag::err_unavailable_message,
+                            rec->getExprLoc());
+    if (!hasSideEffects(E, Pass.Ctx)) {
+      if (tryRemoving(E))
+        return true;
+    }
+    Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
+
+    return true;
+  }
+
+private:
+  bool isRemovable(Expr *E) const {
+    return Removables.count(E);
+  }
+  
+  bool tryRemoving(Expr *E) const {
+    if (isRemovable(E)) {
+      Pass.TA.removeStmt(E);
+      return true;
+    }
+
+    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E)))
+      return tryRemoving(parenE);
+
+    if (BinaryOperator *
+          bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) {
+      if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
+          isRemovable(bopE)) {
+        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+};
+
+} // anonymous namespace
+
+void trans::removeRetainReleaseDealloc(MigrationPass &pass) {
+  BodyTransform<RetainReleaseDeallocRemover> trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
new file mode 100644 (file)
index 0000000..6513d98
--- /dev/null
@@ -0,0 +1,214 @@
+//===--- TransUnbridgedCasts.cpp - Tranformations to ARC mode -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// rewriteUnbridgedCasts:
+//
+// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
+// is from a file-level variable, __bridge cast is used to convert it.
+// For the result of a function call that we know is +1/+0,
+// __bridge/__bridge_transfer is used.
+//
+//  NSString *str = (NSString *)kUTTypePlainText;
+//  str = b ? kUTTypeRTF : kUTTypePlainText;
+//  NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault,
+//                                                         _uuid);
+// ---->
+//  NSString *str = (__bridge NSString *)kUTTypePlainText;
+//  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+// NSString *_uuidString = (__bridge_transfer NSString *)
+//                               CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+//
+// For a C pointer to ObjC, for casting 'self', __bridge is used.
+//
+//  CFStringRef str = (CFStringRef)self;
+// ---->
+//  CFStringRef str = (__bridge CFStringRef)self;
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
+  MigrationPass &Pass;
+  IdentifierInfo *SelfII;
+public:
+  UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass) {
+    SelfII = &Pass.Ctx.Idents.get("self");
+  }
+
+  bool VisitCastExpr(CastExpr *E) {
+    if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
+        && E->getCastKind() != CK_BitCast)
+      return true;
+
+    QualType castType = E->getType();
+    Expr *castExpr = E->getSubExpr();
+    QualType castExprType = castExpr->getType();
+
+    if (castType->isObjCObjectPointerType() &&
+        castExprType->isObjCObjectPointerType())
+      return true;
+    if (!castType->isObjCObjectPointerType() &&
+        !castExprType->isObjCObjectPointerType())
+      return true;
+    
+    bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
+    bool castRetainable = castType->isObjCIndirectLifetimeType();
+    if (exprRetainable == castRetainable) return true;
+
+    if (castExpr->isNullPointerConstant(Pass.Ctx,
+                                        Expr::NPC_ValueDependentIsNull))
+      return true;
+
+    SourceLocation loc = castExpr->getExprLoc();
+    if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
+      return true;
+
+    if (castType->isObjCObjectPointerType())
+      transformNonObjCToObjCCast(E);
+    else
+      transformObjCToNonObjCCast(E);
+
+    return true;
+  }
+
+private:
+  void transformNonObjCToObjCCast(CastExpr *E) {
+    if (!E) return;
+
+    // Global vars are assumed that are cast as unretained.
+    if (isGlobalVar(E))
+      if (E->getSubExpr()->getType()->isPointerType()) {
+        castToObjCObject(E, /*retained=*/false);
+        return;
+      }
+
+    // If the cast is directly over the result of a Core Foundation function
+    // try to figure out whether it should be cast as retained or unretained.
+    Expr *inner = E->IgnoreParenCasts();
+    if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
+      if (FunctionDecl *FD = callE->getDirectCallee()) {
+        if (FD->getAttr<CFReturnsRetainedAttr>()) {
+          castToObjCObject(E, /*retained=*/true);
+          return;
+        }
+        if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
+          castToObjCObject(E, /*retained=*/false);
+          return;
+        }
+        if (FD->isGlobal() &&
+            FD->getIdentifier() &&
+            ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
+                                   FD->getIdentifier()->getName())) {
+          StringRef fname = FD->getIdentifier()->getName();
+          if (fname.endswith("Retain") ||
+              fname.find("Create") != StringRef::npos ||
+              fname.find("Copy") != StringRef::npos) {
+            castToObjCObject(E, /*retained=*/true);
+            return;
+          }
+
+          if (fname.find("Get") != StringRef::npos) {
+            castToObjCObject(E, /*retained=*/false);
+            return;
+          }
+        }
+      }
+    }
+  }
+
+  void castToObjCObject(CastExpr *E, bool retained) {
+    rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
+  }
+
+  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
+    TransformActions &TA = Pass.TA;
+
+    // We will remove the compiler diagnostic.
+    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
+                          diag::err_arc_cast_requires_bridge,
+                          E->getLocStart()))
+      return;
+
+    StringRef bridge;
+    switch(Kind) {
+    case OBC_Bridge:
+      bridge = "__bridge "; break;
+    case OBC_BridgeTransfer:
+      bridge = "__bridge_transfer "; break;
+    case OBC_BridgeRetained:
+      bridge = "__bridge_retained "; break;
+    }
+
+    Transaction Trans(TA);
+    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+                       diag::err_arc_cast_requires_bridge,
+                       E->getLocStart());
+    if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
+      TA.insertAfterToken(CCE->getLParenLoc(), bridge);
+    } else {
+      SourceLocation insertLoc = E->getSubExpr()->getLocStart();
+      llvm::SmallString<128> newCast;
+      newCast += '(';
+      newCast += bridge;
+      newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
+      newCast += ')';
+
+      if (isa<ParenExpr>(E->getSubExpr())) {
+        TA.insert(insertLoc, newCast.str());
+      } else {
+        newCast += '(';
+        TA.insert(insertLoc, newCast.str());
+        TA.insertAfterToken(E->getLocEnd(), ")");
+      }
+    }
+  }
+
+  void transformObjCToNonObjCCast(CastExpr *E) {
+    if (isSelf(E->getSubExpr()))
+      return rewriteToBridgedCast(E, OBC_Bridge);
+  }
+
+  bool isSelf(Expr *E) {
+    E = E->IgnoreParenLValueCasts();
+    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+      if (DRE->getDecl()->getIdentifier() == SelfII)
+        return true;
+    return false;
+  }
+
+  static bool isGlobalVar(Expr *E) {
+    E = E->IgnoreParenCasts();
+    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+      return DRE->getDecl()->getDeclContext()->isFileContext();
+    if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
+      return isGlobalVar(condOp->getTrueExpr()) &&
+             isGlobalVar(condOp->getFalseExpr());
+
+    return false;  
+  }
+};
+
+} // end anonymous namespace
+
+void trans::rewriteUnbridgedCasts(MigrationPass &pass) {
+  UnbridgedCastRewriter trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
new file mode 100644 (file)
index 0000000..2fa18a3
--- /dev/null
@@ -0,0 +1,75 @@
+//===--- TransUnusedInitDelegate.cpp - Tranformations to ARC mode ---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Transformations:
+//===----------------------------------------------------------------------===//
+//
+// rewriteUnusedInitDelegate:
+//
+// Rewrites an unused result of calling a delegate initialization, to assigning
+// the result to self.
+// e.g
+//  [self init];
+// ---->
+//  self = [self init];
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class UnusedInitRewriter : public RecursiveASTVisitor<UnusedInitRewriter> {
+  Decl *Dcl;
+  Stmt *Body;
+  MigrationPass &Pass;
+
+  ExprSet Removables;
+
+public:
+  UnusedInitRewriter(Decl *D, MigrationPass &pass)
+    : Dcl(D), Body(0), Pass(pass) { }
+
+  void transformBody(Stmt *body) {
+    Body = body;
+    collectRemovables(body, Removables);
+    TraverseStmt(body);
+  }
+
+  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+    if (ME->isDelegateInitCall() &&
+        isRemovable(ME) &&
+        Pass.TA.hasDiagnostic(diag::err_arc_unused_init_message,
+                              ME->getExprLoc())) {
+      Transaction Trans(Pass.TA);
+      Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message,
+                              ME->getExprLoc());
+      Pass.TA.insert(ME->getExprLoc(), "self = ");
+    }
+    return true;
+  }
+
+private:
+  bool isRemovable(Expr *E) const {
+    return Removables.count(E);
+  }
+};
+
+} // anonymous namespace
+
+void trans::rewriteUnusedInitDelegate(MigrationPass &pass) {
+  BodyTransform<UnusedInitRewriter> trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
new file mode 100644 (file)
index 0000000..07ccf70
--- /dev/null
@@ -0,0 +1,198 @@
+//===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// removeZeroOutPropsInDealloc:
+//
+// Removes zero'ing out "strong" @synthesized properties in a -dealloc method.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+using llvm::StringRef;
+
+namespace {
+
+class ZeroOutInDeallocRemover :
+                           public RecursiveASTVisitor<ZeroOutInDeallocRemover> {
+  typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base;
+
+  MigrationPass &Pass;
+
+  llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;
+  ImplicitParamDecl *SelfD;
+  ExprSet Removables;
+
+public:
+  ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { }
+
+  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+    ASTContext &Ctx = Pass.Ctx;
+    TransformActions &TA = Pass.TA;
+
+    if (ME->getReceiverKind() != ObjCMessageExpr::Instance)
+      return true;
+    Expr *receiver = ME->getInstanceReceiver();
+    if (!receiver)
+      return true;
+
+    DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());
+    if (!refE || refE->getDecl() != SelfD)
+      return true;
+
+    bool BackedBySynthesizeSetter = false;
+    for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
+         P = SynthesizedProperties.begin(), 
+         E = SynthesizedProperties.end(); P != E; ++P) {
+      ObjCPropertyDecl *PropDecl = P->first;
+      if (PropDecl->getSetterName() == ME->getSelector()) {
+        BackedBySynthesizeSetter = true;
+        break;
+      }
+    }
+    if (!BackedBySynthesizeSetter)
+      return true;
+    
+    // Remove the setter message if RHS is null
+    Transaction Trans(TA);
+    Expr *RHS = ME->getArg(0);
+    bool RHSIsNull = 
+      RHS->isNullPointerConstant(Ctx,
+                                 Expr::NPC_ValueDependentIsNull);
+    if (RHSIsNull && isRemovable(ME))
+      TA.removeStmt(ME);
+
+    return true;
+  }
+
+  bool VisitBinaryOperator(BinaryOperator *BOE) {
+    if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
+      Transaction Trans(Pass.TA);
+      Pass.TA.removeStmt(BOE);
+    }
+
+    return true;
+  }
+
+  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
+    if (D->getMethodFamily() != OMF_dealloc)
+      return true;
+    if (!D->hasBody())
+      return true;
+
+    ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());
+    if (!IMD)
+      return true;
+
+    SelfD = D->getSelfDecl();
+    collectRemovables(D->getBody(), Removables);
+
+    // For a 'dealloc' method use, find all property implementations in
+    // this class implementation.
+    for (ObjCImplDecl::propimpl_iterator
+           I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) {
+        ObjCPropertyImplDecl *PID = *I;
+        if (PID->getPropertyImplementation() ==
+            ObjCPropertyImplDecl::Synthesize) {
+          ObjCPropertyDecl *PD = PID->getPropertyDecl();
+          ObjCMethodDecl *setterM = PD->getSetterMethodDecl();
+          if (!(setterM && setterM->isDefined())) {
+            ObjCPropertyDecl::PropertyAttributeKind AttrKind = 
+              PD->getPropertyAttributes();
+              if (AttrKind & 
+                  (ObjCPropertyDecl::OBJC_PR_retain | 
+                   ObjCPropertyDecl::OBJC_PR_copy   |
+                   ObjCPropertyDecl::OBJC_PR_strong))
+                SynthesizedProperties[PD] = PID;
+          }
+        }
+    }
+
+    // Now, remove all zeroing of ivars etc.
+    base::TraverseObjCMethodDecl(D);
+
+    // clear out for next method.
+    SynthesizedProperties.clear();
+    SelfD = 0;
+    Removables.clear();
+    return true;
+  }
+
+  bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
+  bool TraverseBlockDecl(BlockDecl *block) { return true; }
+  bool TraverseBlockExpr(BlockExpr *block) { return true; }
+
+private:
+  bool isRemovable(Expr *E) const {
+    return Removables.count(E);
+  }
+
+  bool isZeroingPropIvar(Expr *E) {
+    BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
+    if (!BOE) return false;
+
+    if (BOE->getOpcode() == BO_Comma)
+      return isZeroingPropIvar(BOE->getLHS()) &&
+             isZeroingPropIvar(BOE->getRHS());
+
+    if (BOE->getOpcode() != BO_Assign)
+        return false;
+
+    ASTContext &Ctx = Pass.Ctx;
+
+    Expr *LHS = BOE->getLHS();
+    if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
+      ObjCIvarDecl *IVDecl = IV->getDecl();
+      if (!IVDecl->getType()->isObjCObjectPointerType())
+        return false;
+      bool IvarBacksPropertySynthesis = false;
+      for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
+           P = SynthesizedProperties.begin(), 
+           E = SynthesizedProperties.end(); P != E; ++P) {
+        ObjCPropertyImplDecl *PropImpDecl = P->second;
+        if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {
+          IvarBacksPropertySynthesis = true;
+          break;
+        }
+      }
+      if (!IvarBacksPropertySynthesis)
+        return false;
+    }
+    else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
+      // TODO: Using implicit property decl.
+      if (PropRefExp->isImplicitProperty())
+        return false;
+      if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
+        if (!SynthesizedProperties.count(PDecl))
+          return false;
+      }
+    }
+    else
+        return false;
+
+    Expr *RHS = BOE->getRHS();
+    bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
+                                                Expr::NPC_ValueDependentIsNull);
+    if (RHSIsNull)
+      return true;
+
+    return isZeroingPropIvar(RHS);
+  }
+};
+
+} // anonymous namespace
+
+void trans::removeZeroOutPropsInDealloc(MigrationPass &pass) {
+  ZeroOutInDeallocRemover trans(pass);
+  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
index 499c8f034c7984da3257a0f7c2e9b3fd064a55a8..0650e3b94fbc8aaeb7189abc8f1566fd92ff9cfd 100644 (file)
@@ -6,151 +6,8 @@
 // License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
-// Transformations:
-//===----------------------------------------------------------------------===//
-//
-// castNonObjCToObjC:
-//
-// A cast of non-objc pointer to an objc one is checked. If the non-objc pointer
-// is from a file-level variable, objc_unretainedObject function is used to
-// convert it.
-//
-//  NSString *str = (NSString *)kUTTypePlainText;
-//  str = b ? kUTTypeRTF : kUTTypePlainText;
-// ---->
-//  NSString *str = objc_unretainedObject(kUTTypePlainText);
-//  str = objc_unretainedObject(b ? kUTTypeRTF : kUTTypePlainText);
-//
-// For a C pointer to ObjC, objc_unretainedPointer is used.
-//
-//  void *vp = str; // NSString*
-// ---->
-//  void *vp = (void*)objc_unretainedPointer(str);
-//
-//===----------------------------------------------------------------------===//
-//
-// rewriteAllocCopyWithZone:
-//
-// Calls to +allocWithZone/-copyWithZone/-mutableCopyWithZone are changed to
-// +alloc/-copy/-mutableCopy if we can safely remove the given parameter.
-//
-//  Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
-// ---->
-//  Foo *foo1 = [[Foo alloc] init];
-//
-//===----------------------------------------------------------------------===//
-//
-// rewriteAutoreleasePool:
-//
-// Calls to NSAutoreleasePools will be rewritten as an @autorelease scope.
-//
-//  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-//  ...
-//  [pool release];
-// ---->
-//  @autorelease {
-//  ...
-//  }
-//
-// An NSAutoreleasePool will not be touched if:
-// - There is not a corresponding -release/-drain in the same scope
-// - Not all references of the NSAutoreleasePool variable can be removed
-// - There is a variable that is declared inside the intended @autorelease scope
-//   which is also used outside it.
-//
-//===----------------------------------------------------------------------===//
-//
-// makeAssignARCSafe:
-//
-// Add '__strong' where appropriate.
-//
-//  for (id x in collection) {
-//    x = 0;
-//  }
-// ---->
-//  for (__strong id x in collection) {
-//    x = 0;
-//  }
-//
-//===----------------------------------------------------------------------===//
-//
-// removeRetainReleaseDealloc:
-//
-// Removes retain/release/autorelease/dealloc messages.
-//
-//  return [[foo retain] autorelease];
-// ---->
-//  return foo;
-//
-//===----------------------------------------------------------------------===//
-//
-// removeEmptyStatements:
-//
-// Removes empty statements that are leftovers from previous transformations.
-// e.g for
-//
-//  [x retain];
-//
-// removeRetainReleaseDealloc will leave an empty ";" that removeEmptyStatements
-// will remove.
-//
-//===----------------------------------------------------------------------===//
-//
-// changeIvarsOfAssignProperties:
-//
-// If a property is synthesized with 'assign' attribute and the user didn't
-// set a lifetime attribute, change the property to 'weak' or add
-// __unsafe_unretained if the ARC runtime is not available.
-//
-//  @interface Foo : NSObject {
-//      NSObject *x;
-//  }
-//  @property (assign) id x;
-//  @end
-// ---->
-//  @interface Foo : NSObject {
-//      NSObject *__weak x;
-//  }
-//  @property (weak) id x;
-//  @end
-//
-//===----------------------------------------------------------------------===//
-//
-// rewriteUnusedDelegateInit:
-//
-// Rewrites an unused result of calling a delegate initialization, to assigning
-// the result to self.
-// e.g
-//  [self init];
-// ---->
-//  self = [self init];
-//
-//===----------------------------------------------------------------------===//
-//
-// rewriteBlockObjCVariable:
-//
-// Adding __block to an obj-c variable could be either because the the variable
-// is used for output storage or the user wanted to break a retain cycle.
-// This transformation checks whether a reference of the variable for the block
-// is actually needed (it is assigned to or its address is taken) or not.
-// If the reference is not needed it will assume __block was added to break a
-// cycle so it will remove '__block' and add __weak/__unsafe_unretained.
-// e.g
-//
-//   __block Foo *x;
-//   bar(^ { [x cake]; });
-// ---->
-//   __weak Foo *x;
-//   bar(^ { [x cake]; });
-//
-//===----------------------------------------------------------------------===//
-//
-// removeZeroOutIvarsInDealloc:
-//
-// Removes zero'ing out "strong" @synthesized properties in a -dealloc method.
-//
-//===----------------------------------------------------------------------===//
 
+#include "Transforms.h"
 #include "Internals.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 
 using namespace clang;
 using namespace arcmt;
+using namespace trans;
 using llvm::StringRef;
 
 //===----------------------------------------------------------------------===//
-// Transformations.
+// Helpers.
 //===----------------------------------------------------------------------===//
 
-namespace {
+/// \brief 'Loc' is the end of a statement range. This returns the location
+/// immediately after the semicolon following the statement.
+/// If no semicolon is found or the location is inside a macro, the returned
+/// source location will be invalid.
+SourceLocation trans::findLocationAfterSemi(SourceLocation loc,
+                                            ASTContext &Ctx) {
+  SourceManager &SM = Ctx.getSourceManager();
+  if (loc.isMacroID()) {
+    if (!SM.isAtEndOfMacroInstantiation(loc))
+      return SourceLocation();
+    loc = SM.getInstantiationRange(loc).second;
+  }
+  loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
 
-class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
-  llvm::DenseSet<Expr *> &Removables;
+  // Break down the source location.
+  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
 
-public:
-  RemovablesCollector(llvm::DenseSet<Expr *> &removables)
-  : Removables(removables) { }
-  
-  bool shouldWalkTypesOfTypeLocs() const { return false; }
-  
-  bool TraverseStmtExpr(StmtExpr *E) {
-    CompoundStmt *S = E->getSubStmt();
-    for (CompoundStmt::body_iterator
-        I = S->body_begin(), E = S->body_end(); I != E; ++I) {
-      if (I != E - 1)
-        mark(*I);
-      TraverseStmt(*I);
-    }
-    return true;
-  }
-  
-  bool VisitCompoundStmt(CompoundStmt *S) {
-    for (CompoundStmt::body_iterator
-        I = S->body_begin(), E = S->body_end(); I != E; ++I)
-      mark(*I);
-    return true;
-  }
-  
-  bool VisitIfStmt(IfStmt *S) {
-    mark(S->getThen());
-    mark(S->getElse());
-    return true;
-  }
-  
-  bool VisitWhileStmt(WhileStmt *S) {
-    mark(S->getBody());
-    return true;
-  }
-  
-  bool VisitDoStmt(DoStmt *S) {
-    mark(S->getBody());
-    return true;
-  }
-  
-  bool VisitForStmt(ForStmt *S) {
-    mark(S->getInit());
-    mark(S->getInc());
-    mark(S->getBody());
-    return true;
-  }
-  
-private:
-  void mark(Stmt *S) {
-    if (!S) return;
-    
-    if (LabelStmt *Label = dyn_cast<LabelStmt>(S))
-      return mark(Label->getSubStmt());
-    if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(S))
-      return mark(CE->getSubExpr());
-    if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
-      return mark(EWC->getSubExpr());
-    if (Expr *E = dyn_cast<Expr>(S))
-      Removables.insert(E);
-  }
-};
+  // Try to load the file buffer.
+  bool invalidTemp = false;
+  llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
+  if (invalidTemp)
+    return SourceLocation();
+
+  const char *tokenBegin = file.data() + locInfo.second;
+
+  // Lex from the start of the given location.
+  Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
+              Ctx.getLangOptions(),
+              file.begin(), tokenBegin, file.end());
+  Token tok;
+  lexer.LexFromRawLexer(tok);
+  if (tok.isNot(tok::semi))
+    return SourceLocation();
 
-} // end anonymous namespace.
+  return tok.getLocation().getFileLocWithOffset(1);
+}
 
-static bool HasSideEffects(Expr *E, ASTContext &Ctx) {
+bool trans::hasSideEffects(Expr *E, ASTContext &Ctx) {
   if (!E || !E->HasSideEffects(Ctx))
     return false;
 
@@ -257,7 +83,7 @@ static bool HasSideEffects(Expr *E, ASTContext &Ctx) {
     case ObjCMessageExpr::SuperInstance:
       return false;
     case ObjCMessageExpr::Instance:
-      return HasSideEffects(ME->getInstanceReceiver(), Ctx);
+      return hasSideEffects(ME->getInstanceReceiver(), Ctx);
     default:
       break;
     }
@@ -269,66 +95,23 @@ static bool HasSideEffects(Expr *E, ASTContext &Ctx) {
   return true;
 }
 
-static void removeDeallocMethod(MigrationPass &pass) {
-    ASTContext &Ctx = pass.Ctx;
-    TransformActions &TA = pass.TA;
-    DeclContext *DC = Ctx.getTranslationUnitDecl();
-    ObjCMethodDecl *DeallocMethodDecl = 0;
-    IdentifierInfo *II = &Ctx.Idents.get("dealloc");
-    
-    for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
-         I != E; ++I) {
-        Decl *D = *I;
-        if (ObjCImplementationDecl *IMD = 
-            dyn_cast<ObjCImplementationDecl>(D)) {
-            DeallocMethodDecl = 0;
-            for (ObjCImplementationDecl::instmeth_iterator I = 
-                 IMD->instmeth_begin(), E = IMD->instmeth_end();
-                 I != E; ++I) {
-                ObjCMethodDecl *OMD = *I;
-                if (OMD->isInstanceMethod() &&
-                    OMD->getSelector() == Ctx.Selectors.getSelector(0, &II)) {
-                    DeallocMethodDecl = OMD;
-                    break;
-                }
-            }
-            if (DeallocMethodDecl && 
-                DeallocMethodDecl->getCompoundBody()->body_empty()) {
-              Transaction Trans(TA);
-              TA.remove(DeallocMethodDecl->getSourceRange());
-            }
-        }
-    }
-}
-
 namespace {
 
 class ReferenceClear : public RecursiveASTVisitor<ReferenceClear> {
-  llvm::DenseSet<Expr *> &Refs;
+  ExprSet &Refs;
 public:
-  ReferenceClear(llvm::DenseSet<Expr *> &refs) : Refs(refs) { }
+  ReferenceClear(ExprSet &refs) : Refs(refs) { }
   bool VisitDeclRefExpr(DeclRefExpr *E) { Refs.erase(E); return true; }
   bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Refs.erase(E); return true; }
-  void clearRefsIn(Stmt *S) { TraverseStmt(S); }
-  template <typename iterator>
-  void clearRefsIn(iterator begin, iterator end) {
-    for (; begin != end; ++begin)
-      TraverseStmt(*begin);
-  }
 };
 
 class ReferenceCollector : public RecursiveASTVisitor<ReferenceCollector> {
   ValueDecl *Dcl;
-  llvm::DenseSet<Expr *> &Refs;
+  ExprSet &Refs;
 
 public:
-  ReferenceCollector(llvm::DenseSet<Expr *> &refs)
-    : Dcl(0), Refs(refs) { }
-
-  void lookFor(ValueDecl *D, Stmt *S) {
-    Dcl = D;
-    TraverseStmt(S);
-  }
+  ReferenceCollector(ValueDecl *D, ExprSet &refs)
+    : Dcl(D), Refs(refs) { }
 
   bool VisitDeclRefExpr(DeclRefExpr *E) {
     if (E->getDecl() == Dcl)
@@ -343,1718 +126,83 @@ public:
   }
 };
 
-class ReleaseCollector : public RecursiveASTVisitor<ReleaseCollector> {
-  Decl *Dcl;
-  llvm::SmallVectorImpl<ObjCMessageExpr *> &Releases;
+class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
+  ExprSet &Removables;
 
 public:
-  ReleaseCollector(Decl *D, llvm::SmallVectorImpl<ObjCMessageExpr *> &releases)
-    : Dcl(D), Releases(releases) { }
-
-  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
-    if (!E->isInstanceMessage())
-      return true;
-    if (E->getMethodFamily() != OMF_release)
-      return true;
-    Expr *instance = E->getInstanceReceiver()->IgnoreParenCasts();
-    if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(instance)) {
-      if (DE->getDecl() == Dcl)
-        Releases.push_back(E);
+  RemovablesCollector(ExprSet &removables)
+  : Removables(removables) { }
+  
+  bool shouldWalkTypesOfTypeLocs() const { return false; }
+  
+  bool TraverseStmtExpr(StmtExpr *E) {
+    CompoundStmt *S = E->getSubStmt();
+    for (CompoundStmt::body_iterator
+        I = S->body_begin(), E = S->body_end(); I != E; ++I) {
+      if (I != E - 1)
+        mark(*I);
+      TraverseStmt(*I);
     }
     return true;
   }
-};
-
-template <typename BODY_TRANS>
-class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
-  MigrationPass &Pass;
-
-public:
-  BodyTransform(MigrationPass &pass) : Pass(pass) { }
-
-  void handleBody(Decl *D) {
-    Stmt *body = D->getBody();
-    if (body) {
-      BODY_TRANS(D, Pass).transformBody(body);
-    }
-  }
-
-  bool TraverseBlockDecl(BlockDecl *D) {
-    handleBody(D);
+  
+  bool VisitCompoundStmt(CompoundStmt *S) {
+    for (CompoundStmt::body_iterator
+        I = S->body_begin(), E = S->body_end(); I != E; ++I)
+      mark(*I);
     return true;
   }
-  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
-    if (D->isThisDeclarationADefinition())
-      handleBody(D);
+  
+  bool VisitIfStmt(IfStmt *S) {
+    mark(S->getThen());
+    mark(S->getElse());
     return true;
   }
-  bool TraverseFunctionDecl(FunctionDecl *D) {
-    if (D->isThisDeclarationADefinition())
-      handleBody(D);
+  
+  bool VisitWhileStmt(WhileStmt *S) {
+    mark(S->getBody());
     return true;
   }
-};
-
-} // anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// makeAssignARCSafe
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class ARCAssignChecker : public RecursiveASTVisitor<ARCAssignChecker> {
-  MigrationPass &Pass;
-  llvm::DenseSet<VarDecl *> ModifiedVars;
-
-public:
-  ARCAssignChecker(MigrationPass &pass) : Pass(pass) { }
-
-  bool VisitBinaryOperator(BinaryOperator *Exp) {
-    Expr *E = Exp->getLHS();
-    SourceLocation OrigLoc = E->getExprLoc();
-    SourceLocation Loc = OrigLoc;
-    DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
-    if (declRef && isa<VarDecl>(declRef->getDecl())) {
-      ASTContext &Ctx = Pass.Ctx;
-      Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(Ctx, &Loc);
-      if (IsLV != Expr::MLV_ConstQualified)
-        return true;
-      VarDecl *var = cast<VarDecl>(declRef->getDecl());
-      if (var->isARCPseudoStrong()) {
-        Transaction Trans(Pass.TA);
-        if (Pass.TA.clearDiagnostic(diag::err_typecheck_arr_assign_enumeration,
-                                    Exp->getOperatorLoc())) {
-          if (!ModifiedVars.count(var)) {
-            TypeLoc TLoc = var->getTypeSourceInfo()->getTypeLoc();
-            Pass.TA.insert(TLoc.getBeginLoc(), "__strong ");
-            ModifiedVars.insert(var);
-          }
-        }
-      }
-    }
-    
+  
+  bool VisitDoStmt(DoStmt *S) {
+    mark(S->getBody());
     return true;
   }
-};
-
-} // anonymous namespace
-
-static void makeAssignARCSafe(MigrationPass &pass) {
-  ARCAssignChecker assignCheck(pass);
-  assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// castNonObjCToObjC
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class NonObjCToObjCCaster : public RecursiveASTVisitor<NonObjCToObjCCaster> {
-  MigrationPass &Pass;
-  IdentifierInfo *SelfII;
-public:
-  NonObjCToObjCCaster(MigrationPass &pass) : Pass(pass) {
-    SelfII = &Pass.Ctx.Idents.get("self");
-  }
-
-  bool VisitCastExpr(CastExpr *E) {
-    if (E->getCastKind() != CK_AnyPointerToObjCPointerCast
-        && E->getCastKind() != CK_BitCast)
-      return true;
-
-    QualType castType = E->getType();
-    Expr *castExpr = E->getSubExpr();
-    QualType castExprType = castExpr->getType();
-
-    if (castType->isObjCObjectPointerType() &&
-        castExprType->isObjCObjectPointerType())
-      return true;
-    if (!castType->isObjCObjectPointerType() &&
-        !castExprType->isObjCObjectPointerType())
-      return true;
-    
-    bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
-    bool castRetainable = castType->isObjCIndirectLifetimeType();
-    if (exprRetainable == castRetainable) return true;
-
-    if (castExpr->isNullPointerConstant(Pass.Ctx,
-                                        Expr::NPC_ValueDependentIsNull))
-      return true;
-
-    SourceLocation loc = castExpr->getExprLoc();
-    if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
-      return true;
-
-    if (castType->isObjCObjectPointerType())
-      transformNonObjCToObjCCast(E);
-    else
-      transformObjCToNonObjCCast(E);
-
+  
+  bool VisitForStmt(ForStmt *S) {
+    mark(S->getInit());
+    mark(S->getInc());
+    mark(S->getBody());
     return true;
   }
-
+  
 private:
-  void transformNonObjCToObjCCast(CastExpr *E) {
-    if (!E) return;
-
-    // Global vars are assumed that are cast as unretained.
-    if (isGlobalVar(E))
-      if (E->getSubExpr()->getType()->isPointerType()) {
-        castToObjCObject(E, /*retained=*/false);
-        return;
-      }
-
-    // If the cast is directly over the result of a Core Foundation function
-    // try to figure out whether it should be cast as retained or unretained.
-    Expr *inner = E->IgnoreParenCasts();
-    if (CallExpr *callE = dyn_cast<CallExpr>(inner)) {
-      if (FunctionDecl *FD = callE->getDirectCallee()) {
-        if (FD->getAttr<CFReturnsRetainedAttr>()) {
-          castToObjCObject(E, /*retained=*/true);
-          return;
-        }
-        if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
-          castToObjCObject(E, /*retained=*/false);
-          return;
-        }
-        if (FD->isGlobal() &&
-            FD->getIdentifier() &&
-            ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF",
-                                   FD->getIdentifier()->getName())) {
-          StringRef fname = FD->getIdentifier()->getName();
-          if (fname.endswith("Retain") ||
-              fname.find("Create") != StringRef::npos ||
-              fname.find("Copy") != StringRef::npos) {
-            castToObjCObject(E, /*retained=*/true);
-            return;
-          }
-
-          if (fname.find("Get") != StringRef::npos) {
-            castToObjCObject(E, /*retained=*/false);
-            return;
-          }
-        }
-      }
-    }
-  }
-
-  void castToObjCObject(CastExpr *E, bool retained) {
-    rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer : OBC_Bridge);
+  void mark(Stmt *S) {
+    if (!S) return;
+    
+    if (LabelStmt *Label = dyn_cast<LabelStmt>(S))
+      return mark(Label->getSubStmt());
+    if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(S))
+      return mark(CE->getSubExpr());
+    if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
+      return mark(EWC->getSubExpr());
+    if (Expr *E = dyn_cast<Expr>(S))
+      Removables.insert(E);
   }
+};
 
-  void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) {
-    TransformActions &TA = Pass.TA;
-
-    // We will remove the compiler diagnostic.
-    if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast,
-                          diag::err_arc_cast_requires_bridge,
-                          E->getLocStart()))
-      return;
-
-    StringRef bridge;
-    switch(Kind) {
-    case OBC_Bridge:
-      bridge = "__bridge "; break;
-    case OBC_BridgeTransfer:
-      bridge = "__bridge_transfer "; break;
-    case OBC_BridgeRetained:
-      bridge = "__bridge_retained "; break;
-    }
-
-    Transaction Trans(TA);
-    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
-                       diag::err_arc_cast_requires_bridge,
-                       E->getLocStart());
-    if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(E)) {
-      TA.insertAfterToken(CCE->getLParenLoc(), bridge);
-    } else {
-      SourceLocation insertLoc = E->getSubExpr()->getLocStart();
-      llvm::SmallString<128> newCast;
-      newCast += '(';
-      newCast += bridge;
-      newCast += E->getType().getAsString(Pass.Ctx.PrintingPolicy);
-      newCast += ')';
+} // end anonymous namespace
 
-      if (isa<ParenExpr>(E->getSubExpr())) {
-        TA.insert(insertLoc, newCast.str());
-      } else {
-        newCast += '(';
-        TA.insert(insertLoc, newCast.str());
-        TA.insertAfterToken(E->getLocEnd(), ")");
-      }
-    }
-  }
+void trans::clearRefsIn(Stmt *S, ExprSet &refs) {
+  ReferenceClear(refs).TraverseStmt(S);
+}
 
-  void transformObjCToNonObjCCast(CastExpr *E) {
-    if (isSelf(E->getSubExpr()))
-      return rewriteToBridgedCast(E, OBC_Bridge);
-  }
-
-  bool isSelf(Expr *E) {
-    E = E->IgnoreParenLValueCasts();
-    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
-      if (DRE->getDecl()->getIdentifier() == SelfII)
-        return true;
-    return false;
-  }
-
-  static bool isGlobalVar(Expr *E) {
-    E = E->IgnoreParenCasts();
-    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
-      return DRE->getDecl()->getDeclContext()->isFileContext();
-    if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
-      return isGlobalVar(condOp->getTrueExpr()) &&
-             isGlobalVar(condOp->getFalseExpr());
-
-    return false;  
-  }
-};
-
-} // end anonymous namespace
-
-static void castNonObjCToObjC(MigrationPass &pass) {
-  NonObjCToObjCCaster trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// rewriteAllocCopyWithZone
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class AllocCopyWithZoneRewriter :
-                         public RecursiveASTVisitor<AllocCopyWithZoneRewriter> {
-  Decl *Dcl;
-  Stmt *Body;
-  MigrationPass &Pass;
-
-  Selector allocWithZoneSel;
-  Selector copyWithZoneSel;
-  Selector mutableCopyWithZoneSel;
-  Selector zoneSel;
-  IdentifierInfo *NSZoneII;
-
-  std::vector<DeclStmt *> NSZoneVars;
-  std::vector<Expr *> Removals;
-
-public:
-  AllocCopyWithZoneRewriter(Decl *D, MigrationPass &pass)
-    : Dcl(D), Body(0), Pass(pass) {
-    SelectorTable &sels = pass.Ctx.Selectors;
-    IdentifierTable &ids = pass.Ctx.Idents; 
-    allocWithZoneSel = sels.getUnarySelector(&ids.get("allocWithZone"));
-    copyWithZoneSel = sels.getUnarySelector(&ids.get("copyWithZone"));
-    mutableCopyWithZoneSel = sels.getUnarySelector(
-                                               &ids.get("mutableCopyWithZone"));
-    zoneSel = sels.getNullarySelector(&ids.get("zone"));
-    NSZoneII = &ids.get("_NSZone");
-  }
-
-  void transformBody(Stmt *body) {
-    Body = body;
-    // Don't change allocWithZone/copyWithZone messages inside
-    // custom implementations of such methods, it can lead to infinite loops.
-    if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(Dcl)) {
-      Selector sel = MD->getSelector();
-      if (sel == allocWithZoneSel ||
-          sel == copyWithZoneSel ||
-          sel == mutableCopyWithZoneSel ||
-          sel == zoneSel)
-        return;
-    }
-
-    TraverseStmt(body);
-  }
-
-  ~AllocCopyWithZoneRewriter() {
-    for (std::vector<DeclStmt *>::reverse_iterator
-           I = NSZoneVars.rbegin(), E = NSZoneVars.rend(); I != E; ++I) {
-      DeclStmt *DS = *I;
-      DeclGroupRef group = DS->getDeclGroup();
-      std::vector<Expr *> varRemovals = Removals;
-
-      bool areAllVarsUnused = true;
-      for (std::reverse_iterator<DeclGroupRef::iterator>
-             DI(group.end()), DE(group.begin()); DI != DE; ++DI) {
-        VarDecl *VD = cast<VarDecl>(*DI);
-        if (isNSZoneVarUsed(VD, varRemovals)) {
-          areAllVarsUnused = false;
-          break;
-        }
-        varRemovals.push_back(VD->getInit());
-      }
-
-      if (areAllVarsUnused) {
-        Transaction Trans(Pass.TA);
-        clearUnavailableDiags(DS);
-        Pass.TA.removeStmt(DS);
-        Removals.swap(varRemovals);
-      }
-    }
-  }
-
-  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
-    if (!isAllocCopyWithZoneCall(E))
-      return true;
-    Expr *arg = E->getArg(0);
-    if (paramToAllocWithZoneHasSideEffects(arg))
-      return true;
-
-    Pass.TA.startTransaction();
-
-    clearUnavailableDiags(arg);
-    Pass.TA.clearDiagnostic(diag::err_unavailable_message,
-                            E->getReceiverRange().getBegin());
-
-    Pass.TA.remove(SourceRange(E->getSelectorLoc(), arg->getLocEnd()));
-    StringRef rewrite;
-    if (E->getSelector() == allocWithZoneSel)
-      rewrite = "alloc";
-    else if (E->getSelector() == copyWithZoneSel)
-      rewrite = "copy";
-    else {
-      assert(E->getSelector() == mutableCopyWithZoneSel);
-      rewrite = "mutableCopy";
-    }
-    Pass.TA.insert(E->getSelectorLoc(), rewrite);
-
-    bool failed = Pass.TA.commitTransaction();
-    if (!failed)
-      Removals.push_back(arg);
-
-    return true;
-  }
-
-  bool VisitDeclStmt(DeclStmt *DS) {
-    DeclGroupRef group = DS->getDeclGroup();
-    if (group.begin() == group.end())
-      return true;
-    for (DeclGroupRef::iterator
-           DI = group.begin(), DE = group.end(); DI != DE; ++DI)
-      if (!isRemovableNSZoneVar(*DI))
-        return true;
-
-    NSZoneVars.push_back(DS);
-    return true;
-  }
-
-private:
-  bool isRemovableNSZoneVar(Decl *D) {
-    if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
-      if (isNSZone(VD->getType()))
-        return !paramToAllocWithZoneHasSideEffects(VD->getInit());
-    }
-    return false;
-  }
-
-  bool isNSZone(RecordDecl *RD) {
-    return RD && RD->getIdentifier() == NSZoneII;
-  }
-
-  bool isNSZone(QualType Ty) {
-    QualType pointee = Ty->getPointeeType();
-    if (pointee.isNull())
-      return false;
-    if (const RecordType *recT = pointee->getAsStructureType())
-      return isNSZone(recT->getDecl());
-    return false;
-  }
-
-  bool isNSZoneVarUsed(VarDecl *D, std::vector<Expr *> &removals) {
-    llvm::DenseSet<Expr *> refs;
-
-    ReferenceCollector refColl(refs);
-    refColl.lookFor(D, Body);
-
-    ReferenceClear refClear(refs);
-    refClear.clearRefsIn(removals.begin(), removals.end());
-
-    return !refs.empty();
-  }
-
-  bool isAllocCopyWithZoneCall(ObjCMessageExpr *E) {
-    if (E->getNumArgs() == 1 &&
-        E->getSelector() == allocWithZoneSel &&
-        (E->isClassMessage() ||
-         Pass.TA.hasDiagnostic(diag::err_unavailable_message,
-                               E->getReceiverRange().getBegin())))
-      return true;
-
-    return E->isInstanceMessage() &&
-           E->getNumArgs() == 1   &&
-           (E->getSelector() == copyWithZoneSel ||
-            E->getSelector() == mutableCopyWithZoneSel);
-  }
-
-  bool isZoneCall(ObjCMessageExpr *E) {
-    return E->isInstanceMessage() &&
-           E->getNumArgs() == 0   &&
-           E->getSelector() == zoneSel;
-  }
-
-  bool paramToAllocWithZoneHasSideEffects(Expr *E) {
-    if (!HasSideEffects(E, Pass.Ctx))
-      return false;
-    E = E->IgnoreParenCasts();
-    ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
-    if (!ME)
-      return true;
-    if (!isZoneCall(ME))
-      return true;
-    return HasSideEffects(ME->getInstanceReceiver(), Pass.Ctx);
-  }
-
-  void clearUnavailableDiags(Stmt *S) {
-    if (S)
-      Pass.TA.clearDiagnostic(diag::err_unavailable,
-                              diag::err_unavailable_message,
-                              S->getSourceRange());
-  }
-};
-
-} // end anonymous namespace
-
-static void rewriteAllocCopyWithZone(MigrationPass &pass) {
-  BodyTransform<AllocCopyWithZoneRewriter> trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// rewriteAutoreleasePool
-//===----------------------------------------------------------------------===//
-
-/// \brief 'Loc' is the end of a statement range. This returns the location
-/// immediately after the semicolon following the statement.
-/// If no semicolon is found or the location is inside a macro, the returned
-/// source location will be invalid.
-static SourceLocation findLocationAfterSemi(ASTContext &Ctx,
-                                            SourceLocation loc) {
-  SourceManager &SM = Ctx.getSourceManager();
-  if (loc.isMacroID()) {
-    if (!SM.isAtEndOfMacroInstantiation(loc))
-      return SourceLocation();
-    loc = SM.getInstantiationRange(loc).second;
-  }
-  loc = Lexer::getLocForEndOfToken(loc, /*Offset=*/0, SM, Ctx.getLangOptions());
-
-  // Break down the source location.
-  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
-
-  // Try to load the file buffer.
-  bool invalidTemp = false;
-  llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
-  if (invalidTemp)
-    return SourceLocation();
-
-  const char *tokenBegin = file.data() + locInfo.second;
-
-  // Lex from the start of the given location.
-  Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
-              Ctx.getLangOptions(),
-              file.begin(), tokenBegin, file.end());
-  Token tok;
-  lexer.LexFromRawLexer(tok);
-  if (tok.isNot(tok::semi))
-    return SourceLocation();
-
-  return tok.getLocation().getFileLocWithOffset(1);
+void trans::collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs) {
+  ReferenceCollector(D, refs).TraverseStmt(S);
 }
 
-namespace {
-
-class AutoreleasePoolRewriter
-                         : public RecursiveASTVisitor<AutoreleasePoolRewriter> {
-public:
-  AutoreleasePoolRewriter(Decl *D, MigrationPass &pass)
-    : Dcl(D), Body(0), Pass(pass) {
-    PoolII = &pass.Ctx.Idents.get("NSAutoreleasePool");
-    DrainSel = pass.Ctx.Selectors.getNullarySelector(
-                                                 &pass.Ctx.Idents.get("drain"));
-  }
-
-  void transformBody(Stmt *body) {
-    Body = body;
-    TraverseStmt(body);
-  }
-  
-  ~AutoreleasePoolRewriter() {
-    llvm::SmallVector<VarDecl *, 8> VarsToHandle;
-
-    for (std::map<VarDecl *, PoolVarInfo>::iterator
-           I = PoolVars.begin(), E = PoolVars.end(); I != E; ++I) {
-      VarDecl *var = I->first;
-      PoolVarInfo &info = I->second;
-
-      // Check that we can handle/rewrite all references of the pool.
-
-      ReferenceClear refClear(info.Refs);
-      refClear.clearRefsIn(info.Dcl);
-      for (llvm::SmallVectorImpl<PoolScope>::iterator
-             scpI = info.Scopes.begin(),
-             scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
-        PoolScope &scope = *scpI;
-        refClear.clearRefsIn(*scope.Begin);
-        refClear.clearRefsIn(*scope.End);
-        refClear.clearRefsIn(scope.Releases.begin(), scope.Releases.end());
-      }
-
-      // Even if one reference is not handled we will not do anything about that
-      // pool variable.
-      if (info.Refs.empty())
-        VarsToHandle.push_back(var);
-    }
-
-    for (unsigned i = 0, e = VarsToHandle.size(); i != e; ++i) {
-      PoolVarInfo &info = PoolVars[VarsToHandle[i]];
-
-      Transaction Trans(Pass.TA);
-
-      clearUnavailableDiags(info.Dcl);
-      Pass.TA.removeStmt(info.Dcl);
-
-      // Add "@autoreleasepool { }"
-      for (llvm::SmallVectorImpl<PoolScope>::iterator
-             scpI = info.Scopes.begin(),
-             scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
-        PoolScope &scope = *scpI;
-        clearUnavailableDiags(*scope.Begin);
-        clearUnavailableDiags(*scope.End);
-        if (scope.IsFollowedBySimpleReturnStmt) {
-          // Include the return in the scope.
-          Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
-          Pass.TA.removeStmt(*scope.End);
-          Stmt::child_iterator retI = scope.End;
-          ++retI;
-          SourceLocation afterSemi = findLocationAfterSemi(Pass.Ctx,
-                                                          (*retI)->getLocEnd());
-          assert(afterSemi.isValid() &&
-                 "Didn't we check before setting IsFollowedBySimpleReturnStmt "
-                 "to true?");
-          Pass.TA.insertAfterToken(afterSemi, "\n}");
-          Pass.TA.increaseIndentation(
-                                SourceRange(scope.getIndentedRange().getBegin(),
-                                            (*retI)->getLocEnd()),
-                                      scope.CompoundParent->getLocStart());
-        } else {
-          Pass.TA.replaceStmt(*scope.Begin, "@autoreleasepool {");
-          Pass.TA.replaceStmt(*scope.End, "}");
-          Pass.TA.increaseIndentation(scope.getIndentedRange(),
-                                      scope.CompoundParent->getLocStart());
-        }
-      }
-
-      // Remove rest of pool var references.
-      for (llvm::SmallVectorImpl<PoolScope>::iterator
-             scpI = info.Scopes.begin(),
-             scpE = info.Scopes.end(); scpI != scpE; ++scpI) {
-        PoolScope &scope = *scpI;
-        for (llvm::SmallVectorImpl<ObjCMessageExpr *>::iterator
-               relI = scope.Releases.begin(),
-               relE = scope.Releases.end(); relI != relE; ++relI) {
-          clearUnavailableDiags(*relI);
-          Pass.TA.removeStmt(*relI);
-        }
-      }
-    }
-  }
-
-  bool VisitCompoundStmt(CompoundStmt *S) {
-    llvm::SmallVector<PoolScope, 4> Scopes;
-
-    for (Stmt::child_iterator
-           I = S->body_begin(), E = S->body_end(); I != E; ++I) {
-      Stmt *child = getEssential(*I);
-      if (DeclStmt *DclS = dyn_cast<DeclStmt>(child)) {
-        if (DclS->isSingleDecl()) {
-          if (VarDecl *VD = dyn_cast<VarDecl>(DclS->getSingleDecl())) {
-            if (isNSAutoreleasePool(VD->getType())) {
-              PoolVarInfo &info = PoolVars[VD];
-              info.Dcl = DclS;
-              ReferenceCollector refColl(info.Refs);
-              refColl.lookFor(VD, S);
-              // Does this statement follow the pattern:  
-              // NSAutoreleasePool * pool = [NSAutoreleasePool  new];
-              if (isPoolCreation(VD->getInit())) {
-                Scopes.push_back(PoolScope());
-                Scopes.back().PoolVar = VD;
-                Scopes.back().CompoundParent = S;
-                Scopes.back().Begin = I;
-              }
-            }
-          }
-        }
-      } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(child)) {
-        if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(bop->getLHS())) {
-          if (VarDecl *VD = dyn_cast<VarDecl>(dref->getDecl())) {
-            // Does this statement follow the pattern:  
-            // pool = [NSAutoreleasePool  new];
-            if (isNSAutoreleasePool(VD->getType()) &&
-                isPoolCreation(bop->getRHS())) {
-              Scopes.push_back(PoolScope());
-              Scopes.back().PoolVar = VD;
-              Scopes.back().CompoundParent = S;
-              Scopes.back().Begin = I;
-            }
-          }
-        }
-      }
-
-      if (Scopes.empty())
-        continue;
-
-      if (isPoolDrain(Scopes.back().PoolVar, child)) {
-        PoolScope &scope = Scopes.back();
-        scope.End = I;
-        handlePoolScope(scope, S);
-        Scopes.pop_back();
-      }
-    }
-    return true;
-  }
-
-private:
-  void clearUnavailableDiags(Stmt *S) {
-    if (S)
-      Pass.TA.clearDiagnostic(diag::err_unavailable,
-                              diag::err_unavailable_message,
-                              S->getSourceRange());
-  }
-
-  struct PoolScope {
-    VarDecl *PoolVar;
-    CompoundStmt *CompoundParent;
-    Stmt::child_iterator Begin;
-    Stmt::child_iterator End;
-    bool IsFollowedBySimpleReturnStmt;
-    llvm::SmallVector<ObjCMessageExpr *, 4> Releases;
-
-    PoolScope() : PoolVar(0), CompoundParent(0), Begin(), End(),
-                  IsFollowedBySimpleReturnStmt(false) { }
-
-    SourceRange getIndentedRange() const {
-      Stmt::child_iterator rangeS = Begin;
-      ++rangeS;
-      if (rangeS == End)
-        return SourceRange();
-      Stmt::child_iterator rangeE = Begin;
-      for (Stmt::child_iterator I = rangeS; I != End; ++I)
-        ++rangeE;
-      return SourceRange((*rangeS)->getLocStart(), (*rangeE)->getLocEnd());
-    }
-  };
-
-  class NameReferenceChecker : public RecursiveASTVisitor<NameReferenceChecker>{
-    ASTContext &Ctx;
-    SourceRange ScopeRange;
-    SourceLocation &referenceLoc, &declarationLoc;
-
-  public:
-    NameReferenceChecker(ASTContext &ctx, PoolScope &scope,
-                         SourceLocation &referenceLoc,
-                         SourceLocation &declarationLoc)
-      : Ctx(ctx), referenceLoc(referenceLoc),
-        declarationLoc(declarationLoc) {
-      ScopeRange = SourceRange((*scope.Begin)->getLocStart(),
-                               (*scope.End)->getLocStart());
-    }
-
-    bool VisitDeclRefExpr(DeclRefExpr *E) {
-      return checkRef(E->getLocation(), E->getDecl()->getLocation());
-    }
-
-    bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
-      return checkRef(E->getLocation(), E->getDecl()->getLocation());
-    }
-
-    bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
-      return checkRef(TL.getBeginLoc(), TL.getTypedefNameDecl()->getLocation());
-    }
-
-    bool VisitTagTypeLoc(TagTypeLoc TL) {
-      return checkRef(TL.getBeginLoc(), TL.getDecl()->getLocation());
-    }
-
-  private:
-    bool checkRef(SourceLocation refLoc, SourceLocation declLoc) {
-      if (isInScope(declLoc)) {
-        referenceLoc = refLoc;
-        declarationLoc = declLoc;
-        return false;
-      }
-      return true;
-    }
-
-    bool isInScope(SourceLocation loc) {
-      SourceManager &SM = Ctx.getSourceManager();
-      if (SM.isBeforeInTranslationUnit(loc, ScopeRange.getBegin()))
-        return false;
-      return SM.isBeforeInTranslationUnit(loc, ScopeRange.getEnd());
-    }
-  };
-
-  void handlePoolScope(PoolScope &scope, CompoundStmt *compoundS) {
-    // Check that all names declared inside the scope are not used
-    // outside the scope.
-    {
-      bool nameUsedOutsideScope = false;
-      SourceLocation referenceLoc, declarationLoc;
-      Stmt::child_iterator SI = scope.End, SE = compoundS->body_end();
-      ++SI;
-      // Check if the autoreleasepool scope is followed by a simple return
-      // statement, in which case we will include the return in the scope.
-      if (SI != SE)
-        if (ReturnStmt *retS = dyn_cast<ReturnStmt>(*SI))
-          if ((retS->getRetValue() == 0 ||
-               isa<DeclRefExpr>(retS->getRetValue()->IgnoreParenCasts())) &&
-              findLocationAfterSemi(Pass.Ctx, retS->getLocEnd()).isValid()) {
-            scope.IsFollowedBySimpleReturnStmt = true;
-            ++SI; // the return will be included in scope, don't check it.
-          }
-      
-      for (; SI != SE; ++SI) {
-        nameUsedOutsideScope = !NameReferenceChecker(Pass.Ctx, scope,
-                                                     referenceLoc,
-                                              declarationLoc).TraverseStmt(*SI);
-        if (nameUsedOutsideScope)
-          break;
-      }
-
-      // If not all references were cleared it means some variables/typenames/etc
-      // declared inside the pool scope are used outside of it.
-      // We won't try to rewrite the pool.
-      if (nameUsedOutsideScope) {
-        Pass.TA.reportError("a name is referenced outside the "
-            "NSAutoreleasePool scope that it was declared in", referenceLoc);
-        Pass.TA.reportNote("name declared here", declarationLoc);
-        Pass.TA.reportNote("intended @autoreleasepool scope begins here",
-                           (*scope.Begin)->getLocStart());
-        Pass.TA.reportNote("intended @autoreleasepool scope ends here",
-                           (*scope.End)->getLocStart());
-        return;
-      }
-    }
-
-    // Collect all releases of the pool; they will be removed.
-    {
-      ReleaseCollector releaseColl(scope.PoolVar, scope.Releases);
-      Stmt::child_iterator I = scope.Begin;
-      ++I;
-      for (; I != scope.End; ++I)
-        releaseColl.TraverseStmt(*I);
-    }
-
-    PoolVars[scope.PoolVar].Scopes.push_back(scope);
-  }
-
-  bool isPoolCreation(Expr *E) {
-    if (!E) return false;
-    E = getEssential(E);
-    ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
-    if (!ME) return false;
-    if (ME->getMethodFamily() == OMF_new &&
-        ME->getReceiverKind() == ObjCMessageExpr::Class &&
-        isNSAutoreleasePool(ME->getReceiverInterface()))
-      return true;
-    if (ME->getReceiverKind() == ObjCMessageExpr::Instance &&
-        ME->getMethodFamily() == OMF_init) {
-      Expr *rec = getEssential(ME->getInstanceReceiver());
-      if (ObjCMessageExpr *recME = dyn_cast_or_null<ObjCMessageExpr>(rec)) {
-        if (recME->getMethodFamily() == OMF_alloc &&
-            recME->getReceiverKind() == ObjCMessageExpr::Class &&
-            isNSAutoreleasePool(recME->getReceiverInterface()))
-          return true;
-      }
-    }
-
-    return false;
-  }
-
-  bool isPoolDrain(VarDecl *poolVar, Stmt *S) {
-    if (!S) return false;
-    S = getEssential(S);
-    ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
-    if (!ME) return false;
-    if (ME->getReceiverKind() == ObjCMessageExpr::Instance) {
-      Expr *rec = getEssential(ME->getInstanceReceiver());
-      if (DeclRefExpr *dref = dyn_cast<DeclRefExpr>(rec))
-        if (dref->getDecl() == poolVar)
-          return ME->getMethodFamily() == OMF_release ||
-                 ME->getSelector() == DrainSel;
-    }
-
-    return false;
-  }
-
-  bool isNSAutoreleasePool(ObjCInterfaceDecl *IDecl) {
-    return IDecl && IDecl->getIdentifier() == PoolII;
-  }
-
-  bool isNSAutoreleasePool(QualType Ty) {
-    QualType pointee = Ty->getPointeeType();
-    if (pointee.isNull())
-      return false;
-    if (const ObjCInterfaceType *interT = pointee->getAs<ObjCInterfaceType>())
-      return isNSAutoreleasePool(interT->getDecl());
-    return false;
-  }
-
-  static Expr *getEssential(Expr *E) {
-    return cast<Expr>(getEssential((Stmt*)E));
-  }
-  static Stmt *getEssential(Stmt *S) {
-    if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(S))
-      S = EWC->getSubExpr();
-    if (Expr *E = dyn_cast<Expr>(S))
-      S = E->IgnoreParenCasts();
-    return S;
-  }
-
-  Decl *Dcl;
-  Stmt *Body;
-  MigrationPass &Pass;
-
-  IdentifierInfo *PoolII;
-  Selector DrainSel;
-  
-  struct PoolVarInfo {
-    DeclStmt *Dcl;
-    llvm::DenseSet<Expr *> Refs;
-    llvm::SmallVector<PoolScope, 2> Scopes;
-
-    PoolVarInfo() : Dcl(0) { }
-  };
-
-  std::map<VarDecl *, PoolVarInfo> PoolVars;
-};
-
-} // anonymous namespace
-
-static void rewriteAutoreleasePool(MigrationPass &pass) {
-  BodyTransform<AutoreleasePoolRewriter> trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// removeRetainReleaseDealloc
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class RetainReleaseDeallocRemover :
-                       public RecursiveASTVisitor<RetainReleaseDeallocRemover> {
-  Decl *Dcl;
-  Stmt *Body;
-  MigrationPass &Pass;
-
-  llvm::DenseSet<Expr *> Removables;
-  llvm::OwningPtr<ParentMap> StmtMap;
-
-public:
-  RetainReleaseDeallocRemover(Decl *D, MigrationPass &pass)
-    : Dcl(D), Body(0), Pass(pass) { }
-
-  void transformBody(Stmt *body) {
-    Body = body;
-    RemovablesCollector(Removables).TraverseStmt(body);
-    StmtMap.reset(new ParentMap(body));
-    TraverseStmt(body);
-  }
-
-  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
-    switch (E->getMethodFamily()) {
-    default:
-      return true;
-    case OMF_retain:
-    case OMF_release:
-    case OMF_autorelease:
-      if (E->getReceiverKind() == ObjCMessageExpr::Instance)
-        if (Expr *rec = E->getInstanceReceiver()) {
-          rec = rec->IgnoreParenImpCasts();
-          if (rec->getType().getObjCLifetime() == Qualifiers::OCL_ExplicitNone){
-            std::string err = "It is not safe to remove '";
-            err += E->getSelector().getAsString() + "' message on "
-                "an __unsafe_unretained type";
-            Pass.TA.reportError(err, rec->getLocStart());
-            return true;
-          }
-        }
-    case OMF_dealloc:
-      break;
-    }
-
-    switch (E->getReceiverKind()) {
-    default:
-      return true;
-    case ObjCMessageExpr::SuperInstance: {
-      Transaction Trans(Pass.TA);
-      Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
-                              diag::err_unavailable,
-                              diag::err_unavailable_message,
-                              E->getSuperLoc());
-      if (tryRemoving(E))
-        return true;
-      Pass.TA.replace(E->getSourceRange(), "self");
-      return true;
-    }
-    case ObjCMessageExpr::Instance:
-      break;
-    }
-
-    Expr *rec = E->getInstanceReceiver();
-    if (!rec) return true;
-
-    Transaction Trans(Pass.TA);
-    Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
-                            diag::err_unavailable,
-                            diag::err_unavailable_message,
-                            rec->getExprLoc());
-    if (!HasSideEffects(E, Pass.Ctx)) {
-      if (tryRemoving(E))
-        return true;
-    }
-    Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
-
-    return true;
-  }
-
-private:
-  bool isRemovable(Expr *E) const {
-    return Removables.count(E);
-  }
-  
-  bool tryRemoving(Expr *E) const {
-    if (isRemovable(E)) {
-      Pass.TA.removeStmt(E);
-      return true;
-    }
-
-    if (ParenExpr *parenE = dyn_cast_or_null<ParenExpr>(StmtMap->getParent(E)))
-      return tryRemoving(parenE);
-
-    if (BinaryOperator *
-          bopE = dyn_cast_or_null<BinaryOperator>(StmtMap->getParent(E))) {
-      if (bopE->getOpcode() == BO_Comma && bopE->getLHS() == E &&
-          isRemovable(bopE)) {
-        Pass.TA.replace(bopE->getSourceRange(), bopE->getRHS()->getSourceRange());
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-};
-
-} // anonymous namespace
-
-static void removeRetainReleaseDealloc(MigrationPass &pass) {
-  BodyTransform<RetainReleaseDeallocRemover> trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// removeEmptyStatements
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class EmptyStatementsRemover :
-                            public RecursiveASTVisitor<EmptyStatementsRemover> {
-  MigrationPass &Pass;
-  llvm::DenseSet<unsigned> MacroLocs;
-
-public:
-  EmptyStatementsRemover(MigrationPass &pass) : Pass(pass) {
-    for (unsigned i = 0, e = Pass.ARCMTMacroLocs.size(); i != e; ++i)
-      MacroLocs.insert(Pass.ARCMTMacroLocs[i].getRawEncoding());
-  }
-
-  bool TraverseStmtExpr(StmtExpr *E) {
-    CompoundStmt *S = E->getSubStmt();
-    for (CompoundStmt::body_iterator
-           I = S->body_begin(), E = S->body_end(); I != E; ++I) {
-      if (I != E - 1)
-        check(*I);
-      TraverseStmt(*I);
-    }
-    return true;
-  }
-
-  bool VisitCompoundStmt(CompoundStmt *S) {
-    for (CompoundStmt::body_iterator
-           I = S->body_begin(), E = S->body_end(); I != E; ++I)
-      check(*I);
-    return true;
-  }
-
-  bool isMacroLoc(SourceLocation loc) {
-    if (loc.isInvalid()) return false;
-    return MacroLocs.count(loc.getRawEncoding());
-  }
-
-  ASTContext &getContext() { return Pass.Ctx; }
-
-private:
-  /// \brief Returns true if the statement became empty due to previous
-  /// transformations.
-  class EmptyChecker : public StmtVisitor<EmptyChecker, bool> {
-    EmptyStatementsRemover &Trans;
-
-  public:
-    EmptyChecker(EmptyStatementsRemover &trans) : Trans(trans) { }
-
-    bool VisitNullStmt(NullStmt *S) {
-      return Trans.isMacroLoc(S->getLeadingEmptyMacroLoc());
-    }
-    bool VisitCompoundStmt(CompoundStmt *S) {
-      if (S->body_empty())
-        return false; // was already empty, not because of transformations.
-      for (CompoundStmt::body_iterator
-             I = S->body_begin(), E = S->body_end(); I != E; ++I)
-        if (!Visit(*I))
-          return false;
-      return true;
-    }
-    bool VisitIfStmt(IfStmt *S) {
-      if (S->getConditionVariable())
-        return false;
-      Expr *condE = S->getCond();
-      if (!condE)
-        return false;
-      if (HasSideEffects(condE, Trans.getContext()))
-        return false;
-      if (!S->getThen() || !Visit(S->getThen()))
-        return false;
-      if (S->getElse() && !Visit(S->getElse()))
-        return false;
-      return true;
-    }
-    bool VisitWhileStmt(WhileStmt *S) {
-      if (S->getConditionVariable())
-        return false;
-      Expr *condE = S->getCond();
-      if (!condE)
-        return false;
-      if (HasSideEffects(condE, Trans.getContext()))
-        return false;
-      if (!S->getBody())
-        return false;
-      return Visit(S->getBody());
-    }
-    bool VisitDoStmt(DoStmt *S) {
-      Expr *condE = S->getCond();
-      if (!condE)
-        return false;
-      if (HasSideEffects(condE, Trans.getContext()))
-        return false;
-      if (!S->getBody())
-        return false;
-      return Visit(S->getBody());
-    }
-    bool VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
-      Expr *Exp = S->getCollection();
-      if (!Exp)
-        return false;
-      if (HasSideEffects(Exp, Trans.getContext()))
-        return false;
-      if (!S->getBody())
-        return false;
-      return Visit(S->getBody());
-    }
-    bool VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) {
-      if (!S->getSubStmt())
-        return false;
-      return Visit(S->getSubStmt());
-    }
-  };
-
-  void check(Stmt *S) {
-    if (!S) return;
-    if (EmptyChecker(*this).Visit(S)) {
-      Transaction Trans(Pass.TA);
-      Pass.TA.removeStmt(S);
-    }
-  }
-};
-
-} // anonymous namespace
-
-static void removeEmptyStatements(MigrationPass &pass) {
-  EmptyStatementsRemover(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-
-  for (unsigned i = 0, e = pass.ARCMTMacroLocs.size(); i != e; ++i) {
-    Transaction Trans(pass.TA);
-    pass.TA.remove(pass.ARCMTMacroLocs[i]);
-  }
-}
-
-//===----------------------------------------------------------------------===//
-// changeIvarsOfAssignProperties.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class AssignPropertiesTrans {
-  MigrationPass &Pass;
-  struct PropData {
-    ObjCPropertyDecl *PropD;
-    ObjCIvarDecl *IvarD;
-    bool ShouldChangeToWeak;
-    SourceLocation ArcPropAssignErrorLoc;
-  };
-
-  typedef llvm::SmallVector<PropData, 2> PropsTy; 
-  typedef llvm::DenseMap<unsigned, PropsTy> PropsMapTy;
-  PropsMapTy PropsMap;
-
-public:
-  AssignPropertiesTrans(MigrationPass &pass) : Pass(pass) { }
-
-  void doTransform(ObjCImplementationDecl *D) {
-    SourceManager &SM = Pass.Ctx.getSourceManager();
-
-    ObjCInterfaceDecl *IFace = D->getClassInterface();
-    for (ObjCInterfaceDecl::prop_iterator
-           I = IFace->prop_begin(), E = IFace->prop_end(); I != E; ++I) {
-      ObjCPropertyDecl *propD = *I;
-      unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding();
-      PropsTy &props = PropsMap[loc];
-      props.push_back(PropData());
-      props.back().PropD = propD;
-      props.back().IvarD = 0;
-      props.back().ShouldChangeToWeak = false;
-    }
-
-    typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
-        prop_impl_iterator;
-    for (prop_impl_iterator
-           I = prop_impl_iterator(D->decls_begin()),
-           E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
-      VisitObjCPropertyImplDecl(*I);
-    }
-
-    for (PropsMapTy::iterator
-           I = PropsMap.begin(), E = PropsMap.end(); I != E; ++I) {
-      SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first);
-      PropsTy &props = I->second;
-      if (shouldApplyWeakToAllProp(props)) {
-        if (changeAssignToWeak(atLoc)) {
-          // Couldn't add the 'weak' property attribute,
-          // try adding __unsafe_unretained.
-          applyUnsafeUnretained(props);
-        } else {
-          for (PropsTy::iterator
-                 PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
-            applyWeak(*PI);
-          }
-        }
-      } else {
-        // We should not add 'weak' attribute since not all properties need it.
-        // So just add __unsafe_unretained to the ivars.
-        applyUnsafeUnretained(props);
-      }
-    }
-  }
-
-  bool shouldApplyWeakToAllProp(PropsTy &props) {
-    for (PropsTy::iterator
-           PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
-      if (!PI->ShouldChangeToWeak)
-        return false;
-    }
-    return true;
-  }
-
-  void applyWeak(PropData &prop) {
-    assert(!Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime);
-
-    Transaction Trans(Pass.TA);
-    Pass.TA.insert(prop.IvarD->getLocation(), "__weak "); 
-    Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime,
-                            prop.ArcPropAssignErrorLoc);
-  }
-
-  void applyUnsafeUnretained(PropsTy &props) {
-    for (PropsTy::iterator
-           PI = props.begin(), PE = props.end(); PI != PE; ++PI) {
-      if (PI->ShouldChangeToWeak) {
-        Transaction Trans(Pass.TA);
-        Pass.TA.insert(PI->IvarD->getLocation(), "__unsafe_unretained ");
-        Pass.TA.clearDiagnostic(diag::err_arc_assign_property_lifetime,
-                                PI->ArcPropAssignErrorLoc);
-      }
-    }
-  }
-
-  bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
-    SourceManager &SM = Pass.Ctx.getSourceManager();
-
-    if (D->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
-      return true;
-    ObjCPropertyDecl *propD = D->getPropertyDecl();
-    if (!propD || propD->isInvalidDecl())
-      return true;
-    ObjCIvarDecl *ivarD = D->getPropertyIvarDecl();
-    if (!ivarD || ivarD->isInvalidDecl())
-      return true;
-    if (!(propD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign))
-      return true;
-    if (isa<AttributedType>(ivarD->getType().getTypePtr()))
-      return true;
-    if (ivarD->getType().getLocalQualifiers().getObjCLifetime()
-          != Qualifiers::OCL_Strong)
-      return true;
-    if (!Pass.TA.hasDiagnostic(
-                      diag::err_arc_assign_property_lifetime, D->getLocation()))
-      return true;
-
-    // There is a "error: existing ivar for assign property must be
-    // __unsafe_unretained"; fix it.
-
-    if (Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime) {
-      // We will just add __unsafe_unretained to the ivar.
-      Transaction Trans(Pass.TA);
-      Pass.TA.insert(ivarD->getLocation(), "__unsafe_unretained ");
-      Pass.TA.clearDiagnostic(
-                      diag::err_arc_assign_property_lifetime, D->getLocation());
-    } else {
-      // Mark that we want the ivar to become weak.
-      unsigned loc = SM.getInstantiationLoc(propD->getAtLoc()).getRawEncoding();
-      PropsTy &props = PropsMap[loc];
-      for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
-        if (I->PropD == propD) {
-          I->IvarD = ivarD;
-          I->ShouldChangeToWeak = true;
-          I->ArcPropAssignErrorLoc = D->getLocation();
-        }
-      }
-    }
-
-    return true;
-  }
-
-private:
-  bool changeAssignToWeak(SourceLocation atLoc) {
-    SourceManager &SM = Pass.Ctx.getSourceManager();
-
-    // Break down the source location.
-    std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc);
-
-    // Try to load the file buffer.
-    bool invalidTemp = false;
-    llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp);
-    if (invalidTemp)
-      return true;
-
-    const char *tokenBegin = file.data() + locInfo.second;
-
-    // Lex from the start of the given location.
-    Lexer lexer(SM.getLocForStartOfFile(locInfo.first),
-                Pass.Ctx.getLangOptions(),
-                file.begin(), tokenBegin, file.end());
-    Token tok;
-    lexer.LexFromRawLexer(tok);
-    if (tok.isNot(tok::at)) return true;
-    lexer.LexFromRawLexer(tok);
-    if (tok.isNot(tok::raw_identifier)) return true;
-    if (llvm::StringRef(tok.getRawIdentifierData(), tok.getLength())
-          != "property")
-      return true;
-    lexer.LexFromRawLexer(tok);
-    if (tok.isNot(tok::l_paren)) return true;
-    
-    SourceLocation LParen = tok.getLocation();
-    SourceLocation assignLoc;
-    bool isEmpty = false;
-
-    lexer.LexFromRawLexer(tok);
-    if (tok.is(tok::r_paren)) {
-      isEmpty = true;
-    } else {
-      while (1) {
-        if (tok.isNot(tok::raw_identifier)) return true;
-        llvm::StringRef ident(tok.getRawIdentifierData(), tok.getLength());
-        if (ident == "assign")
-          assignLoc = tok.getLocation();
-  
-        do {
-          lexer.LexFromRawLexer(tok);
-        } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren));
-        if (tok.is(tok::r_paren))
-          break;
-        lexer.LexFromRawLexer(tok);
-      }
-    }
-
-    Transaction Trans(Pass.TA);
-    if (assignLoc.isValid())
-      Pass.TA.replaceText(assignLoc, "assign", "weak");
-    else 
-      Pass.TA.insertAfterToken(LParen, isEmpty ? "weak" : "weak, ");
-    return false;
-  }
-};
-
-class PropertiesChecker : public RecursiveASTVisitor<PropertiesChecker> {
-  MigrationPass &Pass;
-
-public:
-  PropertiesChecker(MigrationPass &pass) : Pass(pass) { }
-
-  bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) {
-    AssignPropertiesTrans(Pass).doTransform(D);
-    return true;
-  }
-};
-
-} // anonymous namespace
-
-static void changeIvarsOfAssignProperties(MigrationPass &pass) {
-  PropertiesChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// rewriteUnusedDelegateInit
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class UnusedInitRewriter : public RecursiveASTVisitor<UnusedInitRewriter> {
-  Decl *Dcl;
-  Stmt *Body;
-  MigrationPass &Pass;
-
-  llvm::DenseSet<Expr *> Removables;
-
-public:
-  UnusedInitRewriter(Decl *D, MigrationPass &pass)
-    : Dcl(D), Body(0), Pass(pass) { }
-
-  void transformBody(Stmt *body) {
-    Body = body;
-    RemovablesCollector(Removables).TraverseStmt(body);
-    TraverseStmt(body);
-  }
-
-  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
-    if (ME->isDelegateInitCall() &&
-        isRemovable(ME) &&
-        Pass.TA.hasDiagnostic(diag::err_arc_unused_init_message,
-                              ME->getExprLoc())) {
-      Transaction Trans(Pass.TA);
-      Pass.TA.clearDiagnostic(diag::err_arc_unused_init_message,
-                              ME->getExprLoc());
-      Pass.TA.insert(ME->getExprLoc(), "self = ");
-    }
-    return true;
-  }
-
-private:
-  bool isRemovable(Expr *E) const {
-    return Removables.count(E);
-  }
-};
-
-} // anonymous namespace
-
-static void rewriteUnusedDelegateInit(MigrationPass &pass) {
-  BodyTransform<UnusedInitRewriter> trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// rewriteBlockObjCVariable
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class RootBlockObjCVarRewriter :
-                          public RecursiveASTVisitor<RootBlockObjCVarRewriter> {
-  MigrationPass &Pass;
-  llvm::DenseSet<VarDecl *> CheckedVars;
-
-  class BlockVarChecker : public RecursiveASTVisitor<BlockVarChecker> {
-    VarDecl *Var;
-  
-    typedef RecursiveASTVisitor<BlockVarChecker> base;
-  public:
-    BlockVarChecker(VarDecl *var) : Var(var) { }
-  
-    bool TraverseImplicitCastExpr(ImplicitCastExpr *castE) {
-      if (BlockDeclRefExpr *
-            ref = dyn_cast<BlockDeclRefExpr>(castE->getSubExpr())) {
-        if (ref->getDecl() == Var) {
-          if (castE->getCastKind() == CK_LValueToRValue)
-            return true; // Using the value of the variable.
-          if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
-              Var->getASTContext().getLangOptions().CPlusPlus)
-            return true; // Binding to const C++ reference.
-        }
-      }
-
-      return base::TraverseImplicitCastExpr(castE);
-    }
-
-    bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
-      if (E->getDecl() == Var)
-        return false; // The reference of the variable, and not just its value,
-                      //  is needed.
-      return true;
-    }
-  };
-
-public:
-  RootBlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
-
-  bool VisitBlockDecl(BlockDecl *block) {
-    llvm::SmallVector<VarDecl *, 4> BlockVars;
-    
-    for (BlockDecl::capture_iterator
-           I = block->capture_begin(), E = block->capture_end(); I != E; ++I) {
-      VarDecl *var = I->getVariable();
-      if (I->isByRef() &&
-          !isAlreadyChecked(var) &&
-          var->getType()->isObjCObjectPointerType() &&
-          isImplicitStrong(var->getType())) {
-        BlockVars.push_back(var);
-      }
-    }
-
-    for (unsigned i = 0, e = BlockVars.size(); i != e; ++i) {
-      VarDecl *var = BlockVars[i];
-      CheckedVars.insert(var);
-
-      BlockVarChecker checker(var);
-      bool onlyValueOfVarIsNeeded = checker.TraverseStmt(block->getBody());
-      if (onlyValueOfVarIsNeeded) {
-        BlocksAttr *attr = var->getAttr<BlocksAttr>();
-        if(!attr)
-          continue;
-        bool hasARCRuntime = !Pass.Ctx.getLangOptions().ObjCNoAutoRefCountRuntime;
-        SourceManager &SM = Pass.Ctx.getSourceManager();
-        Transaction Trans(Pass.TA);
-        Pass.TA.replaceText(SM.getInstantiationLoc(attr->getLocation()),
-                            "__block",
-                            hasARCRuntime ? "__weak" : "__unsafe_unretained");
-      }
-
-    }
-
-    return true;
-  }
-
-private:
-  bool isAlreadyChecked(VarDecl *VD) {
-    return CheckedVars.count(VD);
-  }
-
-  bool isImplicitStrong(QualType ty) {
-    if (isa<AttributedType>(ty.getTypePtr()))
-      return false;
-    return ty.getLocalQualifiers().getObjCLifetime() == Qualifiers::OCL_Strong;
-  }
-};
-
-class BlockObjCVarRewriter : public RecursiveASTVisitor<BlockObjCVarRewriter> {
-  MigrationPass &Pass;
-
-public:
-  BlockObjCVarRewriter(MigrationPass &pass) : Pass(pass) { }
-
-  bool TraverseBlockDecl(BlockDecl *block) {
-    RootBlockObjCVarRewriter(Pass).TraverseDecl(block);
-    return true;
-  }
-};
-
-} // anonymous namespace
-
-static void rewriteBlockObjCVariable(MigrationPass &pass) {
-  BlockObjCVarRewriter trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
-}
-
-//===----------------------------------------------------------------------===//
-// removeZeroOutIvarsInDealloc
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class ZeroOutInDeallocRemover :
-                           public RecursiveASTVisitor<ZeroOutInDeallocRemover> {
-  typedef RecursiveASTVisitor<ZeroOutInDeallocRemover> base;
-
-  MigrationPass &Pass;
-
-  llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*> SynthesizedProperties;
-  ImplicitParamDecl *SelfD;
-  llvm::DenseSet<Expr *> Removables;
-
-public:
-  ZeroOutInDeallocRemover(MigrationPass &pass) : Pass(pass), SelfD(0) { }
-
-  bool VisitObjCMessageExpr(ObjCMessageExpr *ME) {
-    ASTContext &Ctx = Pass.Ctx;
-    TransformActions &TA = Pass.TA;
-
-    if (ME->getReceiverKind() != ObjCMessageExpr::Instance)
-      return true;
-    Expr *receiver = ME->getInstanceReceiver();
-    if (!receiver)
-      return true;
-
-    DeclRefExpr *refE = dyn_cast<DeclRefExpr>(receiver->IgnoreParenCasts());
-    if (!refE || refE->getDecl() != SelfD)
-      return true;
-
-    bool BackedBySynthesizeSetter = false;
-    for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
-         P = SynthesizedProperties.begin(), 
-         E = SynthesizedProperties.end(); P != E; ++P) {
-      ObjCPropertyDecl *PropDecl = P->first;
-      if (PropDecl->getSetterName() == ME->getSelector()) {
-        BackedBySynthesizeSetter = true;
-        break;
-      }
-    }
-    if (!BackedBySynthesizeSetter)
-      return true;
-    
-    // Remove the setter message if RHS is null
-    Transaction Trans(TA);
-    Expr *RHS = ME->getArg(0);
-    bool RHSIsNull = 
-      RHS->isNullPointerConstant(Ctx,
-                                 Expr::NPC_ValueDependentIsNull);
-    if (RHSIsNull && isRemovable(ME))
-      TA.removeStmt(ME);
-
-    return true;
-  }
-
-  bool VisitBinaryOperator(BinaryOperator *BOE) {
-    if (isZeroingPropIvar(BOE) && isRemovable(BOE)) {
-      Transaction Trans(Pass.TA);
-      Pass.TA.removeStmt(BOE);
-    }
-
-    return true;
-  }
-
-  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
-    if (D->getMethodFamily() != OMF_dealloc)
-      return true;
-    if (!D->hasBody())
-      return true;
-
-    ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(D->getDeclContext());
-    if (!IMD)
-      return true;
-
-    SelfD = D->getSelfDecl();
-    RemovablesCollector(Removables).TraverseStmt(D->getBody());
-
-    // For a 'dealloc' method use, find all property implementations in
-    // this class implementation.
-    for (ObjCImplDecl::propimpl_iterator
-           I = IMD->propimpl_begin(), EI = IMD->propimpl_end(); I != EI; ++I) {
-        ObjCPropertyImplDecl *PID = *I;
-        if (PID->getPropertyImplementation() ==
-            ObjCPropertyImplDecl::Synthesize) {
-          ObjCPropertyDecl *PD = PID->getPropertyDecl();
-          ObjCMethodDecl *setterM = PD->getSetterMethodDecl();
-          if (!(setterM && setterM->isDefined())) {
-            ObjCPropertyDecl::PropertyAttributeKind AttrKind = 
-              PD->getPropertyAttributes();
-              if (AttrKind & 
-                  (ObjCPropertyDecl::OBJC_PR_retain | 
-                   ObjCPropertyDecl::OBJC_PR_copy   |
-                   ObjCPropertyDecl::OBJC_PR_strong))
-                SynthesizedProperties[PD] = PID;
-          }
-        }
-    }
-
-    // Now, remove all zeroing of ivars etc.
-    base::TraverseObjCMethodDecl(D);
-
-    // clear out for next method.
-    SynthesizedProperties.clear();
-    SelfD = 0;
-    Removables.clear();
-    return true;
-  }
-
-  bool TraverseFunctionDecl(FunctionDecl *D) { return true; }
-  bool TraverseBlockDecl(BlockDecl *block) { return true; }
-  bool TraverseBlockExpr(BlockExpr *block) { return true; }
-
-private:
-  bool isRemovable(Expr *E) const {
-    return Removables.count(E);
-  }
-
-  bool isZeroingPropIvar(Expr *E) {
-    BinaryOperator *BOE = dyn_cast_or_null<BinaryOperator>(E);
-    if (!BOE) return false;
-
-    if (BOE->getOpcode() == BO_Comma)
-      return isZeroingPropIvar(BOE->getLHS()) &&
-             isZeroingPropIvar(BOE->getRHS());
-
-    if (BOE->getOpcode() != BO_Assign)
-        return false;
-
-    ASTContext &Ctx = Pass.Ctx;
-
-    Expr *LHS = BOE->getLHS();
-    if (ObjCIvarRefExpr *IV = dyn_cast<ObjCIvarRefExpr>(LHS)) {
-      ObjCIvarDecl *IVDecl = IV->getDecl();
-      if (!IVDecl->getType()->isObjCObjectPointerType())
-        return false;
-      bool IvarBacksPropertySynthesis = false;
-      for (llvm::DenseMap<ObjCPropertyDecl*, ObjCPropertyImplDecl*>::iterator
-           P = SynthesizedProperties.begin(), 
-           E = SynthesizedProperties.end(); P != E; ++P) {
-        ObjCPropertyImplDecl *PropImpDecl = P->second;
-        if (PropImpDecl && PropImpDecl->getPropertyIvarDecl() == IVDecl) {
-          IvarBacksPropertySynthesis = true;
-          break;
-        }
-      }
-      if (!IvarBacksPropertySynthesis)
-        return false;
-    }
-    else if (ObjCPropertyRefExpr *PropRefExp = dyn_cast<ObjCPropertyRefExpr>(LHS)) {
-      // TODO: Using implicit property decl.
-      if (PropRefExp->isImplicitProperty())
-        return false;
-      if (ObjCPropertyDecl *PDecl = PropRefExp->getExplicitProperty()) {
-        if (!SynthesizedProperties.count(PDecl))
-          return false;
-      }
-    }
-    else
-        return false;
-
-    Expr *RHS = BOE->getRHS();
-    bool RHSIsNull = RHS->isNullPointerConstant(Ctx,
-                                                Expr::NPC_ValueDependentIsNull);
-    if (RHSIsNull)
-      return true;
-
-    return isZeroingPropIvar(RHS);
-  }
-};
-
-} // anonymous namespace
-
-static void removeZeroOutIvarsInDealloc(MigrationPass &pass) {
-  ZeroOutInDeallocRemover trans(pass);
-  trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+void trans::collectRemovables(Stmt *S, ExprSet &exprs) {
+  RemovablesCollector(exprs).TraverseStmt(S);
 }
 
 //===----------------------------------------------------------------------===//
@@ -2065,10 +213,10 @@ static void independentTransforms(MigrationPass &pass) {
   rewriteAutoreleasePool(pass);
   changeIvarsOfAssignProperties(pass);
   removeRetainReleaseDealloc(pass);
-  rewriteUnusedDelegateInit(pass);
-  removeZeroOutIvarsInDealloc(pass);
+  rewriteUnusedInitDelegate(pass);
+  removeZeroOutPropsInDealloc(pass);
   makeAssignARCSafe(pass);
-  castNonObjCToObjC(pass);
+  rewriteUnbridgedCasts(pass);
   rewriteBlockObjCVariable(pass);
   rewriteAllocCopyWithZone(pass);
 }
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
new file mode 100644 (file)
index 0000000..d95b1bc
--- /dev/null
@@ -0,0 +1,105 @@
+//===-- Transforms.h - Tranformations to ARC mode ---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
+#define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace clang {
+  class Decl;
+  class Stmt;
+  class BlockDecl;
+  class ObjCMethodDecl;
+  class FunctionDecl;
+
+namespace arcmt {
+  class MigrationPass;
+
+namespace trans {
+
+//===----------------------------------------------------------------------===//
+// Transformations.
+//===----------------------------------------------------------------------===//
+
+void rewriteAutoreleasePool(MigrationPass &pass);
+void rewriteUnbridgedCasts(MigrationPass &pass);
+void rewriteAllocCopyWithZone(MigrationPass &pass);
+void makeAssignARCSafe(MigrationPass &pass);
+void removeRetainReleaseDealloc(MigrationPass &pass);
+void removeEmptyStatements(MigrationPass &pass);
+void removeZeroOutPropsInDealloc(MigrationPass &pass);
+void changeIvarsOfAssignProperties(MigrationPass &pass);
+void rewriteBlockObjCVariable(MigrationPass &pass);
+void removeDeallocMethod(MigrationPass &pass);
+void rewriteUnusedInitDelegate(MigrationPass &pass);
+
+//===----------------------------------------------------------------------===//
+// Helpers.
+//===----------------------------------------------------------------------===//
+
+/// \brief 'Loc' is the end of a statement range. This returns the location
+/// immediately after the semicolon following the statement.
+/// If no semicolon is found or the location is inside a macro, the returned
+/// source location will be invalid.
+SourceLocation findLocationAfterSemi(SourceLocation loc, ASTContext &Ctx);
+
+bool hasSideEffects(Expr *E, ASTContext &Ctx);
+
+template <typename BODY_TRANS>
+class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > {
+  MigrationPass &Pass;
+
+public:
+  BodyTransform(MigrationPass &pass) : Pass(pass) { }
+
+  void handleBody(Decl *D) {
+    Stmt *body = D->getBody();
+    if (body) {
+      BODY_TRANS(D, Pass).transformBody(body);
+    }
+  }
+
+  bool TraverseBlockDecl(BlockDecl *D) {
+    handleBody(D);
+    return true;
+  }
+  bool TraverseObjCMethodDecl(ObjCMethodDecl *D) {
+    if (D->isThisDeclarationADefinition())
+      handleBody(D);
+    return true;
+  }
+  bool TraverseFunctionDecl(FunctionDecl *D) {
+    if (D->isThisDeclarationADefinition())
+      handleBody(D);
+    return true;
+  }
+};
+
+typedef llvm::DenseSet<Expr *> ExprSet;
+
+void clearRefsIn(Stmt *S, ExprSet &refs);
+template <typename iterator>
+void clearRefsIn(iterator begin, iterator end, ExprSet &refs) {
+  for (; begin != end; ++begin)
+    clearRefsIn(*begin, refs);
+}
+
+void collectRefs(ValueDecl *D, Stmt *S, ExprSet &refs);
+
+void collectRemovables(Stmt *S, ExprSet &exprs);
+
+} // end namespace trans
+
+} // end namespace arcmt
+
+} // end namespace clang
+
+#endif