[cfe-commits] r133104 - in /cfe/trunk: clang.xcodeproj/ include/clang/ARCMigrate/ lib/ lib/ARCMigrate/ lib/Driver/ lib/Frontend/ test/ARCMT/ tools/ tools/arcmt-test/ tools/driver/ tools/scan-build/ unittests/Frontend/

John McCall rjmccall at apple.com
Wed Jun 15 16:25:18 PDT 2011


Author: rjmccall
Date: Wed Jun 15 18:25:17 2011
New Revision: 133104

URL: http://llvm.org/viewvc/llvm-project?rev=133104&view=rev
Log:
The ARC Migration Tool.  All the credit goes to Argyrios and Fariborz
for this.


Added:
    cfe/trunk/include/clang/ARCMigrate/
    cfe/trunk/include/clang/ARCMigrate/ARCMT.h
    cfe/trunk/include/clang/ARCMigrate/FileRemapper.h
    cfe/trunk/lib/ARCMigrate/
    cfe/trunk/lib/ARCMigrate/ARCMT.cpp
    cfe/trunk/lib/ARCMigrate/CMakeLists.txt
    cfe/trunk/lib/ARCMigrate/FileRemapper.cpp
    cfe/trunk/lib/ARCMigrate/Internals.h
    cfe/trunk/lib/ARCMigrate/Makefile
    cfe/trunk/lib/ARCMigrate/TransformActions.cpp
    cfe/trunk/lib/ARCMigrate/Transforms.cpp
    cfe/trunk/test/ARCMT/
    cfe/trunk/test/ARCMT/Common.h
    cfe/trunk/test/ARCMT/alloc-with-zone-check.m
    cfe/trunk/test/ARCMT/alloc-with-zone.m
    cfe/trunk/test/ARCMT/alloc-with-zone.m.result
    cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m
    cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m.result
    cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m
    cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result
    cfe/trunk/test/ARCMT/atautorelease-2.m
    cfe/trunk/test/ARCMT/atautorelease-2.m.result
    cfe/trunk/test/ARCMT/atautorelease-3.m
    cfe/trunk/test/ARCMT/atautorelease-3.m.result
    cfe/trunk/test/ARCMT/atautorelease-check.m
    cfe/trunk/test/ARCMT/atautorelease.m
    cfe/trunk/test/ARCMT/atautorelease.m.result
    cfe/trunk/test/ARCMT/autoreleases.m
    cfe/trunk/test/ARCMT/autoreleases.m.result
    cfe/trunk/test/ARCMT/checking.m
    cfe/trunk/test/ARCMT/cxx-checking.mm
    cfe/trunk/test/ARCMT/dealloc.m
    cfe/trunk/test/ARCMT/dealloc.m.result
    cfe/trunk/test/ARCMT/init.m
    cfe/trunk/test/ARCMT/init.m.result
    cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m
    cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m
    cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result
    cfe/trunk/test/ARCMT/releases.m
    cfe/trunk/test/ARCMT/releases.m.result
    cfe/trunk/test/ARCMT/remove-dealloc-method.m
    cfe/trunk/test/ARCMT/remove-dealloc-method.m.result
    cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m
    cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m.result
    cfe/trunk/test/ARCMT/remove-statements.m
    cfe/trunk/test/ARCMT/remove-statements.m.result
    cfe/trunk/test/ARCMT/retains.m
    cfe/trunk/test/ARCMT/retains.m.result
    cfe/trunk/test/ARCMT/rewrite-block-var.m
    cfe/trunk/test/ARCMT/rewrite-block-var.m.result
    cfe/trunk/test/ARCMT/safe-arc-assign.m
    cfe/trunk/test/ARCMT/safe-arc-assign.m.result
    cfe/trunk/test/ARCMT/with-working-dir.m
    cfe/trunk/test/ARCMT/with-working-dir.m.result
    cfe/trunk/tools/arcmt-test/
    cfe/trunk/tools/arcmt-test/CMakeLists.txt
    cfe/trunk/tools/arcmt-test/Makefile
    cfe/trunk/tools/arcmt-test/arcmt-test.cpp
Modified:
    cfe/trunk/clang.xcodeproj/project.pbxproj
    cfe/trunk/lib/CMakeLists.txt
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CMakeLists.txt
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Makefile
    cfe/trunk/tools/CMakeLists.txt
    cfe/trunk/tools/Makefile
    cfe/trunk/tools/driver/CMakeLists.txt
    cfe/trunk/tools/driver/Makefile
    cfe/trunk/tools/scan-build/ccc-analyzer
    cfe/trunk/unittests/Frontend/Makefile

Modified: cfe/trunk/clang.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/clang.xcodeproj/project.pbxproj?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/clang.xcodeproj/project.pbxproj (original)
+++ cfe/trunk/clang.xcodeproj/project.pbxproj Wed Jun 15 18:25:17 2011
@@ -373,6 +373,12 @@
 		90FD6D90103C3D80005F5B73 /* TypeXML.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = TypeXML.def; path = clang/Frontend/TypeXML.def; sourceTree = "<group>"; };
 		90FD6D91103C3D80005F5B73 /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = clang/Frontend/Utils.h; sourceTree = "<group>"; };
 		90FD6DB5103D977E005F5B73 /* index-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = "index-test.cpp"; path = "tools/index-test/index-test.cpp"; sourceTree = "<group>"; };
+		BB20603B131EDDBF003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+		BB20603C131EDDBF003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
+		BB206041131EDDDA003C3343 /* ARRMT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARRMT.h; sourceTree = "<group>"; };
+		BB206043131EDE03003C3343 /* arrmt-test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "arrmt-test.cpp"; sourceTree = "<group>"; };
+		BB206044131EDE03003C3343 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+		BB206045131EDE03003C3343 /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
 		BB5C372812A5057500259F53 /* DumpXML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DumpXML.cpp; path = /Volumes/Data/llvm/tools/clang/lib/AST/DumpXML.cpp; sourceTree = "<absolute>"; };
 		BBA5AB141309C2FA000B38F1 /* AdjustedReturnValueChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdjustedReturnValueChecker.cpp; sourceTree = "<group>"; };
 		BBA5AB151309C2FA000B38F1 /* AnalyzerStatsChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AnalyzerStatsChecker.cpp; sourceTree = "<group>"; };
@@ -777,6 +783,7 @@
 		08FB7795FE84155DC02AAC07 /* Libraries */ = {
 			isa = PBXGroup;
 			children = (
+				BB20603A131EDDBF003C3343 /* ARRMigrate */,
 				BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */,
 				57EB5660121B034300ECA335 /* Serialization */,
 				BFE2F67911DA95590007EDC0 /* Rewrite */,
@@ -1105,6 +1112,38 @@
 			name = "index-test";
 			sourceTree = "<group>";
 		};
+		BB20603A131EDDBF003C3343 /* ARRMigrate */ = {
+			isa = PBXGroup;
+			children = (
+				BB20603B131EDDBF003C3343 /* CMakeLists.txt */,
+				BB20603C131EDDBF003C3343 /* Makefile */,
+				BDDF60E91337BF40009F1764 /* Transforms.cpp */,
+			);
+			name = ARRMigrate;
+			path = lib/ARRMigrate;
+			sourceTree = "<group>";
+		};
+		BB206040131EDDDA003C3343 /* ARRMigrate */ = {
+			isa = PBXGroup;
+			children = (
+				BB206041131EDDDA003C3343 /* ARRMT.h */,
+			);
+			name = ARRMigrate;
+			path = clang/ARRMigrate;
+			sourceTree = "<group>";
+		};
+		BB206042131EDE03003C3343 /* arrmt-test */ = {
+			isa = PBXGroup;
+			children = (
+				BD8A47E7133D32660066FE40 /* ARRMT.cpp */,
+				BB206043131EDE03003C3343 /* arrmt-test.cpp */,
+				BB206044131EDE03003C3343 /* CMakeLists.txt */,
+				BB206045131EDE03003C3343 /* Makefile */,
+			);
+			name = "arrmt-test";
+			path = "tools/arrmt-test";
+			sourceTree = "<group>";
+		};
 		BBA5AB121309C2FA000B38F1 /* StaticAnalyzer */ = {
 			isa = PBXGroup;
 			children = (
@@ -1575,6 +1614,7 @@
 		DED7D72E0A524295003AD0FB /* include */ = {
 			isa = PBXGroup;
 			children = (
+				BB206040131EDDDA003C3343 /* ARRMigrate */,
 				DED7D7300A524295003AD0FB /* Basic */,
 				DED7D7390A524295003AD0FB /* Lex */,
 				DE1F21F20A7D84E800FBF588 /* Parse */,
@@ -1724,6 +1764,7 @@
 		DEDFE61F0F7B3AE10035BD10 /* Tools */ = {
 			isa = PBXGroup;
 			children = (
+				BB206042131EDE03003C3343 /* arrmt-test */,
 				90F9EFA8104ABDC400D09A15 /* c-index-test */,
 				9012911E104812DA0083456D /* CIndex */,
 				90FD6DB4103D9763005F5B73 /* index-test */,

Added: cfe/trunk/include/clang/ARCMigrate/ARCMT.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ARCMigrate/ARCMT.h?rev=133104&view=auto
==============================================================================
--- cfe/trunk/include/clang/ARCMigrate/ARCMT.h (added)
+++ cfe/trunk/include/clang/ARCMigrate/ARCMT.h Wed Jun 15 18:25:17 2011
@@ -0,0 +1,83 @@
+//===-- ARCMT.h - ARC Migration Rewriter ------------------------*- 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_ARCMIGRATE_ARCMT_H
+#define LLVM_CLANG_ARCMIGRATE_ARCMT_H
+
+#include "clang/ARCMigrate/FileRemapper.h"
+#include "clang/Frontend/CompilerInvocation.h"
+
+namespace clang {
+  class ASTContext;
+  class DiagnosticClient;
+
+namespace arcmt {
+  class MigrationPass;
+
+/// \brief Creates an AST with the provided CompilerInvocation but with these
+/// changes:
+///   -if a PCH/PTH is set, the original header is used instead
+///   -Automatic Reference Counting mode is enabled
+///
+/// It then checks the AST and produces errors/warning for ARC migration issues
+/// that the user needs to handle manually.
+///
+/// \returns false if no error is produced, true otherwise.
+bool checkForManualIssues(CompilerInvocation &CI,
+                          llvm::StringRef Filename, InputKind Kind,
+                          DiagnosticClient *DiagClient);
+
+/// \brief Works similar to checkForManualIssues but instead of checking, it
+/// applies automatic modifications to source files to conform to ARC.
+///
+/// \returns false if no error is produced, true otherwise.
+bool applyTransformations(CompilerInvocation &origCI,
+                          llvm::StringRef Filename, InputKind Kind,
+                          DiagnosticClient *DiagClient);
+
+/// \brief Like applyTransformations but no source file is modified, compilation
+/// happens using in-memory buffers.
+bool applyTransformationsInMemory(CompilerInvocation &origCI,
+                                  llvm::StringRef Filename, InputKind Kind,
+                                  DiagnosticClient *DiagClient);
+
+typedef void (*TransformFn)(MigrationPass &pass);
+
+std::vector<TransformFn> getAllTransformations();
+
+class MigrationProcess {
+  CompilerInvocation OrigCI;
+  DiagnosticClient *DiagClient;
+  FileRemapper Remapper;
+
+public:
+  MigrationProcess(const CompilerInvocation &CI, DiagnosticClient *diagClient)
+    : OrigCI(CI), DiagClient(diagClient) { }
+
+  class RewriteListener {
+  public:
+    virtual ~RewriteListener();
+
+    virtual void start(ASTContext &Ctx) { }
+    virtual void finish() { }
+
+    virtual void insert(SourceLocation loc, llvm::StringRef text) { }
+    virtual void remove(CharSourceRange range) { }
+  };
+
+  bool applyTransform(TransformFn trans, RewriteListener *listener = 0);
+
+  FileRemapper &getRemapper() { return Remapper; }
+};
+
+} // end namespace arcmt
+
+}  // end namespace clang
+
+#endif

Added: cfe/trunk/include/clang/ARCMigrate/FileRemapper.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ARCMigrate/FileRemapper.h?rev=133104&view=auto
==============================================================================
--- cfe/trunk/include/clang/ARCMigrate/FileRemapper.h (added)
+++ cfe/trunk/include/clang/ARCMigrate/FileRemapper.h Wed Jun 15 18:25:17 2011
@@ -0,0 +1,76 @@
+//===-- FileRemapper.h - File Remapping Helper ------------------*- 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_ARCMIGRATE_FILEREMAPPER_H
+#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
+
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+  class MemoryBuffer;
+}
+
+namespace clang {
+  class FileManager;
+  class FileEntry;
+  class Diagnostic;
+  class CompilerInvocation;
+
+namespace arcmt {
+
+class FileRemapper {
+  // FIXME: Reuse the same FileManager for multiple ASTContexts.
+  llvm::OwningPtr<FileManager> FileMgr;
+
+  typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target;
+  typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy;
+  MappingsTy FromToMappings;
+
+  llvm::DenseMap<const FileEntry *, const FileEntry *> ToFromMappings;
+
+public:
+  FileRemapper();
+  ~FileRemapper();
+  
+  bool initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
+                    bool ignoreIfFilesChanged);
+  bool flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag);
+
+  bool overwriteOriginal(Diagnostic &Diag,
+                         llvm::StringRef outputDir = llvm::StringRef());
+
+  void remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf);
+  void remap(llvm::StringRef filePath, llvm::StringRef newPath);
+
+  void applyMappings(CompilerInvocation &CI) const;
+
+  void transferMappingsAndClear(CompilerInvocation &CI);
+
+  void clear(llvm::StringRef outputDir = llvm::StringRef());
+
+private:
+  void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf);
+  void remap(const FileEntry *file, const FileEntry *newfile);
+
+  const FileEntry *getOriginalFile(llvm::StringRef filePath);
+  void resetTarget(Target &targ);
+
+  bool report(const std::string &err, Diagnostic &Diag);
+
+  std::string getRemapInfoFile(llvm::StringRef outputDir);
+};
+
+} // end namespace arcmt
+
+}  // end namespace clang
+
+#endif

Added: cfe/trunk/lib/ARCMigrate/ARCMT.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/ARCMT.cpp?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/ARCMT.cpp (added)
+++ cfe/trunk/lib/ARCMigrate/ARCMT.cpp Wed Jun 15 18:25:17 2011
@@ -0,0 +1,484 @@
+//===--- ARCMT.cpp - Migration 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 "Internals.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Basic/DiagnosticCategories.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/ADT/Triple.h"
+
+using namespace clang;
+using namespace arcmt;
+using llvm::StringRef;
+
+bool CapturedDiagList::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+                                       SourceRange range) {
+  if (range.isInvalid())
+    return false;
+
+  bool cleared = false;
+  ListTy::iterator I = List.begin();
+  while (I != List.end()) {
+    FullSourceLoc diagLoc = I->getLocation();
+    if ((IDs.empty() || // empty means clear all diagnostics in the range.
+         std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
+        !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
+        (diagLoc == range.getEnd() ||
+           diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
+      cleared = true;
+      ListTy::iterator eraseS = I++;
+      while (I != List.end() && I->getLevel() == Diagnostic::Note)
+        ++I;
+      // Clear the diagnostic and any notes following it.
+      List.erase(eraseS, I);
+      continue;
+    }
+
+    ++I;
+  }
+
+  return cleared;
+}
+
+bool CapturedDiagList::hasDiagnostic(llvm::ArrayRef<unsigned> IDs,
+                                     SourceRange range) {
+  if (range.isInvalid())
+    return false;
+
+  ListTy::iterator I = List.begin();
+  while (I != List.end()) {
+    FullSourceLoc diagLoc = I->getLocation();
+    if ((IDs.empty() || // empty means any diagnostic in the range.
+         std::find(IDs.begin(), IDs.end(), I->getID()) != IDs.end()) &&
+        !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) &&
+        (diagLoc == range.getEnd() ||
+           diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
+      return true;
+    }
+
+    ++I;
+  }
+
+  return false;
+}
+
+void CapturedDiagList::reportDiagnostics(Diagnostic &Diags) {
+  for (ListTy::iterator I = List.begin(), E = List.end(); I != E; ++I)
+    Diags.Report(*I);
+}
+
+namespace {
+
+class CaptureDiagnosticClient : public DiagnosticClient {
+  Diagnostic &Diags;
+  CapturedDiagList &CapturedDiags;
+public:
+  CaptureDiagnosticClient(Diagnostic &diags,
+                          CapturedDiagList &capturedDiags)
+    : Diags(diags), CapturedDiags(capturedDiags) { }
+
+  virtual void HandleDiagnostic(Diagnostic::Level level,
+                                const DiagnosticInfo &Info) {
+    if (arcmt::isARCDiagnostic(Info.getID(), Diags) ||
+        level >= Diagnostic::Error || level == Diagnostic::Note) {
+      CapturedDiags.push_back(StoredDiagnostic(level, Info));
+      return;
+    }
+
+    // Non-ARC warnings are ignored.
+    Diags.setLastDiagnosticIgnored();
+  }
+};
+
+} // end anonymous namespace
+
+CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) {
+  llvm::OwningPtr<CompilerInvocation> CInvok;
+  CInvok.reset(new CompilerInvocation(origCI));
+  CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string();
+  CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string();
+  std::string define = getARCMTMacroName();
+  define += '=';
+  CInvok->getPreprocessorOpts().addMacroDef(define);
+  CInvok->getLangOpts().ObjCAutoRefCount = true;
+  CInvok->getDiagnosticOpts().ErrorLimit = 0;
+  
+  // FIXME: Hackety hack! Try to find out if there is an ARC runtime.
+  bool hasARCRuntime = false;
+  llvm::SmallVector<std::string, 16> args;
+  args.push_back("-x");
+  args.push_back("objective-c");
+  args.push_back("-fobjc-arc");
+
+  llvm::Triple triple(CInvok->getTargetOpts().Triple);
+  if (triple.getOS() == llvm::Triple::IOS ||
+      triple.getOS() == llvm::Triple::MacOSX) {
+    unsigned Major, Minor, Micro;
+    triple.getOSVersion(Major, Minor, Micro);
+    llvm::SmallString<100> flag;
+    if (triple.getOS() == llvm::Triple::IOS)
+      flag += "-miphoneos-version-min=";
+    else
+      flag += "-mmacosx-version-min=";
+    llvm::raw_svector_ostream(flag) << Major << '.' << Minor << '.' << Micro;
+    args.push_back(flag.str());
+  }
+
+  args.push_back(origCI.getFrontendOpts().Inputs[0].second.c_str());
+  // Also push all defines to deal with the iOS simulator hack.
+  for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size();
+         i != e; ++i) {
+    std::string &def = origCI.getPreprocessorOpts().Macros[i].first;
+    bool isUndef = origCI.getPreprocessorOpts().Macros[i].second;
+    if (!isUndef) {
+      std::string newdef = "-D";
+      newdef += def;
+      args.push_back(newdef);
+    }
+  }
+
+  llvm::SmallVector<const char *, 16> cargs;
+  for (unsigned i = 0, e = args.size(); i != e; ++i)
+    cargs.push_back(args[i].c_str());
+
+  llvm::OwningPtr<CompilerInvocation> checkCI;
+  checkCI.reset(clang::createInvocationFromCommandLine(cargs));
+  if (checkCI)
+    hasARCRuntime = !checkCI->getLangOpts().ObjCNoAutoRefCountRuntime;
+
+  CInvok->getLangOpts().ObjCNoAutoRefCountRuntime = !hasARCRuntime;
+
+  return CInvok.take();
+}
+
+//===----------------------------------------------------------------------===//
+// checkForManualIssues.
+//===----------------------------------------------------------------------===//
+
+bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
+                                 llvm::StringRef Filename, InputKind Kind,
+                                 DiagnosticClient *DiagClient) {
+  if (!origCI.getLangOpts().ObjC1)
+    return false;
+
+  std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+  assert(!transforms.empty());
+
+  llvm::OwningPtr<CompilerInvocation> CInvok;
+  CInvok.reset(createInvocationForMigration(origCI));
+  CInvok->getFrontendOpts().Inputs.clear();
+  CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
+
+  CapturedDiagList capturedDiags;
+
+  assert(DiagClient);
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+                 new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+
+  // Filter of all diagnostics.
+  CaptureDiagnosticClient errRec(*Diags, capturedDiags);
+  Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
+
+  llvm::OwningPtr<ASTUnit> Unit(
+      ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags));
+  if (!Unit)
+    return true;
+
+  // Don't filter diagnostics anymore.
+  Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
+
+  ASTContext &Ctx = Unit->getASTContext();
+
+  if (Diags->hasFatalErrorOccurred()) {
+    Diags->Reset();
+    DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+    capturedDiags.reportDiagnostics(*Diags);
+    DiagClient->EndSourceFile();
+    return true;
+  }
+
+  // After parsing of source files ended, we want to reuse the
+  // diagnostics objects to emit further diagnostics.
+  // We call BeginSourceFile because DiagnosticClient requires that 
+  // diagnostics with source range information are emitted only in between
+  // BeginSourceFile() and EndSourceFile().
+  DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+
+  // No macros will be added since we are just checking and we won't modify
+  // source code.
+  std::vector<SourceLocation> ARCMTMacroLocs;
+
+  TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
+  MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs);
+
+  for (unsigned i=0, e = transforms.size(); i != e; ++i)
+    transforms[i](pass);
+
+  capturedDiags.reportDiagnostics(*Diags);
+
+  DiagClient->EndSourceFile();
+
+  return Diags->getClient()->getNumErrors() > 0;
+}
+
+//===----------------------------------------------------------------------===//
+// applyTransformations.
+//===----------------------------------------------------------------------===//
+
+bool arcmt::applyTransformations(CompilerInvocation &origCI,
+                                 llvm::StringRef Filename, InputKind Kind,
+                                 DiagnosticClient *DiagClient) {
+  if (!origCI.getLangOpts().ObjC1)
+    return false;
+
+  // Make sure checking is successful first.
+  CompilerInvocation CInvokForCheck(origCI);
+  if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient))
+    return true;
+
+  CompilerInvocation CInvok(origCI);
+  CInvok.getFrontendOpts().Inputs.clear();
+  CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
+  
+  MigrationProcess migration(CInvok, DiagClient);
+
+  std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+  assert(!transforms.empty());
+
+  for (unsigned i=0, e = transforms.size(); i != e; ++i) {
+    bool err = migration.applyTransform(transforms[i]);
+    if (err) return true;
+  }
+
+  origCI.getLangOpts().ObjCAutoRefCount = true;
+
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+                 new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+  return migration.getRemapper().overwriteOriginal(*Diags);
+}
+
+//===----------------------------------------------------------------------===//
+// applyTransformationsInMemory.
+//===----------------------------------------------------------------------===//
+
+bool arcmt::applyTransformationsInMemory(CompilerInvocation &origCI,
+                                       llvm::StringRef Filename, InputKind Kind,
+                                       DiagnosticClient *DiagClient) {
+  if (!origCI.getLangOpts().ObjC1)
+    return false;
+
+  // Make sure checking is successful first.
+  CompilerInvocation CInvokForCheck(origCI);
+  if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient))
+    return true;
+
+  CompilerInvocation CInvok(origCI);
+  CInvok.getFrontendOpts().Inputs.clear();
+  CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename));
+  
+  MigrationProcess migration(CInvok, DiagClient);
+
+  std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+  assert(!transforms.empty());
+
+  for (unsigned i=0, e = transforms.size(); i != e; ++i) {
+    bool err = migration.applyTransform(transforms[i]);
+    if (err) return true;
+  }
+
+  origCI.getLangOpts().ObjCAutoRefCount = true;
+  migration.getRemapper().transferMappingsAndClear(origCI);
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// CollectTransformActions.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
+  std::vector<SourceLocation> &ARCMTMacroLocs;
+
+public:
+  ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
+    : ARCMTMacroLocs(ARCMTMacroLocs) { }
+
+  virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI) {
+    if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
+      ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
+  }
+};
+
+class ARCMTMacroTrackerAction : public ASTFrontendAction {
+  std::vector<SourceLocation> &ARCMTMacroLocs;
+
+public:
+  ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs)
+    : ARCMTMacroLocs(ARCMTMacroLocs) { }
+
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile) {
+    CI.getPreprocessor().addPPCallbacks(
+                              new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs));
+    return new ASTConsumer();
+  }
+};
+
+class RewritesApplicator : public TransformActions::RewriteReceiver {
+  Rewriter &rewriter;
+  ASTContext &Ctx;
+  MigrationProcess::RewriteListener *Listener;
+
+public:
+  RewritesApplicator(Rewriter &rewriter, ASTContext &ctx,
+                     MigrationProcess::RewriteListener *listener)
+    : rewriter(rewriter), Ctx(ctx), Listener(listener) {
+    if (Listener)
+      Listener->start(ctx);
+  }
+  ~RewritesApplicator() {
+    if (Listener)
+      Listener->finish();
+  }
+
+  virtual void insert(SourceLocation loc, llvm::StringRef text) {
+    bool err = rewriter.InsertText(loc, text, /*InsertAfter=*/true,
+                                   /*indentNewLines=*/true);
+    if (!err && Listener)
+      Listener->insert(loc, text);
+  }
+
+  virtual void remove(CharSourceRange range) {
+    Rewriter::RewriteOptions removeOpts;
+    removeOpts.IncludeInsertsAtBeginOfRange = false;
+    removeOpts.IncludeInsertsAtEndOfRange = false;
+    removeOpts.RemoveLineIfEmpty = true;
+
+    bool err = rewriter.RemoveText(range, removeOpts);
+    if (!err && Listener)
+      Listener->remove(range);
+  }
+
+  virtual void increaseIndentation(CharSourceRange range,
+                                    SourceLocation parentIndent) {
+    rewriter.IncreaseIndentation(range, parentIndent);
+  }
+};
+
+} // end anonymous namespace.
+
+/// \brief Anchor for VTable.
+MigrationProcess::RewriteListener::~RewriteListener() { }
+
+bool MigrationProcess::applyTransform(TransformFn trans,
+                                      RewriteListener *listener) {
+  llvm::OwningPtr<CompilerInvocation> CInvok;
+  CInvok.reset(createInvocationForMigration(OrigCI));
+  CInvok->getDiagnosticOpts().IgnoreWarnings = true;
+
+  Remapper.applyMappings(*CInvok);
+
+  CapturedDiagList capturedDiags;
+  std::vector<SourceLocation> ARCMTMacroLocs;
+
+  assert(DiagClient);
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
+               new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+
+  // Filter of all diagnostics.
+  CaptureDiagnosticClient errRec(*Diags, capturedDiags);
+  Diags->setClient(&errRec, /*ShouldOwnClient=*/false);
+
+  llvm::OwningPtr<ARCMTMacroTrackerAction> ASTAction;
+  ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
+
+  llvm::OwningPtr<ASTUnit> Unit(
+      ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags,
+                                                ASTAction.get()));
+  if (!Unit)
+    return true;
+  Unit->setOwnsRemappedFileBuffers(false); // FileRemapper manages that.
+
+  // Don't filter diagnostics anymore.
+  Diags->setClient(DiagClient, /*ShouldOwnClient=*/false);
+
+  ASTContext &Ctx = Unit->getASTContext();
+
+  if (Diags->hasFatalErrorOccurred()) {
+    Diags->Reset();
+    DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+    capturedDiags.reportDiagnostics(*Diags);
+    DiagClient->EndSourceFile();
+    return true;
+  }
+
+  // After parsing of source files ended, we want to reuse the
+  // diagnostics objects to emit further diagnostics.
+  // We call BeginSourceFile because DiagnosticClient requires that 
+  // diagnostics with source range information are emitted only in between
+  // BeginSourceFile() and EndSourceFile().
+  DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor());
+
+  Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions());
+  TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
+  MigrationPass pass(Ctx, Unit->getSema(), TA, ARCMTMacroLocs);
+
+  trans(pass);
+
+  {
+    RewritesApplicator applicator(rewriter, Ctx, listener);
+    TA.applyRewrites(applicator);
+  }
+
+  DiagClient->EndSourceFile();
+
+  if (DiagClient->getNumErrors())
+    return true;
+
+  for (Rewriter::buffer_iterator
+        I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
+    FileID FID = I->first;
+    RewriteBuffer &buf = I->second;
+    const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
+    assert(file);
+    std::string newFname = file->getName();
+    newFname += "-trans";
+    llvm::SmallString<512> newText;
+    llvm::raw_svector_ostream vecOS(newText);
+    buf.write(vecOS);
+    vecOS.flush();
+    llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
+                   llvm::StringRef(newText.data(), newText.size()), newFname);
+    llvm::SmallString<64> filePath(file->getName());
+    Unit->getFileManager().FixupRelativePath(filePath);
+    Remapper.remap(filePath.str(), memBuf);
+  }
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// isARCDiagnostic.
+//===----------------------------------------------------------------------===//
+
+bool arcmt::isARCDiagnostic(unsigned diagID, Diagnostic &Diag) {
+  return Diag.getDiagnosticIDs()->getCategoryNumberForDiag(diagID) ==
+           diag::DiagCat_Automatic_Reference_Counting_Issue;
+}

Added: cfe/trunk/lib/ARCMigrate/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/CMakeLists.txt?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/CMakeLists.txt (added)
+++ cfe/trunk/lib/ARCMigrate/CMakeLists.txt Wed Jun 15 18:25:17 2011
@@ -0,0 +1,14 @@
+set(LLVM_USED_LIBS clangBasic clangAST clangParse clangFrontend clangRewrite)
+
+add_clang_library(clangARCMigrate
+  ARCMT.cpp
+  FileRemapper.cpp
+  TransformActions.cpp
+  Transforms.cpp
+  )
+
+add_dependencies(clangARCMigrate
+  ClangAttrClasses
+  ClangAttrList
+  ClangDeclNodes
+  ClangStmtNodes)

Added: cfe/trunk/lib/ARCMigrate/FileRemapper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/FileRemapper.cpp?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/FileRemapper.cpp (added)
+++ cfe/trunk/lib/ARCMigrate/FileRemapper.cpp Wed Jun 15 18:25:17 2011
@@ -0,0 +1,290 @@
+//===--- FileRemapper.cpp - File Remapping Helper -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ARCMigrate/FileRemapper.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+
+using namespace clang;
+using namespace arcmt;
+
+FileRemapper::FileRemapper() {
+  FileMgr.reset(new FileManager(FileSystemOptions()));
+}
+
+FileRemapper::~FileRemapper() {
+  clear();
+}
+
+void FileRemapper::clear(llvm::StringRef outputDir) {
+  for (MappingsTy::iterator
+         I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I)
+    resetTarget(I->second);
+  FromToMappings.clear();
+  assert(ToFromMappings.empty());
+  if (!outputDir.empty()) {
+    std::string infoFile = getRemapInfoFile(outputDir);
+    bool existed;
+    llvm::sys::fs::remove(infoFile, existed);
+  }
+}
+
+std::string FileRemapper::getRemapInfoFile(llvm::StringRef outputDir) {
+  assert(!outputDir.empty());
+  llvm::sys::Path dir(outputDir);
+  llvm::sys::Path infoFile = dir;
+  infoFile.appendComponent("remap");
+  return infoFile.str();
+}
+
+bool FileRemapper::initFromDisk(llvm::StringRef outputDir, Diagnostic &Diag,
+                                bool ignoreIfFilesChanged) {
+  assert(FromToMappings.empty() &&
+         "initFromDisk should be called before any remap calls");
+  std::string infoFile = getRemapInfoFile(outputDir);
+  bool fileExists = false;
+  llvm::sys::fs::exists(infoFile, fileExists);
+  if (!fileExists)
+    return false;
+
+  std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs;
+
+  std::ifstream fin(infoFile.c_str());
+  if (!fin.good())
+    return report(std::string("Error opening file: ") + infoFile, Diag);
+
+  while (true) {
+    std::string fromFilename, toFilename;
+    uint64_t timeModified;
+
+    fin >> fromFilename >> timeModified >> toFilename;
+    if (fin.eof())
+      break;
+    if (!fin.good()) {
+      if (ignoreIfFilesChanged)
+        return false;
+      return report(std::string("Error in format of file: ") + infoFile, Diag);
+    }
+
+    const FileEntry *origFE = FileMgr->getFile(fromFilename);
+    if (!origFE) {
+      if (ignoreIfFilesChanged)
+        continue;
+      return report(std::string("File does not exist: ") + fromFilename, Diag);
+    }
+    const FileEntry *newFE = FileMgr->getFile(toFilename);
+    if (!newFE) {
+      if (ignoreIfFilesChanged)
+        continue;
+      return report(std::string("File does not exist: ") + toFilename, Diag);
+    }
+
+    if ((uint64_t)origFE->getModificationTime() != timeModified) {
+      if (ignoreIfFilesChanged)
+        continue;
+      return report(std::string("File was modified: ") + fromFilename, Diag);
+    }
+
+    pairs.push_back(std::make_pair(origFE, newFE));
+  }
+
+  for (unsigned i = 0, e = pairs.size(); i != e; ++i)
+    remap(pairs[i].first, pairs[i].second);
+
+  return false;
+}
+
+bool FileRemapper::flushToDisk(llvm::StringRef outputDir, Diagnostic &Diag) {
+  using namespace llvm::sys;
+
+  bool existed;
+  if (fs::create_directory(outputDir, existed) != llvm::errc::success)
+    return report(std::string("Could not create directory: ") + outputDir.str(),
+                  Diag);
+
+  std::string errMsg;
+  std::string infoFile = getRemapInfoFile(outputDir);
+  llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
+                               llvm::raw_fd_ostream::F_Binary);
+  if (!errMsg.empty() || infoOut.has_error())
+    return report(errMsg, Diag);
+
+  for (MappingsTy::iterator
+         I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
+
+    const FileEntry *origFE = I->first;
+    infoOut << origFE->getName() << '\n';
+    infoOut << (uint64_t)origFE->getModificationTime() << '\n';
+
+    if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
+      infoOut << FE->getName() << '\n';
+    } else {
+
+      llvm::SmallString<64> tempPath;
+      tempPath = path::filename(origFE->getName());
+      tempPath += "-%%%%%%%%";
+      tempPath += path::extension(origFE->getName());
+      int fd;
+      if (fs::unique_file(tempPath.str(), fd, tempPath) != llvm::errc::success)
+        return report(std::string("Could not create file: ") + tempPath.c_str(),
+                      Diag);
+
+      llvm::raw_fd_ostream newOut(fd, /*shouldClose=*/true);
+      llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+      newOut.write(mem->getBufferStart(), mem->getBufferSize());
+      newOut.close();
+      
+      const FileEntry *newE = FileMgr->getFile(tempPath);
+      remap(origFE, newE);
+      infoOut << newE->getName() << '\n';
+    }
+  }
+
+  infoOut.close();
+  return false;
+}
+
+bool FileRemapper::overwriteOriginal(Diagnostic &Diag,
+                                     llvm::StringRef outputDir) {
+  using namespace llvm::sys;
+
+  for (MappingsTy::iterator
+         I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
+    const FileEntry *origFE = I->first;
+    if (const FileEntry *newFE = I->second.dyn_cast<const FileEntry *>()) {
+      if (fs::copy_file(newFE->getName(), origFE->getName(),
+                 fs::copy_option::overwrite_if_exists) != llvm::errc::success) {
+        std::string err = "Could not copy file '";
+        llvm::raw_string_ostream os(err);
+        os << "Could not copy file '" << newFE->getName() << "' to file '"
+           << origFE->getName() << "'";
+        os.flush();
+        return report(err, Diag);
+      }
+    } else {
+
+      bool fileExists = false;
+      fs::exists(origFE->getName(), fileExists);
+      if (!fileExists)
+        return report(std::string("File does not exist: ") + origFE->getName(),
+                      Diag);
+
+      std::string errMsg;
+      llvm::raw_fd_ostream Out(origFE->getName(), errMsg,
+                               llvm::raw_fd_ostream::F_Binary);
+      if (!errMsg.empty() || Out.has_error())
+        return report(errMsg, Diag);
+
+      llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+      Out.write(mem->getBufferStart(), mem->getBufferSize());
+      Out.close();
+    }
+  }
+
+  clear(outputDir);
+  return false;
+}
+
+void FileRemapper::applyMappings(CompilerInvocation &CI) const {
+  PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+  for (MappingsTy::const_iterator
+         I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
+    if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
+      PPOpts.addRemappedFile(I->first->getName(), FE->getName());
+    } else {
+      llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+      PPOpts.addRemappedFile(I->first->getName(), mem);
+    }
+  }
+
+  PPOpts.RetainRemappedFileBuffers = true;
+}
+
+void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) {
+  PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+  for (MappingsTy::iterator
+         I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
+    if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
+      PPOpts.addRemappedFile(I->first->getName(), FE->getName());
+    } else {
+      llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>();
+      PPOpts.addRemappedFile(I->first->getName(), mem);
+    }
+    I->second = Target();
+  }
+
+  PPOpts.RetainRemappedFileBuffers = false;
+  clear();
+}
+
+void FileRemapper::remap(llvm::StringRef filePath, llvm::MemoryBuffer *memBuf) {
+  remap(getOriginalFile(filePath), memBuf);
+}
+
+void FileRemapper::remap(llvm::StringRef filePath, llvm::StringRef newPath) {
+  const FileEntry *file = getOriginalFile(filePath);
+  const FileEntry *newfile = FileMgr->getFile(newPath);
+  remap(file, newfile);
+}
+
+void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) {
+  assert(file);
+  Target &targ = FromToMappings[file];
+  resetTarget(targ);
+  targ = memBuf;
+}
+
+void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) {
+  assert(file && newfile);
+  Target &targ = FromToMappings[file];
+  resetTarget(targ);
+  targ = newfile;
+  ToFromMappings[newfile] = file;
+}
+
+const FileEntry *FileRemapper::getOriginalFile(llvm::StringRef filePath) {
+  const FileEntry *file = FileMgr->getFile(filePath);
+  // If we are updating a file that overriden an original file,
+  // actually update the original file.
+  llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
+    I = ToFromMappings.find(file);
+  if (I != ToFromMappings.end()) {
+    file = I->second;
+    assert(FromToMappings.find(file) != FromToMappings.end() &&
+           "Original file not in mappings!");
+  }
+  return file;
+}
+
+void FileRemapper::resetTarget(Target &targ) {
+  if (!targ)
+    return;
+
+  if (llvm::MemoryBuffer *oldmem = targ.dyn_cast<llvm::MemoryBuffer *>()) {
+    delete oldmem;
+  } else {
+    const FileEntry *toFE = targ.get<const FileEntry *>();
+    llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator
+      I = ToFromMappings.find(toFE);
+    if (I != ToFromMappings.end())
+      ToFromMappings.erase(I);
+  }
+}
+
+bool FileRemapper::report(const std::string &err, Diagnostic &Diag) {
+  unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
+                                                         err);
+  Diag.Report(ID);
+  return true;
+}

Added: cfe/trunk/lib/ARCMigrate/Internals.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Internals.h?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Internals.h (added)
+++ cfe/trunk/lib/ARCMigrate/Internals.h Wed Jun 15 18:25:17 2011
@@ -0,0 +1,146 @@
+//===-- Internals.h - Implementation Details---------------------*- 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_INTERNALS_H
+#define LLVM_CLANG_LIB_ARCMIGRATE_INTERNALS_H
+
+#include "clang/ARCMigrate/ARCMT.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace clang {
+  class Sema;
+  class Stmt;
+
+namespace arcmt {
+
+class CapturedDiagList {
+  typedef std::list<StoredDiagnostic> ListTy;
+  ListTy List;
+  
+public:
+  void push_back(const StoredDiagnostic &diag) { List.push_back(diag); }
+
+  bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+  bool hasDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+
+  void reportDiagnostics(Diagnostic &diags);
+};
+
+class TransformActions {
+  Diagnostic &Diags;
+  CapturedDiagList &CapturedDiags;
+  void *Impl; // TransformActionsImpl.
+
+public:
+  TransformActions(Diagnostic &diag, CapturedDiagList &capturedDiags,
+                   ASTContext &ctx, Preprocessor &PP);
+  ~TransformActions();
+
+  void startTransaction();
+  bool commitTransaction();
+  void abortTransaction();
+
+  void insert(SourceLocation loc, llvm::StringRef text);
+  void insertAfterToken(SourceLocation loc, llvm::StringRef text);
+  void remove(SourceRange range);
+  void removeStmt(Stmt *S);
+  void replace(SourceRange range, llvm::StringRef text);
+  void replace(SourceRange range, SourceRange replacementRange);
+  void replaceStmt(Stmt *S, llvm::StringRef text);
+  void replaceText(SourceLocation loc, llvm::StringRef text,
+                   llvm::StringRef replacementText);
+  void increaseIndentation(SourceRange range,
+                           SourceLocation parentIndent);
+
+  bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+  bool clearAllDiagnostics(SourceRange range) {
+    return clearDiagnostic(llvm::ArrayRef<unsigned>(), range);
+  }
+  bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) {
+    unsigned IDs[] = { ID1, ID2 };
+    return clearDiagnostic(IDs, range);
+  }
+  bool clearDiagnostic(unsigned ID1, unsigned ID2, unsigned ID3,
+                       SourceRange range) {
+    unsigned IDs[] = { ID1, ID2, ID3 };
+    return clearDiagnostic(IDs, range);
+  }
+
+  bool hasDiagnostic(unsigned ID, SourceRange range) {
+    return CapturedDiags.hasDiagnostic(ID, range);
+  }
+
+  bool hasDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) {
+    unsigned IDs[] = { ID1, ID2 };
+    return CapturedDiags.hasDiagnostic(IDs, range);
+  }
+
+  void reportError(llvm::StringRef error, SourceLocation loc,
+                   SourceRange range = SourceRange());
+  void reportNote(llvm::StringRef note, SourceLocation loc,
+                  SourceRange range = SourceRange());
+
+  class RewriteReceiver {
+  public:
+    virtual ~RewriteReceiver();
+
+    virtual void insert(SourceLocation loc, llvm::StringRef text) = 0;
+    virtual void remove(CharSourceRange range) = 0;
+    virtual void increaseIndentation(CharSourceRange range,
+                                     SourceLocation parentIndent) = 0;
+  };
+
+  void applyRewrites(RewriteReceiver &receiver);
+};
+
+class Transaction {
+  TransformActions &TA;
+  bool Aborted;
+
+public:
+  Transaction(TransformActions &TA) : TA(TA), Aborted(false) {
+    TA.startTransaction();
+  }
+
+  ~Transaction() {
+    if (!isAborted())
+      TA.commitTransaction();
+  }
+
+  void abort() {
+    TA.abortTransaction();
+    Aborted = true;
+  }
+
+  bool isAborted() const { return Aborted; }
+};
+
+class MigrationPass {
+public:
+  ASTContext &Ctx;
+  Sema &SemaRef;
+  TransformActions &TA;
+  std::vector<SourceLocation> &ARCMTMacroLocs;
+
+  MigrationPass(ASTContext &Ctx, Sema &sema, TransformActions &TA,
+                std::vector<SourceLocation> &ARCMTMacroLocs)
+    : Ctx(Ctx), SemaRef(sema), TA(TA), ARCMTMacroLocs(ARCMTMacroLocs) { }
+};
+
+bool isARCDiagnostic(unsigned diagID, Diagnostic &Diag);
+
+static inline llvm::StringRef getARCMTMacroName() {
+  return "__IMPL_ARCMT_REMOVED_EXPR__";
+}
+
+} // end namespace arcmt
+
+} // end namespace clang
+
+#endif

Added: cfe/trunk/lib/ARCMigrate/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Makefile?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Makefile (added)
+++ cfe/trunk/lib/ARCMigrate/Makefile Wed Jun 15 18:25:17 2011
@@ -0,0 +1,18 @@
+##===- clang/lib/ARCMigrate/Makefile --------------------------*- Makefile -*-===##
+# 
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 
+##===----------------------------------------------------------------------===##
+#
+# This implements code transformation to ARC mode.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangARCMigrate
+
+include $(CLANG_LEVEL)/Makefile
+

Added: cfe/trunk/lib/ARCMigrate/TransformActions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/TransformActions.cpp?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/TransformActions.cpp (added)
+++ cfe/trunk/lib/ARCMigrate/TransformActions.cpp Wed Jun 15 18:25:17 2011
@@ -0,0 +1,699 @@
+//===--- ARCMT.cpp - Migration 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 "Internals.h"
+#include "clang/AST/Expr.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/DenseSet.h"
+#include <map>
+
+using namespace clang;
+using namespace arcmt;
+using llvm::StringRef;
+
+namespace {
+
+/// \brief Collects transformations and merges them before applying them with
+/// with applyRewrites(). E.g. if the same source range
+/// is requested to be removed twice, only one rewriter remove will be invoked.
+/// Rewrites happen in "transactions"; if one rewrite in the transaction cannot
+/// be done (e.g. it resides in a macro) all rewrites in the transaction are
+/// aborted.
+/// FIXME: "Transactional" rewrites support should be baked in the Rewriter.
+class TransformActionsImpl {
+  CapturedDiagList &CapturedDiags;
+  ASTContext &Ctx;
+  Preprocessor &PP;
+
+  bool IsInTransaction;
+
+  enum ActionKind {
+    Act_Insert, Act_InsertAfterToken,
+    Act_Remove, Act_RemoveStmt,
+    Act_Replace, Act_ReplaceText,
+    Act_IncreaseIndentation,
+    Act_ClearDiagnostic
+  };
+
+  struct ActionData {
+    ActionKind Kind;
+    SourceLocation Loc;
+    SourceRange R1, R2;
+    llvm::StringRef Text1, Text2;
+    Stmt *S;
+    llvm::SmallVector<unsigned, 2> DiagIDs;
+  };
+
+  std::vector<ActionData> CachedActions;
+
+  enum RangeComparison {
+    Range_Before,
+    Range_After,
+    Range_Contains,
+    Range_Contained,
+    Range_ExtendsBegin,
+    Range_ExtendsEnd
+  };
+
+  /// \brief A range to remove. It is a character range.
+  struct CharRange {
+    FullSourceLoc Begin, End;
+
+    CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) {
+      SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd();
+      assert(beginLoc.isValid() && endLoc.isValid());
+      if (range.isTokenRange()) {
+        Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr);
+        End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr);
+      } else {
+        Begin = FullSourceLoc(srcMgr.getInstantiationLoc(beginLoc), srcMgr);
+        End = FullSourceLoc(srcMgr.getInstantiationLoc(endLoc), srcMgr);
+      }
+      assert(Begin.isValid() && End.isValid());
+    } 
+
+    RangeComparison compareWith(const CharRange &RHS) const {
+      if (End.isBeforeInTranslationUnitThan(RHS.Begin))
+        return Range_Before;
+      if (RHS.End.isBeforeInTranslationUnitThan(Begin))
+        return Range_After;
+      if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&
+          !RHS.End.isBeforeInTranslationUnitThan(End))
+        return Range_Contained;
+      if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) &&
+          RHS.End.isBeforeInTranslationUnitThan(End))
+        return Range_Contains;
+      if (Begin.isBeforeInTranslationUnitThan(RHS.Begin))
+        return Range_ExtendsBegin;
+      else
+        return Range_ExtendsEnd;
+    }
+    
+    static RangeComparison compare(SourceRange LHS, SourceRange RHS,
+                                   SourceManager &SrcMgr, Preprocessor &PP) {
+      return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP)
+                  .compareWith(CharRange(CharSourceRange::getTokenRange(RHS),
+                                            SrcMgr, PP));
+    }
+  };
+
+  typedef llvm::SmallVector<StringRef, 2> TextsVec;
+  typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare>
+      InsertsMap;
+  InsertsMap Inserts;
+  /// \brief A list of ranges to remove. They are always sorted and they never
+  /// intersect with each other.
+  std::list<CharRange> Removals;
+
+  llvm::DenseSet<Stmt *> StmtRemovals;
+
+  std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges;
+
+  /// \brief Keeps text passed to transformation methods.
+  llvm::StringMap<bool> UniqueText;
+
+public:
+  TransformActionsImpl(CapturedDiagList &capturedDiags,
+                       ASTContext &ctx, Preprocessor &PP)
+    : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { }
+
+  void startTransaction();
+  bool commitTransaction();
+  void abortTransaction();
+
+  bool isInTransaction() const { return IsInTransaction; }
+
+  void insert(SourceLocation loc, llvm::StringRef text);
+  void insertAfterToken(SourceLocation loc, llvm::StringRef text);
+  void remove(SourceRange range);
+  void removeStmt(Stmt *S);
+  void replace(SourceRange range, llvm::StringRef text);
+  void replace(SourceRange range, SourceRange replacementRange);
+  void replaceStmt(Stmt *S, llvm::StringRef text);
+  void replaceText(SourceLocation loc, llvm::StringRef text,
+                   llvm::StringRef replacementText);
+  void increaseIndentation(SourceRange range,
+                           SourceLocation parentIndent);
+
+  bool clearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+
+  void applyRewrites(TransformActions::RewriteReceiver &receiver);
+
+private:
+  bool canInsert(SourceLocation loc);
+  bool canInsertAfterToken(SourceLocation loc);
+  bool canRemoveRange(SourceRange range);
+  bool canReplaceRange(SourceRange range, SourceRange replacementRange);
+  bool canReplaceText(SourceLocation loc, llvm::StringRef text);
+
+  void commitInsert(SourceLocation loc, StringRef text);
+  void commitInsertAfterToken(SourceLocation loc, StringRef text);
+  void commitRemove(SourceRange range);
+  void commitRemoveStmt(Stmt *S);
+  void commitReplace(SourceRange range, SourceRange replacementRange);
+  void commitReplaceText(SourceLocation loc, llvm::StringRef text,
+                         llvm::StringRef replacementText);
+  void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent);
+  void commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs, SourceRange range);
+
+  void addRemoval(CharSourceRange range);
+  void addInsertion(SourceLocation loc, StringRef text);
+
+  /// \brief Stores text passed to the transformation methods to keep the string
+  /// "alive". Since the vast majority of text will be the same, we also unique
+  /// the strings using a StringMap.
+  StringRef getUniqueText(StringRef text);
+
+  /// \brief Computes the source location just past the end of the token at
+  /// the given source location. If the location points at a macro, the whole
+  /// macro instantiation is skipped.
+  static SourceLocation getLocForEndOfToken(SourceLocation loc,
+                                            SourceManager &SM,Preprocessor &PP);
+};
+
+} // anonymous namespace
+
+void TransformActionsImpl::startTransaction() {
+  assert(!IsInTransaction &&
+         "Cannot start a transaction in the middle of another one");
+  IsInTransaction = true;
+}
+
+bool TransformActionsImpl::commitTransaction() {
+  assert(IsInTransaction && "No transaction started");
+
+  if (CachedActions.empty()) {
+    IsInTransaction = false;
+    return false;
+  }
+
+  // Verify that all actions are possible otherwise abort the whole transaction.
+  bool AllActionsPossible = true;
+  for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
+    ActionData &act = CachedActions[i];
+    switch (act.Kind) {
+    case Act_Insert:
+      if (!canInsert(act.Loc))
+        AllActionsPossible = false;
+      break;
+    case Act_InsertAfterToken:
+      if (!canInsertAfterToken(act.Loc))
+        AllActionsPossible = false;
+      break;
+    case Act_Remove:
+      if (!canRemoveRange(act.R1))
+        AllActionsPossible = false;
+      break;
+    case Act_RemoveStmt:
+      assert(act.S);
+      if (!canRemoveRange(act.S->getSourceRange()))
+        AllActionsPossible = false;
+      break;
+    case Act_Replace:
+      if (!canReplaceRange(act.R1, act.R2))
+        AllActionsPossible = false;
+      break;
+    case Act_ReplaceText:
+      if (!canReplaceText(act.Loc, act.Text1))
+        AllActionsPossible = false;
+      break;
+    case Act_IncreaseIndentation:
+      // This is not important, we don't care if it will fail.
+      break;
+    case Act_ClearDiagnostic:
+      // We are just checking source rewrites.
+      break;
+    }
+    if (!AllActionsPossible)
+      break;
+  }
+
+  if (!AllActionsPossible) {
+    abortTransaction();
+    return true;
+  }
+
+  for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) {
+    ActionData &act = CachedActions[i];
+    switch (act.Kind) {
+    case Act_Insert:
+      commitInsert(act.Loc, act.Text1);
+      break;
+    case Act_InsertAfterToken:
+      commitInsertAfterToken(act.Loc, act.Text1);
+      break;
+    case Act_Remove:
+      commitRemove(act.R1);
+      break;
+    case Act_RemoveStmt:
+      commitRemoveStmt(act.S);
+      break;
+    case Act_Replace:
+      commitReplace(act.R1, act.R2);
+      break;
+    case Act_ReplaceText:
+      commitReplaceText(act.Loc, act.Text1, act.Text2);
+      break;
+    case Act_IncreaseIndentation:
+      commitIncreaseIndentation(act.R1, act.Loc);
+      break;
+    case Act_ClearDiagnostic:
+      commitClearDiagnostic(act.DiagIDs, act.R1);
+      break;
+    }
+  }
+
+  CachedActions.clear();
+  IsInTransaction = false;
+  return false;
+}
+
+void TransformActionsImpl::abortTransaction() {
+  assert(IsInTransaction && "No transaction started");
+  CachedActions.clear();
+  IsInTransaction = false;
+}
+
+void TransformActionsImpl::insert(SourceLocation loc, StringRef text) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  text = getUniqueText(text);
+  ActionData data;
+  data.Kind = Act_Insert;
+  data.Loc = loc;
+  data.Text1 = text;
+  CachedActions.push_back(data);
+}
+
+void TransformActionsImpl::insertAfterToken(SourceLocation loc, StringRef text) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  text = getUniqueText(text);
+  ActionData data;
+  data.Kind = Act_InsertAfterToken;
+  data.Loc = loc;
+  data.Text1 = text;
+  CachedActions.push_back(data);
+}
+
+void TransformActionsImpl::remove(SourceRange range) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  ActionData data;
+  data.Kind = Act_Remove;
+  data.R1 = range;
+  CachedActions.push_back(data);
+}
+
+void TransformActionsImpl::removeStmt(Stmt *S) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  ActionData data;
+  data.Kind = Act_RemoveStmt;
+  data.S = S;
+  CachedActions.push_back(data);
+}
+
+void TransformActionsImpl::replace(SourceRange range, StringRef text) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  text = getUniqueText(text);
+  remove(range);
+  insert(range.getBegin(), text);
+}
+
+void TransformActionsImpl::replace(SourceRange range,
+                                   SourceRange replacementRange) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  ActionData data;
+  data.Kind = Act_Replace;
+  data.R1 = range;
+  data.R2 = replacementRange;
+  CachedActions.push_back(data);
+}
+
+void TransformActionsImpl::replaceText(SourceLocation loc, StringRef text,
+                                       StringRef replacementText) {
+  text = getUniqueText(text);
+  replacementText = getUniqueText(replacementText);
+  ActionData data;
+  data.Kind = Act_ReplaceText;
+  data.Loc = loc;
+  data.Text1 = text;
+  data.Text2 = replacementText;
+  CachedActions.push_back(data);
+}
+
+void TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  text = getUniqueText(text);
+  insert(S->getLocStart(), text);
+  removeStmt(S);
+}
+
+void TransformActionsImpl::increaseIndentation(SourceRange range,
+                                               SourceLocation parentIndent) {
+  if (range.isInvalid()) return;
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  ActionData data;
+  data.Kind = Act_IncreaseIndentation;
+  data.R1 = range;
+  data.Loc = parentIndent;
+  CachedActions.push_back(data);
+}
+
+bool TransformActionsImpl::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+                                           SourceRange range) {
+  assert(IsInTransaction && "Actions only allowed during a transaction");
+  if (!CapturedDiags.hasDiagnostic(IDs, range))
+    return false;
+
+  ActionData data;
+  data.Kind = Act_ClearDiagnostic;
+  data.R1 = range;
+  data.DiagIDs.append(IDs.begin(), IDs.end());
+  CachedActions.push_back(data);
+  return true;
+}
+
+bool TransformActionsImpl::canInsert(SourceLocation loc) {
+  if (loc.isInvalid())
+    return false;
+
+  SourceManager &SM = Ctx.getSourceManager();
+  if (SM.isInSystemHeader(SM.getInstantiationLoc(loc)))
+    return false;
+
+  if (loc.isFileID())
+    return true;
+  return SM.isAtStartOfMacroInstantiation(loc);
+}
+
+bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) {
+  if (loc.isInvalid())
+    return false;
+
+  SourceManager &SM = Ctx.getSourceManager();
+  if (SM.isInSystemHeader(SM.getInstantiationLoc(loc)))
+    return false;
+
+  if (loc.isFileID())
+    return true;
+  return SM.isAtEndOfMacroInstantiation(loc);
+}
+
+bool TransformActionsImpl::canRemoveRange(SourceRange range) {
+  return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd());
+}
+
+bool TransformActionsImpl::canReplaceRange(SourceRange range,
+                                           SourceRange replacementRange) {
+  return canRemoveRange(range) && canRemoveRange(replacementRange);
+}
+
+bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) {
+  if (!canInsert(loc))
+    return false;
+
+  SourceManager &SM = Ctx.getSourceManager();
+  loc = SM.getInstantiationLoc(loc);
+
+  // 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 false;
+
+  return file.substr(locInfo.second).startswith(text);
+}
+
+void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) {
+  addInsertion(loc, text);
+}
+
+void TransformActionsImpl::commitInsertAfterToken(SourceLocation loc,
+                                                  StringRef text) {
+  addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text);
+}
+
+void TransformActionsImpl::commitRemove(SourceRange range) {
+  addRemoval(CharSourceRange::getTokenRange(range));
+}
+
+void TransformActionsImpl::commitRemoveStmt(Stmt *S) {
+  assert(S);
+  if (StmtRemovals.count(S))
+    return; // already removed.
+
+  if (Expr *E = dyn_cast<Expr>(S)) {
+    commitRemove(E->getSourceRange());
+    commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName());
+  } else
+    commitRemove(S->getSourceRange());
+
+  StmtRemovals.insert(S);
+}
+
+void TransformActionsImpl::commitReplace(SourceRange range,
+                                         SourceRange replacementRange) {
+  RangeComparison comp = CharRange::compare(replacementRange, range,
+                                               Ctx.getSourceManager(), PP);
+  assert(comp == Range_Contained);
+  if (comp != Range_Contained)
+    return; // Although we asserted, be extra safe for release build.
+  if (range.getBegin() != replacementRange.getBegin())
+    addRemoval(CharSourceRange::getCharRange(range.getBegin(),
+                                             replacementRange.getBegin()));
+  if (replacementRange.getEnd() != range.getEnd())
+    addRemoval(CharSourceRange::getTokenRange(
+                                  getLocForEndOfToken(replacementRange.getEnd(),
+                                                      Ctx.getSourceManager(), PP),
+                                  range.getEnd()));
+}
+void TransformActionsImpl::commitReplaceText(SourceLocation loc,
+                                             StringRef text,
+                                             StringRef replacementText) {
+  SourceManager &SM = Ctx.getSourceManager();
+  loc = SM.getInstantiationLoc(loc);
+  // canReplaceText already checked if loc points at text.
+  SourceLocation afterText = loc.getFileLocWithOffset(text.size());
+
+  addRemoval(CharSourceRange::getCharRange(loc, afterText));
+  commitInsert(loc, replacementText);  
+}
+
+void TransformActionsImpl::commitIncreaseIndentation(SourceRange range,
+                                                  SourceLocation parentIndent) {
+  SourceManager &SM = Ctx.getSourceManager();
+  IndentationRanges.push_back(
+                 std::make_pair(CharRange(CharSourceRange::getTokenRange(range),
+                                          SM, PP),
+                                SM.getInstantiationLoc(parentIndent)));
+}
+
+void TransformActionsImpl::commitClearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+                                                 SourceRange range) {
+  CapturedDiags.clearDiagnostic(IDs, range);
+}
+
+void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) {
+  SourceManager &SM = Ctx.getSourceManager();
+  loc = SM.getInstantiationLoc(loc);
+  for (std::list<CharRange>::reverse_iterator
+         I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) {
+    if (!SM.isBeforeInTranslationUnit(loc, I->End))
+      break;
+    if (I->Begin.isBeforeInTranslationUnitThan(loc))
+      return;
+  }
+
+  Inserts[FullSourceLoc(loc, SM)].push_back(text);
+}
+
+void TransformActionsImpl::addRemoval(CharSourceRange range) {
+  CharRange newRange(range, Ctx.getSourceManager(), PP);
+  if (newRange.Begin == newRange.End)
+    return;
+
+  Inserts.erase(Inserts.upper_bound(newRange.Begin),
+                Inserts.lower_bound(newRange.End));
+
+  std::list<CharRange>::iterator I = Removals.end();
+  while (I != Removals.begin()) {
+    std::list<CharRange>::iterator RI = I;
+    --RI;
+    RangeComparison comp = newRange.compareWith(*RI);
+    switch (comp) {
+    case Range_Before:
+      --I;
+      break;
+    case Range_After:
+      Removals.insert(I, newRange);
+      return;
+    case Range_Contained:
+      return;
+    case Range_Contains:
+      RI->End = newRange.End;
+    case Range_ExtendsBegin:
+      newRange.End = RI->End;
+      Removals.erase(RI);
+      break;
+    case Range_ExtendsEnd:
+      RI->End = newRange.End;
+      return;
+    }
+  }
+
+  Removals.insert(Removals.begin(), newRange);
+}
+
+void TransformActionsImpl::applyRewrites(
+                                  TransformActions::RewriteReceiver &receiver) {
+  for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) {
+    SourceLocation loc = I->first;
+    for (TextsVec::iterator
+           TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) {
+      receiver.insert(loc, *TI);
+    }
+  }
+
+  for (std::vector<std::pair<CharRange, SourceLocation> >::iterator
+       I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) {
+    CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin,
+                                                          I->first.End);
+    receiver.increaseIndentation(range, I->second);
+  }
+
+  for (std::list<CharRange>::iterator
+         I = Removals.begin(), E = Removals.end(); I != E; ++I) {
+    CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End);
+    receiver.remove(range);
+  }
+}
+
+/// \brief Stores text passed to the transformation methods to keep the string
+/// "alive". Since the vast majority of text will be the same, we also unique
+/// the strings using a StringMap.
+StringRef TransformActionsImpl::getUniqueText(StringRef text) {
+  llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text);
+  return entry.getKey();
+}
+
+/// \brief Computes the source location just past the end of the token at
+/// the given source location. If the location points at a macro, the whole
+/// macro instantiation is skipped.
+SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc,
+                                                         SourceManager &SM,
+                                                         Preprocessor &PP) {
+  if (loc.isMacroID())
+    loc = SM.getInstantiationRange(loc).second;
+  return PP.getLocForEndOfToken(loc);
+}
+
+TransformActions::RewriteReceiver::~RewriteReceiver() { }
+
+TransformActions::TransformActions(Diagnostic &diag,
+                                   CapturedDiagList &capturedDiags,
+                                   ASTContext &ctx, Preprocessor &PP)
+  : Diags(diag), CapturedDiags(capturedDiags) {
+  Impl = new TransformActionsImpl(capturedDiags, ctx, PP);
+}
+
+TransformActions::~TransformActions() {
+  delete static_cast<TransformActionsImpl*>(Impl);
+}
+
+void TransformActions::startTransaction() {
+  static_cast<TransformActionsImpl*>(Impl)->startTransaction();
+}
+
+bool TransformActions::commitTransaction() {
+  return static_cast<TransformActionsImpl*>(Impl)->commitTransaction();
+}
+
+void TransformActions::abortTransaction() {
+  static_cast<TransformActionsImpl*>(Impl)->abortTransaction();
+}
+
+
+void TransformActions::insert(SourceLocation loc, llvm::StringRef text) {
+  static_cast<TransformActionsImpl*>(Impl)->insert(loc, text);
+}
+
+void TransformActions::insertAfterToken(SourceLocation loc,
+                                        llvm::StringRef text) {
+  static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text);
+}
+
+void TransformActions::remove(SourceRange range) {
+  static_cast<TransformActionsImpl*>(Impl)->remove(range);
+}
+
+void TransformActions::removeStmt(Stmt *S) {
+  static_cast<TransformActionsImpl*>(Impl)->removeStmt(S);
+}
+
+void TransformActions::replace(SourceRange range, llvm::StringRef text) {
+  static_cast<TransformActionsImpl*>(Impl)->replace(range, text);
+}
+
+void TransformActions::replace(SourceRange range,
+                               SourceRange replacementRange) {
+  static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange);
+}
+
+void TransformActions::replaceStmt(Stmt *S, llvm::StringRef text) {
+  static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text);
+}
+
+void TransformActions::replaceText(SourceLocation loc, llvm::StringRef text,
+                                   llvm::StringRef replacementText) {
+  static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text,
+                                                        replacementText);
+}
+
+void TransformActions::increaseIndentation(SourceRange range,
+                                           SourceLocation parentIndent) {
+  static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range,
+                                                                parentIndent);
+}
+
+bool TransformActions::clearDiagnostic(llvm::ArrayRef<unsigned> IDs,
+                                       SourceRange range) {
+  return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range);
+}
+
+void TransformActions::applyRewrites(RewriteReceiver &receiver) {
+  static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver);
+}
+
+void TransformActions::reportError(llvm::StringRef error, SourceLocation loc,
+                                   SourceRange range) {
+  assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
+         "Errors should be emitted out of a transaction");
+  // FIXME: Use a custom category name to distinguish rewriter errors.
+  std::string rewriteErr = "[rewriter] ";
+  rewriteErr += error;
+  unsigned diagID
+     = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error,
+                                                 rewriteErr);
+  Diags.Report(loc, diagID) << range;
+}
+
+void TransformActions::reportNote(llvm::StringRef note, SourceLocation loc,
+                                  SourceRange range) {
+  assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() &&
+         "Errors should be emitted out of a transaction");
+  // FIXME: Use a custom category name to distinguish rewriter errors.
+  std::string rewriteNote = "[rewriter] ";
+  rewriteNote += note;
+  unsigned diagID
+     = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note,
+                                                 rewriteNote);
+  Diags.Report(loc, diagID) << range;
+}

Added: cfe/trunk/lib/ARCMigrate/Transforms.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ARCMigrate/Transforms.cpp?rev=133104&view=auto
==============================================================================
--- cfe/trunk/lib/ARCMigrate/Transforms.cpp (added)
+++ cfe/trunk/lib/ARCMigrate/Transforms.cpp Wed Jun 15 18:25:17 2011
@@ -0,0 +1,2094 @@
+//===--- Tranforms.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:
+//===----------------------------------------------------------------------===//
+//
+// 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 "Internals.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/DenseSet.h"
+#include <map>
+
+using namespace clang;
+using namespace arcmt;
+using llvm::StringRef;
+
+//===----------------------------------------------------------------------===//
+// Transformations.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class RemovablesCollector : public RecursiveASTVisitor<RemovablesCollector> {
+  llvm::DenseSet<Expr *> &Removables;
+
+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);
+  }
+};
+
+} // end anonymous namespace.
+
+static bool HasSideEffects(Expr *E, ASTContext &Ctx) {
+  if (!E || !E->HasSideEffects(Ctx))
+    return false;
+
+  E = E->IgnoreParenCasts();
+  ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E);
+  if (!ME)
+    return true;
+  switch (ME->getMethodFamily()) {
+  case OMF_autorelease:
+  case OMF_dealloc:
+  case OMF_release:
+  case OMF_retain:
+    switch (ME->getReceiverKind()) {
+    case ObjCMessageExpr::SuperInstance:
+      return false;
+    case ObjCMessageExpr::Instance:
+      return HasSideEffects(ME->getInstanceReceiver(), Ctx);
+    default:
+      break;
+    }
+    break;
+  default:
+    break;
+  }
+
+  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;
+public:
+  ReferenceClear(llvm::DenseSet<Expr *> &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;
+
+public:
+  ReferenceCollector(llvm::DenseSet<Expr *> &refs)
+    : Dcl(0), Refs(refs) { }
+
+  void lookFor(ValueDecl *D, Stmt *S) {
+    Dcl = D;
+    TraverseStmt(S);
+  }
+
+  bool VisitDeclRefExpr(DeclRefExpr *E) {
+    if (E->getDecl() == Dcl)
+      Refs.insert(E);
+    return true;
+  }
+
+  bool VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
+    if (E->getDecl() == Dcl)
+      Refs.insert(E);
+    return true;
+  }
+};
+
+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;
+  }
+};
+
+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;
+  }
+};
+
+} // 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->getType().getLocalQualifiers().getObjCLifetime()
+          == Qualifiers::OCL_ExplicitNone &&
+          (var->getTypeSourceInfo() &&
+           !var->getTypeSourceInfo()->getType().isConstQualified())) {
+        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
+
+static void makeAssignARCSafe(MigrationPass &pass) {
+  ARCAssignChecker assignCheck(pass);
+  assignCheck.TraverseDecl(pass.Ctx.getTranslationUnitDecl());
+}
+
+//===----------------------------------------------------------------------===//
+// castNonObjCToObjC
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class NonObjCToObjCCaster : public RecursiveASTVisitor<NonObjCToObjCCaster> {
+  MigrationPass &Pass;
+public:
+  NonObjCToObjCCaster(MigrationPass &pass) : Pass(pass) { }
+
+  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) {
+    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;
+
+    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(), retained ? "__bridge_transfer "
+                                                        : "__bridge ");
+    } else {
+      SourceLocation insertLoc = E->getSubExpr()->getLocStart();
+      llvm::SmallString<128> newCast;
+      newCast += '(';
+      newCast +=  retained ? "__bridge_transfer " : "__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) {
+    // FIXME: Handle these casts.
+    return;
+#if 0
+    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;
+
+    Transaction Trans(TA);
+    TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+                              diag::err_arc_cast_requires_bridge,
+                              E->getLocStart());
+
+    assert(!E->getType()->isObjCObjectPointerType());
+
+    bool shouldCast = !isa<CStyleCastExpr>(E) &&
+                      !E->getType()->getPointeeType().isConstQualified();
+    SourceLocation loc = E->getSubExpr()->getLocStart();
+    if (isa<ParenExpr>(E->getSubExpr())) {
+      TA.insert(loc, shouldCast ? "(void*)objc_unretainedPointer"
+                                : "objc_unretainedPointer");
+    } else {
+      TA.insert(loc, shouldCast ? "(void*)objc_unretainedPointer("
+                                : "objc_unretainedPointer(");
+      TA.insertAfterToken(E->getLocEnd(), ")");
+    }
+#endif
+  }
+
+  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);
+}
+
+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());
+}
+
+//===----------------------------------------------------------------------===//
+// getAllTransformations.
+//===----------------------------------------------------------------------===//
+
+static void independentTransforms(MigrationPass &pass) {
+  rewriteAutoreleasePool(pass);
+  changeIvarsOfAssignProperties(pass);
+  removeRetainReleaseDealloc(pass);
+  rewriteUnusedDelegateInit(pass);
+  removeZeroOutIvarsInDealloc(pass);
+  makeAssignARCSafe(pass);
+  castNonObjCToObjC(pass);
+  rewriteBlockObjCVariable(pass);
+  rewriteAllocCopyWithZone(pass);
+}
+
+std::vector<TransformFn> arcmt::getAllTransformations() {
+  std::vector<TransformFn> transforms;
+
+  // This must come first since rewriteAutoreleasePool depends on -release
+  // calls being present to determine the @autorelease ending scope.
+  transforms.push_back(independentTransforms);
+
+  transforms.push_back(removeEmptyStatements);
+  transforms.push_back(removeDeallocMethod);
+
+  return transforms;
+}

Modified: cfe/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CMakeLists.txt?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/lib/CMakeLists.txt (original)
+++ cfe/trunk/lib/CMakeLists.txt Wed Jun 15 18:25:17 2011
@@ -7,6 +7,7 @@
 add_subdirectory(CodeGen)
 add_subdirectory(Analysis)
 add_subdirectory(Rewrite)
+add_subdirectory(ARCMigrate)
 add_subdirectory(Driver)
 add_subdirectory(Serialization)
 add_subdirectory(Frontend)

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Wed Jun 15 18:25:17 2011
@@ -1389,6 +1389,26 @@
 
   Args.AddLastArg(CmdArgs, options::OPT_working_directory);
 
+  if (!Args.hasArg(options::OPT_fno_objc_arc)) {
+    if (const Arg *A = Args.getLastArg(options::OPT_ccc_arrmt_check,
+                                       options::OPT_ccc_arrmt_modify,
+                                       options::OPT_ccc_arrmt_modify_in_memory)) {
+      switch (A->getOption().getID()) {
+      default:
+        llvm_unreachable("missed a case");
+      case options::OPT_ccc_arrmt_check:
+        CmdArgs.push_back("-arcmt-check");
+        break;
+      case options::OPT_ccc_arrmt_modify:
+        CmdArgs.push_back("-arcmt-modify");
+        break;
+      case options::OPT_ccc_arrmt_modify_in_memory:
+        CmdArgs.push_back("-arcmt-modify-in-memory");
+        break;
+      }
+    }
+  }
+    
   // Add preprocessing options like -I, -D, etc. if we are using the
   // preprocessor.
   //

Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/Frontend/CMakeLists.txt Wed Jun 15 18:25:17 2011
@@ -1,4 +1,5 @@
 set( LLVM_USED_LIBS
+  clangARCMigrate
   clangAST
   clangBasic
   clangDriver

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Wed Jun 15 18:25:17 2011
@@ -26,6 +26,7 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/VerifyDiagnosticsClient.h"
 #include "clang/Frontend/Utils.h"
+#include "clang/ARCMigrate/ARCMT.h"
 #include "clang/Serialization/ASTReader.h"
 #include "clang/Sema/CodeCompleteConsumer.h"
 #include "llvm/Support/FileSystem.h"
@@ -596,6 +597,34 @@
     if (hasSourceManager())
       getSourceManager().clearIDTables();
 
+    switch (getFrontendOpts().ARCMTAction) {
+    default:
+      break;
+
+    case FrontendOptions::ARCMT_Check:
+      if (arcmt::checkForManualIssues(getInvocation(), InFile,
+                                      getFrontendOpts().Inputs[i].first,
+                                      getDiagnostics().getClient()))
+        continue;
+      // We only want to see warnings reported from arcmt::checkForManualIssues.
+      getDiagnostics().setIgnoreAllWarnings(true);
+      break;
+
+    case FrontendOptions::ARCMT_Modify:
+      if (arcmt::applyTransformations(getInvocation(), InFile,
+                                      getFrontendOpts().Inputs[i].first,
+                                      getDiagnostics().getClient()))
+        continue;
+      break;
+
+    case FrontendOptions::ARCMT_ModifyInMemory:
+      if (arcmt::applyTransformationsInMemory(getInvocation(), InFile,
+                                              getFrontendOpts().Inputs[i].first,
+                                              getDiagnostics().getClient()))
+        continue;
+      break;
+    }
+
     if (Act.BeginSourceFile(*this, InFile, getFrontendOpts().Inputs[i].first)) {
       Act.Execute();
       Act.EndSourceFile();

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Wed Jun 15 18:25:17 2011
@@ -415,6 +415,19 @@
     Res.push_back("-version");
   if (Opts.FixWhatYouCan)
     Res.push_back("-fix-what-you-can");
+  switch (Opts.ARCMTAction) {
+  case FrontendOptions::ARCMT_None:
+    break;
+  case FrontendOptions::ARCMT_Check:
+    Res.push_back("-arcmt-check");
+    break;
+  case FrontendOptions::ARCMT_Modify:
+    Res.push_back("-arcmt-modify");
+    break;
+  case FrontendOptions::ARCMT_ModifyInMemory:
+    Res.push_back("-arcmt-modify-in-memory");
+    break;
+  }
 
   bool NeedLang = false;
   for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
@@ -1227,6 +1240,25 @@
   Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can);
   Opts.Modules = Args.getAllArgValues(OPT_import_module);
 
+  Opts.ARCMTAction = FrontendOptions::ARCMT_None;
+  if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
+                                     OPT_arcmt_modify,
+                                     OPT_arcmt_modify_in_memory)) {
+    switch (A->getOption().getID()) {
+    default:
+      llvm_unreachable("missed a case");
+    case OPT_arcmt_check:
+      Opts.ARCMTAction = FrontendOptions::ARCMT_Check;
+      break;
+    case OPT_arcmt_modify:
+      Opts.ARCMTAction = FrontendOptions::ARCMT_Modify;
+      break;
+    case OPT_arcmt_modify_in_memory:
+      Opts.ARCMTAction = FrontendOptions::ARCMT_ModifyInMemory;
+      break;
+    }
+  }
+
   InputKind DashX = IK_None;
   if (const Arg *A = Args.getLastArg(OPT_x)) {
     DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))

Modified: cfe/trunk/lib/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Makefile?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/lib/Makefile (original)
+++ cfe/trunk/lib/Makefile Wed Jun 15 18:25:17 2011
@@ -9,8 +9,8 @@
 CLANG_LEVEL := ..
 
 PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
-                StaticAnalyzer Rewrite Serialization Frontend FrontendTool \
-                Index Driver
+                StaticAnalyzer Rewrite ARCMigrate Serialization Frontend \
+                FrontendTool Index Driver
 
 include $(CLANG_LEVEL)/Makefile
 

Added: cfe/trunk/test/ARCMT/Common.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/Common.h?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/Common.h (added)
+++ cfe/trunk/test/ARCMT/Common.h Wed Jun 15 18:25:17 2011
@@ -0,0 +1,72 @@
+#if __has_feature(objc_arr)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef struct _NSZone NSZone;
+typedef int BOOL;
+typedef unsigned NSUInteger;
+typedef int int32_t;
+typedef unsigned char uint8_t;
+typedef int32_t UChar32;
+typedef unsigned char UChar;
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+
+- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ at end
+
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+
+ at protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+
+ at interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)new;
++ (id)allocWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+
++ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ at end
+
+extern void NSRecycleZone(NSZone *zone);
+
+NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+ at interface NSAutoreleasePool : NSObject {
+ at private
+    void    *_token;
+    void    *_reserved3;
+    void    *_reserved2;
+    void    *_reserved;
+}
+
++ (void)addObject:(id)anObject;
+
+- (void)addObject:(id)anObject;
+
+- (void)drain;
+
+ at end
+
+typedef const void* objc_objectptr_t; 
+extern __attribute__((ns_returns_retained)) id objc_retainedObject(objc_objectptr_t __attribute__((cf_consumed)) pointer);
+extern __attribute__((ns_returns_not_retained)) id objc_unretainedObject(objc_objectptr_t pointer);
+extern objc_objectptr_t objc_unretainedPointer(id object);

Added: cfe/trunk/test/ARCMT/alloc-with-zone-check.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/alloc-with-zone-check.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/alloc-with-zone-check.m (added)
+++ cfe/trunk/test/ARCMT/alloc-with-zone-check.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,80 @@
+// RUN: arcmt-test -check-only -verify --args %s
+
+#if __has_feature(objc_arr)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef struct _NSZone NSZone;
+typedef int BOOL;
+typedef unsigned NSUInteger;
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+
+- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE; // expected-note {{marked unavailable here}}
+ at end
+
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+
+ at protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+
+ at interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)allocWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE; // expected-note 2 {{marked unavailable here}}
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+
++ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ at end
+
+extern void NSRecycleZone(NSZone *zone);
+
+id IhaveSideEffect();
+
+ at interface Foo : NSObject <NSCopying, NSMutableCopying> {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(id)obj;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(id)test:(id)obj {
+  Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
+  Foo *foo2 = [[Foo allocWithZone:[super zone]] init];
+  Foo *foo3 = [[Foo allocWithZone:[IhaveSideEffect() zone]] init]; // expected-error {{not available}}
+  NSRecycleZone([self zone]); // expected-error {{not available}}
+  
+  foo1 = [foo1 copyWithZone:[self zone]];
+  foo2 = [foo1 copyWithZone:[super zone]];
+  foo3 = [foo1 copyWithZone:[IhaveSideEffect() zone]];
+  foo1 = [foo1 mutableCopyWithZone:[self zone]];
+
+  return foo1;
+}
+
++(id)allocWithZone:(NSZone *)zone {
+  return [super allocWithZone:zone]; // expected-error {{not available in automatic reference counting mode}}
+}
+
+ at end

Added: cfe/trunk/test/ARCMT/alloc-with-zone.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/alloc-with-zone.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/alloc-with-zone.m (added)
+++ cfe/trunk/test/ARCMT/alloc-with-zone.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject <NSCopying, NSMutableCopying> {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(NSZone *)z;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
++(id)class_test:(NSZone *)z {
+  return [self allocWithZone:z];
+}
+
+-(id)test:(NSZone *)z {
+  NSZone *z2 = [self zone], *z3 = z2;
+  NSZone *z4 = z3;
+
+  Foo *foo1 = [[Foo allocWithZone:[self zone]] init];
+  Foo *foo2 = [[Foo allocWithZone:[super zone]] init];
+  Foo *foo3 = [[Foo allocWithZone:z] init];
+
+  Foo *foo4 = [[Foo allocWithZone:z2] init];
+  Foo *foo5 = [[Foo allocWithZone:z3] init];
+  Foo *foo6 = [[Foo allocWithZone:z4] init];
+
+  foo1 = [foo1 copyWithZone:[self zone]];
+  foo2 = [foo1 copyWithZone:[super zone]];
+  foo3 = [foo1 copyWithZone:z];
+  foo1 = [foo1 mutableCopyWithZone:[self zone]];
+
+  return foo1;
+}
+
+ at end

Added: cfe/trunk/test/ARCMT/alloc-with-zone.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/alloc-with-zone.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/alloc-with-zone.m.result (added)
+++ cfe/trunk/test/ARCMT/alloc-with-zone.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject <NSCopying, NSMutableCopying> {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(NSZone *)z;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
++(id)class_test:(NSZone *)z {
+  return [self alloc];
+}
+
+-(id)test:(NSZone *)z {
+
+  Foo *foo1 = [[Foo alloc] init];
+  Foo *foo2 = [[Foo alloc] init];
+  Foo *foo3 = [[Foo alloc] init];
+
+  Foo *foo4 = [[Foo alloc] init];
+  Foo *foo5 = [[Foo alloc] init];
+  Foo *foo6 = [[Foo alloc] init];
+
+  foo1 = [foo1 copy];
+  foo2 = [foo1 copy];
+  foo3 = [foo1 copy];
+  foo1 = [foo1 mutableCopy];
+
+  return foo1;
+}
+
+ at end

Added: cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m (added)
+++ cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-no-arc-runtime -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -D__IPHONE_OS_VERSION_MIN_REQUIRED=40300 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -miphoneos-version-min=4.3 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -mmacosx-version-min=10.6 > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject {
+  NSObject *x;
+}
+ at property (readonly,assign) id x;
+ at end
+
+ at implementation Foo
+ at synthesize x;
+ at end

Added: cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m.result (added)
+++ cfe/trunk/test/ARCMT/assign-prop-no-arc-runtime.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -fobjc-no-arc-runtime -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -D__IPHONE_OS_VERSION_MIN_REQUIRED=40300 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -miphoneos-version-min=4.3 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -mmacosx-version-min=10.6 > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject {
+  NSObject *__unsafe_unretained x;
+}
+ at property (readonly,assign) id x;
+ at end
+
+ at implementation Foo
+ at synthesize x;
+ at end

Added: cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m (added)
+++ cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -miphoneos-version-min=5.0 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -mmacosx-version-min=10.7 > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject {
+  NSObject *x, *w, *q1, *q2;
+  NSObject *z1, *__unsafe_unretained z2;
+}
+ at property (readonly,assign) id x;
+ at property (assign) id w;
+ at property (assign) id q1, q2;
+ at property (assign) id z1, z2;
+ at end
+
+ at implementation Foo
+ at synthesize x,w,q1,q2,z1,z2;
+ at end

Added: cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result (added)
+++ cfe/trunk/test/ARCMT/assign-prop-with-arc-runtime.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -miphoneos-version-min=5.0 > %t
+// RUN: diff %t %s.result
+// RUN: arcmt-test --args -arch x86_64 %s -mmacosx-version-min=10.7 > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject {
+  NSObject *__weak x, *__weak w, *__weak q1, *__weak q2;
+  NSObject *__unsafe_unretained z1, *__unsafe_unretained z2;
+}
+ at property (readonly,weak) id x;
+ at property (weak) id w;
+ at property (weak) id q1, q2;
+ at property (assign) id z1, z2;
+ at end
+
+ at implementation Foo
+ at synthesize x,w,q1,q2,z1,z2;
+ at end

Added: cfe/trunk/test/ARCMT/atautorelease-2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease-2.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease-2.m (added)
+++ cfe/trunk/test/ARCMT/atautorelease-2.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+-release;
+ at end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init];
+
+    while (argc) {
+      [chunkPool release];
+      return 0;
+    }
+
+    [chunkPool drain];
+    [pool drain];
+
+    return 0;
+}

Added: cfe/trunk/test/ARCMT/atautorelease-2.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease-2.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease-2.m.result (added)
+++ cfe/trunk/test/ARCMT/atautorelease-2.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+-release;
+ at end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+    @autoreleasepool {
+        @autoreleasepool {
+
+            while (argc) {
+              return 0;
+            }
+
+        }
+    }
+
+    return 0;
+}

Added: cfe/trunk/test/ARCMT/atautorelease-3.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease-3.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease-3.m (added)
+++ cfe/trunk/test/ARCMT/atautorelease-3.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+- release;
+ at end
+
+void NSLog(id, ...);
+
+void test1(int x) {
+  // All this stuff get removed since nothing is happening inside.
+  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+  NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init];
+  while (x) {
+    chunkPool = [[NSAutoreleasePool alloc] init];
+    [chunkPool release];
+  }
+
+  [chunkPool drain];
+  [pool drain];
+}
+
+void test2(int x) {
+  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+  NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init];
+  while (x) {
+    chunkPool = [[NSAutoreleasePool alloc] init];
+    ++x;
+    [chunkPool release];
+  }
+
+  [chunkPool drain];
+  [pool drain];
+}

Added: cfe/trunk/test/ARCMT/atautorelease-3.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease-3.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease-3.m.result (added)
+++ cfe/trunk/test/ARCMT/atautorelease-3.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface NSAutoreleasePool
+- drain;
++new;
++alloc;
+-init;
+-autorelease;
+- release;
+ at end
+
+void NSLog(id, ...);
+
+void test1(int x) {
+  // All this stuff get removed since nothing is happening inside.
+}
+
+void test2(int x) {
+  @autoreleasepool {
+    @autoreleasepool {
+      while (x) {
+        @autoreleasepool {
+          ++x;
+        }
+      }
+
+    }
+  }
+}

Added: cfe/trunk/test/ARCMT/atautorelease-check.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease-check.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease-check.m (added)
+++ cfe/trunk/test/ARCMT/atautorelease-check.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,144 @@
+// RUN: arcmt-test -check-only -verify --args %s 
+
+#if __has_feature(objc_arr)
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode")))
+#else
+#define NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+#endif
+
+typedef struct _NSZone NSZone;
+typedef int BOOL;
+typedef unsigned NSUInteger;
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (NSUInteger)retainCount NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (oneway void)release NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+- (id)autorelease NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+
+- (NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ at end
+
+ at protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+ at end
+
+ at protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+ at end
+
+ at interface NSObject <NSObject> {}
+- (id)init;
+
++ (id)new;
++ (id)allocWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)alloc;
+- (void)dealloc;
+
+- (void)finalize;
+
+- (id)copy;
+- (id)mutableCopy;
+
++ (id)copyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
++ (id)mutableCopyWithZone:(NSZone *)zone NS_AUTOMATED_REFCOUNT_UNAVAILABLE;
+ at end
+
+extern void NSRecycleZone(NSZone *zone);
+
+NS_AUTOMATED_REFCOUNT_UNAVAILABLE
+ at interface NSAutoreleasePool : NSObject { // expected-note 13 {{marked unavailable here}}
+ at private
+    void    *_token;
+    void    *_reserved3;
+    void    *_reserved2;
+    void    *_reserved;
+}
+
++ (void)addObject:(id)anObject;
+
+- (void)addObject:(id)anObject;
+
+- (void)drain;
+
+ at end
+
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
+    NSAutoreleasePool *chunkPool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}}
+
+    while (argc) {
+      [chunkPool release];
+      // the following pool was not released in this scope, don't touch it. 
+      chunkPool = [[NSAutoreleasePool alloc] init]; // expected-error {{'NSAutoreleasePool' is unavailable}}
+    }
+
+    [chunkPool drain];
+    [pool drain];
+
+    return 0;
+}
+
+void f(void) {
+    NSAutoreleasePool * pool;  // expected-error {{'NSAutoreleasePool' is unavailable}}
+
+    for (int i=0; i != 10; ++i) {
+      id x = pool; // We won't touch a NSAutoreleasePool if we can't safely
+                   // remove all the references to it.
+    }
+
+    pool = [[NSAutoreleasePool alloc] init];  // expected-error {{'NSAutoreleasePool' is unavailable}}
+    NSLog(@"%s", "YES");
+    [pool release];
+}
+
+void f2(void) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+                                            // expected-note {{scope begins here}}
+
+    // 'x' is declared inside the "pool scope" but used outside it, if we create
+    // a @autorelease scope it will be undefined outside it so don't touch the pool.
+    int x = 0; // expected-note {{declared here}}
+
+    [pool release]; // expected-note {{scope ends here}}
+    
+    ++x; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+}
+
+void f3(void) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+                                            // expected-note {{scope begins here}}
+
+    struct S { int x; }; // expected-note {{declared here}}
+
+    [pool release]; // expected-note {{scope ends here}}
+
+    struct S *var; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+    var->x = 0;
+}
+
+void f4(void) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+                                            // expected-note {{scope begins here}}
+
+    enum { Bar }; // expected-note {{declared here}}
+
+    [pool release]; // expected-note {{scope ends here}}
+
+    int x = Bar; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+}
+
+void f5(void) {
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // expected-error 2 {{'NSAutoreleasePool' is unavailable}} \
+                                            // expected-note {{scope begins here}}
+
+    typedef int Bar; // expected-note {{declared here}}
+
+    [pool release]; // expected-note {{scope ends here}}
+
+    Bar x; // expected-error {{a name is referenced outside the NSAutoreleasePool scope that it was declared in}}
+}

Added: cfe/trunk/test/ARCMT/atautorelease.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease.m (added)
+++ cfe/trunk/test/ARCMT/atautorelease.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+
+    if (argc) {
+        NSAutoreleasePool * pool = [NSAutoreleasePool  new];
+        NSLog(@"%s", "YES");
+        [pool drain];
+    }
+    [pool drain];
+
+    NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];
+    NSLog(@"%s", "YES");
+    [pool1 release];
+
+    return 0;
+}
+
+void f(void) {
+  NSAutoreleasePool *pool1;
+
+  pool1 = [NSAutoreleasePool new];
+  int x = 4;
+
+  NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
+  ++x;
+  [pool2 drain];
+
+  [pool1 release];
+}
+
+int UIApplicationMain(int argc, char *argv[]);
+
+int main2(int argc, char *argv[]) {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    int result = UIApplicationMain(argc, argv);
+    [pool release];
+    return result;
+}

Added: cfe/trunk/test/ARCMT/atautorelease.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/atautorelease.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/atautorelease.m.result (added)
+++ cfe/trunk/test/ARCMT/atautorelease.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+
+    @autoreleasepool {
+
+        if (argc) {
+            @autoreleasepool {
+                NSLog(@"%s", "YES");
+            }
+        }
+    }
+
+    @autoreleasepool {
+        NSLog(@"%s", "YES");
+    }
+
+    return 0;
+}
+
+void f(void) {
+
+  @autoreleasepool {
+    int x = 4;
+
+    @autoreleasepool {
+      ++x;
+    }
+
+  }
+}
+
+int UIApplicationMain(int argc, char *argv[]);
+
+int main2(int argc, char *argv[]) {
+    @autoreleasepool {
+        int result = UIApplicationMain(argc, argv);
+        return result;
+    }
+}

Added: cfe/trunk/test/ARCMT/autoreleases.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/autoreleases.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/autoreleases.m (added)
+++ cfe/trunk/test/ARCMT/autoreleases.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+typedef unsigned char BOOL;
+
+ at interface NSObject {
+  id isa;
+}
++new;
++alloc;
+-init;
+-autorelease;
+ at end
+
+ at interface NSAutoreleasePool : NSObject
+- drain;
+ at end
+ 
+ at interface A : NSObject {
+ at package
+    id object;
+}
+ at end
+
+ at interface B : NSObject
+- (BOOL)containsSelf:(A*)a;
+ at end
+
+ at implementation A
+ at end
+
+ at implementation B
+- (BOOL)containsSelf:(A*)a {
+    return a->object == self;
+}
+ at end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+    A *a = [[A new] autorelease];
+    B *b = [[B new] autorelease];
+    NSLog(@"%s", [b containsSelf:a] ? "YES" : "NO");
+    [pool drain];
+    return 0;
+}

Added: cfe/trunk/test/ARCMT/autoreleases.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/autoreleases.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/autoreleases.m.result (added)
+++ cfe/trunk/test/ARCMT/autoreleases.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+typedef unsigned char BOOL;
+
+ at interface NSObject {
+  id isa;
+}
++new;
++alloc;
+-init;
+-autorelease;
+ at end
+
+ at interface NSAutoreleasePool : NSObject
+- drain;
+ at end
+ 
+ at interface A : NSObject {
+ at package
+    id object;
+}
+ at end
+
+ at interface B : NSObject
+- (BOOL)containsSelf:(A*)a;
+ at end
+
+ at implementation A
+ at end
+
+ at implementation B
+- (BOOL)containsSelf:(A*)a {
+    return a->object == self;
+}
+ at end
+
+void NSLog(id, ...);
+
+int main (int argc, const char * argv[]) {
+    @autoreleasepool {
+        A *a = [A new];
+        B *b = [B new];
+        NSLog(@"%s", [b containsSelf:a] ? "YES" : "NO");
+    }
+    return 0;
+}

Added: cfe/trunk/test/ARCMT/checking.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/checking.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/checking.m (added)
+++ cfe/trunk/test/ARCMT/checking.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,255 @@
+// RUN: arcmt-test -check-only -verify --args %s
+
+#include "Common.h"
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+ at class NSString;
+ at class A;
+
+struct UnsafeS {
+  A *__unsafe_unretained unsafeObj;
+};
+
+ at interface A : NSObject
+- (id)retain;
+- (id)retainCount;
+- (id)autorelease;
+- (id)init;
+- (oneway void)release;
+- (void)dealloc;
+-(void)test;
+ at end
+
+ at implementation A
+-(void)test {
+  [super dealloc];
+}
+-(void)dealloc {
+  [super dealloc];
+}
+
+- (id)retain { return self; } // expected-error {{ARC forbids implementation}}
+- (id)retainCount { return self; } // expected-error {{ARC forbids implementation}}
+- (id)autorelease { return self; } // expected-error {{ARC forbids implementation}}
+- (oneway void)release { } // expected-error {{ARC forbids implementation}}
+ at end
+
+void test1(A *a, BOOL b, struct UnsafeS *unsafeS) {
+  [unsafeS->unsafeObj retain]; // expected-error {{It is not safe to remove 'retain' message on an __unsafe_unretained type}} \
+                               // expected-error {{ARC forbids explicit message send}}
+  [a dealloc];
+  [a retain];
+  [a retainCount]; // expected-error {{ARC forbids explicit message send of 'retainCount'}}
+  [a release];
+  [a autorelease];
+
+  CFStringRef cfstr;
+  NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
+  // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+  // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+  str = (NSString *)kUTTypePlainText;
+  str = b ? kUTTypeRTF : kUTTypePlainText;
+  str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+  str = (NSString *)a; // no change.
+
+  SEL s = @selector(retain);  // expected-error {{ARC forbids use of 'retain' in a @selector}}
+  s = @selector(release); // expected-error {{ARC forbids use of 'release' in a @selector}}
+  s = @selector(autorelease); // expected-error {{ARC forbids use of 'autorelease' in a @selector}}
+  s = @selector(dealloc); // expected-error {{ARC forbids use of 'dealloc' in a @selector}}
+
+  static id __autoreleasing X1; // expected-error {{global variables cannot have __autoreleasing lifetime}}
+}
+
+struct S {
+  A* a; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+};
+
+ at interface B
+-(id)alloc;
+- (id)initWithInt: (int) i;
+ at end
+
+void rdar8861761() {
+  B *o1 = [[B alloc] initWithInt:0];
+  B *o2 = [B alloc];
+  [o2 initWithInt:0];
+}
+
+ at interface Test13
+- (id) init0;
+- (void) noninit;
+ at end
+ at implementation Test13
+- (id) init0 {
+  self = 0;
+}
+- (void) noninit {
+  self = 0; // expected-error {{cannot assign to 'self' outside of a method in the init family}}
+
+  for (id x in collection) { // expected-error {{use of undeclared identifier 'collection'}}
+    x = 0;
+  }
+}
+ at end
+
+void * cvt(id arg)
+{
+  void* voidp_val;
+  (void)(int*)arg; // expected-error {{disallowed}}
+  (void)(id)arg;
+  (void)(__autoreleasing id*)arg; // expected-error {{disallowed}}
+  (void)(id*)arg; // expected-error {{pointer to non-const type 'id' with no explicit lifetime}} expected-error {{disallowed}}
+
+  (void)(__autoreleasing id**)voidp_val;
+  (void)(void*)voidp_val;
+  (void)(void**)arg; // expected-error {{disallowed}}
+  cvt((void*)arg); // expected-error {{requires a bridged cast}} expected-error {{disallowed}} \
+                   // expected-note {{use __bridge}} expected-note {{use __bridge_retained}} 
+  cvt(0);
+  (void)(__strong id**)(0);
+  return arg; // expected-error {{disallowed}}
+}
+
+
+void test12(id collection) {
+  for (id x in collection) {
+    x = 0;
+  }
+
+  for (__strong id x in collection) {
+    x = 0;
+  }
+}
+
+void test6(unsigned cond) {
+  // FIXME: Fix this automatically ?
+  switch (cond) {
+  case 0:
+    ;
+    id x; // expected-note {{jump bypasses initialization of retaining variable}}
+
+  case 1: // expected-error {{switch case is in protected scope}}
+    break;
+  }
+}
+
+ at class Test8_incomplete;
+ at interface Test8_complete @end;
+ at interface Test8_super @end;
+ at interface Test8 : Test8_super
+- (id) init00;
+- (id) init01; // expected-note {{declaration in interface}}
+- (id) init02;
+- (id) init03; // covariance
+- (id) init04; // covariance
+- (id) init05;
+
+- (void) init10; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init11;
+- (void) init12;
+- (void) init13; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init14; // expected-note {{declaration in interface is not in the 'init' family because its result type is not an object pointer}}
+- (void) init15;
+
+// These should be invalid to actually call.
+- (Test8_incomplete*) init20;
+- (Test8_incomplete*) init21; // expected-note {{declaration in interface}}
+- (Test8_incomplete*) init22;
+- (Test8_incomplete*) init23;
+- (Test8_incomplete*) init24;
+- (Test8_incomplete*) init25;
+
+- (Test8_super*) init30; // id exception to covariance
+- (Test8_super*) init31; // expected-note {{declaration in interface}}
+- (Test8_super*) init32;
+- (Test8_super*) init33;
+- (Test8_super*) init34; // covariance
+- (Test8_super*) init35;
+
+- (Test8*) init40; // id exception to covariance
+- (Test8*) init41; // expected-note {{declaration in interface}}
+- (Test8*) init42;
+- (Test8*) init43; // this should be a warning, but that's a general language thing, not an ARC thing
+- (Test8*) init44;
+- (Test8*) init45;
+
+- (Test8_complete*) init50; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init51; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init52; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init53; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init54; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init55; // expected-error {{init methods must return a type related to the receiver type}}
+ at end
+ at implementation Test8
+- (id) init00 { return 0; }
+- (id) init10 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (id) init20 { return 0; }
+- (id) init30 { return 0; }
+- (id) init40 { return 0; }
+- (id) init50 { return 0; }
+
+- (void) init01 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init11 {}
+- (void) init21 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init31 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init41 {} // expected-error {{method was declared as an 'init' method, but its implementation doesn't match because its result type is not an object pointer}}
+- (void) init51 {}
+
+- (Test8_incomplete*) init02 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init12 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init22 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init32 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init42 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_incomplete*) init52 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+
+- (Test8_super*) init03 { return 0; }
+- (Test8_super*) init13 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8_super*) init23 { return 0; }
+- (Test8_super*) init33 { return 0; }
+- (Test8_super*) init43 { return 0; }
+- (Test8_super*) init53 { return 0; }
+
+- (Test8*) init04 { return 0; }
+- (Test8*) init14 { return 0; } // expected-error {{method implementation does not match its declaration}}
+- (Test8*) init24 { return 0; }
+- (Test8*) init34 { return 0; }
+- (Test8*) init44 { return 0; }
+- (Test8*) init54 { return 0; }
+
+- (Test8_complete*) init05 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init15 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init25 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init35 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init45 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+- (Test8_complete*) init55 { return 0; } // expected-error {{init methods must return a type related to the receiver type}}
+ at end
+
+ at class Test9_incomplete;
+ at interface Test9
+- (Test9_incomplete*) init1; // expected-error {{init methods must return a type related to the receiver type}}
+- (Test9_incomplete*) init2;
+ at end
+id test9(Test9 *v) {
+  return [v init1];
+}
+
+// rdar://9491791
+void rdar9491791(int p) {
+  switch (p) {
+  case 3:;
+    NSObject *o = [[NSObject alloc] init]; // expected-note {{jump bypasses initialization of retaining variable}}
+    [o release];
+    break;
+  default: // expected-error {{switch case is in protected scope}}
+    break;
+  }
+}
+
+#define RELEASE_MACRO(x) do { [x release]; } while(1)
+
+// rdar://9504750
+void rdar9504750(id p) {
+  RELEASE_MACRO(p); // expected-error {{ARC forbids explicit message send of 'release'}}
+}

Added: cfe/trunk/test/ARCMT/cxx-checking.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/cxx-checking.mm?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/cxx-checking.mm (added)
+++ cfe/trunk/test/ARCMT/cxx-checking.mm Wed Jun 15 18:25:17 2011
@@ -0,0 +1,105 @@
+// RUN: arcmt-test -check-only -verify --args -Warc-abi  %s
+
+// Classes that have an Objective-C object pointer.
+struct HasObjectMember0 { // expected-warning{{'HasObjectMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  id x;
+};
+
+struct HasObjectMember1 { // expected-warning{{'HasObjectMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  id x[3];
+};
+
+struct HasObjectMember2 { // expected-warning{{'HasObjectMember2' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  id x[3][2];
+};
+
+// Don't complain if the type has non-external linkage
+namespace {
+  struct HasObjectMember3 {
+    id x[3][2];
+  };
+}
+
+// Don't complain if the Objective-C pointer type was explicitly given
+// no lifetime.
+struct HasObjectMember3 { 
+  __unsafe_unretained id x[3][2];
+};
+
+struct HasBlockPointerMember0 { // expected-warning{{'HasBlockPointerMember0' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  int (^bp)(int);
+};
+
+struct HasBlockPointerMember1 { // expected-warning{{'HasBlockPointerMember1' cannot be shared between ARC and non-ARC code; add a copy constructor, a copy assignment operator, and a destructor to make it ABI-compatible}}
+  int (^bp[2][3])(int);
+};
+
+struct NonPOD {
+  NonPOD(const NonPOD&);
+};
+
+struct HasObjectMemberAndNonPOD0 { // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+  // expected-warning{{'HasObjectMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  id x;
+  NonPOD np;
+};
+
+struct HasObjectMemberAndNonPOD1 { // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+  // expected-warning{{'HasObjectMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  id x[3];
+};
+
+struct HasObjectMemberAndNonPOD2 { // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+  // expected-warning{{'HasObjectMemberAndNonPOD2' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  id x[3][2];
+};
+
+struct HasObjectMemberAndNonPOD3 {
+  HasObjectMemberAndNonPOD3 &operator=(const HasObjectMemberAndNonPOD3&);
+  ~HasObjectMemberAndNonPOD3();
+  NonPOD np;
+  id x[3][2];
+};
+
+struct HasBlockPointerMemberAndNonPOD0 { // expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD0' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  int (^bp)(int);
+};
+
+struct HasBlockPointerMemberAndNonPOD1 { // expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial copy assignment operator to make it ABI-compatible}} \
+// expected-warning{{'HasBlockPointerMemberAndNonPOD1' cannot be shared between ARC and non-ARC code; add a non-trivial destructor to make it ABI-compatible}}
+  NonPOD np;
+  int (^bp[2][3])(int);
+};
+
+int check_non_pod_objc_pointer0[__is_pod(id)? -1 : 1];
+int check_non_pod_objc_pointer1[__is_pod(__strong id)? -1 : 1];
+int check_non_pod_objc_pointer2[__is_pod(__unsafe_unretained id)? 1 : -1];
+int check_non_pod_objc_pointer3[__is_pod(id[2][3])? -1 : 1];
+int check_non_pod_objc_pointer4[__is_pod(__unsafe_unretained id[2][3])? 1 : -1];
+int check_non_pod_block0[__is_pod(int (^)(int))? -1 : 1];
+int check_non_pod_block1[__is_pod(int (^ __unsafe_unretained)(int))? 1 : -1];
+
+struct FlexibleArrayMember0 {
+  int length;
+  id array[]; // expected-error{{flexible array member 'array' of non-POD element type 'id __strong[]'}}
+};
+
+struct FlexibleArrayMember1 {
+  int length;
+  __unsafe_unretained id array[];
+};
+
+// It's okay to pass a retainable type through an ellipsis.
+void variadic(...);
+void test_variadic() {
+  variadic(1, 17, @"Foo");
+}
+
+// It's okay to create a VLA of retainable types.
+void vla(int n) {
+  id vla[n];
+}

Added: cfe/trunk/test/ARCMT/dealloc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/dealloc.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/dealloc.m (added)
+++ cfe/trunk/test/ARCMT/dealloc.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface A
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (void)dealloc;
+ at end
+
+void test1(A *a) {
+  [a dealloc];
+}
+
+ at interface Test2 : A
+- (void) dealloc;
+ at end
+
+ at implementation Test2
+- (void) dealloc {
+  [super dealloc];
+}
+ at end

Added: cfe/trunk/test/ARCMT/dealloc.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/dealloc.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/dealloc.m.result (added)
+++ cfe/trunk/test/ARCMT/dealloc.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface A
+- (id)retain;
+- (id)autorelease;
+- (oneway void)release;
+- (void)dealloc;
+ at end
+
+void test1(A *a) {
+}
+
+ at interface Test2 : A
+- (void) dealloc;
+ at end
+
+ at implementation Test2
+ at end

Added: cfe/trunk/test/ARCMT/init.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/init.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/init.m (added)
+++ cfe/trunk/test/ARCMT/init.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface NSObject
+-init;
+ at end
+
+ at interface A : NSObject
+-init;
+-init2;
+-foo;
++alloc;
+ at end
+
+ at implementation A
+-(id) init {
+  [self init];
+  id a;
+  [a init];
+  a = [[A alloc] init];
+
+  return self;
+}
+
+-(id) init2 {
+  [super init];
+  return self;
+}
+
+-(id) foo {
+  [self init];
+  [super init];
+
+  return self;
+}
+ at end

Added: cfe/trunk/test/ARCMT/init.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/init.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/init.m.result (added)
+++ cfe/trunk/test/ARCMT/init.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface NSObject
+-init;
+ at end
+
+ at interface A : NSObject
+-init;
+-init2;
+-foo;
++alloc;
+ at end
+
+ at implementation A
+-(id) init {
+  self = [self init];
+  id a;
+  [a init];
+  a = [[A alloc] init];
+
+  return self;
+}
+
+-(id) init2 {
+  self = [super init];
+  return self;
+}
+
+-(id) foo {
+  [self init];
+  [super init];
+
+  return self;
+}
+ at end

Added: cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m (added)
+++ cfe/trunk/test/ARCMT/nonobjc-to-objc-cast-2.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,14 @@
+// RUN: arcmt-test -check-only -verify --args %s
+
+typedef int BOOL;
+typedef const struct __CFString * CFStringRef;
+
+ at class NSString;
+
+void f(BOOL b) {
+  CFStringRef cfstr;
+  NSString *str = (NSString *)cfstr; // expected-error {{cast of C pointer type 'CFStringRef' (aka 'const struct __CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast}} \
+    // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+    // expected-note{{use __bridge_transfer to transfer ownership of a +1 'CFStringRef' (aka 'const struct __CFString *') into ARC}}
+  void *vp = str;  // expected-error {{disallowed}}
+}

Added: cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m (added)
+++ cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface NSString : NSObject
+ at end
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFUUID * CFUUIDRef;
+
+extern const CFAllocatorRef kCFAllocatorDefault;
+
+extern CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid);
+
+void f(BOOL b, id p) {
+  NSString *str = (NSString *)kUTTypePlainText;
+  str = b ? kUTTypeRTF : kUTTypePlainText;
+  str = (NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+  str = (NSString *)p; // no change.
+
+  // FIXME: Add objc -> c examples that we can handle.
+
+  CFUUIDRef   _uuid;
+  NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+  _uuidString = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid) autorelease];
+}

Added: cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result (added)
+++ cfe/trunk/test/ARCMT/nonobjc-to-objc-cast.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface NSString : NSObject
+ at end
+
+typedef const struct __CFString * CFStringRef;
+extern const CFStringRef kUTTypePlainText;
+extern const CFStringRef kUTTypeRTF;
+
+typedef const struct __CFAllocator * CFAllocatorRef;
+typedef const struct __CFUUID * CFUUIDRef;
+
+extern const CFAllocatorRef kCFAllocatorDefault;
+
+extern CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid);
+
+void f(BOOL b, id p) {
+  NSString *str = (__bridge NSString *)kUTTypePlainText;
+  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+  str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText);
+  str = (NSString *)p; // no change.
+
+  // FIXME: Add objc -> c examples that we can handle.
+
+  CFUUIDRef   _uuid;
+  NSString *_uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+  _uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, _uuid);
+}

Added: cfe/trunk/test/ARCMT/releases.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/releases.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/releases.m (added)
+++ cfe/trunk/test/ARCMT/releases.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+typedef int BOOL;
+
+id IhaveSideEffect();
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+ at end
+
+ at interface NSObject <NSObject> {}
+ at end
+
+ at interface Foo : NSObject {
+  id bar;
+}
+ at property (retain) id bar;
+-(void)test:(id)obj;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(void)test:(id)obj {
+  id x = self.bar;
+  [x retain];
+  self.bar = obj;
+  // do stuff with x;
+  [x release];
+
+  [IhaveSideEffect() release];
+
+  [x release], x = 0;
+}
+  
+ at end
+
+void func(Foo *p) {
+  [p release];
+  (([p release]));
+}
+
+ at interface Baz {
+	id <NSObject> _foo;
+}
+ at end
+
+ at implementation Baz
+- dealloc {
+  [_foo release];
+  return 0;
+}
+ at end
+
+void block_test(Foo *p) {
+  id (^B)() = ^() {
+    if (p) {
+      id (^IB)() = ^() {
+        id bar = [p retain];
+	      [p release];
+        return bar;
+      };
+      IB();
+    }
+    return [p retain];
+  };
+}
+
+#define RELEASE_MACRO(x) [x release]
+#define RELEASE_MACRO2(x) RELEASE_MACRO(x)
+
+void test2(id p) {
+  RELEASE_MACRO(p);
+  RELEASE_MACRO2(p);
+}

Added: cfe/trunk/test/ARCMT/releases.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/releases.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/releases.m.result (added)
+++ cfe/trunk/test/ARCMT/releases.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+typedef int BOOL;
+
+id IhaveSideEffect();
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+ at end
+
+ at interface NSObject <NSObject> {}
+ at end
+
+ at interface Foo : NSObject {
+  id bar;
+}
+ at property (retain) id bar;
+-(void)test:(id)obj;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(void)test:(id)obj {
+  id x = self.bar;
+  self.bar = obj;
+  // do stuff with x;
+
+  IhaveSideEffect();
+
+  x = 0;
+}
+  
+ at end
+
+void func(Foo *p) {
+}
+
+ at interface Baz {
+	id <NSObject> _foo;
+}
+ at end
+
+ at implementation Baz
+- dealloc {
+  return 0;
+}
+ at end
+
+void block_test(Foo *p) {
+  id (^B)() = ^() {
+    if (p) {
+      id (^IB)() = ^() {
+        id bar = p;
+        return bar;
+      };
+      IB();
+    }
+    return p;
+  };
+}
+
+#define RELEASE_MACRO(x) [x release]
+#define RELEASE_MACRO2(x) RELEASE_MACRO(x)
+
+void test2(id p) {
+}

Added: cfe/trunk/test/ARCMT/remove-dealloc-method.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/remove-dealloc-method.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/remove-dealloc-method.m (added)
+++ cfe/trunk/test/ARCMT/remove-dealloc-method.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#define nil ((void*) 0)
+
+ at interface Foo 
+ at property (retain) id x;
+ at property (retain) id y;
+ at property (retain) id w;
+ at property (retain) id z;
+ at end
+
+ at implementation Foo 
+ at synthesize x;
+ at synthesize y;
+ at synthesize w;
+ at synthesize z;
+
+- (void) dealloc {
+  self.x = 0;
+  [self setY:nil];
+  w = nil;
+  self.z = nil;
+}
+ at end

Added: cfe/trunk/test/ARCMT/remove-dealloc-method.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/remove-dealloc-method.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/remove-dealloc-method.m.result (added)
+++ cfe/trunk/test/ARCMT/remove-dealloc-method.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#define nil ((void*) 0)
+
+ at interface Foo 
+ at property (retain) id x;
+ at property (retain) id y;
+ at property (retain) id w;
+ at property (retain) id z;
+ at end
+
+ at implementation Foo 
+ at synthesize x;
+ at synthesize y;
+ at synthesize w;
+ at synthesize z;
+
+ at end

Added: cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m (added)
+++ cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface Foo 
+ at property (retain) id x;
+ at property (retain) id y;
+ at property (retain) id w;
+ at property (retain) id z;
+ at property (strong) id q;
+ at end
+
+ at implementation Foo 
+ at synthesize x;
+ at synthesize y;
+ at synthesize w;
+ at synthesize q;
+ at dynamic z;
+
+- (void) dealloc {
+  self.x = self.y = self.w = 0;
+  self.x = 0, w = 0, y = 0;
+  [self setY:0];
+  w = 0;
+  q = 0;
+  self.z = 0;
+}
+ at end
+
+ at interface Bar
+ at property (retain) Foo *a;
+- (void) setA:(Foo*) val;
+- (id) a;
+ at end
+
+ at implementation Bar
+- (void) dealloc {
+  [self setA:0];  // This is user-defined setter overriding synthesize, don't touch it.
+  self.a.x = 0;  // every dealloc must zero out its own ivar. This patter is not recognized.
+}
+ at synthesize a;
+- (void) setA:(Foo*) val { }
+- (id) a {return 0;}
+ at end

Added: cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m.result (added)
+++ cfe/trunk/test/ARCMT/remove-dealloc-zerouts.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+ at interface Foo 
+ at property (retain) id x;
+ at property (retain) id y;
+ at property (retain) id w;
+ at property (retain) id z;
+ at property (strong) id q;
+ at end
+
+ at implementation Foo 
+ at synthesize x;
+ at synthesize y;
+ at synthesize w;
+ at synthesize q;
+ at dynamic z;
+
+- (void) dealloc {
+  self.z = 0;
+}
+ at end
+
+ at interface Bar
+ at property (retain) Foo *a;
+- (void) setA:(Foo*) val;
+- (id) a;
+ at end
+
+ at implementation Bar
+- (void) dealloc {
+  [self setA:0];  // This is user-defined setter overriding synthesize, don't touch it.
+  self.a.x = 0;  // every dealloc must zero out its own ivar. This patter is not recognized.
+}
+ at synthesize a;
+- (void) setA:(Foo*) val { }
+- (id) a {return 0;}
+ at end

Added: cfe/trunk/test/ARCMT/remove-statements.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/remove-statements.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/remove-statements.m (added)
+++ cfe/trunk/test/ARCMT/remove-statements.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface myController : NSObject
+-(id)test:(id)x;
+ at end
+
+#define MY_MACRO1(x)
+#define MY_MACRO2(x) (void)x
+
+ at implementation myController
+-(id) test:(id) x {
+  [[x retain] autorelease];
+  return [[x retain] autorelease];
+}
+
+-(void)dealloc
+{
+  id array, array_already_empty;
+  for (id element in array_already_empty) {
+  }
+
+  [array release];
+  ;
+
+  int b, b_array_already_empty;
+  if (b)
+    [array release];
+  if (b_array_already_empty) ;
+
+  if (b) {
+    [array release];
+  }
+  if (b_array_already_empty) {
+  }
+
+  if (b)
+    MY_MACRO1(array);
+  if (b)
+    MY_MACRO2(array);
+}
+ at end

Added: cfe/trunk/test/ARCMT/remove-statements.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/remove-statements.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/remove-statements.m.result (added)
+++ cfe/trunk/test/ARCMT/remove-statements.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface myController : NSObject
+-(id)test:(id)x;
+ at end
+
+#define MY_MACRO1(x)
+#define MY_MACRO2(x) (void)x
+
+ at implementation myController
+-(id) test:(id) x {
+  return x;
+}
+
+-(void)dealloc
+{
+  id array, array_already_empty;
+  for (id element in array_already_empty) {
+  }
+
+  ;
+
+  int b, b_array_already_empty;
+  if (b_array_already_empty) ;
+
+  if (b_array_already_empty) {
+  }
+
+  if (b)
+    MY_MACRO1(array);
+  if (b)
+    MY_MACRO2(array);
+}
+ at end

Added: cfe/trunk/test/ARCMT/retains.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/retains.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/retains.m (added)
+++ cfe/trunk/test/ARCMT/retains.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+id IhaveSideEffect();
+
+ at interface Foo : NSObject {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(id)obj;
+-(id)something;
+ at end
+
+#define Something_Macro(key, comment) \
+ [[Foo new] something]
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(id)something {}
+
+-(id)test:(id)obj {
+  id x = self.bar;
+  [x retain];
+  self.bar = obj;
+  if (obj)
+    [obj retain];
+
+  [Something_Macro(@"foo", "@bar") retain];
+
+  [IhaveSideEffect() retain];
+
+  [[self something] retain];
+
+  [[self retain] something];
+
+  [[IhaveSideEffect() retain] autorelease];
+  [[x retain] autorelease];
+  // do stuff with x;
+  [x release];
+  return [self retain];
+}
+  
+- (id)test1 {
+  id x=0;
+  ([x retain]);
+  return ((([x retain])));
+}
+ at end
+
+id foo (Foo *p) {
+    p = [p retain];
+    return ([p retain]);
+}
+
+void block_tests(Foo *p) {
+  id (^B)() = ^() {
+    if (p) {
+      id (^IB)() = ^() {
+        id bar = [p retain];
+        return bar;
+      };
+      IB();
+    }
+    return [p retain];
+  };
+}

Added: cfe/trunk/test/ARCMT/retains.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/retains.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/retains.m.result (added)
+++ cfe/trunk/test/ARCMT/retains.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+id IhaveSideEffect();
+
+ at interface Foo : NSObject {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(id)obj;
+-(id)something;
+ at end
+
+#define Something_Macro(key, comment) \
+ [[Foo new] something]
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(id)something {}
+
+-(id)test:(id)obj {
+  id x = self.bar;
+  self.bar = obj;
+
+  Something_Macro(@"foo", "@bar");
+
+  IhaveSideEffect();
+
+  [self something];
+
+  [self something];
+
+  IhaveSideEffect();
+  // do stuff with x;
+  return self;
+}
+  
+- (id)test1 {
+  id x=0;
+  return (((x)));
+}
+ at end
+
+id foo (Foo *p) {
+    p = p;
+    return (p);
+}
+
+void block_tests(Foo *p) {
+  id (^B)() = ^() {
+    if (p) {
+      id (^IB)() = ^() {
+        id bar = p;
+        return bar;
+      };
+      IB();
+    }
+    return p;
+  };
+}

Added: cfe/trunk/test/ARCMT/rewrite-block-var.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/rewrite-block-var.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/rewrite-block-var.m (added)
+++ cfe/trunk/test/ARCMT/rewrite-block-var.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000
+// RUN: arcmt-test --args -arch x86_64 %s -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject
+-(Foo *)something;
+ at end
+
+void bar(void (^block)());
+
+void test1(Foo *p) {
+  __block Foo *x = p; // __block used just to break cycle.
+  bar(^{
+    [x something];
+  });
+}
+
+void test2(Foo *p) {
+  __block Foo *x; // __block used as output variable.
+  bar(^{
+    x = [p something];
+  });
+}

Added: cfe/trunk/test/ARCMT/rewrite-block-var.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/rewrite-block-var.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/rewrite-block-var.m.result (added)
+++ cfe/trunk/test/ARCMT/rewrite-block-var.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000
+// RUN: arcmt-test --args -arch x86_64 %s -D__IPHONE_OS_VERSION_MIN_REQUIRED=50000 > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+ at interface Foo : NSObject
+-(Foo *)something;
+ at end
+
+void bar(void (^block)());
+
+void test1(Foo *p) {
+  __weak Foo *x = p; // __block used just to break cycle.
+  bar(^{
+    [x something];
+  });
+}
+
+void test2(Foo *p) {
+  __block Foo *x; // __block used as output variable.
+  bar(^{
+    x = [p something];
+  });
+}

Added: cfe/trunk/test/ARCMT/safe-arc-assign.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/safe-arc-assign.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/safe-arc-assign.m (added)
+++ cfe/trunk/test/ARCMT/safe-arc-assign.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+void test12(id collection) {
+  for (id x in collection) {
+    x = 0;
+    x = 0;
+  }
+
+  for (__strong id x in collection) {
+    x = 0;
+  }
+}

Added: cfe/trunk/test/ARCMT/safe-arc-assign.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/safe-arc-assign.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/safe-arc-assign.m.result (added)
+++ cfe/trunk/test/ARCMT/safe-arc-assign.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -arch x86_64 %s > %t
+// RUN: diff %t %s.result
+
+void test12(id collection) {
+  for (__strong id x in collection) {
+    x = 0;
+    x = 0;
+  }
+
+  for (__strong id x in collection) {
+    x = 0;
+  }
+}

Added: cfe/trunk/test/ARCMT/with-working-dir.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/with-working-dir.m?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/with-working-dir.m (added)
+++ cfe/trunk/test/ARCMT/with-working-dir.m Wed Jun 15 18:25:17 2011
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -working-directory %S with-working-dir.m > %t
+// RUN: diff %t %s.result
+
+typedef int BOOL;
+id IhaveSideEffect();
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)something;
+ at end
+
+ at interface NSObject <NSObject> {}
+ at end
+
+ at interface Foo : NSObject {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(id)obj;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(id)test:(id)obj {
+  id x = self.bar;
+  [x retain];
+  self.bar = obj;
+  if (obj)
+    [obj retain];
+
+  [IhaveSideEffect() retain];
+
+  [[self something] retain];
+
+  [[self retain] something];
+
+  // do stuff with x;
+  [x release];
+  return [self retain];
+}
+  
+ at end

Added: cfe/trunk/test/ARCMT/with-working-dir.m.result
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ARCMT/with-working-dir.m.result?rev=133104&view=auto
==============================================================================
--- cfe/trunk/test/ARCMT/with-working-dir.m.result (added)
+++ cfe/trunk/test/ARCMT/with-working-dir.m.result Wed Jun 15 18:25:17 2011
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -working-directory %S with-working-dir.m > %t
+// RUN: diff %t %s.result
+
+typedef int BOOL;
+id IhaveSideEffect();
+
+ at protocol NSObject
+- (BOOL)isEqual:(id)object;
+- (id)retain;
+- (oneway void)release;
+- (id)something;
+ at end
+
+ at interface NSObject <NSObject> {}
+ at end
+
+ at interface Foo : NSObject {
+  id bar;
+}
+ at property (retain) id bar;
+-(id)test:(id)obj;
+ at end
+
+ at implementation Foo
+
+ at synthesize bar;
+
+-(id)test:(id)obj {
+  id x = self.bar;
+  self.bar = obj;
+
+  IhaveSideEffect();
+
+  [self something];
+
+  [self something];
+
+  // do stuff with x;
+  return self;
+}
+  
+ at end

Modified: cfe/trunk/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CMakeLists.txt?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/tools/CMakeLists.txt (original)
+++ cfe/trunk/tools/CMakeLists.txt Wed Jun 15 18:25:17 2011
@@ -1,3 +1,4 @@
 add_subdirectory(libclang)
 add_subdirectory(c-index-test)
+add_subdirectory(arcmt-test)
 add_subdirectory(driver)

Modified: cfe/trunk/tools/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/Makefile?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/tools/Makefile (original)
+++ cfe/trunk/tools/Makefile Wed Jun 15 18:25:17 2011
@@ -8,12 +8,12 @@
 ##===----------------------------------------------------------------------===##
 
 CLANG_LEVEL := ..
-DIRS := driver libclang c-index-test
+DIRS := driver libclang c-index-test arcmt-test
 
 include $(CLANG_LEVEL)/../../Makefile.config
 
 ifeq ($(OS), $(filter $(OS), Minix))
-DIRS := $(filter-out libclang c-index-test, $(DIRS))
+DIRS := $(filter-out libclang c-index-test, arcmt-test, $(DIRS))
 endif
 
 include $(CLANG_LEVEL)/Makefile

Added: cfe/trunk/tools/arcmt-test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/arcmt-test/CMakeLists.txt?rev=133104&view=auto
==============================================================================
--- cfe/trunk/tools/arcmt-test/CMakeLists.txt (added)
+++ cfe/trunk/tools/arcmt-test/CMakeLists.txt Wed Jun 15 18:25:17 2011
@@ -0,0 +1,14 @@
+set(LLVM_USED_LIBS
+  libclang
+  clangARCMigrate
+  clangRewrite
+  )
+
+set( LLVM_LINK_COMPONENTS
+  support
+  mc
+  )
+
+add_clang_executable(arcmt-test
+  arcmt-test.cpp
+  )

Added: cfe/trunk/tools/arcmt-test/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/arcmt-test/Makefile?rev=133104&view=auto
==============================================================================
--- cfe/trunk/tools/arcmt-test/Makefile (added)
+++ cfe/trunk/tools/arcmt-test/Makefile Wed Jun 15 18:25:17 2011
@@ -0,0 +1,24 @@
+##===- tools/arcmt-test/Makefile ---------------------------*- Makefile -*-===##
+# 
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 
+##===----------------------------------------------------------------------===##
+CLANG_LEVEL := ../..
+
+TOOLNAME = arcmt-test
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+# Don't install this. It is used for tests.
+NO_INSTALL = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clang.a clangIndex.a clangARCMigrate.a clangRewrite.a \
+		 clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
+		 clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile

Added: cfe/trunk/tools/arcmt-test/arcmt-test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/arcmt-test/arcmt-test.cpp?rev=133104&view=auto
==============================================================================
--- cfe/trunk/tools/arcmt-test/arcmt-test.cpp (added)
+++ cfe/trunk/tools/arcmt-test/arcmt-test.cpp Wed Jun 15 18:25:17 2011
@@ -0,0 +1,253 @@
+//===-- arcmt-test.cpp - ARC Migration Tool testbed -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ARCMigrate/ARCMT.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
+
+using namespace clang;
+using namespace arcmt;
+
+static llvm::cl::opt<bool>
+CheckOnly("check-only",
+      llvm::cl::desc("Just check for issues that need to be handled manually"));
+
+//static llvm::cl::opt<bool>
+//TestResultForARC("test-result",
+//llvm::cl::desc("Test the result of transformations by parsing it in ARC mode"));
+
+static llvm::cl::opt<bool>
+OutputTransformations("output-transformations",
+                      llvm::cl::desc("Print the source transformations"));
+
+static llvm::cl::opt<bool>
+VerifyDiags("verify",llvm::cl::desc("Verify emitted diagnostics and warnings"));
+
+static llvm::cl::opt<bool>
+VerboseOpt("v", llvm::cl::desc("Enable verbose output"));
+
+static llvm::cl::extrahelp extraHelp(
+  "\nusage with compiler args: arcmt-test [options] --args [compiler flags]\n");
+
+// This function isn't referenced outside its translation unit, but it
+// can't use the "static" keyword because its address is used for
+// GetMainExecutable (since some platforms don't support taking the
+// address of main, and some platforms can't implement GetMainExecutable
+// without being given the address of a function in the main executable).
+llvm::sys::Path GetExecutablePath(const char *Argv0) {
+  // This just needs to be some symbol in the binary; C++ doesn't
+  // allow taking the address of ::main however.
+  void *MainAddr = (void*) (intptr_t) GetExecutablePath;
+  return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
+}
+
+static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
+                                llvm::raw_ostream &OS);
+static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
+                             llvm::raw_ostream &OS);
+
+namespace {
+
+class PrintTransforms : public MigrationProcess::RewriteListener {
+  ASTContext *Ctx;
+  llvm::raw_ostream &OS;
+
+public:
+  PrintTransforms(llvm::raw_ostream &OS)
+    : Ctx(0), OS(OS) { }
+
+  virtual void start(ASTContext &ctx) { Ctx = &ctx; }
+  virtual void finish() { Ctx = 0; }
+
+  virtual void insert(SourceLocation loc, llvm::StringRef text) {
+    assert(Ctx);
+    OS << "Insert: ";
+    printSourceLocation(loc, *Ctx, OS);
+    OS << " \"" << text << "\"\n";
+  }
+
+  virtual void remove(CharSourceRange range) {
+    assert(Ctx);
+    OS << "Remove: ";
+    printSourceRange(range, *Ctx, OS);
+    OS << '\n';
+  }
+};
+
+} // anonymous namespace
+
+static bool checkForMigration(llvm::StringRef resourcesPath,
+                              llvm::ArrayRef<const char *> Args) {
+  DiagnosticClient *DiagClient =
+    new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID, DiagClient));
+  // Chain in -verify checker, if requested.
+  VerifyDiagnosticsClient *verifyDiag = 0;
+  if (VerifyDiags) {
+    verifyDiag = new VerifyDiagnosticsClient(*Diags, Diags->takeClient());
+    Diags->setClient(verifyDiag);
+  }
+
+  llvm::OwningPtr<CompilerInvocation> CI;
+  CI.reset(clang::createInvocationFromCommandLine(Args, Diags));
+  if (!CI)
+    return true;
+
+  if (CI->getFrontendOpts().Inputs.empty()) {
+    llvm::errs() << "error: no input files\n";
+    return true;
+  }
+
+  if (!CI->getLangOpts().ObjC1)
+    return false;
+
+  return arcmt::checkForManualIssues(*CI,
+                                     CI->getFrontendOpts().Inputs[0].second,
+                                     CI->getFrontendOpts().Inputs[0].first,
+                                     Diags->getClient());
+}
+
+static void printResult(FileRemapper &remapper, llvm::raw_ostream &OS) {
+  CompilerInvocation CI;
+  remapper.applyMappings(CI);
+  PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+  // The changed files will be in memory buffers, print them.
+  for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) {
+    const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second;
+    OS << mem->getBuffer();
+  }
+}
+
+static bool performTransformations(llvm::StringRef resourcesPath,
+                                   llvm::ArrayRef<const char *> Args) {
+  // Check first.
+  if (checkForMigration(resourcesPath, Args))
+    return true;
+
+  DiagnosticClient *DiagClient =
+    new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<Diagnostic> TopDiags(new Diagnostic(DiagID, DiagClient));
+
+  llvm::OwningPtr<CompilerInvocation> origCI;
+  origCI.reset(clang::createInvocationFromCommandLine(Args, TopDiags));
+  if (!origCI)
+    return true;
+
+  if (origCI->getFrontendOpts().Inputs.empty()) {
+    llvm::errs() << "error: no input files\n";
+    return true;
+  }
+
+  if (!origCI->getLangOpts().ObjC1)
+    return false;
+
+  MigrationProcess migration(*origCI, DiagClient);
+
+  std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+  assert(!transforms.empty());
+
+  llvm::OwningPtr<PrintTransforms> transformPrinter;
+  if (OutputTransformations)
+    transformPrinter.reset(new PrintTransforms(llvm::outs()));
+
+  for (unsigned i=0, e = transforms.size(); i != e; ++i) {
+    bool err = migration.applyTransform(transforms[i], transformPrinter.get());
+    if (err) return true;
+
+    if (VerboseOpt) {
+      if (i == e-1)
+        llvm::errs() << "\n##### FINAL RESULT #####\n";
+      else
+        llvm::errs() << "\n##### OUTPUT AFTER "<< i+1 <<". TRANSFORMATION #####\n";
+      printResult(migration.getRemapper(), llvm::errs());
+      llvm::errs() << "\n##########################\n\n";
+    }
+  }
+
+  if (!OutputTransformations)
+    printResult(migration.getRemapper(), llvm::outs());
+
+  // FIXME: TestResultForARC
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Misc. functions.
+//===----------------------------------------------------------------------===//
+
+static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
+                                llvm::raw_ostream &OS) {
+  SourceManager &SM = Ctx.getSourceManager();
+  PresumedLoc PL = SM.getPresumedLoc(loc);
+
+  OS << llvm::sys::path::filename(PL.getFilename());
+  OS << ":" << PL.getLine() << ":"
+            << PL.getColumn();
+}
+
+static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
+                             llvm::raw_ostream &OS) {
+  SourceManager &SM = Ctx.getSourceManager();
+  const LangOptions &langOpts = Ctx.getLangOptions();
+
+  PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
+
+  OS << llvm::sys::path::filename(PL.getFilename());
+  OS << " [" << PL.getLine() << ":"
+             << PL.getColumn();
+  OS << " - ";
+
+  SourceLocation end = range.getEnd();
+  PL = SM.getPresumedLoc(end);
+
+  unsigned endCol = PL.getColumn() - 1;
+  if (!range.isTokenRange())
+    endCol += Lexer::MeasureTokenLength(end, SM, langOpts);
+  OS << PL.getLine() << ":" << endCol << "]";
+}
+
+//===----------------------------------------------------------------------===//
+// Command line processing.
+//===----------------------------------------------------------------------===//
+
+int main(int argc, const char **argv) {
+  using llvm::StringRef;
+  void *MainAddr = (void*) (intptr_t) GetExecutablePath;
+  llvm::sys::PrintStackTraceOnErrorSignal();
+
+  std::string
+    resourcesPath = CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
+
+  int optargc = 0;
+  for (; optargc != argc; ++optargc) {
+    if (StringRef(argv[optargc]) == "--args")
+      break;
+  }
+  llvm::cl::ParseCommandLineOptions(optargc, const_cast<char **>(argv), "arcmt-test");
+  
+  if (optargc == argc) {
+    llvm::cl::PrintHelpMessage();
+    return 1;
+  }
+
+  llvm::ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1);
+
+  if (CheckOnly)
+    return checkForMigration(resourcesPath, Args);
+
+  return performTransformations(resourcesPath, Args);
+}

Modified: cfe/trunk/tools/driver/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/CMakeLists.txt?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/tools/driver/CMakeLists.txt (original)
+++ cfe/trunk/tools/driver/CMakeLists.txt Wed Jun 15 18:25:17 2011
@@ -9,6 +9,7 @@
   clangIndex
   clangLex
   clangParse
+  clangARCMigrate
   clangRewrite
   clangSema
   clangSerialization

Modified: cfe/trunk/tools/driver/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/Makefile?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/tools/driver/Makefile (original)
+++ cfe/trunk/tools/driver/Makefile Wed Jun 15 18:25:17 2011
@@ -41,7 +41,7 @@
            clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
            clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
            clangStaticAnalyzerCore.a \
-           clangAnalysis.a clangIndex.a clangRewrite.a \
+           clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \
            clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile

Modified: cfe/trunk/tools/scan-build/ccc-analyzer
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/scan-build/ccc-analyzer?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/tools/scan-build/ccc-analyzer (original)
+++ cfe/trunk/tools/scan-build/ccc-analyzer Wed Jun 15 18:25:17 2011
@@ -365,11 +365,9 @@
   'cp'  => 'c++',
   'cpp' => 'c++',
   'cc'  => 'c++',
-  'ii'  => 'c++',
   'i'   => 'c-cpp-output',
   'm'   => 'objective-c',
-  'mi'  => 'objective-c-cpp-output',
-  'mm'  => 'objective-c++'
+  'mi'  => 'objective-c-cpp-output'
 );
 
 my %UniqueOptions = (
@@ -382,11 +380,14 @@
 
 my %LangsAccepted = (
   "objective-c" => 1,
-  "c" => 1,
-  "c++" => 1,
-  "objective-c++" => 1
+  "c" => 1
 );
 
+if (defined $ENV{'CCC_ANALYZER_CPLUSPLUS'}) {
+  $LangsAccepted{"c++"} = 1;
+  $LangsAccepted{"objective-c++"} = 1;
+}
+
 ##----------------------------------------------------------------------------##
 #  Main Logic.
 ##----------------------------------------------------------------------------##
@@ -620,9 +621,9 @@
       push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel";
     }
     
-    if (defined $Analyses) {
-      push @AnalyzeArgs, split '\s+', $Analyses;
-    }
+#    if (defined $Analyses) {
+#      push @AnalyzeArgs, split '\s+', $Analyses;
+#    }
 
     if (defined $OutputFormat) {
       push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat;

Modified: cfe/trunk/unittests/Frontend/Makefile
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Frontend/Makefile?rev=133104&r1=133103&r2=133104&view=diff
==============================================================================
--- cfe/trunk/unittests/Frontend/Makefile (original)
+++ cfe/trunk/unittests/Frontend/Makefile Wed Jun 15 18:25:17 2011
@@ -13,7 +13,7 @@
 USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
            clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
            clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
-           clangAnalysis.a clangIndex.a clangRewrite.a \
+           clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \
            clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/unittests/Makefile





More information about the cfe-commits mailing list