]> granicus.if.org Git - clang/commitdiff
Add new code migrator support for migrating existing Objective-C code to use
authorTed Kremenek <kremenek@apple.com>
Tue, 6 Mar 2012 20:06:33 +0000 (20:06 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 6 Mar 2012 20:06:33 +0000 (20:06 +0000)
the new Objective-C NSArray/NSDictionary/NSNumber literal syntax.

This introduces a new library, libEdit, which provides a new way to support
migration of code that improves on the original ARC migrator.  We now believe
that most of its functionality can be refactored into the existing libraries,
and thus this new library may shortly disappear.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@152141 91177308-0d34-0410-b5e6-96231b3b80d8

64 files changed:
include/clang-c/Index.h
include/clang/ARCMigrate/ARCMT.h
include/clang/ARCMigrate/ARCMTActions.h
include/clang/ARCMigrate/FileRemapper.h
include/clang/Basic/Diagnostic.h
include/clang/Driver/Action.h
include/clang/Driver/CC1Options.td
include/clang/Driver/Options.td
include/clang/Driver/Types.def
include/clang/Edit/Commit.h [new file with mode: 0644]
include/clang/Edit/EditedSource.h [new file with mode: 0644]
include/clang/Edit/EditsReceiver.h [new file with mode: 0644]
include/clang/Edit/FileOffset.h [new file with mode: 0644]
include/clang/Edit/Rewriters.h [new file with mode: 0644]
include/clang/Frontend/FrontendOptions.h
include/clang/Rewrite/FixItRewriter.h
lib/ARCMigrate/ARCMT.cpp
lib/ARCMigrate/CMakeLists.txt
lib/ARCMigrate/FileRemapper.cpp
lib/ARCMigrate/ObjCMT.cpp [new file with mode: 0644]
lib/ARCMigrate/TransRetainReleaseDealloc.cpp
lib/Basic/DiagnosticIDs.cpp
lib/CMakeLists.txt
lib/Driver/Action.cpp
lib/Driver/Driver.cpp
lib/Driver/ToolChain.cpp
lib/Driver/ToolChains.cpp
lib/Driver/Tools.cpp
lib/Driver/WindowsToolChain.cpp
lib/Edit/CMakeLists.txt [new file with mode: 0644]
lib/Edit/Commit.cpp [new file with mode: 0644]
lib/Edit/EditedSource.cpp [new file with mode: 0644]
lib/Edit/Makefile [new file with mode: 0644]
lib/Edit/RewriteObjCFoundationAPI.cpp [new file with mode: 0644]
lib/Frontend/CompilerInvocation.cpp
lib/Frontend/DiagnosticRenderer.cpp
lib/FrontendTool/ExecuteCompilerInvocation.cpp
lib/Makefile
lib/Rewrite/FixItRewriter.cpp
test/ARCMT/dispatch.m [new file with mode: 0644]
test/ARCMT/dispatch.m.result [new file with mode: 0644]
test/ARCMT/driver-migrate.m
test/ARCMT/migrate-emit-errors.m
test/ARCMT/migrate-plist-output.m
test/ARCMT/migrate-space-in-path.m
test/ARCMT/migrate.m
test/ARCMT/objcmt-numeric-literals.m [new file with mode: 0644]
test/ARCMT/objcmt-numeric-literals.m.result [new file with mode: 0644]
test/ARCMT/objcmt-subscripting-literals.m [new file with mode: 0644]
test/ARCMT/objcmt-subscripting-literals.m.result [new file with mode: 0644]
test/ARCMT/with-arc-mode-migrate.m
test/ARCMT/with-arc-mode-migrate.m.result
tools/arcmt-test/CMakeLists.txt
tools/arcmt-test/Makefile
tools/arcmt-test/arcmt-test.cpp
tools/c-arcmt-test/c-arcmt-test.c
tools/driver/CMakeLists.txt
tools/driver/Makefile
tools/libclang/ARCMigrate.cpp
tools/libclang/CMakeLists.txt
tools/libclang/Makefile
tools/libclang/libclang.exports
unittests/Frontend/Makefile
unittests/Lex/LexerTest.cpp

index 746490be8812ab01db7857f2781817f06c45eb67..fd7a9f3a0152d3d51529bd6b4cbe6f089b1683a0 100644 (file)
@@ -3982,6 +3982,20 @@ typedef void *CXRemapping;
  */
 CINDEX_LINKAGE CXRemapping clang_getRemappings(const char *path);
 
+/**
+ * \brief Retrieve a remapping.
+ *
+ * \param filePaths pointer to an array of file paths containing remapping info.
+ *
+ * \param numFiles number of file paths.
+ *
+ * \returns the requested remapping. This remapping must be freed
+ * via a call to \c clang_remap_dispose(). Can return NULL if an error occurred.
+ */
+CINDEX_LINKAGE
+CXRemapping clang_getRemappingsFromFileList(const char **filePaths,
+                                            unsigned numFiles);
+
 /**
  * \brief Determine the number of remappings.
  */
index 738a00dcd01d757018bc5ff3b8c1d95c0df07e0e..86a6cbb22aae38e0248e6db97211e8cb7903a811 100644 (file)
@@ -76,6 +76,15 @@ bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap,
                        StringRef outputDir,
                        DiagnosticConsumer *DiagClient);
 
+/// \brief Get the set of file remappings from a list of files with remapping
+/// info.
+///
+/// \returns false if no error is produced, true otherwise.
+bool getFileRemappingsFromFileList(
+                        std::vector<std::pair<std::string,std::string> > &remap,
+                        ArrayRef<StringRef> remapFiles,
+                        DiagnosticConsumer *DiagClient);
+
 typedef void (*TransformFn)(MigrationPass &pass);
 
 std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode,
index 4eac4facdd82a31ab83d68f3b6ea2b3d9f48c719..e0752521378b9a14b5b40a9eb1f25329ff10adbf 100644 (file)
@@ -11,6 +11,7 @@
 #define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
 
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/ARCMigrate/FileRemapper.h"
 #include "llvm/ADT/OwningPtr.h"
 
 namespace clang {
@@ -32,6 +33,14 @@ public:
   ModifyAction(FrontendAction *WrappedAction);
 };
 
+class MigrateSourceAction : public ASTFrontendAction {
+  FileRemapper Remapper;
+protected:
+  virtual bool BeginInvocation(CompilerInstance &CI);
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         StringRef InFile);
+};
+
 class MigrateAction : public WrapperFrontendAction {
   std::string MigrateDir;
   std::string PlistOut;
@@ -45,6 +54,23 @@ public:
                 bool emitPremigrationARCErrors);
 };
 
+/// \brief Migrates to modern ObjC syntax.
+class ObjCMigrateAction : public WrapperFrontendAction {
+  std::string MigrateDir;
+  bool MigrateLiterals;
+  bool MigrateSubscripting;
+  FileRemapper Remapper;
+  CompilerInstance *CompInst;
+public:
+  ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir,
+                    bool migrateLiterals,
+                    bool migrateSubscripting);
+
+protected:
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile);
+  virtual bool BeginInvocation(CompilerInstance &CI);
+};
+
 }
 }
 
index a451988f9330d0557a56c9614f134d8476d6ccb9..fe7cfadb497316aa65d5d0e6fa25e0a9d408f3c8 100644 (file)
@@ -24,7 +24,7 @@ namespace clang {
   class FileManager;
   class FileEntry;
   class DiagnosticsEngine;
-  class CompilerInvocation;
+  class PreprocessorOptions;
 
 namespace arcmt {
 
@@ -44,7 +44,10 @@ public:
   
   bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
                     bool ignoreIfFilesChanged);
+  bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
+                    bool ignoreIfFilesChanged);
   bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag);
+  bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag);
 
   bool overwriteOriginal(DiagnosticsEngine &Diag,
                          StringRef outputDir = StringRef());
@@ -52,9 +55,9 @@ public:
   void remap(StringRef filePath, llvm::MemoryBuffer *memBuf);
   void remap(StringRef filePath, StringRef newPath);
 
-  void applyMappings(CompilerInvocation &CI) const;
+  void applyMappings(PreprocessorOptions &PPOpts) const;
 
-  void transferMappingsAndClear(CompilerInvocation &CI);
+  void transferMappingsAndClear(PreprocessorOptions &PPOpts);
 
   void clear(StringRef outputDir = StringRef());
 
index 3e54b4352b6801d4d1457440bc358d74282d8192..2b71d445cc9c1c4b6da32cafbafa7ce73b21d6d8 100644 (file)
@@ -50,13 +50,19 @@ public:
   /// insertion hint.
   CharSourceRange RemoveRange;
 
+  /// \brief Code in the specific range that should be inserted in the insertion
+  /// location.
+  CharSourceRange InsertFromRange;
+
   /// \brief The actual code to insert at the insertion location, as a
   /// string.
   std::string CodeToInsert;
 
+  bool BeforePreviousInsertions;
+
   /// \brief Empty code modification hint, indicating that no code
   /// modification is known.
-  FixItHint() : RemoveRange() { }
+  FixItHint() : BeforePreviousInsertions(false) { }
 
   bool isNull() const {
     return !RemoveRange.isValid();
@@ -65,11 +71,26 @@ public:
   /// \brief Create a code modification hint that inserts the given
   /// code string at a specific location.
   static FixItHint CreateInsertion(SourceLocation InsertionLoc,
-                                   StringRef Code) {
+                                   StringRef Code,
+                                   bool BeforePreviousInsertions = false) {
     FixItHint Hint;
     Hint.RemoveRange =
       CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
     Hint.CodeToInsert = Code;
+    Hint.BeforePreviousInsertions = BeforePreviousInsertions;
+    return Hint;
+  }
+  
+  /// \brief Create a code modification hint that inserts the given
+  /// code from \arg FromRange at a specific location.
+  static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc,
+                                            CharSourceRange FromRange,
+                                        bool BeforePreviousInsertions = false) {
+    FixItHint Hint;
+    Hint.RemoveRange =
+      CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
+    Hint.InsertFromRange = FromRange;
+    Hint.BeforePreviousInsertions = BeforePreviousInsertions;
     return Hint;
   }
 
index 41ce4d92c40ea6189737fd57e4cdc3d9dd1c424d..6e317a0726b534ea13936423b8e9d483e23389be 100644 (file)
@@ -39,6 +39,7 @@ public:
     PreprocessJobClass,
     PrecompileJobClass,
     AnalyzeJobClass,
+    MigrateJobClass,
     CompileJobClass,
     AssembleJobClass,
     LinkJobClass,
@@ -171,6 +172,17 @@ public:
   static bool classof(const AnalyzeJobAction *) { return true; }
 };
 
+class MigrateJobAction : public JobAction {
+  virtual void anchor();
+public:
+  MigrateJobAction(Action *Input, types::ID OutputType);
+
+  static bool classof(const Action *A) {
+    return A->getKind() == MigrateJobClass;
+  }
+  static bool classof(const MigrateJobAction *) { return true; }
+};
+
 class CompileJobAction : public JobAction {
   virtual void anchor();
 public:
index 93e63dee61ae70c152e3f3c0c3321d2ef89c840e..2fe4eba2057bd0cbcf7fc8d1f11998eaebb2a8fb 100644 (file)
@@ -433,21 +433,28 @@ def rewrite_objc : Flag<"-rewrite-objc">,
   HelpText<"Rewrite ObjC into C (code rewriter example)">;
 def rewrite_macros : Flag<"-rewrite-macros">,
   HelpText<"Expand macros without full preprocessing">;
+def migrate : Flag<"-migrate">,
+  HelpText<"Migrate source code">;
 }
 
+def mt_migrate_directory : Separate<"-mt-migrate-directory">,
+  HelpText<"Directory for temporary files produced during ARC or ObjC migration">;
 def arcmt_check : Flag<"-arcmt-check">,
   HelpText<"Check for ARC migration issues that need manual handling">;
 def arcmt_modify : Flag<"-arcmt-modify">,
   HelpText<"Apply modifications to files to conform to ARC">;
 def arcmt_migrate : Flag<"-arcmt-migrate">,
   HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">,
-  HelpText<"Directory for temporary files produced during ARC migration">;
 def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
   HelpText<"Output path for the plist report">;
 def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
   HelpText<"Emit ARC errors even if the migrator can fix them">;
 
+def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">,
+  HelpText<"Enable migration to modern ObjC literals">;
+def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">,
+  HelpText<"Enable migration to modern ObjC subscripting">;
+
 def working_directory : JoinedOrSeparate<"-working-directory">,
   HelpText<"Resolve file paths relative to the specified directory">;
 def working_directory_EQ : Joined<"-working-directory=">,
index b269ddb045ed1908765572a9f00229795b311c7b..51c5e020e1ba864c0e886b227bed0bcbb4a1ac1a 100644 (file)
@@ -118,13 +118,21 @@ def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, Alias<ccc_arcmt_check>;
 def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias<ccc_arcmt_modify>;
 def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt,
   HelpText<"Apply modifications and produces temporary files that conform to ARC">;
-def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt,
-  Alias<ccc_arcmt_migrate>;
 def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
   HelpText<"Output path for the plist report">;
 def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
   HelpText<"Emit ARC errors even if the migrator can fix them">;
 
+def _migrate : Flag<"--migrate">, Flags<[DriverOption]>,
+  HelpText<"Run the migrator">;
+def ccc_objcmt_migrate : Separate<"-ccc-objcmt-migrate">, CCCDriverOpt,
+  HelpText<"Apply modifications and produces temporary files to migrate to "
+   "modern ObjC syntax">;
+def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">,
+  HelpText<"Enable migration to modern ObjC literals">;
+def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">,
+  HelpText<"Enable migration to modern ObjC subscripting">;
+
 // Make sure all other -ccc- options are rejected.
 def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
 
index 8449d639e6982da8f5c50a0c41da4dc7fe9d1583..bba888ca4a79ce781becca0037de8b223843a942 100644 (file)
@@ -82,6 +82,7 @@ TYPE("lto-bc",                   LTO_BC,       INVALID,         "o",     "")
 TYPE("ast",                      AST,          INVALID,         "ast",   "u")
 TYPE("plist",                    Plist,        INVALID,         "plist", "")
 TYPE("rewritten-objc",           RewrittenObjC,INVALID,         "cpp",   "")
+TYPE("remap",                    Remap,        INVALID,         "remap", "")
 TYPE("precompiled-header",       PCH,          INVALID,         "gch",   "A")
 TYPE("object",                   Object,       INVALID,         "o",     "")
 TYPE("treelang",                 Treelang,     INVALID,         0,       "u")
diff --git a/include/clang/Edit/Commit.h b/include/clang/Edit/Commit.h
new file mode 100644 (file)
index 0000000..aaf6b18
--- /dev/null
@@ -0,0 +1,140 @@
+//===----- Commit.h - A unit of edits ---------------------------*- 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_EDIT_COMMIT_H
+#define LLVM_CLANG_EDIT_COMMIT_H
+
+#include "clang/Edit/FileOffset.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+  class LangOptions;
+  class PreprocessingRecord;
+
+namespace edit {
+  class EditedSource;
+
+class Commit {
+public:
+  enum EditKind {
+    Act_Insert,
+    Act_InsertFromRange,
+    Act_Remove
+  };
+
+  struct Edit {
+    EditKind Kind;
+    StringRef Text;
+    SourceLocation OrigLoc;
+    FileOffset Offset;
+    FileOffset InsertFromRangeOffs;
+    unsigned Length;
+    bool BeforePrev;
+
+    SourceLocation getFileLocation(SourceManager &SM) const;
+    CharSourceRange getFileRange(SourceManager &SM) const;
+    CharSourceRange getInsertFromRange(SourceManager &SM) const;
+  };
+
+private:
+  const SourceManager &SourceMgr;
+  const LangOptions &LangOpts;
+  const PreprocessingRecord *PPRec;
+  EditedSource *Editor;
+
+  bool IsCommitable;
+  SmallVector<Edit, 8> CachedEdits;
+
+public:
+  explicit Commit(EditedSource &Editor);
+  Commit(const SourceManager &SM, const LangOptions &LangOpts,
+         const PreprocessingRecord *PPRec = 0)
+    : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0),
+      IsCommitable(true) { }
+
+  bool isCommitable() const { return IsCommitable; }
+
+  bool insert(SourceLocation loc, StringRef text, bool afterToken = false,
+              bool beforePreviousInsertions = false);
+  bool insertAfterToken(SourceLocation loc, StringRef text,
+                        bool beforePreviousInsertions = false) {
+    return insert(loc, text, /*afterToken=*/true, beforePreviousInsertions);
+  }
+  bool insertBefore(SourceLocation loc, StringRef text) {
+    return insert(loc, text, /*afterToken=*/false,
+                  /*beforePreviousInsertions=*/true);
+  }
+  bool insertFromRange(SourceLocation loc, CharSourceRange range,
+                       bool afterToken = false,
+                       bool beforePreviousInsertions = false);
+  bool insertWrap(StringRef before, CharSourceRange range, StringRef after);
+
+  bool remove(CharSourceRange range);
+
+  bool replace(CharSourceRange range, StringRef text);
+  bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange);
+  bool replaceText(SourceLocation loc, StringRef text,
+                   StringRef replacementText);
+
+  bool insertFromRange(SourceLocation loc, SourceRange TokenRange,
+                       bool afterToken = false,
+                       bool beforePreviousInsertions = false) {
+    return insertFromRange(loc, CharSourceRange::getTokenRange(TokenRange),
+                           afterToken, beforePreviousInsertions);
+  }
+  bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after) {
+    return insertWrap(before, CharSourceRange::getTokenRange(TokenRange), after);
+  }
+  bool remove(SourceRange TokenRange) {
+    return remove(CharSourceRange::getTokenRange(TokenRange));
+  }
+  bool replace(SourceRange TokenRange, StringRef text) {
+    return replace(CharSourceRange::getTokenRange(TokenRange), text);
+  }
+  bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange) {
+    return replaceWithInner(CharSourceRange::getTokenRange(TokenRange),
+                            CharSourceRange::getTokenRange(TokenInnerRange));
+  }
+
+  typedef SmallVector<Edit, 8>::const_iterator edit_iterator;
+  edit_iterator edit_begin() const { return CachedEdits.begin(); }
+  edit_iterator edit_end() const { return CachedEdits.end(); }
+
+private:
+  void addInsert(SourceLocation OrigLoc,
+                FileOffset Offs, StringRef text, bool beforePreviousInsertions);
+  void addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
+                          FileOffset RangeOffs, unsigned RangeLen,
+                          bool beforePreviousInsertions);
+  void addRemove(SourceLocation OrigLoc, FileOffset Offs, unsigned Len);
+
+  bool canInsert(SourceLocation loc, FileOffset &Offset);
+  bool canInsertAfterToken(SourceLocation loc, FileOffset &Offset,
+                           SourceLocation &AfterLoc);
+  bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
+  bool canRemoveRange(CharSourceRange range, FileOffset &Offs, unsigned &Len);
+  bool canReplaceText(SourceLocation loc, StringRef text,
+                      FileOffset &Offs, unsigned &Len);
+
+  void commitInsert(FileOffset offset, StringRef text,
+                    bool beforePreviousInsertions);
+  void commitRemove(FileOffset offset, unsigned length);
+
+  bool isAtStartOfMacroExpansion(SourceLocation loc,
+                                 SourceLocation *MacroBegin = 0) const;
+  bool isAtEndOfMacroExpansion(SourceLocation loc,
+                               SourceLocation *MacroEnd = 0) const;
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
new file mode 100644 (file)
index 0000000..273921c
--- /dev/null
@@ -0,0 +1,87 @@
+//===----- EditedSource.h - Collection of source edits ----------*- 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_EDIT_EDITEDSOURCE_H
+#define LLVM_CLANG_EDIT_EDITEDSOURCE_H
+
+#include "clang/Edit/FileOffset.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <map>
+
+namespace clang {
+  class LangOptions;
+  class PreprocessingRecord;
+
+namespace edit {
+  class Commit;
+  class EditsReceiver;
+
+class EditedSource {
+  const SourceManager &SourceMgr;
+  const LangOptions &LangOpts;
+  const PreprocessingRecord *PPRec;
+
+  struct FileEdit {
+    StringRef Text;
+    unsigned RemoveLen;
+
+    FileEdit() : RemoveLen(0) {}
+  };
+
+  typedef std::map<FileOffset, FileEdit> FileEditsTy;
+  FileEditsTy FileEdits;
+
+  llvm::DenseMap<unsigned, SourceLocation> ExpansionToArgMap;
+
+  llvm::BumpPtrAllocator StrAlloc;
+
+public:
+  EditedSource(const SourceManager &SM, const LangOptions &LangOpts,
+               const PreprocessingRecord *PPRec = 0)
+    : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec),
+      StrAlloc(/*size=*/512) { }
+
+  const SourceManager &getSourceManager() const { return SourceMgr; }
+  const LangOptions &getLangOptions() const { return LangOpts; }
+  const PreprocessingRecord *getPreprocessingRecord() const { return PPRec; }
+
+  bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
+
+  bool commit(const Commit &commit);
+  
+  void applyRewrites(EditsReceiver &receiver);
+  void clearRewrites();
+
+  StringRef copyString(StringRef str) {
+    char *buf = StrAlloc.Allocate<char>(str.size());
+    std::uninitialized_copy(str.begin(), str.end(), buf);
+    return StringRef(buf, str.size());
+  }
+  StringRef copyString(const Twine &twine);
+
+private:
+  bool commitInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
+                    bool beforePreviousInsertions);
+  bool commitInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
+                             FileOffset InsertFromRangeOffs, unsigned Len,
+                             bool beforePreviousInsertions);
+  void commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len);
+
+  StringRef getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
+                          bool &Invalid);
+  FileEditsTy::iterator getActionForOffset(FileOffset Offs);
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/EditsReceiver.h b/include/clang/Edit/EditsReceiver.h
new file mode 100644 (file)
index 0000000..600ac28
--- /dev/null
@@ -0,0 +1,35 @@
+//===----- EditedSource.h - Collection of source edits ----------*- 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_EDIT_EDITSRECEIVER_H
+#define LLVM_CLANG_EDIT_EDITSRECEIVER_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+  class SourceLocation;
+  class CharSourceRange;
+
+namespace edit {
+
+class EditsReceiver {
+public:
+  virtual ~EditsReceiver() { }
+
+  virtual void insert(SourceLocation loc, StringRef text) = 0;
+  virtual void replace(CharSourceRange range, StringRef text) = 0;
+  /// \brief By default it calls replace with an empty string.
+  virtual void remove(CharSourceRange range);
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/FileOffset.h b/include/clang/Edit/FileOffset.h
new file mode 100644 (file)
index 0000000..675ad18
--- /dev/null
@@ -0,0 +1,65 @@
+//===----- FileOffset.h - Offset in a file ----------------------*- 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_EDIT_FILEOFFSET_H
+#define LLVM_CLANG_EDIT_FILEOFFSET_H
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+namespace edit {
+
+class FileOffset {
+  FileID FID;
+  unsigned Offs;
+public:
+  FileOffset() : Offs(0) { }
+  FileOffset(FileID fid, unsigned offs) : FID(fid), Offs(offs) { }
+
+  bool isInvalid() const { return FID.isInvalid(); }
+
+  FileID getFID() const { return FID; }
+  unsigned getOffset() const { return Offs; }
+
+  FileOffset getWithOffset(unsigned offset) const {
+    FileOffset NewOffs = *this;
+    NewOffs.Offs += offset;
+    return NewOffs;
+  }
+
+  friend bool operator==(FileOffset LHS, FileOffset RHS) {
+    return LHS.FID == RHS.FID && LHS.Offs == RHS.Offs;
+  }
+  friend bool operator!=(FileOffset LHS, FileOffset RHS) {
+    return !(LHS == RHS);
+  }
+  friend bool operator<(FileOffset LHS, FileOffset RHS) {
+    if (LHS.FID != RHS.FID)
+      return LHS.FID < RHS.FID;
+    return LHS.Offs < RHS.Offs;
+  }
+  friend bool operator>(FileOffset LHS, FileOffset RHS) {
+    if (LHS.FID != RHS.FID)
+      return LHS.FID > RHS.FID;
+    return LHS.Offs > RHS.Offs;
+  }
+  friend bool operator>=(FileOffset LHS, FileOffset RHS) {
+    return LHS > RHS || LHS == RHS;
+  }
+  friend bool operator<=(FileOffset LHS, FileOffset RHS) {
+    return LHS < RHS || LHS == RHS;
+  }
+};
+
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Edit/Rewriters.h b/include/clang/Edit/Rewriters.h
new file mode 100644 (file)
index 0000000..aa7a5b2
--- /dev/null
@@ -0,0 +1,33 @@
+//===--- Rewriters.h - Rewritings     ---------------------------*- 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_EDIT_REWRITERS_H
+#define LLVM_CLANG_EDIT_REWRITERS_H
+
+namespace clang {
+  class ObjCMessageExpr;
+  class NSAPI;
+
+namespace edit {
+  class Commit;
+
+bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
+                                         const NSAPI &NS, Commit &commit);
+
+bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
+                                const NSAPI &NS, Commit &commit);
+
+bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
+                                  const NSAPI &NS, Commit &commit);
+
+}
+
+}  // end namespace clang
+
+#endif
index f18fdebba7747f20575f6cccffa4f058a32e737f..0ec2f6b1ef32cf546bc250673ac32afc6f1fe53b 100644 (file)
@@ -46,6 +46,7 @@ namespace frontend {
     RewriteObjC,            ///< ObjC->C Rewriter.
     RewriteTest,            ///< Rewriter playground
     RunAnalysis,            ///< Run one or more source code analyses.
+    MigrateSource,          ///< Run migrator.
     RunPreprocessorOnly     ///< Just lex, no output.
   };
 }
@@ -118,7 +119,16 @@ public:
     ARCMT_Migrate
   } ARCMTAction;
 
-  std::string ARCMTMigrateDir;
+  enum {
+    ObjCMT_None = 0,
+    /// \brief Enable migration to modern ObjC literals.
+    ObjCMT_Literals = 0x1,
+    /// \brief Enable migration to modern ObjC subscripting.
+    ObjCMT_Subscripting = 0x2
+  };
+  unsigned ObjCMTAction;
+
+  std::string MTMigrateDir;
   std::string ARCMTMigrateReportOut;
 
   /// The input files and their types.
@@ -177,6 +187,7 @@ public:
     ShowVersion = 0;
     ARCMTAction = ARCMT_None;
     ARCMTMigrateEmitARCErrors = 0;
+    ObjCMTAction = ObjCMT_None;
   }
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
index 0ebd62c560f474c5101bddaa6cbbef90079c03d9..44f0611b17e6389fc9d92ea1edda249021295c7a 100644 (file)
@@ -18,6 +18,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Rewrite/Rewriter.h"
+#include "clang/Edit/EditedSource.h"
 
 namespace clang {
 
@@ -56,6 +57,8 @@ class FixItRewriter : public DiagnosticConsumer {
   /// \brief The diagnostics machinery.
   DiagnosticsEngine &Diags;
 
+  edit::EditedSource Editor;
+
   /// \brief The rewriter used to perform the various code
   /// modifications.
   Rewriter Rewrite;
index 61753074e82c5b7ee17b30e3c5ced0db01b9f7c1..07f22c4f3698fe7412b91cf060471631390ca2de 100644 (file)
@@ -398,13 +398,51 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
   if (err)
     return true;
 
-  CompilerInvocation CI;
-  remapper.applyMappings(CI);
-  remap = CI.getPreprocessorOpts().RemappedFiles;
+  PreprocessorOptions PPOpts;
+  remapper.applyMappings(PPOpts);
+  remap = PPOpts.RemappedFiles;
 
   return false;
 }
 
+bool arcmt::getFileRemappingsFromFileList(
+                        std::vector<std::pair<std::string,std::string> > &remap,
+                        ArrayRef<StringRef> remapFiles,
+                        DiagnosticConsumer *DiagClient) {
+  bool hasErrorOccurred = false;
+  llvm::StringMap<bool> Uniquer;
+
+  llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+  llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+      new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false));
+
+  for (ArrayRef<StringRef>::iterator
+         I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
+    StringRef file = *I;
+
+    FileRemapper remapper;
+    bool err = remapper.initFromFile(file, *Diags,
+                                     /*ignoreIfFilesChanged=*/true);
+    hasErrorOccurred = hasErrorOccurred || err;
+    if (err)
+      continue;
+
+    PreprocessorOptions PPOpts;
+    remapper.applyMappings(PPOpts);
+    for (PreprocessorOptions::remapped_file_iterator
+           RI = PPOpts.remapped_file_begin(), RE = PPOpts.remapped_file_end();
+           RI != RE; ++RI) {
+      bool &inserted = Uniquer[RI->first];
+      if (inserted)
+        continue;
+      inserted = true;
+      remap.push_back(*RI);
+    }
+  }
+
+  return hasErrorOccurred;
+}
+
 //===----------------------------------------------------------------------===//
 // CollectTransformActions.
 //===----------------------------------------------------------------------===//
@@ -504,7 +542,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
   CInvok.reset(createInvocationForMigration(OrigCI));
   CInvok->getDiagnosticOpts().IgnoreWarnings = true;
 
-  Remapper.applyMappings(*CInvok);
+  Remapper.applyMappings(CInvok->getPreprocessorOpts());
 
   CapturedDiagList capturedDiags;
   std::vector<SourceLocation> ARCMTMacroLocs;
index 1a64b12721d968bd3254aa71451cde1e4dbdb0b5..fcb7f72ee21ddb0a9a269d8a52c1f773d760ce0d 100644 (file)
@@ -4,6 +4,7 @@ add_clang_library(clangARCMigrate
   ARCMT.cpp
   ARCMTActions.cpp
   FileRemapper.cpp
+  ObjCMT.cpp
   PlistReporter.cpp
   TransAPIUses.cpp
   TransARCAssign.cpp
index 0e6e35c748f52cb7492d4bf94f43e4f7fdf6fa8b..1e97c9eed523a89cacbd1028d794e5db7c6275fe 100644 (file)
@@ -8,8 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PreprocessorOptions.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/FileSystem.h"
@@ -50,9 +51,15 @@ std::string FileRemapper::getRemapInfoFile(StringRef outputDir) {
 
 bool FileRemapper::initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag,
                                 bool ignoreIfFilesChanged) {
+  std::string infoFile = getRemapInfoFile(outputDir);
+  return initFromFile(infoFile, Diag, ignoreIfFilesChanged);
+}
+
+bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag,
+                                bool ignoreIfFilesChanged) {
   assert(FromToMappings.empty() &&
          "initFromDisk should be called before any remap calls");
-  std::string infoFile = getRemapInfoFile(outputDir);
+  std::string infoFile = filePath;
   bool fileExists = false;
   llvm::sys::fs::exists(infoFile, fileExists);
   if (!fileExists)
@@ -108,8 +115,15 @@ bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) {
   if (fs::create_directory(outputDir, existed) != llvm::errc::success)
     return report("Could not create directory: " + outputDir, Diag);
 
-  std::string errMsg;
   std::string infoFile = getRemapInfoFile(outputDir);
+  return flushToFile(infoFile, Diag);
+}
+
+bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) {
+  using namespace llvm::sys;
+
+  std::string errMsg;
+  std::string infoFile = outputPath;
   llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg,
                                llvm::raw_fd_ostream::F_Binary);
   if (!errMsg.empty())
@@ -189,8 +203,7 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag,
   return false;
 }
 
-void FileRemapper::applyMappings(CompilerInvocation &CI) const {
-  PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const {
   for (MappingsTy::const_iterator
          I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
     if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
@@ -204,8 +217,7 @@ void FileRemapper::applyMappings(CompilerInvocation &CI) const {
   PPOpts.RetainRemappedFileBuffers = true;
 }
 
-void FileRemapper::transferMappingsAndClear(CompilerInvocation &CI) {
-  PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+void FileRemapper::transferMappingsAndClear(PreprocessorOptions &PPOpts) {
   for (MappingsTy::iterator
          I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) {
     if (const FileEntry *FE = I->second.dyn_cast<const FileEntry *>()) {
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
new file mode 100644 (file)
index 0000000..497377a
--- /dev/null
@@ -0,0 +1,226 @@
+//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ARCMigrate/ARCMTActions.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/NSAPI.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Edit/Rewriters.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
+#include "clang/Rewrite/Rewriter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+using namespace arcmt;
+
+namespace {
+
+class ObjCMigrateASTConsumer : public ASTConsumer {
+  void migrateDecl(Decl *D);
+
+public:
+  std::string MigrateDir;
+  bool MigrateLiterals;
+  bool MigrateSubscripting;
+  llvm::OwningPtr<NSAPI> NSAPIObj;
+  llvm::OwningPtr<edit::EditedSource> Editor;
+  FileRemapper &Remapper;
+  FileManager &FileMgr;
+  const PreprocessingRecord *PPRec;
+  bool IsOutputFile;
+
+  ObjCMigrateASTConsumer(StringRef migrateDir,
+                         bool migrateLiterals,
+                         bool migrateSubscripting,
+                         FileRemapper &remapper,
+                         FileManager &fileMgr,
+                         const PreprocessingRecord *PPRec,
+                         bool isOutputFile = false)
+  : MigrateDir(migrateDir),
+    MigrateLiterals(migrateLiterals),
+    MigrateSubscripting(migrateSubscripting),
+    Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec),
+    IsOutputFile(isOutputFile) { }
+
+protected:
+  virtual void Initialize(ASTContext &Context) {
+    NSAPIObj.reset(new NSAPI(Context));
+    Editor.reset(new edit::EditedSource(Context.getSourceManager(),
+                                        Context.getLangOptions(),
+                                        PPRec));
+  }
+
+  virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+    for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+      migrateDecl(*I);
+    return true;
+  }
+  virtual void HandleInterestingDecl(DeclGroupRef DG) {
+    // Ignore decls from the PCH.
+  }
+  virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {
+    ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
+  }
+
+  virtual void HandleTranslationUnit(ASTContext &Ctx);
+};
+
+}
+
+ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
+                             StringRef migrateDir,
+                             bool migrateLiterals,
+                             bool migrateSubscripting)
+  : WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
+    MigrateLiterals(migrateLiterals), MigrateSubscripting(migrateSubscripting),
+    CompInst(0) {
+  if (MigrateDir.empty())
+    MigrateDir = "."; // user current directory if none is given.
+}
+
+ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
+                                                  StringRef InFile) {
+  ASTConsumer *
+    WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+  ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
+                                                       MigrateLiterals,
+                                                       MigrateSubscripting,
+                                                       Remapper,
+                                                    CompInst->getFileManager(),
+                          CompInst->getPreprocessor().getPreprocessingRecord()); 
+  ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
+  return new MultiplexConsumer(Consumers);
+}
+
+bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
+  Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
+                        /*ignoreIfFilesChanges=*/true);
+  CompInst = &CI;
+  CI.getDiagnostics().setIgnoreAllWarnings(true);
+  CI.getPreprocessorOpts().DetailedRecord = true;
+  CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
+  return true;
+}
+
+namespace {
+class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
+  ObjCMigrateASTConsumer &Consumer;
+
+public:
+  ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+
+  bool shouldVisitTemplateInstantiations() const { return false; }
+  bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+    if (Consumer.MigrateLiterals) {
+      edit::Commit commit(*Consumer.Editor);
+      edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit);
+      Consumer.Editor->commit(commit);
+    }
+
+    if (Consumer.MigrateSubscripting) {
+      edit::Commit commit(*Consumer.Editor);
+      edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
+      Consumer.Editor->commit(commit);
+    }
+
+    return true;
+  }
+
+  bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
+    // Do depth first; we want to rewrite the subexpressions first so that if
+    // we have to move expressions we will move them already rewritten.
+    for (Stmt::child_range range = E->children(); range; ++range)
+      if (!TraverseStmt(*range))
+        return false;
+
+    return WalkUpFromObjCMessageExpr(E);
+  }
+};
+}
+
+void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
+  if (!D)
+    return;
+  if (isa<ObjCMethodDecl>(D))
+    return; // Wait for the ObjC container declaration.
+
+  ObjCMigrator(*this).TraverseDecl(D);
+}
+
+namespace {
+
+class RewritesReceiver : public edit::EditsReceiver {
+  Rewriter &Rewrite;
+
+public:
+  RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
+
+  virtual void insert(SourceLocation loc, StringRef text) {
+    Rewrite.InsertText(loc, text);
+  }
+  virtual void replace(CharSourceRange range, StringRef text) {
+    Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
+  }
+};
+
+}
+
+void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
+  Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOptions());
+  RewritesReceiver Rec(rewriter);
+  Editor->applyRewrites(Rec);
+
+  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);
+    llvm::SmallString<512> newText;
+    llvm::raw_svector_ostream vecOS(newText);
+    buf.write(vecOS);
+    vecOS.flush();
+    llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
+                   StringRef(newText.data(), newText.size()), file->getName());
+    llvm::SmallString<64> filePath(file->getName());
+    FileMgr.FixupRelativePath(filePath);
+    Remapper.remap(filePath.str(), memBuf);
+  }
+
+  if (IsOutputFile) {
+    Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
+  } else {
+    Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
+  }
+}
+
+bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
+  CI.getPreprocessorOpts().DetailedRecord = true;
+  CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
+  return true;
+}
+
+ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
+                                                  StringRef InFile) {
+  return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
+                                    /*MigrateLiterals=*/true,
+                                    /*MigrateSubscripting=*/true,
+                                    Remapper,
+                                    CI.getFileManager(),
+                                  CI.getPreprocessor().getPreprocessingRecord(),
+                                    /*isOutputFile=*/true); 
+}
index 7bb7b5eeeae9aee3b9e1edee831ef9fba1dc13c4..15669ac973c8d8d3ab01bfb57e23ba90cd7b3489 100644 (file)
@@ -21,6 +21,8 @@
 #include "Internals.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "clang/AST/ParentMap.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
 
 using namespace clang;
 using namespace arcmt;
@@ -128,27 +130,105 @@ public:
     Transaction Trans(Pass.TA);
     clearDiagnostics(rec->getExprLoc());
 
-    if (E->getMethodFamily() == OMF_release &&
-        isRemovable(E) && isInAtFinally(E)) {
+    ObjCMessageExpr *Msg = E;
+    Expr *RecContainer = Msg;
+    SourceRange RecRange = rec->getSourceRange();
+    checkForGCDOrXPC(Msg, RecContainer, rec, RecRange);
+
+    if (Msg->getMethodFamily() == OMF_release &&
+        isRemovable(RecContainer) && isInAtFinally(RecContainer)) {
       // Change the -release to "receiver = nil" in a finally to avoid a leak
       // when an exception is thrown.
-      Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
+      Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
       std::string str = " = ";
       str += getNilString(Pass.Ctx);
-      Pass.TA.insertAfterToken(rec->getLocEnd(), str);
+      Pass.TA.insertAfterToken(RecRange.getEnd(), str);
       return true;
     }
 
-    if (!hasSideEffects(E, Pass.Ctx)) {
-      if (tryRemoving(E))
+    if (!hasSideEffects(rec, Pass.Ctx)) {
+      if (tryRemoving(RecContainer))
         return true;
     }
-    Pass.TA.replace(E->getSourceRange(), rec->getSourceRange());
+    Pass.TA.replace(RecContainer->getSourceRange(), RecRange);
 
     return true;
   }
 
 private:
+  /// \brief Check if the retain/release is due to a GCD/XPC macro that are
+  /// defined as:
+  ///
+  /// #define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
+  /// #define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
+  /// #define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
+  /// #define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
+  ///
+  /// and return the top container which is the StmtExpr and the macro argument
+  /// expression.
+  void checkForGCDOrXPC(ObjCMessageExpr *Msg, Expr *&RecContainer,
+                        Expr *&Rec, SourceRange &RecRange) {
+    SourceLocation Loc = Msg->getExprLoc();
+    if (!Loc.isMacroID())
+      return;
+    SourceManager &SM = Pass.Ctx.getSourceManager();
+    StringRef MacroName = Lexer::getImmediateMacroName(Loc, SM,
+                                                     Pass.Ctx.getLangOptions());
+    bool isGCDOrXPC = llvm::StringSwitch<bool>(MacroName)
+        .Case("dispatch_retain", true)
+        .Case("dispatch_release", true)
+        .Case("xpc_retain", true)
+        .Case("xpc_release", true)
+        .Default(false);
+    if (!isGCDOrXPC)
+      return;
+
+    StmtExpr *StmtE = 0;
+    Stmt *S = Msg;
+    while (S) {
+      if (StmtExpr *SE = dyn_cast<StmtExpr>(S)) {
+        StmtE = SE;
+        break;
+      }
+      S = StmtMap->getParent(S);
+    }
+
+    if (!StmtE)
+      return;
+
+    Stmt::child_range StmtExprChild = StmtE->children();
+    if (!StmtExprChild)
+      return;
+    CompoundStmt *CompS = dyn_cast_or_null<CompoundStmt>(*StmtExprChild);
+    if (!CompS)
+      return;
+
+    Stmt::child_range CompStmtChild = CompS->children();
+    if (!CompStmtChild)
+      return;
+    DeclStmt *DeclS = dyn_cast_or_null<DeclStmt>(*CompStmtChild);
+    if (!DeclS)
+      return;
+    if (!DeclS->isSingleDecl())
+      return;
+    VarDecl *VD = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl());
+    if (!VD)
+      return;
+    Expr *Init = VD->getInit();
+    if (!Init)
+      return;
+
+    RecContainer = StmtE;
+    Rec = Init->IgnoreParenImpCasts();
+    if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Rec))
+      Rec = EWC->getSubExpr()->IgnoreParenImpCasts();
+    RecRange = Rec->getSourceRange();
+    if (SM.isMacroArgExpansion(RecRange.getBegin()))
+      RecRange.setBegin(SM.getImmediateSpellingLoc(RecRange.getBegin()));
+    if (SM.isMacroArgExpansion(RecRange.getEnd()))
+      RecRange.setEnd(SM.getImmediateSpellingLoc(RecRange.getEnd()));
+  }
+
   void clearDiagnostics(SourceLocation loc) const {
     Pass.TA.clearDiagnostic(diag::err_arc_illegal_explicit_message,
                             diag::err_unavailable,
index f0e0c9c778f6119b7196c6bac874e970cedb4c2d..8c33a963c927572a3aafc1b52795a175873a2d42 100644 (file)
@@ -657,19 +657,6 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
     }
   }
 
-  // If we have any Fix-Its, make sure that all of the Fix-Its point into
-  // source locations that aren't macro expansions. If any point into macro
-  // expansions, remove all of the Fix-Its.
-  for (unsigned I = 0, N = Diag.FixItHints.size(); I != N; ++I) {
-    const FixItHint &FixIt = Diag.FixItHints[I];
-    if (FixIt.RemoveRange.isInvalid() ||
-        FixIt.RemoveRange.getBegin().isMacroID() ||
-        FixIt.RemoveRange.getEnd().isMacroID()) {
-      Diag.FixItHints.clear();
-      break;
-    }    
-  }
-  
   // Finally, report it.
   Diag.Client->HandleDiagnostic((DiagnosticsEngine::Level)DiagLevel, Info);
   if (Diag.Client->IncludeInDiagnosticCounts()) {
index 7b46c6040a9c41a79818b96546d2c2607dc431ff..54d296c3abb6cc144418edbe732b609c62af2742 100644 (file)
@@ -6,6 +6,7 @@ add_subdirectory(AST)
 add_subdirectory(Sema)
 add_subdirectory(CodeGen)
 add_subdirectory(Analysis)
+add_subdirectory(Edit)
 add_subdirectory(Rewrite)
 add_subdirectory(ARCMigrate)
 add_subdirectory(Driver)
index a9dc17b320f880095f06a2bc613edc7bafe7e17b..d7b4bc705305ad9ea19e812d7f2de81f200cb75b 100644 (file)
@@ -27,6 +27,7 @@ const char *Action::getClassName(ActionClass AC) {
   case PreprocessJobClass: return "preprocessor";
   case PrecompileJobClass: return "precompiler";
   case AnalyzeJobClass: return "analyzer";
+  case MigrateJobClass: return "migrator";
   case CompileJobClass: return "compiler";
   case AssembleJobClass: return "assembler";
   case LinkJobClass: return "linker";
@@ -78,6 +79,12 @@ AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)
   : JobAction(AnalyzeJobClass, Input, OutputType) {
 }
 
+void MigrateJobAction::anchor() {}
+
+MigrateJobAction::MigrateJobAction(Action *Input, types::ID OutputType)
+  : JobAction(MigrateJobClass, Input, OutputType) {
+}
+
 void CompileJobAction::anchor() {}
 
 CompileJobAction::CompileJobAction(Action *Input, types::ID OutputType)
index e71f5a60650de0ccceae20f4ad18e6f3e7ec7291..30b7eccc8a13e4340c201742d1b086cbb17684e1 100644 (file)
@@ -141,6 +141,7 @@ const {
     // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
   } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
+             (PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
              (PhaseArg = DAL.getLastArg(options::OPT__analyze,
                                               options::OPT__analyze_auto)) ||
              (PhaseArg = DAL.getLastArg(options::OPT_emit_ast)) ||
@@ -1140,6 +1141,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
       return new CompileJobAction(Input, types::TY_RewrittenObjC);
     } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) {
       return new AnalyzeJobAction(Input, types::TY_Plist);
+    } else if (Args.hasArg(options::OPT__migrate)) {
+      return new MigrateJobAction(Input, types::TY_Remap);
     } else if (Args.hasArg(options::OPT_emit_ast)) {
       return new CompileJobAction(Input, types::TY_AST);
     } else if (IsUsingLTO(Args)) {
index c0c9c504b6d1387242e6a919779fcba572dbfec1..b4f5d0b421080c245d91aca8c75e62ce78a0a3bd 100644 (file)
@@ -54,6 +54,7 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
     // Assume a minimal NeXT runtime.
     runtime.HasARC = false;
     runtime.HasWeak = false;
+    runtime.HasSubscripting = false;
     runtime.HasTerminate = false;
     return;
 
@@ -61,6 +62,7 @@ void ToolChain::configureObjCRuntime(ObjCRuntime &runtime) const {
     // Assume a maximal GNU runtime.
     runtime.HasARC = true;
     runtime.HasWeak = true;
+    runtime.HasSubscripting = false; // to be added
     runtime.HasTerminate = false; // to be added
     return;
   }
index 5ff82c7600746a5bf436ab3f32a26d14bfa4d2f8..a45722315e4337649ddf6df9294579cea79a0466 100644 (file)
@@ -227,6 +227,7 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
     case Action::PreprocessJobClass:
       T = new tools::darwin::Preprocess(*this); break;
     case Action::AnalyzeJobClass:
+    case Action::MigrateJobClass:
       T = new tools::Clang(*this); break;
     case Action::PrecompileJobClass:
     case Action::CompileJobClass:
@@ -1409,6 +1410,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C,
     case Action::PrecompileJobClass:
       T = new tools::gcc::Precompile(*this); break;
     case Action::AnalyzeJobClass:
+    case Action::MigrateJobClass:
       T = new tools::Clang(*this); break;
     case Action::CompileJobClass:
       T = new tools::gcc::Compile(*this); break;
index 38f21c08829e27709d389aa6448501d4c705ee86..076311a78edc2545e6400ee034c921803f1c44ee 100644 (file)
@@ -1247,6 +1247,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (isa<AnalyzeJobAction>(JA)) {
     assert(JA.getType() == types::TY_Plist && "Invalid output type.");
     CmdArgs.push_back("-analyze");
+  } else if (isa<MigrateJobAction>(JA)) {
+    CmdArgs.push_back("-migrate");
   } else if (isa<PreprocessJobAction>(JA)) {
     if (Output.getType() == types::TY_Dependencies)
       CmdArgs.push_back("-Eonly");
@@ -1716,10 +1718,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
 
   Args.AddLastArg(CmdArgs, options::OPT_working_directory);
 
+  bool ARCMTEnabled = false;
   if (!Args.hasArg(options::OPT_fno_objc_arc)) {
     if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check,
                                        options::OPT_ccc_arcmt_modify,
                                        options::OPT_ccc_arcmt_migrate)) {
+      ARCMTEnabled = true;
       switch (A->getOption().getID()) {
       default:
         llvm_unreachable("missed a case");
@@ -1731,7 +1735,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
         break;
       case options::OPT_ccc_arcmt_migrate:
         CmdArgs.push_back("-arcmt-migrate");
-        CmdArgs.push_back("-arcmt-migrate-directory");
+        CmdArgs.push_back("-mt-migrate-directory");
         CmdArgs.push_back(A->getValue(Args));
 
         Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
@@ -1741,6 +1745,25 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     }
   }
 
+  if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) {
+    if (ARCMTEnabled) {
+      D.Diag(diag::err_drv_argument_not_allowed_with)
+        << A->getAsString(Args) << "-ccc-arcmt-migrate";
+    }
+    CmdArgs.push_back("-mt-migrate-directory");
+    CmdArgs.push_back(A->getValue(Args));
+
+    if (!Args.hasArg(options::OPT_objcmt_migrate_literals,
+                     options::OPT_objcmt_migrate_subscripting)) {
+      // None specified, means enable them all.
+      CmdArgs.push_back("-objcmt-migrate-literals");
+      CmdArgs.push_back("-objcmt-migrate-subscripting");
+    } else {
+      Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals);
+      Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting);
+    }
+  }
+
   // Add preprocessing options like -I, -D, etc. if we are using the
   // preprocessor.
   //
index 8a32db2fcad258229a25afa0fd45633a77c2c696..70bd4f1fc367f6a3a1a127a02f698bd2f309d596 100644 (file)
@@ -59,6 +59,7 @@ Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
     case Action::PreprocessJobClass:
     case Action::PrecompileJobClass:
     case Action::AnalyzeJobClass:
+    case Action::MigrateJobClass:
     case Action::CompileJobClass:
       T = new tools::Clang(*this); break;
     case Action::AssembleJobClass:
diff --git a/lib/Edit/CMakeLists.txt b/lib/Edit/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c87478c
--- /dev/null
@@ -0,0 +1,7 @@
+set(LLVM_USED_LIBS clangBasic clangAST clangLex)
+
+add_clang_library(clangEdit
+  Commit.cpp
+  EditedSource.cpp
+  RewriteObjCFoundationAPI.cpp
+  )
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
new file mode 100644 (file)
index 0000000..e0250cc
--- /dev/null
@@ -0,0 +1,345 @@
+//===----- Commit.cpp - A unit of edits -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Basic/SourceManager.h"
+
+using namespace clang;
+using namespace edit;
+
+SourceLocation Commit::Edit::getFileLocation(SourceManager &SM) const {
+  SourceLocation Loc = SM.getLocForStartOfFile(Offset.getFID());
+  Loc = Loc.getLocWithOffset(Offset.getOffset());
+  assert(Loc.isFileID());
+  return Loc;
+}
+
+CharSourceRange Commit::Edit::getFileRange(SourceManager &SM) const {
+  SourceLocation Loc = getFileLocation(SM);
+  return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
+}
+
+CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
+  SourceLocation Loc = SM.getLocForStartOfFile(InsertFromRangeOffs.getFID());
+  Loc = Loc.getLocWithOffset(InsertFromRangeOffs.getOffset());
+  assert(Loc.isFileID());
+  return CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(Length));
+}
+
+Commit::Commit(EditedSource &Editor)
+  : SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOptions()),
+    PPRec(Editor.getPreprocessingRecord()),
+    Editor(&Editor), IsCommitable(true) { }
+
+bool Commit::insert(SourceLocation loc, StringRef text,
+                    bool afterToken, bool beforePreviousInsertions) {
+  if (text.empty())
+    return true;
+
+  FileOffset Offs;
+  if ((!afterToken && !canInsert(loc, Offs)) ||
+      ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
+    IsCommitable = false;
+    return false;
+  }
+
+  addInsert(loc, Offs, text, beforePreviousInsertions);
+  return true;
+}
+
+bool Commit::insertFromRange(SourceLocation loc,
+                             CharSourceRange range,
+                             bool afterToken, bool beforePreviousInsertions) {
+  FileOffset RangeOffs;
+  unsigned RangeLen;
+  if (!canRemoveRange(range, RangeOffs, RangeLen)) {
+    IsCommitable = false;
+    return false;
+  }
+
+  FileOffset Offs;
+  if ((!afterToken && !canInsert(loc, Offs)) ||
+      ( afterToken && !canInsertAfterToken(loc, Offs, loc))) {
+    IsCommitable = false;
+    return false;
+  }
+
+  if (PPRec &&
+      PPRec->areInDifferentConditionalDirectiveRegion(loc, range.getBegin())) {
+    IsCommitable = false;
+    return false;
+  }
+
+  addInsertFromRange(loc, Offs, RangeOffs, RangeLen, beforePreviousInsertions);
+  return true;
+}
+
+bool Commit::remove(CharSourceRange range) {
+  FileOffset Offs;
+  unsigned Len;
+  if (!canRemoveRange(range, Offs, Len)) {
+    IsCommitable = false;
+    return false;
+  }
+
+  addRemove(range.getBegin(), Offs, Len);
+  return true;
+}
+
+bool Commit::insertWrap(StringRef before, CharSourceRange range,
+                        StringRef after) {
+  bool commitableBefore = insert(range.getBegin(), before, /*afterToken=*/false,
+                                 /*beforePreviousInsertions=*/true);
+  bool commitableAfter;
+  if (range.isTokenRange())
+    commitableAfter = insertAfterToken(range.getEnd(), after);
+  else
+    commitableAfter = insert(range.getEnd(), after);
+
+  return commitableBefore && commitableAfter;
+}
+
+bool Commit::replace(CharSourceRange range, StringRef text) {
+  if (text.empty())
+    return remove(range);
+
+  FileOffset Offs;
+  unsigned Len;
+  if (!canInsert(range.getBegin(), Offs) || !canRemoveRange(range, Offs, Len)) {
+    IsCommitable = false;
+    return false;
+  }
+
+  addRemove(range.getBegin(), Offs, Len);
+  addInsert(range.getBegin(), Offs, text, false);
+  return true;
+}
+
+bool Commit::replaceWithInner(CharSourceRange range,
+                              CharSourceRange replacementRange) {
+  FileOffset OuterBegin;
+  unsigned OuterLen;
+  if (!canRemoveRange(range, OuterBegin, OuterLen)) {
+    IsCommitable = false;
+    return false;
+  }
+
+  FileOffset InnerBegin;
+  unsigned InnerLen;
+  if (!canRemoveRange(replacementRange, InnerBegin, InnerLen)) {
+    IsCommitable = false;
+    return false;
+  }
+
+  FileOffset OuterEnd = OuterBegin.getWithOffset(OuterLen);
+  FileOffset InnerEnd = InnerBegin.getWithOffset(InnerLen); 
+  if (OuterBegin.getFID() != InnerBegin.getFID() ||
+      InnerBegin < OuterBegin ||
+      InnerBegin > OuterEnd ||
+      InnerEnd > OuterEnd) {
+    IsCommitable = false;
+    return false;
+  }
+
+  addRemove(range.getBegin(),
+            OuterBegin, InnerBegin.getOffset() - OuterBegin.getOffset());
+  addRemove(replacementRange.getEnd(),
+            InnerEnd, OuterEnd.getOffset() - InnerEnd.getOffset());
+  return true;
+}
+
+bool Commit::replaceText(SourceLocation loc, StringRef text,
+                         StringRef replacementText) {
+  if (text.empty() || replacementText.empty())
+    return true;
+
+  FileOffset Offs;
+  unsigned Len;
+  if (!canReplaceText(loc, replacementText, Offs, Len)) {
+    IsCommitable = false;
+    return false;
+  }
+
+  addRemove(loc, Offs, Len);
+  addInsert(loc, Offs, text, false);
+  return true;
+}
+
+void Commit::addInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
+                       bool beforePreviousInsertions) {
+  if (text.empty())
+    return;
+
+  Edit data;
+  data.Kind = Act_Insert;
+  data.OrigLoc = OrigLoc;
+  data.Offset = Offs;
+  data.Text = text;
+  data.BeforePrev = beforePreviousInsertions;
+  CachedEdits.push_back(data);
+}
+
+void Commit::addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
+                                FileOffset RangeOffs, unsigned RangeLen,
+                                bool beforePreviousInsertions) {
+  if (RangeLen == 0)
+    return;
+
+  Edit data;
+  data.Kind = Act_InsertFromRange;
+  data.OrigLoc = OrigLoc;
+  data.Offset = Offs;
+  data.InsertFromRangeOffs = RangeOffs;
+  data.Length = RangeLen;
+  data.BeforePrev = beforePreviousInsertions;
+  CachedEdits.push_back(data);
+}
+
+void Commit::addRemove(SourceLocation OrigLoc,
+                       FileOffset Offs, unsigned Len) {
+  if (Len == 0)
+    return;
+
+  Edit data;
+  data.Kind = Act_Remove;
+  data.OrigLoc = OrigLoc;
+  data.Offset = Offs;
+  data.Length = Len;
+  CachedEdits.push_back(data);
+}
+
+bool Commit::canInsert(SourceLocation loc, FileOffset &offs) {
+  if (loc.isInvalid())
+    return false;
+
+  if (loc.isMacroID())
+    isAtStartOfMacroExpansion(loc, &loc);
+
+  const SourceManager &SM = SourceMgr;
+  while (SM.isMacroArgExpansion(loc))
+    loc = SM.getImmediateSpellingLoc(loc);
+
+  if (loc.isMacroID())
+    if (!isAtStartOfMacroExpansion(loc, &loc))
+      return false;
+
+  if (SM.isInSystemHeader(loc))
+    return false;
+
+  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+  if (locInfo.first.isInvalid())
+    return false;
+  offs = FileOffset(locInfo.first, locInfo.second);
+  return canInsertInOffset(loc, offs);
+}
+
+bool Commit::canInsertAfterToken(SourceLocation loc, FileOffset &offs,
+                                 SourceLocation &AfterLoc) {
+  if (loc.isInvalid())
+
+    return false;
+
+  SourceLocation spellLoc = SourceMgr.getSpellingLoc(loc);
+  unsigned tokLen = Lexer::MeasureTokenLength(spellLoc, SourceMgr, LangOpts);
+  AfterLoc = loc.getLocWithOffset(tokLen);
+
+  if (loc.isMacroID())
+    isAtEndOfMacroExpansion(loc, &loc);
+
+  const SourceManager &SM = SourceMgr;
+  while (SM.isMacroArgExpansion(loc))
+    loc = SM.getImmediateSpellingLoc(loc);
+
+  if (loc.isMacroID())
+    if (!isAtEndOfMacroExpansion(loc, &loc))
+      return false;
+
+  if (SM.isInSystemHeader(loc))
+    return false;
+
+  loc = Lexer::getLocForEndOfToken(loc, 0, SourceMgr, LangOpts);
+  if (loc.isInvalid())
+    return false;
+
+  std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
+  if (locInfo.first.isInvalid())
+    return false;
+  offs = FileOffset(locInfo.first, locInfo.second);
+  return canInsertInOffset(loc, offs);
+}
+
+bool Commit::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
+  for (unsigned i = 0, e = CachedEdits.size(); i != e; ++i) {
+    Edit &act = CachedEdits[i];
+    if (act.Kind == Act_Remove) {
+      if (act.Offset.getFID() == Offs.getFID() &&
+          Offs > act.Offset && Offs < act.Offset.getWithOffset(act.Length))
+        return false; // position has been removed.
+    }
+  }
+
+  if (!Editor)
+    return true;
+  return Editor->canInsertInOffset(OrigLoc, Offs);
+}
+
+bool Commit::canRemoveRange(CharSourceRange range,
+                            FileOffset &Offs, unsigned &Len) {
+  const SourceManager &SM = SourceMgr;
+  range = Lexer::makeFileCharRange(range, SM, LangOpts);
+  if (range.isInvalid())
+    return false;
+  
+  if (range.getBegin().isMacroID() || range.getEnd().isMacroID())
+    return false;
+  if (SM.isInSystemHeader(range.getBegin()) ||
+      SM.isInSystemHeader(range.getEnd()))
+    return false;
+
+  if (PPRec && PPRec->rangeIntersectsConditionalDirective(range.getAsRange()))
+    return false;
+
+  std::pair<FileID, unsigned> beginInfo = SM.getDecomposedLoc(range.getBegin());
+  std::pair<FileID, unsigned> endInfo = SM.getDecomposedLoc(range.getEnd());
+  if (beginInfo.first != endInfo.first ||
+      beginInfo.second > endInfo.second)
+    return false;
+
+  Offs = FileOffset(beginInfo.first, beginInfo.second);
+  Len = endInfo.second - beginInfo.second;
+  return true;
+}
+
+bool Commit::canReplaceText(SourceLocation loc, StringRef text,
+                            FileOffset &Offs, unsigned &Len) {
+  assert(!text.empty());
+
+  if (!canInsert(loc, Offs))
+    return false;
+
+  // Try to load the file buffer.
+  bool invalidTemp = false;
+  StringRef file = SourceMgr.getBufferData(Offs.getFID(), &invalidTemp);
+  if (invalidTemp)
+    return false;
+
+  return file.substr(Offs.getOffset()).startswith(text);
+}
+
+bool Commit::isAtStartOfMacroExpansion(SourceLocation loc,
+                                       SourceLocation *MacroBegin) const {
+  return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, MacroBegin);
+}
+bool Commit::isAtEndOfMacroExpansion(SourceLocation loc,
+                                     SourceLocation *MacroEnd) const {
+  return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd);
+}
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
new file mode 100644 (file)
index 0000000..5b7fa4a
--- /dev/null
@@ -0,0 +1,329 @@
+//===----- EditedSource.cpp - Collection of source edits ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace clang;
+using namespace edit;
+
+void EditsReceiver::remove(CharSourceRange range) {
+  replace(range, StringRef());
+}
+
+StringRef EditedSource::copyString(const Twine &twine) {
+  llvm::SmallString<128> Data;
+  return copyString(twine.toStringRef(Data));
+}
+
+bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
+  FileEditsTy::iterator FA = getActionForOffset(Offs);
+  if (FA != FileEdits.end()) {
+    if (FA->first != Offs)
+      return false; // position has been removed.
+  }
+
+  if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
+    SourceLocation
+      DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
+    SourceLocation
+      ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+    llvm::DenseMap<unsigned, SourceLocation>::iterator
+      I = ExpansionToArgMap.find(ExpLoc.getRawEncoding());
+    if (I != ExpansionToArgMap.end() && I->second != DefArgLoc)
+      return false; // Trying to write in a macro argument input that has
+                 // already been written for another argument of the same macro. 
+  }
+
+  return true;
+}
+
+bool EditedSource::commitInsert(SourceLocation OrigLoc,
+                                FileOffset Offs, StringRef text,
+                                bool beforePreviousInsertions) {
+  if (!canInsertInOffset(OrigLoc, Offs))
+    return false;
+  if (text.empty())
+    return true;
+
+  if (SourceMgr.isMacroArgExpansion(OrigLoc)) {
+    SourceLocation
+      DefArgLoc = SourceMgr.getImmediateExpansionRange(OrigLoc).first;
+    SourceLocation
+      ExpLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first;
+    ExpansionToArgMap[ExpLoc.getRawEncoding()] = DefArgLoc;
+  }
+  
+  FileEdit &FA = FileEdits[Offs];
+  if (FA.Text.empty()) {
+    FA.Text = copyString(text);
+    return true;
+  }
+
+  Twine concat;
+  if (beforePreviousInsertions)
+    concat = Twine(text) + FA.Text;
+  else
+    concat = Twine(FA.Text) +  text;
+
+  FA.Text = copyString(concat);
+  return true;
+}
+
+bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
+                                   FileOffset Offs,
+                                   FileOffset InsertFromRangeOffs, unsigned Len,
+                                   bool beforePreviousInsertions) {
+  if (Len == 0)
+    return true;
+
+  llvm::SmallString<128> StrVec;
+  FileOffset BeginOffs = InsertFromRangeOffs;
+  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
+  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
+  if (I != FileEdits.begin())
+    --I;
+
+  for (; I != FileEdits.end(); ++I) {
+    FileEdit &FA = I->second;
+    FileOffset B = I->first;
+    FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+    if (BeginOffs < E) {
+      if (BeginOffs >= B) {
+        BeginOffs = E;
+        ++I;
+      }
+      break;
+    }
+  }
+
+  for (; I != FileEdits.end() && EndOffs > I->first; ++I) {
+    FileEdit &FA = I->second;
+    FileOffset B = I->first;
+    FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+    if (BeginOffs < B) {
+      bool Invalid = false;
+      StringRef text = getSourceText(BeginOffs, B, Invalid);
+      if (Invalid)
+        return false;
+      StrVec += text;
+    }
+    StrVec += FA.Text;
+    BeginOffs = E;
+  }
+
+  if (BeginOffs < EndOffs) {
+    bool Invalid = false;
+    StringRef text = getSourceText(BeginOffs, EndOffs, Invalid);
+    if (Invalid)
+      return false;
+    StrVec += text;
+  }
+
+  return commitInsert(OrigLoc, Offs, StrVec.str(), beforePreviousInsertions);
+}
+
+void EditedSource::commitRemove(SourceLocation OrigLoc,
+                                FileOffset BeginOffs, unsigned Len) {
+  if (Len == 0)
+    return;
+
+  FileOffset EndOffs = BeginOffs.getWithOffset(Len);
+  FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
+  if (I != FileEdits.begin())
+    --I;
+
+  for (; I != FileEdits.end(); ++I) {
+    FileEdit &FA = I->second;
+    FileOffset B = I->first;
+    FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+    if (BeginOffs < E)
+      break;
+  }
+
+  FileOffset TopBegin, TopEnd;
+  FileEdit *TopFA = 0;
+
+  if (I == FileEdits.end()) {
+    FileEditsTy::iterator
+      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
+    NewI->second.RemoveLen = Len;
+    return;
+  }
+
+  FileEdit &FA = I->second;
+  FileOffset B = I->first;
+  FileOffset E = B.getWithOffset(FA.RemoveLen);
+  if (BeginOffs < B) {
+    FileEditsTy::iterator
+      NewI = FileEdits.insert(I, std::make_pair(BeginOffs, FileEdit()));
+    TopBegin = BeginOffs;
+    TopEnd = EndOffs;
+    TopFA = &NewI->second;
+    TopFA->RemoveLen = Len;
+  } else {
+    TopBegin = B;
+    TopEnd = E;
+    TopFA = &I->second;
+    if (TopEnd >= EndOffs)
+      return;
+    unsigned diff = EndOffs.getOffset() - TopEnd.getOffset();
+    TopEnd = EndOffs;
+    TopFA->RemoveLen += diff;
+    ++I;
+  }
+
+  while (I != FileEdits.end()) {
+    FileEdit &FA = I->second;
+    FileOffset B = I->first;
+    FileOffset E = B.getWithOffset(FA.RemoveLen);
+
+    if (B >= TopEnd)
+      break;
+
+    if (E <= TopEnd) {
+      FileEdits.erase(I++);
+      continue;
+    }
+
+    if (B < TopEnd) {
+      unsigned diff = E.getOffset() - TopEnd.getOffset();
+      TopEnd = E;
+      TopFA->RemoveLen += diff;
+      FileEdits.erase(I);
+    }
+
+    break;
+  }
+}
+
+bool EditedSource::commit(const Commit &commit) {
+  if (!commit.isCommitable())
+    return false;
+
+  for (edit::Commit::edit_iterator
+         I = commit.edit_begin(), E = commit.edit_end(); I != E; ++I) {
+    const edit::Commit::Edit &edit = *I;
+    switch (edit.Kind) {
+    case edit::Commit::Act_Insert:
+      commitInsert(edit.OrigLoc, edit.Offset, edit.Text, edit.BeforePrev);
+      break;
+    case edit::Commit::Act_InsertFromRange:
+      commitInsertFromRange(edit.OrigLoc, edit.Offset,
+                            edit.InsertFromRangeOffs, edit.Length,
+                            edit.BeforePrev);
+      break;
+    case edit::Commit::Act_Remove:
+      commitRemove(edit.OrigLoc, edit.Offset, edit.Length);
+      break;
+    }
+  }
+
+  return true;
+}
+
+static void applyRewrite(EditsReceiver &receiver,
+                         StringRef text, FileOffset offs, unsigned len,
+                         const SourceManager &SM) {
+  assert(!offs.getFID().isInvalid());
+  SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
+  Loc = Loc.getLocWithOffset(offs.getOffset());
+  assert(Loc.isFileID());
+  CharSourceRange range = CharSourceRange::getCharRange(Loc,
+                                                     Loc.getLocWithOffset(len));
+
+  if (text.empty()) {
+    assert(len);
+    receiver.remove(range);
+    return;
+  }
+
+  if (len)
+    receiver.replace(range, text);
+  else
+    receiver.insert(Loc, text);
+}
+
+void EditedSource::applyRewrites(EditsReceiver &receiver) {
+  llvm::SmallString<128> StrVec;
+  FileOffset CurOffs, CurEnd;
+  unsigned CurLen;
+
+  if (FileEdits.empty())
+    return;
+
+  FileEditsTy::iterator I = FileEdits.begin();
+  CurOffs = I->first;
+  StrVec = I->second.Text;
+  CurLen = I->second.RemoveLen;
+  CurEnd = CurOffs.getWithOffset(CurLen);
+  ++I;
+
+  for (FileEditsTy::iterator E = FileEdits.end(); I != E; ++I) {
+    FileOffset offs = I->first;
+    FileEdit act = I->second;
+    assert(offs >= CurEnd);
+
+    if (offs == CurEnd) {
+      StrVec += act.Text;
+      CurLen += act.RemoveLen;
+      CurEnd.getWithOffset(act.RemoveLen);
+      continue;
+    }
+
+    applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+    CurOffs = offs;
+    StrVec = act.Text;
+    CurLen = act.RemoveLen;
+    CurEnd = CurOffs.getWithOffset(CurLen);
+  }
+
+  applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+}
+
+void EditedSource::clearRewrites() {
+  FileEdits.clear();
+  StrAlloc.Reset();
+}
+
+StringRef EditedSource::getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
+                                      bool &Invalid) {
+  assert(BeginOffs.getFID() == EndOffs.getFID());
+  assert(BeginOffs <= EndOffs);
+  SourceLocation BLoc = SourceMgr.getLocForStartOfFile(BeginOffs.getFID());
+  BLoc = BLoc.getLocWithOffset(BeginOffs.getOffset());
+  assert(BLoc.isFileID());
+  SourceLocation
+    ELoc = BLoc.getLocWithOffset(EndOffs.getOffset() - BeginOffs.getOffset());
+  return Lexer::getSourceText(CharSourceRange::getCharRange(BLoc, ELoc),
+                              SourceMgr, LangOpts, &Invalid);
+}
+
+EditedSource::FileEditsTy::iterator
+EditedSource::getActionForOffset(FileOffset Offs) {
+  FileEditsTy::iterator I = FileEdits.upper_bound(Offs);
+  if (I == FileEdits.begin())
+    return FileEdits.end();
+  --I;
+  FileEdit &FA = I->second;
+  FileOffset B = I->first;
+  FileOffset E = B.getWithOffset(FA.RemoveLen);
+  if (Offs >= B && Offs < E)
+    return I;
+
+  return FileEdits.end();
+}
diff --git a/lib/Edit/Makefile b/lib/Edit/Makefile
new file mode 100644 (file)
index 0000000..92a67eb
--- /dev/null
@@ -0,0 +1,14 @@
+##===- clang/lib/Edit/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 := ../..
+LIBRARYNAME := clangEdit
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
new file mode 100644 (file)
index 0000000..a092768
--- /dev/null
@@ -0,0 +1,589 @@
+//===--- RewriteObjCFoundationAPI.cpp - Foundation API Rewriter -----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Rewrites legacy method calls to modern syntax.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Edit/Rewriters.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/NSAPI.h"
+
+using namespace clang;
+using namespace edit;
+
+static bool checkForLiteralCreation(const ObjCMessageExpr *Msg,
+                                    IdentifierInfo *&ClassId) {
+  if (!Msg || Msg->isImplicit() || !Msg->getMethodDecl())
+    return false;
+
+  const ObjCInterfaceDecl *Receiver = Msg->getReceiverInterface();
+  if (!Receiver)
+    return false;
+  ClassId = Receiver->getIdentifier();
+
+  if (Msg->getReceiverKind() == ObjCMessageExpr::Class)
+    return true;
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteObjCRedundantCallWithLiteral.
+//===----------------------------------------------------------------------===//
+
+bool edit::rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
+                                              const NSAPI &NS, Commit &commit) {
+  IdentifierInfo *II = 0;
+  if (!checkForLiteralCreation(Msg, II))
+    return false;
+  if (Msg->getNumArgs() != 1)
+    return false;
+
+  const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
+  Selector Sel = Msg->getSelector();
+
+  if ((isa<ObjCStringLiteral>(Arg) &&
+       NS.getNSClassId(NSAPI::ClassId_NSString) == II &&
+       NS.getNSStringSelector(NSAPI::NSStr_stringWithString) == Sel)    ||
+
+      (isa<ObjCArrayLiteral>(Arg) &&
+       NS.getNSClassId(NSAPI::ClassId_NSArray) == II &&
+       NS.getNSArraySelector(NSAPI::NSArr_arrayWithArray) == Sel)      ||
+
+      (isa<ObjCDictionaryLiteral>(Arg) &&
+       NS.getNSClassId(NSAPI::ClassId_NSDictionary) == II &&
+       NS.getNSDictionarySelector(
+                              NSAPI::NSDict_dictionaryWithDictionary) == Sel)) {
+    
+    commit.replaceWithInner(Msg->getSourceRange(),
+                           Msg->getArg(0)->getSourceRange());
+    return true;
+  }
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToObjCSubscriptSyntax.
+//===----------------------------------------------------------------------===//
+
+static void maybePutParensOnReceiver(const Expr *Receiver, Commit &commit) {
+  Receiver = Receiver->IgnoreImpCasts();
+  if (isa<BinaryOperator>(Receiver) || isa<UnaryOperator>(Receiver)) {
+    SourceRange RecRange = Receiver->getSourceRange();
+    commit.insertWrap("(", RecRange, ")");
+  }
+}
+
+static bool rewriteToSubscriptGet(const ObjCMessageExpr *Msg, Commit &commit) {
+  if (Msg->getNumArgs() != 1)
+    return false;
+  const Expr *Rec = Msg->getInstanceReceiver();
+  if (!Rec)
+    return false;
+
+  SourceRange MsgRange = Msg->getSourceRange();
+  SourceRange RecRange = Rec->getSourceRange();
+  SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
+
+  commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
+                                                       ArgRange.getBegin()),
+                         CharSourceRange::getTokenRange(RecRange));
+  commit.replaceWithInner(SourceRange(ArgRange.getBegin(), MsgRange.getEnd()),
+                         ArgRange);
+  commit.insertWrap("[", ArgRange, "]");
+  maybePutParensOnReceiver(Rec, commit);
+  return true;
+}
+
+static bool rewriteToArraySubscriptSet(const ObjCMessageExpr *Msg,
+                                       Commit &commit) {
+  if (Msg->getNumArgs() != 2)
+    return false;
+  const Expr *Rec = Msg->getInstanceReceiver();
+  if (!Rec)
+    return false;
+
+  SourceRange MsgRange = Msg->getSourceRange();
+  SourceRange RecRange = Rec->getSourceRange();
+  SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
+  SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
+
+  commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
+                                                       Arg0Range.getBegin()),
+                         CharSourceRange::getTokenRange(RecRange));
+  commit.replaceWithInner(CharSourceRange::getCharRange(Arg0Range.getBegin(),
+                                                       Arg1Range.getBegin()),
+                         CharSourceRange::getTokenRange(Arg0Range));
+  commit.replaceWithInner(SourceRange(Arg1Range.getBegin(), MsgRange.getEnd()),
+                         Arg1Range);
+  commit.insertWrap("[", CharSourceRange::getCharRange(Arg0Range.getBegin(),
+                                                       Arg1Range.getBegin()),
+                    "] = ");
+  maybePutParensOnReceiver(Rec, commit);
+  return true;
+}
+
+static bool rewriteToDictionarySubscriptSet(const ObjCMessageExpr *Msg,
+                                            Commit &commit) {
+  if (Msg->getNumArgs() != 2)
+    return false;
+  const Expr *Rec = Msg->getInstanceReceiver();
+  if (!Rec)
+    return false;
+
+  SourceRange MsgRange = Msg->getSourceRange();
+  SourceRange RecRange = Rec->getSourceRange();
+  SourceRange Arg0Range = Msg->getArg(0)->getSourceRange();
+  SourceRange Arg1Range = Msg->getArg(1)->getSourceRange();
+
+  SourceLocation LocBeforeVal = Arg0Range.getBegin();
+  commit.insertBefore(LocBeforeVal, "] = ");
+  commit.insertFromRange(LocBeforeVal, Arg1Range, /*afterToken=*/false,
+                         /*beforePreviousInsertions=*/true);
+  commit.insertBefore(LocBeforeVal, "[");
+  commit.replaceWithInner(CharSourceRange::getCharRange(MsgRange.getBegin(),
+                                                       Arg0Range.getBegin()),
+                         CharSourceRange::getTokenRange(RecRange));
+  commit.replaceWithInner(SourceRange(Arg0Range.getBegin(), MsgRange.getEnd()),
+                         Arg0Range);
+  maybePutParensOnReceiver(Rec, commit);
+  return true;
+}
+
+bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
+                                           const NSAPI &NS, Commit &commit) {
+  if (!Msg || Msg->isImplicit() ||
+      Msg->getReceiverKind() != ObjCMessageExpr::Instance)
+    return false;
+  const ObjCMethodDecl *Method = Msg->getMethodDecl();
+  if (!Method)
+    return false;
+
+  const ObjCInterfaceDecl *
+    IFace = NS.getASTContext().getObjContainingInterface(
+                                          const_cast<ObjCMethodDecl *>(Method));
+  if (!IFace)
+    return false;
+  IdentifierInfo *II = IFace->getIdentifier();
+  Selector Sel = Msg->getSelector();
+
+  if ((II == NS.getNSClassId(NSAPI::ClassId_NSArray) &&
+       Sel == NS.getNSArraySelector(NSAPI::NSArr_objectAtIndex)) ||
+      (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary) &&
+       Sel == NS.getNSDictionarySelector(NSAPI::NSDict_objectForKey)))
+    return rewriteToSubscriptGet(Msg, commit);
+
+  if (Msg->getNumArgs() != 2)
+    return false;
+
+  if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableArray) &&
+      Sel == NS.getNSArraySelector(NSAPI::NSMutableArr_replaceObjectAtIndex))
+    return rewriteToArraySubscriptSet(Msg, commit);
+
+  if (II == NS.getNSClassId(NSAPI::ClassId_NSMutableDictionary) &&
+      Sel == NS.getNSDictionarySelector(NSAPI::NSMutableDict_setObjectForKey))
+    return rewriteToDictionarySubscriptSet(Msg, commit);
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToObjCLiteralSyntax.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
+                                  const NSAPI &NS, Commit &commit);
+static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
+                                  const NSAPI &NS, Commit &commit);
+static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
+                                  const NSAPI &NS, Commit &commit);
+
+bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
+                                      const NSAPI &NS, Commit &commit) {
+  IdentifierInfo *II = 0;
+  if (!checkForLiteralCreation(Msg, II))
+    return false;
+
+  if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
+    return rewriteToArrayLiteral(Msg, NS, commit);
+  if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
+    return rewriteToDictionaryLiteral(Msg, NS, commit);
+  if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
+    return rewriteToNumberLiteral(Msg, NS, commit);
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToArrayLiteral.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
+                                  const NSAPI &NS, Commit &commit) {
+  Selector Sel = Msg->getSelector();
+  SourceRange MsgRange = Msg->getSourceRange();
+
+  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array)) {
+    if (Msg->getNumArgs() != 0)
+      return false;
+    commit.replace(MsgRange, "@[]");
+    return true;
+  }
+
+  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
+    if (Msg->getNumArgs() != 1)
+      return false;
+    SourceRange ArgRange = Msg->getArg(0)->getSourceRange();
+    commit.replaceWithInner(MsgRange, ArgRange);
+    commit.insertWrap("@[", ArgRange, "]");
+    return true;
+  }
+
+  if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects)) {
+    if (Msg->getNumArgs() == 0)
+      return false;
+    const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
+    if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+      return false;
+
+    if (Msg->getNumArgs() == 1) {
+      commit.replace(MsgRange, "@[]");
+      return true;
+    }
+    SourceRange ArgRange(Msg->getArg(0)->getLocStart(),
+                         Msg->getArg(Msg->getNumArgs()-2)->getLocEnd());
+    commit.replaceWithInner(MsgRange, ArgRange);
+    commit.insertWrap("@[", ArgRange, "]");
+    return true;
+  }
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToDictionaryLiteral.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
+                                       const NSAPI &NS, Commit &commit) {
+  Selector Sel = Msg->getSelector();
+  SourceRange MsgRange = Msg->getSourceRange();
+
+  if (Sel == NS.getNSDictionarySelector(NSAPI::NSDict_dictionary)) {
+    if (Msg->getNumArgs() != 0)
+      return false;
+    commit.replace(MsgRange, "@{}");
+    return true;
+  }
+
+  if (Sel == NS.getNSDictionarySelector(
+                                    NSAPI::NSDict_dictionaryWithObjectForKey)) {
+    if (Msg->getNumArgs() != 2)
+      return false;
+    SourceRange ValRange = Msg->getArg(0)->getSourceRange();
+    SourceRange KeyRange = Msg->getArg(1)->getSourceRange();
+    // Insert key before the value.
+    commit.insertBefore(ValRange.getBegin(), ": ");
+    commit.insertFromRange(ValRange.getBegin(),
+                           CharSourceRange::getTokenRange(KeyRange),
+                       /*afterToken=*/false, /*beforePreviousInsertions=*/true);
+    commit.insertBefore(ValRange.getBegin(), "@{");
+    commit.insertAfterToken(ValRange.getEnd(), "}");
+    commit.replaceWithInner(MsgRange, ValRange);
+    return true;
+  }
+
+  if (Sel == NS.getNSDictionarySelector(
+                                  NSAPI::NSDict_dictionaryWithObjectsAndKeys)) {
+    if (Msg->getNumArgs() % 2 != 1)
+      return false;
+    unsigned SentinelIdx = Msg->getNumArgs() - 1;
+    const Expr *SentinelExpr = Msg->getArg(SentinelIdx);
+    if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+      return false;
+
+    if (Msg->getNumArgs() == 1) {
+      commit.replace(MsgRange, "@{}");
+      return true;
+    }
+
+    for (unsigned i = 0; i < SentinelIdx; i += 2) {
+      SourceRange ValRange = Msg->getArg(i)->getSourceRange();
+      SourceRange KeyRange = Msg->getArg(i+1)->getSourceRange();
+      // Insert value after key.
+      commit.insertAfterToken(KeyRange.getEnd(), ": ");
+      commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
+      commit.remove(CharSourceRange::getCharRange(ValRange.getBegin(),
+                                                  KeyRange.getBegin()));
+    }
+    // Range of arguments up until and including the last key.
+    // The sentinel and first value are cut off, the value will move after the
+    // key.
+    SourceRange ArgRange(Msg->getArg(1)->getLocStart(),
+                         Msg->getArg(SentinelIdx-1)->getLocEnd());
+    commit.insertWrap("@{", ArgRange, "}");
+    commit.replaceWithInner(MsgRange, ArgRange);
+    return true;
+  }
+
+  return false;
+}
+
+//===----------------------------------------------------------------------===//
+// rewriteToNumberLiteral.
+//===----------------------------------------------------------------------===//
+
+static bool rewriteToCharLiteral(const ObjCMessageExpr *Msg,
+                                   const CharacterLiteral *Arg,
+                                   const NSAPI &NS, Commit &commit) {
+  if (Arg->getKind() != CharacterLiteral::Ascii)
+    return false;
+  if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithChar,
+                                   Msg->getSelector())) {
+    SourceRange ArgRange = Arg->getSourceRange();
+    commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+    commit.insert(ArgRange.getBegin(), "@");
+    return true;
+  }
+
+  return false;
+}
+
+static bool rewriteToBoolLiteral(const ObjCMessageExpr *Msg,
+                                   const Expr *Arg,
+                                   const NSAPI &NS, Commit &commit) {
+  if (NS.isNSNumberLiteralSelector(NSAPI::NSNumberWithBool,
+                                   Msg->getSelector())) {
+    SourceRange ArgRange = Arg->getSourceRange();
+    commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+    commit.insert(ArgRange.getBegin(), "@");
+    return true;
+  }
+
+  return false;
+}
+
+namespace {
+
+struct LiteralInfo {
+  bool Hex, Octal;
+  StringRef U, F, L, LL;
+  CharSourceRange WithoutSuffRange;
+};
+
+}
+
+static bool getLiteralInfo(SourceRange literalRange,
+                           bool isFloat, bool isIntZero,
+                          ASTContext &Ctx, LiteralInfo &Info) {
+  if (literalRange.getBegin().isMacroID() ||
+      literalRange.getEnd().isMacroID())
+    return false;
+  StringRef text = Lexer::getSourceText(
+                                  CharSourceRange::getTokenRange(literalRange),
+                                  Ctx.getSourceManager(), Ctx.getLangOptions());
+  if (text.empty())
+    return false;
+
+  llvm::Optional<bool> UpperU, UpperL; 
+  bool UpperF = false;
+
+  struct Suff {
+    static bool has(StringRef suff, StringRef &text) {
+      if (text.endswith(suff)) {
+        text = text.substr(0, text.size()-suff.size());
+        return true;
+      }
+      return false;
+    }
+  };
+
+  while (1) {
+    if (Suff::has("u", text)) {
+      UpperU = false;
+    } else if (Suff::has("U", text)) {
+      UpperU = true;
+    } else if (Suff::has("ll", text)) {
+      UpperL = false;
+    } else if (Suff::has("LL", text)) {
+      UpperL = true;
+    } else if (Suff::has("l", text)) {
+      UpperL = false;
+    } else if (Suff::has("L", text)) {
+      UpperL = true;
+    } else if (isFloat && Suff::has("f", text)) {
+      UpperF = false;
+    } else if (isFloat && Suff::has("F", text)) {
+      UpperF = true;
+    } else
+      break;
+  }
+  
+  if (!UpperU.hasValue() && !UpperL.hasValue())
+    UpperU = UpperL = true;
+  else if (UpperU.hasValue() && !UpperL.hasValue())
+    UpperL = UpperU;
+  else if (UpperL.hasValue() && !UpperU.hasValue())
+    UpperU = UpperL;
+
+  Info.U = *UpperU ? "U" : "u";
+  Info.L = *UpperL ? "L" : "l";
+  Info.LL = *UpperL ? "LL" : "ll";
+  Info.F = UpperF ? "F" : "f";
+  
+  Info.Hex = Info.Octal = false;
+  if (text.startswith("0x"))
+    Info.Hex = true;
+  else if (!isFloat && !isIntZero && text.startswith("0"))
+    Info.Octal = true;
+
+  SourceLocation B = literalRange.getBegin();
+  Info.WithoutSuffRange =
+      CharSourceRange::getCharRange(B, B.getLocWithOffset(text.size()));
+  return true;
+}
+
+static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
+                                   const NSAPI &NS, Commit &commit) {
+  if (Msg->getNumArgs() != 1)
+    return false;
+
+  const Expr *Arg = Msg->getArg(0)->IgnoreParenImpCasts();
+  if (const CharacterLiteral *CharE = dyn_cast<CharacterLiteral>(Arg))
+    return rewriteToCharLiteral(Msg, CharE, NS, commit);
+  if (const ObjCBoolLiteralExpr *BE = dyn_cast<ObjCBoolLiteralExpr>(Arg))
+    return rewriteToBoolLiteral(Msg, BE, NS, commit);
+  if (const CXXBoolLiteralExpr *BE = dyn_cast<CXXBoolLiteralExpr>(Arg))
+    return rewriteToBoolLiteral(Msg, BE, NS, commit);
+
+  const Expr *literalE = Arg;
+  if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(literalE)) {
+    if (UOE->getOpcode() == UO_Plus || UOE->getOpcode() == UO_Minus)
+      literalE = UOE->getSubExpr();
+  }
+
+  // Only integer and floating literals; non-literals or imaginary literal
+  // cannot be rewritten.
+  if (!isa<IntegerLiteral>(literalE) && !isa<FloatingLiteral>(literalE))
+    return false;
+
+  ASTContext &Ctx = NS.getASTContext();
+  Selector Sel = Msg->getSelector();
+  llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+    MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
+  if (!MKOpt)
+    return false;
+  NSAPI::NSNumberLiteralMethodKind MK = *MKOpt;
+
+  bool CallIsInteger = false, CallIsUnsigned = false;
+  bool CallIsLong = false, CallIsLongLong = false; 
+  bool CallIsFloating = false, CallIsDouble = false;
+
+  switch (MK) {
+  // We cannot have these calls with int/float literals.
+  case NSAPI::NSNumberWithChar:
+  case NSAPI::NSNumberWithUnsignedChar:
+  case NSAPI::NSNumberWithShort:
+  case NSAPI::NSNumberWithUnsignedShort:
+  case NSAPI::NSNumberWithBool:
+    return false;
+
+  case NSAPI::NSNumberWithUnsignedInt:
+  case NSAPI::NSNumberWithUnsignedInteger:
+    CallIsUnsigned = true;
+  case NSAPI::NSNumberWithInt:
+  case NSAPI::NSNumberWithInteger:
+    CallIsInteger = true;
+    break;
+
+  case NSAPI::NSNumberWithUnsignedLong:
+    CallIsUnsigned = true;
+  case NSAPI::NSNumberWithLong:
+    CallIsInteger = true; CallIsLong = true;
+    break;
+
+  case NSAPI::NSNumberWithUnsignedLongLong:
+    CallIsUnsigned = true;
+  case NSAPI::NSNumberWithLongLong:
+    CallIsInteger = true; CallIsLongLong = true;
+    break;
+
+  case NSAPI::NSNumberWithDouble:
+    CallIsDouble = true;
+  case NSAPI::NSNumberWithFloat:
+    CallIsFloating = true;
+    break;
+  }
+
+  SourceRange ArgRange = Arg->getSourceRange();
+  QualType ArgTy = Arg->getType();
+  QualType CallTy = Msg->getArg(0)->getType();
+
+  // Check for the easy case, the literal maps directly to the call.
+  if (Ctx.hasSameType(ArgTy, CallTy)) {
+    commit.replaceWithInner(Msg->getSourceRange(), ArgRange);
+    commit.insert(ArgRange.getBegin(), "@");
+    return true;
+  }
+
+  // We will need to modify the literal suffix to get the same type as the call.
+  // Don't even try if it came from a macro.
+  if (ArgRange.getBegin().isMacroID())
+    return false;
+
+  bool LitIsFloat = ArgTy->isFloatingType();
+  // For a float passed to integer call, don't try rewriting. It is difficult
+  // and a very uncommon case anyway.
+  if (LitIsFloat && !CallIsFloating)
+    return false;
+
+  // Try to modify the literal make it the same type as the method call.
+  // -Modify the suffix, and/or
+  // -Change integer to float
+  
+  LiteralInfo LitInfo;
+  bool isIntZero = false;
+  if (const IntegerLiteral *IntE = dyn_cast<IntegerLiteral>(literalE))
+    isIntZero = !IntE->getValue().getBoolValue();
+  if (!getLiteralInfo(ArgRange, LitIsFloat, isIntZero, Ctx, LitInfo))
+    return false;
+
+  // Not easy to do int -> float with hex/octal and uncommon anyway.
+  if (!LitIsFloat && CallIsFloating && (LitInfo.Hex || LitInfo.Octal))
+    return false;
+  
+  SourceLocation LitB = LitInfo.WithoutSuffRange.getBegin();
+  SourceLocation LitE = LitInfo.WithoutSuffRange.getEnd();
+
+  commit.replaceWithInner(CharSourceRange::getTokenRange(Msg->getSourceRange()),
+                         LitInfo.WithoutSuffRange);
+  commit.insert(LitB, "@");
+
+  if (!LitIsFloat && CallIsFloating)
+    commit.insert(LitE, ".0");
+
+  if (CallIsFloating) {
+    if (!CallIsDouble)
+      commit.insert(LitE, LitInfo.F);
+  } else {
+    if (CallIsUnsigned)
+      commit.insert(LitE, LitInfo.U);
+  
+    if (CallIsLong)
+      commit.insert(LitE, LitInfo.L);
+    else if (CallIsLongLong)
+      commit.insert(LitE, LitInfo.LL);
+  }
+  return true;
+}
index 43ac4752112f999a84afbd074f658dfdd4274c93..9391eea32d0a5e50e7737152406a8f4a11a4bd30 100644 (file)
@@ -428,6 +428,7 @@ static const char *getActionName(frontend::ActionKind Kind) {
   case frontend::RewriteObjC:            return "-rewrite-objc";
   case frontend::RewriteTest:            return "-rewrite-test";
   case frontend::RunAnalysis:            return "-analyze";
+  case frontend::MigrateSource:          return "-migrate";
   case frontend::RunPreprocessorOnly:    return "-Eonly";
   }
 
@@ -483,9 +484,9 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
     Res.push_back("-arcmt-migrate");
     break;
   }
-  if (!Opts.ARCMTMigrateDir.empty()) {
-    Res.push_back("-arcmt-migrate-directory");
-    Res.push_back(Opts.ARCMTMigrateDir);
+  if (!Opts.MTMigrateDir.empty()) {
+    Res.push_back("-mt-migrate-directory");
+    Res.push_back(Opts.MTMigrateDir);
   }
   if (!Opts.ARCMTMigrateReportOut.empty()) {
     Res.push_back("-arcmt-migrate-report-output");
@@ -494,6 +495,11 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
   if (Opts.ARCMTMigrateEmitARCErrors)
     Res.push_back("-arcmt-migrate-emit-errors");
 
+  if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals)
+    Res.push_back("-objcmt-migrate-literals");
+  if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting)
+    Res.push_back("-objcmt-migrate-subscripting");
+
   bool NeedLang = false;
   for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
     if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) !=
@@ -828,6 +834,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
     Res.push_back("-fdebugger-support");
   if (Opts.DebuggerCastResultToId)
     Res.push_back("-fdebugger-cast-result-to-id");
+  if (Opts.DebuggerObjCLiteral)
+    Res.push_back("-fdebugger-objc-literal");
   if (Opts.DelayedTemplateParsing)
     Res.push_back("-fdelayed-template-parsing");
   if (Opts.Deprecated)
@@ -1376,6 +1384,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
       Opts.ProgramAction = frontend::RewriteTest; break;
     case OPT_analyze:
       Opts.ProgramAction = frontend::RunAnalysis; break;
+    case OPT_migrate:
+      Opts.ProgramAction = frontend::MigrateSource; break;
     case OPT_Eonly:
       Opts.ProgramAction = frontend::RunPreprocessorOnly; break;
     }
@@ -1432,7 +1442,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
   Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
   Opts.OverrideRecordLayoutsFile
     = Args.getLastArgValue(OPT_foverride_record_layout_EQ);
-  Opts.ARCMTAction = FrontendOptions::ARCMT_None;
   if (const Arg *A = Args.getLastArg(OPT_arcmt_check,
                                      OPT_arcmt_modify,
                                      OPT_arcmt_migrate)) {
@@ -1450,12 +1459,23 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
       break;
     }
   }
-  Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory);
+  Opts.MTMigrateDir = Args.getLastArgValue(OPT_mt_migrate_directory);
   Opts.ARCMTMigrateReportOut
     = Args.getLastArgValue(OPT_arcmt_migrate_report_output);
   Opts.ARCMTMigrateEmitARCErrors
     = Args.hasArg(OPT_arcmt_migrate_emit_arc_errors);
 
+  if (Args.hasArg(OPT_objcmt_migrate_literals))
+    Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Literals;
+  if (Args.hasArg(OPT_objcmt_migrate_subscripting))
+    Opts.ObjCMTAction |= FrontendOptions::ObjCMT_Subscripting;
+
+  if (Opts.ARCMTAction != FrontendOptions::ARCMT_None &&
+      Opts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
+    Diags.Report(diag::err_drv_argument_not_allowed_with)
+      << "ARC migration" << "ObjC migration";
+  }
+
   InputKind DashX = IK_None;
   if (const Arg *A = Args.getLastArg(OPT_x)) {
     DashX = llvm::StringSwitch<InputKind>(A->getValue(Args))
@@ -1899,6 +1919,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype);
   Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support);
   Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id);
+  Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal);
   Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer);
   Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer);
   Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
index 29f9ed5a7d47be8891490354210f11ba32b86208..6c3bb1d6953453a6ffe49fd81ad27b40e3665a96 100644 (file)
@@ -12,6 +12,9 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/DiagnosticOptions.h"
 #include "clang/Lex/Lexer.h"
+#include "clang/Edit/EditedSource.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -127,6 +130,54 @@ DiagnosticRenderer::DiagnosticRenderer(const SourceManager &SM,
 
 DiagnosticRenderer::~DiagnosticRenderer() {}
 
+namespace {
+
+class FixitReceiver : public edit::EditsReceiver {
+  SmallVectorImpl<FixItHint> &MergedFixits;
+
+public:
+  FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits)
+    : MergedFixits(MergedFixits) { }
+  virtual void insert(SourceLocation loc, StringRef text) {
+    MergedFixits.push_back(FixItHint::CreateInsertion(loc, text));
+  }
+  virtual void replace(CharSourceRange range, StringRef text) {
+    MergedFixits.push_back(FixItHint::CreateReplacement(range, text));
+  }
+};
+
+}
+
+static void mergeFixits(ArrayRef<FixItHint> FixItHints,
+                        const SourceManager &SM, const LangOptions &LangOpts,
+                        SmallVectorImpl<FixItHint> &MergedFixits) {
+  edit::Commit commit(SM, LangOpts);
+  for (ArrayRef<FixItHint>::const_iterator
+         I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) {
+    const FixItHint &Hint = *I;
+    if (Hint.CodeToInsert.empty()) {
+      if (Hint.InsertFromRange.isValid())
+        commit.insertFromRange(Hint.RemoveRange.getBegin(),
+                           Hint.InsertFromRange, /*afterToken=*/false,
+                           Hint.BeforePreviousInsertions);
+      else
+        commit.remove(Hint.RemoveRange);
+    } else {
+      if (Hint.RemoveRange.isTokenRange() ||
+          Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
+        commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
+      else
+        commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
+                    /*afterToken=*/false, Hint.BeforePreviousInsertions);
+    }
+  }
+
+  edit::EditedSource Editor(SM, LangOpts);
+  if (Editor.commit(commit)) {
+    FixitReceiver Rec(MergedFixits);
+    Editor.applyRewrites(Rec);
+  }
+}
 
 void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
                                         DiagnosticsEngine::Level Level,
@@ -152,6 +203,12 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
     SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
                                                    Ranges.end());
     
+    llvm::SmallVector<FixItHint, 8> MergedFixits;
+    if (!FixItHints.empty()) {
+      mergeFixits(FixItHints, SM, LangOpts, MergedFixits);
+      FixItHints = MergedFixits;
+    }
+
     for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
          E = FixItHints.end();
          I != E; ++I)
index 0841b2cef81120047cded0224b5f620ceef51535..07d2b8d19f2401f142ec3e13c50853cafd0ea5b5 100644 (file)
@@ -76,6 +76,7 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
   case RewriteObjC:            return new RewriteObjCAction();
   case RewriteTest:            return new RewriteTestAction();
   case RunAnalysis:            return new ento::AnalysisAction();
+  case MigrateSource:          return new arcmt::MigrateSourceAction();
   case RunPreprocessorOnly:    return new PreprocessOnlyAction();
   }
   llvm_unreachable("Invalid program action!");
@@ -105,12 +106,18 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
     break;
   case FrontendOptions::ARCMT_Migrate:
     Act = new arcmt::MigrateAction(Act,
-                                   FEOpts.ARCMTMigrateDir,
+                                   FEOpts.MTMigrateDir,
                                    FEOpts.ARCMTMigrateReportOut,
                                    FEOpts.ARCMTMigrateEmitARCErrors);
     break;
   }
 
+  if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
+    Act = new arcmt::ObjCMigrateAction(Act, FEOpts.MTMigrateDir,
+                   FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals,
+                   FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting);
+  }
+
   // If there are any AST files to merge, create a frontend action
   // adaptor to perform the merge.
   if (!FEOpts.ASTMergeFiles.empty())
index 74df7abcef24d4d9dbcc963ee4ee47e23c2abcac..69c5cd5d830be03ff77eb080ce4d5c672b72ba96 100755 (executable)
@@ -9,7 +9,7 @@
 CLANG_LEVEL := ..
 
 PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
-                StaticAnalyzer Rewrite ARCMigrate Serialization Frontend \
+                StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \
                 FrontendTool Index Driver
 
 include $(CLANG_LEVEL)/Makefile
index caa7d06ac2e54b2aca4b62c14ae68addf41d611a..3863adb4f1625ad8b3ce10fc6a1be20139fc2881 100644 (file)
@@ -14,6 +14,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Rewrite/FixItRewriter.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
@@ -29,6 +31,7 @@ FixItRewriter::FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
                              const LangOptions &LangOpts,
                              FixItOptions *FixItOpts)
   : Diags(Diags),
+    Editor(SourceMgr, LangOpts),
     Rewrite(SourceMgr, LangOpts),
     FixItOpts(FixItOpts),
     NumFailures(0),
@@ -51,6 +54,24 @@ bool FixItRewriter::WriteFixedFile(FileID ID, raw_ostream &OS) {
   return false;
 }
 
+namespace {
+
+class RewritesReceiver : public edit::EditsReceiver {
+  Rewriter &Rewrite;
+
+public:
+  RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
+
+  virtual void insert(SourceLocation loc, StringRef text) {
+    Rewrite.InsertText(loc, text);
+  }
+  virtual void replace(CharSourceRange range, StringRef text) {
+    Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
+  }
+};
+
+}
+
 bool FixItRewriter::WriteFixedFiles(
             std::vector<std::pair<std::string, std::string> > *RewrittenFiles) {
   if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) {
@@ -58,6 +79,9 @@ bool FixItRewriter::WriteFixedFiles(
     return true;
   }
 
+  RewritesReceiver Rec(Rewrite);
+  Editor.applyRewrites(Rec);
+
   for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) {
     const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
     int fd;
@@ -116,16 +140,28 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
 
   // Make sure that we can perform all of the modifications we
   // in this diagnostic.
-  bool CanRewrite = Info.getNumFixItHints() > 0;
+  edit::Commit commit(Editor);
   for (unsigned Idx = 0, Last = Info.getNumFixItHints();
        Idx < Last; ++Idx) {
     const FixItHint &Hint = Info.getFixItHint(Idx);
-    if (Hint.RemoveRange.isValid() &&
-        Rewrite.getRangeSize(Hint.RemoveRange) == -1) {
-      CanRewrite = false;
-      break;
+
+    if (Hint.CodeToInsert.empty()) {
+      if (Hint.InsertFromRange.isValid())
+        commit.insertFromRange(Hint.RemoveRange.getBegin(),
+                           Hint.InsertFromRange, /*afterToken=*/false,
+                           Hint.BeforePreviousInsertions);
+      else
+        commit.remove(Hint.RemoveRange);
+    } else {
+      if (Hint.RemoveRange.isTokenRange() ||
+          Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
+        commit.replace(Hint.RemoveRange, Hint.CodeToInsert);
+      else
+        commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
+                    /*afterToken=*/false, Hint.BeforePreviousInsertions);
     }
   }
+  bool CanRewrite = Info.getNumFixItHints() > 0 && commit.isCommitable();
 
   if (!CanRewrite) {
     if (Info.getNumFixItHints() > 0)
@@ -138,27 +174,8 @@ void FixItRewriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
     }
     return;
   }
-
-  bool Failed = false;
-  for (unsigned Idx = 0, Last = Info.getNumFixItHints();
-       Idx < Last; ++Idx) {
-    const FixItHint &Hint = Info.getFixItHint(Idx);
-
-    if (Hint.CodeToInsert.empty()) {
-      // We're removing code.
-      if (Rewrite.RemoveText(Hint.RemoveRange))
-        Failed = true;
-      continue;
-    }
-
-    // We're replacing code.
-    if (Rewrite.ReplaceText(Hint.RemoveRange.getBegin(),
-                            Rewrite.getRangeSize(Hint.RemoveRange),
-                            Hint.CodeToInsert))
-      Failed = true;
-  }
-
-  if (Failed) {
+  
+  if (!Editor.commit(commit)) {
     ++NumFailures;
     Diag(Info.getLocation(), diag::note_fixit_failed);
     return;
diff --git a/test/ARCMT/dispatch.m b/test/ARCMT/dispatch.m
new file mode 100644 (file)
index 0000000..75c4a83
--- /dev/null
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+#define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
+#define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
+#define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
+#define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
+
+typedef id dispatch_object_t;
+typedef id xpc_object_t;
+
+void _dispatch_object_validate(dispatch_object_t object);
+void _xpc_object_validate(xpc_object_t object);
+
+dispatch_object_t getme(void);
+
+void func(dispatch_object_t o) {
+  dispatch_retain(o);
+  dispatch_release(o);
+  dispatch_retain(getme());
+}
+
+void func2(xpc_object_t o) {
+  xpc_retain(o);
+  xpc_release(o);
+}
diff --git a/test/ARCMT/dispatch.m.result b/test/ARCMT/dispatch.m.result
new file mode 100644 (file)
index 0000000..e897672
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+#define dispatch_retain(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); (void)[_o retain]; })
+#define dispatch_release(object) ({ dispatch_object_t _o = (object); _dispatch_object_validate(_o); [_o release]; })
+#define xpc_retain(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o retain]; })
+#define xpc_release(object) ({ xpc_object_t _o = (object); _xpc_object_validate(_o); [_o release]; })
+
+typedef id dispatch_object_t;
+typedef id xpc_object_t;
+
+void _dispatch_object_validate(dispatch_object_t object);
+void _xpc_object_validate(xpc_object_t object);
+
+dispatch_object_t getme(void);
+
+void func(dispatch_object_t o) {
+  getme();
+}
+
+void func2(xpc_object_t o) {
+}
index a2b1a7dc27a7435da19357695ecf98c20e8d5c82..a912ad95b156d762929861960f48a0636a400716 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: %clang -### -ccc-arcmt-migrate /foo/bar -fsyntax-only %s 2>&1 | FileCheck %s
 
-// CHECK: "-arcmt-migrate" "-arcmt-migrate-directory" "{{[^"]*}}/foo/bar"
+// CHECK: "-arcmt-migrate" "-mt-migrate-directory" "{{[^"]*}}/foo/bar"
 
 // RUN: touch %t.o
 // RUN: %clang -ccc-arcmt-check -target i386-apple-darwin9 -### %t.o 2> %t.log
index 6a4a3963ca0bcaa6a724380b462edae68b1eeb90..95c0d2f8f073e6dad476b795705e5d61bef6e5de 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -arcmt-migrate-emit-errors %s 2>&1 | FileCheck %s
 // RUN: rm -rf %t
 
 @protocol NSObject
index b9e3ceff8645f0fcd63a8b3465cef3c4f1fa4666..12efa93f07526d66c5e946c88599a8d41c6440c4 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s 
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s 
 // RUN: FileCheck %s -input-file=%t.plist
 // RUN: rm -rf %t.dir
 
index e454fae642fd46a6fbee6dc62fa5bc1d225c5aa3..89dfe1475cfe9b59dff38568de0f3458159621f2 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: rm -rf %t.migrate
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c 
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c 
-// RUN: c-arcmt-test -arcmt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.migrate %S/"with space"/test1.m.in -x objective-c 
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t.migrate %S/"with space"/test2.m.in -x objective-c 
+// RUN: c-arcmt-test -mt-migrate-directory %t.migrate | arcmt-test -verify-transformed-files %S/"with space"/test1.m.in.result %S/"with space"/test2.m.in.result %S/"with space"/test.h.result
 // RUN: rm -rf %t.migrate
 // DISABLE: mingw32
index beaf8e5b1523d85321324599e4adcfae818f5b98..6f41258e59d60104b8b4f909286960c450451d43 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c 
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c 
-// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c 
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
 // RUN: rm -rf %t
 // DISABLE: mingw32
diff --git a/test/ARCMT/objcmt-numeric-literals.m b/test/ARCMT/objcmt-numeric-literals.m
new file mode 100644 (file)
index 0000000..b86af4d
--- /dev/null
@@ -0,0 +1,501 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+#define YES __objc_yes
+#define NO __objc_no
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
+- (id)initWithChar:(char)value;
+- (id)initWithUnsignedChar:(unsigned char)value;
+- (id)initWithShort:(short)value;
+- (id)initWithUnsignedShort:(unsigned short)value;
+- (id)initWithInt:(int)value;
+- (id)initWithUnsignedInt:(unsigned int)value;
+- (id)initWithLong:(long)value;
+- (id)initWithUnsignedLong:(unsigned long)value;
+- (id)initWithLongLong:(long long)value;
+- (id)initWithUnsignedLongLong:(unsigned long long)value;
+- (id)initWithFloat:(float)value;
+- (id)initWithDouble:(double)value;
+- (id)initWithBool:(BOOL)value;
+- (id)initWithInteger:(NSInteger)value;
+- (id)initWithUnsignedInteger:(NSUInteger)value;
+
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+@end
+
+#define VAL_INT 2
+#define VAL_UINT 2U
+#define VAL_CHAR 'a'
+
+void foo() {
+  [NSNumber numberWithChar:'a'];
+  [NSNumber numberWithChar:L'a'];
+  [NSNumber numberWithChar:2];
+  [NSNumber numberWithChar:2U];
+  [NSNumber numberWithChar:2u];
+  [NSNumber numberWithChar:2L];
+  [NSNumber numberWithChar:2l];
+  [NSNumber numberWithChar:2LL];
+  [NSNumber numberWithChar:2ll];
+  [NSNumber numberWithChar:2ul];
+  [NSNumber numberWithChar:2lu];
+  [NSNumber numberWithChar:2ull];
+  [NSNumber numberWithChar:2llu];
+  [NSNumber numberWithChar:2.0];
+  [NSNumber numberWithChar:2.0f];
+  [NSNumber numberWithChar:2.0F];
+  [NSNumber numberWithChar:2.0l];
+  [NSNumber numberWithChar:2.0L];
+  [NSNumber numberWithChar:0x2f];
+  [NSNumber numberWithChar:04];
+  [NSNumber numberWithChar:0];
+  [NSNumber numberWithChar:0.0];
+  [NSNumber numberWithChar:YES];
+  [NSNumber numberWithChar:NO];
+  [NSNumber numberWithChar:true];
+  [NSNumber numberWithChar:false];
+  [NSNumber numberWithChar:VAL_INT];
+  [NSNumber numberWithChar:VAL_UINT];
+  [NSNumber numberWithChar:VAL_CHAR];
+
+  [NSNumber numberWithUnsignedChar:'a'];
+  [NSNumber numberWithUnsignedChar:L'a'];
+  [NSNumber numberWithUnsignedChar:2];
+  [NSNumber numberWithUnsignedChar:2U];
+  [NSNumber numberWithUnsignedChar:2u];
+  [NSNumber numberWithUnsignedChar:2L];
+  [NSNumber numberWithUnsignedChar:2l];
+  [NSNumber numberWithUnsignedChar:2LL];
+  [NSNumber numberWithUnsignedChar:2ll];
+  [NSNumber numberWithUnsignedChar:2ul];
+  [NSNumber numberWithUnsignedChar:2lu];
+  [NSNumber numberWithUnsignedChar:2ull];
+  [NSNumber numberWithUnsignedChar:2llu];
+  [NSNumber numberWithUnsignedChar:2.0];
+  [NSNumber numberWithUnsignedChar:2.0f];
+  [NSNumber numberWithUnsignedChar:2.0F];
+  [NSNumber numberWithUnsignedChar:2.0l];
+  [NSNumber numberWithUnsignedChar:2.0L];
+  [NSNumber numberWithUnsignedChar:0x2f];
+  [NSNumber numberWithUnsignedChar:04];
+  [NSNumber numberWithUnsignedChar:0];
+  [NSNumber numberWithUnsignedChar:0.0];
+  [NSNumber numberWithUnsignedChar:YES];
+  [NSNumber numberWithUnsignedChar:NO];
+  [NSNumber numberWithUnsignedChar:true];
+  [NSNumber numberWithUnsignedChar:false];
+  [NSNumber numberWithUnsignedChar:VAL_INT];
+  [NSNumber numberWithUnsignedChar:VAL_UINT];
+  [NSNumber numberWithUnsignedChar:VAL_CHAR];
+
+  [NSNumber numberWithShort:'a'];
+  [NSNumber numberWithShort:L'a'];
+  [NSNumber numberWithShort:2];
+  [NSNumber numberWithShort:2U];
+  [NSNumber numberWithShort:2u];
+  [NSNumber numberWithShort:2L];
+  [NSNumber numberWithShort:2l];
+  [NSNumber numberWithShort:2LL];
+  [NSNumber numberWithShort:2ll];
+  [NSNumber numberWithShort:2ul];
+  [NSNumber numberWithShort:2lu];
+  [NSNumber numberWithShort:2ull];
+  [NSNumber numberWithShort:2llu];
+  [NSNumber numberWithShort:2.0];
+  [NSNumber numberWithShort:2.0f];
+  [NSNumber numberWithShort:2.0F];
+  [NSNumber numberWithShort:2.0l];
+  [NSNumber numberWithShort:2.0L];
+  [NSNumber numberWithShort:0x2f];
+  [NSNumber numberWithShort:04];
+  [NSNumber numberWithShort:0];
+  [NSNumber numberWithShort:0.0];
+  [NSNumber numberWithShort:YES];
+  [NSNumber numberWithShort:NO];
+  [NSNumber numberWithShort:true];
+  [NSNumber numberWithShort:false];
+  [NSNumber numberWithShort:VAL_INT];
+  [NSNumber numberWithShort:VAL_UINT];
+
+  [NSNumber numberWithUnsignedShort:'a'];
+  [NSNumber numberWithUnsignedShort:L'a'];
+  [NSNumber numberWithUnsignedShort:2];
+  [NSNumber numberWithUnsignedShort:2U];
+  [NSNumber numberWithUnsignedShort:2u];
+  [NSNumber numberWithUnsignedShort:2L];
+  [NSNumber numberWithUnsignedShort:2l];
+  [NSNumber numberWithUnsignedShort:2LL];
+  [NSNumber numberWithUnsignedShort:2ll];
+  [NSNumber numberWithUnsignedShort:2ul];
+  [NSNumber numberWithUnsignedShort:2lu];
+  [NSNumber numberWithUnsignedShort:2ull];
+  [NSNumber numberWithUnsignedShort:2llu];
+  [NSNumber numberWithUnsignedShort:2.0];
+  [NSNumber numberWithUnsignedShort:2.0f];
+  [NSNumber numberWithUnsignedShort:2.0F];
+  [NSNumber numberWithUnsignedShort:2.0l];
+  [NSNumber numberWithUnsignedShort:2.0L];
+  [NSNumber numberWithUnsignedShort:0x2f];
+  [NSNumber numberWithUnsignedShort:04];
+  [NSNumber numberWithUnsignedShort:0];
+  [NSNumber numberWithUnsignedShort:0.0];
+  [NSNumber numberWithUnsignedShort:YES];
+  [NSNumber numberWithUnsignedShort:NO];
+  [NSNumber numberWithUnsignedShort:true];
+  [NSNumber numberWithUnsignedShort:false];
+  [NSNumber numberWithUnsignedShort:VAL_INT];
+  [NSNumber numberWithUnsignedShort:VAL_UINT];
+
+  [NSNumber numberWithInt:'a'];
+  [NSNumber numberWithInt:L'a'];
+  [NSNumber numberWithInt:2];
+  [NSNumber numberWithInt:2U];
+  [NSNumber numberWithInt:2u];
+  [NSNumber numberWithInt:2L];
+  [NSNumber numberWithInt:2l];
+  [NSNumber numberWithInt:2LL];
+  [NSNumber numberWithInt:2ll];
+  [NSNumber numberWithInt:2ul];
+  [NSNumber numberWithInt:2lu];
+  [NSNumber numberWithInt:2ull];
+  [NSNumber numberWithInt:2llu];
+  [NSNumber numberWithInt:2.0];
+  [NSNumber numberWithInt:2.0f];
+  [NSNumber numberWithInt:2.0F];
+  [NSNumber numberWithInt:2.0l];
+  [NSNumber numberWithInt:2.0L];
+  [NSNumber numberWithInt:0x2f];
+  [NSNumber numberWithInt:04];
+  [NSNumber numberWithInt:0];
+  [NSNumber numberWithInt:0.0];
+  [NSNumber numberWithInt:YES];
+  [NSNumber numberWithInt:NO];
+  [NSNumber numberWithInt:true];
+  [NSNumber numberWithInt:false];
+  [NSNumber numberWithInt:VAL_INT];
+  [NSNumber numberWithInt:VAL_UINT];
+
+  (void)[[NSNumber alloc] initWithInt:2];
+  (void)[[NSNumber alloc] initWithInt:2U];
+
+  [NSNumber numberWithInt:+2];
+  [NSNumber numberWithInt:-2];
+
+  [NSNumber numberWithUnsignedInt:'a'];
+  [NSNumber numberWithUnsignedInt:L'a'];
+  [NSNumber numberWithUnsignedInt:2];
+  [NSNumber numberWithUnsignedInt:2U];
+  [NSNumber numberWithUnsignedInt:2u];
+  [NSNumber numberWithUnsignedInt:2L];
+  [NSNumber numberWithUnsignedInt:2l];
+  [NSNumber numberWithUnsignedInt:2LL];
+  [NSNumber numberWithUnsignedInt:2ll];
+  [NSNumber numberWithUnsignedInt:2ul];
+  [NSNumber numberWithUnsignedInt:2lu];
+  [NSNumber numberWithUnsignedInt:2ull];
+  [NSNumber numberWithUnsignedInt:2llu];
+  [NSNumber numberWithUnsignedInt:2.0];
+  [NSNumber numberWithUnsignedInt:2.0f];
+  [NSNumber numberWithUnsignedInt:2.0F];
+  [NSNumber numberWithUnsignedInt:2.0l];
+  [NSNumber numberWithUnsignedInt:2.0L];
+  [NSNumber numberWithUnsignedInt:0x2f];
+  [NSNumber numberWithUnsignedInt:04];
+  [NSNumber numberWithUnsignedInt:0];
+  [NSNumber numberWithUnsignedInt:0.0];
+  [NSNumber numberWithUnsignedInt:YES];
+  [NSNumber numberWithUnsignedInt:NO];
+  [NSNumber numberWithUnsignedInt:true];
+  [NSNumber numberWithUnsignedInt:false];
+  [NSNumber numberWithUnsignedInt:VAL_INT];
+  [NSNumber numberWithUnsignedInt:VAL_UINT];
+
+  [NSNumber numberWithLong:'a'];
+  [NSNumber numberWithLong:L'a'];
+  [NSNumber numberWithLong:2];
+  [NSNumber numberWithLong:2U];
+  [NSNumber numberWithLong:2u];
+  [NSNumber numberWithLong:2L];
+  [NSNumber numberWithLong:2l];
+  [NSNumber numberWithLong:2LL];
+  [NSNumber numberWithLong:2ll];
+  [NSNumber numberWithLong:2ul];
+  [NSNumber numberWithLong:2lu];
+  [NSNumber numberWithLong:2ull];
+  [NSNumber numberWithLong:2llu];
+  [NSNumber numberWithLong:2.0];
+  [NSNumber numberWithLong:2.0f];
+  [NSNumber numberWithLong:2.0F];
+  [NSNumber numberWithLong:2.0l];
+  [NSNumber numberWithLong:2.0L];
+  [NSNumber numberWithLong:0x2f];
+  [NSNumber numberWithLong:04];
+  [NSNumber numberWithLong:0];
+  [NSNumber numberWithLong:0.0];
+  [NSNumber numberWithLong:YES];
+  [NSNumber numberWithLong:NO];
+  [NSNumber numberWithLong:true];
+  [NSNumber numberWithLong:false];
+  [NSNumber numberWithLong:VAL_INT];
+  [NSNumber numberWithLong:VAL_UINT];
+
+  [NSNumber numberWithUnsignedLong:'a'];
+  [NSNumber numberWithUnsignedLong:L'a'];
+  [NSNumber numberWithUnsignedLong:2];
+  [NSNumber numberWithUnsignedLong:2U];
+  [NSNumber numberWithUnsignedLong:2u];
+  [NSNumber numberWithUnsignedLong:2L];
+  [NSNumber numberWithUnsignedLong:2l];
+  [NSNumber numberWithUnsignedLong:2LL];
+  [NSNumber numberWithUnsignedLong:2ll];
+  [NSNumber numberWithUnsignedLong:2ul];
+  [NSNumber numberWithUnsignedLong:2lu];
+  [NSNumber numberWithUnsignedLong:2ull];
+  [NSNumber numberWithUnsignedLong:2llu];
+  [NSNumber numberWithUnsignedLong:2.0];
+  [NSNumber numberWithUnsignedLong:2.0f];
+  [NSNumber numberWithUnsignedLong:2.0F];
+  [NSNumber numberWithUnsignedLong:2.0l];
+  [NSNumber numberWithUnsignedLong:2.0L];
+  [NSNumber numberWithUnsignedLong:0x2f];
+  [NSNumber numberWithUnsignedLong:04];
+  [NSNumber numberWithUnsignedLong:0];
+  [NSNumber numberWithUnsignedLong:0.0];
+  [NSNumber numberWithUnsignedLong:YES];
+  [NSNumber numberWithUnsignedLong:NO];
+  [NSNumber numberWithUnsignedLong:true];
+  [NSNumber numberWithUnsignedLong:false];
+  [NSNumber numberWithUnsignedLong:VAL_INT];
+  [NSNumber numberWithUnsignedLong:VAL_UINT];
+
+  [NSNumber numberWithLongLong:'a'];
+  [NSNumber numberWithLongLong:L'a'];
+  [NSNumber numberWithLongLong:2];
+  [NSNumber numberWithLongLong:2U];
+  [NSNumber numberWithLongLong:2u];
+  [NSNumber numberWithLongLong:2L];
+  [NSNumber numberWithLongLong:2l];
+  [NSNumber numberWithLongLong:2LL];
+  [NSNumber numberWithLongLong:2ll];
+  [NSNumber numberWithLongLong:2ul];
+  [NSNumber numberWithLongLong:2lu];
+  [NSNumber numberWithLongLong:2ull];
+  [NSNumber numberWithLongLong:2llu];
+  [NSNumber numberWithLongLong:2.0];
+  [NSNumber numberWithLongLong:2.0f];
+  [NSNumber numberWithLongLong:2.0F];
+  [NSNumber numberWithLongLong:2.0l];
+  [NSNumber numberWithLongLong:2.0L];
+  [NSNumber numberWithLongLong:0x2f];
+  [NSNumber numberWithLongLong:04];
+  [NSNumber numberWithLongLong:0];
+  [NSNumber numberWithLongLong:0.0];
+  [NSNumber numberWithLongLong:YES];
+  [NSNumber numberWithLongLong:NO];
+  [NSNumber numberWithLongLong:true];
+  [NSNumber numberWithLongLong:false];
+  [NSNumber numberWithLongLong:VAL_INT];
+  [NSNumber numberWithLongLong:VAL_UINT];
+
+  [NSNumber numberWithUnsignedLongLong:'a'];
+  [NSNumber numberWithUnsignedLongLong:L'a'];
+  [NSNumber numberWithUnsignedLongLong:2];
+  [NSNumber numberWithUnsignedLongLong:2U];
+  [NSNumber numberWithUnsignedLongLong:2u];
+  [NSNumber numberWithUnsignedLongLong:2L];
+  [NSNumber numberWithUnsignedLongLong:2l];
+  [NSNumber numberWithUnsignedLongLong:2LL];
+  [NSNumber numberWithUnsignedLongLong:2ll];
+  [NSNumber numberWithUnsignedLongLong:2ul];
+  [NSNumber numberWithUnsignedLongLong:2lu];
+  [NSNumber numberWithUnsignedLongLong:2ull];
+  [NSNumber numberWithUnsignedLongLong:2llu];
+  [NSNumber numberWithUnsignedLongLong:2.0];
+  [NSNumber numberWithUnsignedLongLong:2.0f];
+  [NSNumber numberWithUnsignedLongLong:2.0F];
+  [NSNumber numberWithUnsignedLongLong:2.0l];
+  [NSNumber numberWithUnsignedLongLong:2.0L];
+  [NSNumber numberWithUnsignedLongLong:0x2f];
+  [NSNumber numberWithUnsignedLongLong:04];
+  [NSNumber numberWithUnsignedLongLong:0];
+  [NSNumber numberWithUnsignedLongLong:0.0];
+  [NSNumber numberWithUnsignedLongLong:YES];
+  [NSNumber numberWithUnsignedLongLong:NO];
+  [NSNumber numberWithUnsignedLongLong:true];
+  [NSNumber numberWithUnsignedLongLong:false];
+  [NSNumber numberWithUnsignedLongLong:VAL_INT];
+  [NSNumber numberWithUnsignedLongLong:VAL_UINT];
+
+  [NSNumber numberWithFloat:'a'];
+  [NSNumber numberWithFloat:L'a'];
+  [NSNumber numberWithFloat:2];
+  [NSNumber numberWithFloat:2U];
+  [NSNumber numberWithFloat:2u];
+  [NSNumber numberWithFloat:2L];
+  [NSNumber numberWithFloat:2l];
+  [NSNumber numberWithFloat:2LL];
+  [NSNumber numberWithFloat:2ll];
+  [NSNumber numberWithFloat:2ul];
+  [NSNumber numberWithFloat:2lu];
+  [NSNumber numberWithFloat:2ull];
+  [NSNumber numberWithFloat:2llu];
+  [NSNumber numberWithFloat:2.0];
+  [NSNumber numberWithFloat:2.0f];
+  [NSNumber numberWithFloat:2.0F];
+  [NSNumber numberWithFloat:2.0l];
+  [NSNumber numberWithFloat:2.0L];
+  [NSNumber numberWithFloat:0x2f];
+  [NSNumber numberWithFloat:04];
+  [NSNumber numberWithFloat:0];
+  [NSNumber numberWithFloat:0.0];
+  [NSNumber numberWithFloat:YES];
+  [NSNumber numberWithFloat:NO];
+  [NSNumber numberWithFloat:true];
+  [NSNumber numberWithFloat:false];
+  [NSNumber numberWithFloat:VAL_INT];
+  [NSNumber numberWithFloat:VAL_UINT];
+
+  [NSNumber numberWithDouble:'a'];
+  [NSNumber numberWithDouble:L'a'];
+  [NSNumber numberWithDouble:2];
+  [NSNumber numberWithDouble:2U];
+  [NSNumber numberWithDouble:2u];
+  [NSNumber numberWithDouble:2L];
+  [NSNumber numberWithDouble:2l];
+  [NSNumber numberWithDouble:2LL];
+  [NSNumber numberWithDouble:2ll];
+  [NSNumber numberWithDouble:2ul];
+  [NSNumber numberWithDouble:2lu];
+  [NSNumber numberWithDouble:2ull];
+  [NSNumber numberWithDouble:2llu];
+  [NSNumber numberWithDouble:2.0];
+  [NSNumber numberWithDouble:2.0f];
+  [NSNumber numberWithDouble:2.0F];
+  [NSNumber numberWithDouble:2.0l];
+  [NSNumber numberWithDouble:2.0L];
+  [NSNumber numberWithDouble:0x2f];
+  [NSNumber numberWithDouble:04];
+  [NSNumber numberWithDouble:0];
+  [NSNumber numberWithDouble:0.0];
+  [NSNumber numberWithDouble:YES];
+  [NSNumber numberWithDouble:NO];
+  [NSNumber numberWithDouble:true];
+  [NSNumber numberWithDouble:false];
+  [NSNumber numberWithDouble:VAL_INT];
+  [NSNumber numberWithDouble:VAL_UINT];
+
+  [NSNumber numberWithBool:'a'];
+  [NSNumber numberWithBool:L'a'];
+  [NSNumber numberWithBool:2];
+  [NSNumber numberWithBool:2U];
+  [NSNumber numberWithBool:2u];
+  [NSNumber numberWithBool:2L];
+  [NSNumber numberWithBool:2l];
+  [NSNumber numberWithBool:2LL];
+  [NSNumber numberWithBool:2ll];
+  [NSNumber numberWithBool:2ul];
+  [NSNumber numberWithBool:2lu];
+  [NSNumber numberWithBool:2ull];
+  [NSNumber numberWithBool:2llu];
+  [NSNumber numberWithBool:2.0];
+  [NSNumber numberWithBool:2.0f];
+  [NSNumber numberWithBool:2.0F];
+  [NSNumber numberWithBool:2.0l];
+  [NSNumber numberWithBool:2.0L];
+  [NSNumber numberWithBool:0x2f];
+  [NSNumber numberWithBool:04];
+  [NSNumber numberWithBool:0];
+  [NSNumber numberWithBool:0.0];
+  [NSNumber numberWithBool:YES];
+  [NSNumber numberWithBool:NO];
+  [NSNumber numberWithBool:true];
+  [NSNumber numberWithBool:false];
+  [NSNumber numberWithBool:VAL_INT];
+  [NSNumber numberWithBool:VAL_UINT];
+
+  [NSNumber numberWithInteger:'a'];
+  [NSNumber numberWithInteger:L'a'];
+  [NSNumber numberWithInteger:2];
+  [NSNumber numberWithInteger:2U];
+  [NSNumber numberWithInteger:2u];
+  [NSNumber numberWithInteger:2L];
+  [NSNumber numberWithInteger:2l];
+  [NSNumber numberWithInteger:2LL];
+  [NSNumber numberWithInteger:2ll];
+  [NSNumber numberWithInteger:2ul];
+  [NSNumber numberWithInteger:2lu];
+  [NSNumber numberWithInteger:2ull];
+  [NSNumber numberWithInteger:2llu];
+  [NSNumber numberWithInteger:2.0];
+  [NSNumber numberWithInteger:2.0f];
+  [NSNumber numberWithInteger:2.0F];
+  [NSNumber numberWithInteger:2.0l];
+  [NSNumber numberWithInteger:2.0L];
+  [NSNumber numberWithInteger:0x2f];
+  [NSNumber numberWithInteger:04];
+  [NSNumber numberWithInteger:0];
+  [NSNumber numberWithInteger:0.0];
+  [NSNumber numberWithInteger:YES];
+  [NSNumber numberWithInteger:NO];
+  [NSNumber numberWithInteger:true];
+  [NSNumber numberWithInteger:false];
+  [NSNumber numberWithInteger:VAL_INT];
+  [NSNumber numberWithInteger:VAL_UINT];
+
+  [NSNumber numberWithUnsignedInteger:'a'];
+  [NSNumber numberWithUnsignedInteger:L'a'];
+  [NSNumber numberWithUnsignedInteger:2];
+  [NSNumber numberWithUnsignedInteger:2U];
+  [NSNumber numberWithUnsignedInteger:2u];
+  [NSNumber numberWithUnsignedInteger:2L];
+  [NSNumber numberWithUnsignedInteger:2l];
+  [NSNumber numberWithUnsignedInteger:2LL];
+  [NSNumber numberWithUnsignedInteger:2ll];
+  [NSNumber numberWithUnsignedInteger:2ul];
+  [NSNumber numberWithUnsignedInteger:2lu];
+  [NSNumber numberWithUnsignedInteger:2ull];
+  [NSNumber numberWithUnsignedInteger:2llu];
+  [NSNumber numberWithUnsignedInteger:2.0];
+  [NSNumber numberWithUnsignedInteger:2.0f];
+  [NSNumber numberWithUnsignedInteger:2.0F];
+  [NSNumber numberWithUnsignedInteger:2.0l];
+  [NSNumber numberWithUnsignedInteger:2.0L];
+  [NSNumber numberWithUnsignedInteger:0x2f];
+  [NSNumber numberWithUnsignedInteger:04];
+  [NSNumber numberWithUnsignedInteger:0];
+  [NSNumber numberWithUnsignedInteger:0.0];
+  [NSNumber numberWithUnsignedInteger:YES];
+  [NSNumber numberWithUnsignedInteger:NO];
+  [NSNumber numberWithUnsignedInteger:true];
+  [NSNumber numberWithUnsignedInteger:false];
+  [NSNumber numberWithUnsignedInteger:VAL_INT];
+  [NSNumber numberWithUnsignedInteger:VAL_UINT];
+}
diff --git a/test/ARCMT/objcmt-numeric-literals.m.result b/test/ARCMT/objcmt-numeric-literals.m.result
new file mode 100644 (file)
index 0000000..1c4187a
--- /dev/null
@@ -0,0 +1,501 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c++ 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+#define YES __objc_yes
+#define NO __objc_no
+
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
+- (id)initWithChar:(char)value;
+- (id)initWithUnsignedChar:(unsigned char)value;
+- (id)initWithShort:(short)value;
+- (id)initWithUnsignedShort:(unsigned short)value;
+- (id)initWithInt:(int)value;
+- (id)initWithUnsignedInt:(unsigned int)value;
+- (id)initWithLong:(long)value;
+- (id)initWithUnsignedLong:(unsigned long)value;
+- (id)initWithLongLong:(long long)value;
+- (id)initWithUnsignedLongLong:(unsigned long long)value;
+- (id)initWithFloat:(float)value;
+- (id)initWithDouble:(double)value;
+- (id)initWithBool:(BOOL)value;
+- (id)initWithInteger:(NSInteger)value;
+- (id)initWithUnsignedInteger:(NSUInteger)value;
+
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+@end
+
+#define VAL_INT 2
+#define VAL_UINT 2U
+#define VAL_CHAR 'a'
+
+void foo() {
+  @'a';
+  [NSNumber numberWithChar:L'a'];
+  [NSNumber numberWithChar:2];
+  [NSNumber numberWithChar:2U];
+  [NSNumber numberWithChar:2u];
+  [NSNumber numberWithChar:2L];
+  [NSNumber numberWithChar:2l];
+  [NSNumber numberWithChar:2LL];
+  [NSNumber numberWithChar:2ll];
+  [NSNumber numberWithChar:2ul];
+  [NSNumber numberWithChar:2lu];
+  [NSNumber numberWithChar:2ull];
+  [NSNumber numberWithChar:2llu];
+  [NSNumber numberWithChar:2.0];
+  [NSNumber numberWithChar:2.0f];
+  [NSNumber numberWithChar:2.0F];
+  [NSNumber numberWithChar:2.0l];
+  [NSNumber numberWithChar:2.0L];
+  [NSNumber numberWithChar:0x2f];
+  [NSNumber numberWithChar:04];
+  [NSNumber numberWithChar:0];
+  [NSNumber numberWithChar:0.0];
+  [NSNumber numberWithChar:YES];
+  [NSNumber numberWithChar:NO];
+  [NSNumber numberWithChar:true];
+  [NSNumber numberWithChar:false];
+  [NSNumber numberWithChar:VAL_INT];
+  [NSNumber numberWithChar:VAL_UINT];
+  @VAL_CHAR;
+
+  [NSNumber numberWithUnsignedChar:'a'];
+  [NSNumber numberWithUnsignedChar:L'a'];
+  [NSNumber numberWithUnsignedChar:2];
+  [NSNumber numberWithUnsignedChar:2U];
+  [NSNumber numberWithUnsignedChar:2u];
+  [NSNumber numberWithUnsignedChar:2L];
+  [NSNumber numberWithUnsignedChar:2l];
+  [NSNumber numberWithUnsignedChar:2LL];
+  [NSNumber numberWithUnsignedChar:2ll];
+  [NSNumber numberWithUnsignedChar:2ul];
+  [NSNumber numberWithUnsignedChar:2lu];
+  [NSNumber numberWithUnsignedChar:2ull];
+  [NSNumber numberWithUnsignedChar:2llu];
+  [NSNumber numberWithUnsignedChar:2.0];
+  [NSNumber numberWithUnsignedChar:2.0f];
+  [NSNumber numberWithUnsignedChar:2.0F];
+  [NSNumber numberWithUnsignedChar:2.0l];
+  [NSNumber numberWithUnsignedChar:2.0L];
+  [NSNumber numberWithUnsignedChar:0x2f];
+  [NSNumber numberWithUnsignedChar:04];
+  [NSNumber numberWithUnsignedChar:0];
+  [NSNumber numberWithUnsignedChar:0.0];
+  [NSNumber numberWithUnsignedChar:YES];
+  [NSNumber numberWithUnsignedChar:NO];
+  [NSNumber numberWithUnsignedChar:true];
+  [NSNumber numberWithUnsignedChar:false];
+  [NSNumber numberWithUnsignedChar:VAL_INT];
+  [NSNumber numberWithUnsignedChar:VAL_UINT];
+  [NSNumber numberWithUnsignedChar:VAL_CHAR];
+
+  [NSNumber numberWithShort:'a'];
+  [NSNumber numberWithShort:L'a'];
+  [NSNumber numberWithShort:2];
+  [NSNumber numberWithShort:2U];
+  [NSNumber numberWithShort:2u];
+  [NSNumber numberWithShort:2L];
+  [NSNumber numberWithShort:2l];
+  [NSNumber numberWithShort:2LL];
+  [NSNumber numberWithShort:2ll];
+  [NSNumber numberWithShort:2ul];
+  [NSNumber numberWithShort:2lu];
+  [NSNumber numberWithShort:2ull];
+  [NSNumber numberWithShort:2llu];
+  [NSNumber numberWithShort:2.0];
+  [NSNumber numberWithShort:2.0f];
+  [NSNumber numberWithShort:2.0F];
+  [NSNumber numberWithShort:2.0l];
+  [NSNumber numberWithShort:2.0L];
+  [NSNumber numberWithShort:0x2f];
+  [NSNumber numberWithShort:04];
+  [NSNumber numberWithShort:0];
+  [NSNumber numberWithShort:0.0];
+  [NSNumber numberWithShort:YES];
+  [NSNumber numberWithShort:NO];
+  [NSNumber numberWithShort:true];
+  [NSNumber numberWithShort:false];
+  [NSNumber numberWithShort:VAL_INT];
+  [NSNumber numberWithShort:VAL_UINT];
+
+  [NSNumber numberWithUnsignedShort:'a'];
+  [NSNumber numberWithUnsignedShort:L'a'];
+  [NSNumber numberWithUnsignedShort:2];
+  [NSNumber numberWithUnsignedShort:2U];
+  [NSNumber numberWithUnsignedShort:2u];
+  [NSNumber numberWithUnsignedShort:2L];
+  [NSNumber numberWithUnsignedShort:2l];
+  [NSNumber numberWithUnsignedShort:2LL];
+  [NSNumber numberWithUnsignedShort:2ll];
+  [NSNumber numberWithUnsignedShort:2ul];
+  [NSNumber numberWithUnsignedShort:2lu];
+  [NSNumber numberWithUnsignedShort:2ull];
+  [NSNumber numberWithUnsignedShort:2llu];
+  [NSNumber numberWithUnsignedShort:2.0];
+  [NSNumber numberWithUnsignedShort:2.0f];
+  [NSNumber numberWithUnsignedShort:2.0F];
+  [NSNumber numberWithUnsignedShort:2.0l];
+  [NSNumber numberWithUnsignedShort:2.0L];
+  [NSNumber numberWithUnsignedShort:0x2f];
+  [NSNumber numberWithUnsignedShort:04];
+  [NSNumber numberWithUnsignedShort:0];
+  [NSNumber numberWithUnsignedShort:0.0];
+  [NSNumber numberWithUnsignedShort:YES];
+  [NSNumber numberWithUnsignedShort:NO];
+  [NSNumber numberWithUnsignedShort:true];
+  [NSNumber numberWithUnsignedShort:false];
+  [NSNumber numberWithUnsignedShort:VAL_INT];
+  [NSNumber numberWithUnsignedShort:VAL_UINT];
+
+  [NSNumber numberWithInt:'a'];
+  [NSNumber numberWithInt:L'a'];
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  [NSNumber numberWithInt:2.0];
+  [NSNumber numberWithInt:2.0f];
+  [NSNumber numberWithInt:2.0F];
+  [NSNumber numberWithInt:2.0l];
+  [NSNumber numberWithInt:2.0L];
+  @0x2f;
+  @04;
+  @0;
+  [NSNumber numberWithInt:0.0];
+  [NSNumber numberWithInt:YES];
+  [NSNumber numberWithInt:NO];
+  [NSNumber numberWithInt:true];
+  [NSNumber numberWithInt:false];
+  @VAL_INT;
+  [NSNumber numberWithInt:VAL_UINT];
+
+  (void)[[NSNumber alloc] initWithInt:2];
+  (void)[[NSNumber alloc] initWithInt:2U];
+
+  @+2;
+  @-2;
+
+  [NSNumber numberWithUnsignedInt:'a'];
+  [NSNumber numberWithUnsignedInt:L'a'];
+  @2U;
+  @2U;
+  @2u;
+  @2U;
+  @2u;
+  @2U;
+  @2u;
+  @2u;
+  @2u;
+  @2u;
+  @2u;
+  [NSNumber numberWithUnsignedInt:2.0];
+  [NSNumber numberWithUnsignedInt:2.0f];
+  [NSNumber numberWithUnsignedInt:2.0F];
+  [NSNumber numberWithUnsignedInt:2.0l];
+  [NSNumber numberWithUnsignedInt:2.0L];
+  @0x2fU;
+  @04U;
+  @0U;
+  [NSNumber numberWithUnsignedInt:0.0];
+  [NSNumber numberWithUnsignedInt:YES];
+  [NSNumber numberWithUnsignedInt:NO];
+  [NSNumber numberWithUnsignedInt:true];
+  [NSNumber numberWithUnsignedInt:false];
+  [NSNumber numberWithUnsignedInt:VAL_INT];
+  @VAL_UINT;
+
+  [NSNumber numberWithLong:'a'];
+  [NSNumber numberWithLong:L'a'];
+  @2L;
+  @2L;
+  @2l;
+  @2L;
+  @2l;
+  @2L;
+  @2l;
+  @2l;
+  @2l;
+  @2l;
+  @2l;
+  [NSNumber numberWithLong:2.0];
+  [NSNumber numberWithLong:2.0f];
+  [NSNumber numberWithLong:2.0F];
+  [NSNumber numberWithLong:2.0l];
+  [NSNumber numberWithLong:2.0L];
+  @0x2fL;
+  @04L;
+  @0L;
+  [NSNumber numberWithLong:0.0];
+  [NSNumber numberWithLong:YES];
+  [NSNumber numberWithLong:NO];
+  [NSNumber numberWithLong:true];
+  [NSNumber numberWithLong:false];
+  [NSNumber numberWithLong:VAL_INT];
+  [NSNumber numberWithLong:VAL_UINT];
+
+  [NSNumber numberWithUnsignedLong:'a'];
+  [NSNumber numberWithUnsignedLong:L'a'];
+  @2UL;
+  @2UL;
+  @2ul;
+  @2UL;
+  @2ul;
+  @2UL;
+  @2ul;
+  @2ul;
+  @2lu;
+  @2ul;
+  @2ul;
+  [NSNumber numberWithUnsignedLong:2.0];
+  [NSNumber numberWithUnsignedLong:2.0f];
+  [NSNumber numberWithUnsignedLong:2.0F];
+  [NSNumber numberWithUnsignedLong:2.0l];
+  [NSNumber numberWithUnsignedLong:2.0L];
+  @0x2fUL;
+  @04UL;
+  @0UL;
+  [NSNumber numberWithUnsignedLong:0.0];
+  [NSNumber numberWithUnsignedLong:YES];
+  [NSNumber numberWithUnsignedLong:NO];
+  [NSNumber numberWithUnsignedLong:true];
+  [NSNumber numberWithUnsignedLong:false];
+  [NSNumber numberWithUnsignedLong:VAL_INT];
+  [NSNumber numberWithUnsignedLong:VAL_UINT];
+
+  [NSNumber numberWithLongLong:'a'];
+  [NSNumber numberWithLongLong:L'a'];
+  @2LL;
+  @2LL;
+  @2ll;
+  @2LL;
+  @2ll;
+  @2LL;
+  @2ll;
+  @2ll;
+  @2ll;
+  @2ll;
+  @2ll;
+  [NSNumber numberWithLongLong:2.0];
+  [NSNumber numberWithLongLong:2.0f];
+  [NSNumber numberWithLongLong:2.0F];
+  [NSNumber numberWithLongLong:2.0l];
+  [NSNumber numberWithLongLong:2.0L];
+  @0x2fLL;
+  @04LL;
+  @0LL;
+  [NSNumber numberWithLongLong:0.0];
+  [NSNumber numberWithLongLong:YES];
+  [NSNumber numberWithLongLong:NO];
+  [NSNumber numberWithLongLong:true];
+  [NSNumber numberWithLongLong:false];
+  [NSNumber numberWithLongLong:VAL_INT];
+  [NSNumber numberWithLongLong:VAL_UINT];
+
+  [NSNumber numberWithUnsignedLongLong:'a'];
+  [NSNumber numberWithUnsignedLongLong:L'a'];
+  @2ULL;
+  @2ULL;
+  @2ull;
+  @2ULL;
+  @2ull;
+  @2ULL;
+  @2ull;
+  @2ull;
+  @2ull;
+  @2ull;
+  @2llu;
+  [NSNumber numberWithUnsignedLongLong:2.0];
+  [NSNumber numberWithUnsignedLongLong:2.0f];
+  [NSNumber numberWithUnsignedLongLong:2.0F];
+  [NSNumber numberWithUnsignedLongLong:2.0l];
+  [NSNumber numberWithUnsignedLongLong:2.0L];
+  @0x2fULL;
+  @04ULL;
+  @0ULL;
+  [NSNumber numberWithUnsignedLongLong:0.0];
+  [NSNumber numberWithUnsignedLongLong:YES];
+  [NSNumber numberWithUnsignedLongLong:NO];
+  [NSNumber numberWithUnsignedLongLong:true];
+  [NSNumber numberWithUnsignedLongLong:false];
+  [NSNumber numberWithUnsignedLongLong:VAL_INT];
+  [NSNumber numberWithUnsignedLongLong:VAL_UINT];
+
+  [NSNumber numberWithFloat:'a'];
+  [NSNumber numberWithFloat:L'a'];
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0f;
+  @2.0F;
+  @2.0f;
+  @2.0f;
+  [NSNumber numberWithFloat:0x2f];
+  [NSNumber numberWithFloat:04];
+  @0.0f;
+  @0.0f;
+  [NSNumber numberWithFloat:YES];
+  [NSNumber numberWithFloat:NO];
+  [NSNumber numberWithFloat:true];
+  [NSNumber numberWithFloat:false];
+  [NSNumber numberWithFloat:VAL_INT];
+  [NSNumber numberWithFloat:VAL_UINT];
+
+  [NSNumber numberWithDouble:'a'];
+  [NSNumber numberWithDouble:L'a'];
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  @2.0;
+  [NSNumber numberWithDouble:0x2f];
+  [NSNumber numberWithDouble:04];
+  @0.0;
+  @0.0;
+  [NSNumber numberWithDouble:YES];
+  [NSNumber numberWithDouble:NO];
+  [NSNumber numberWithDouble:true];
+  [NSNumber numberWithDouble:false];
+  [NSNumber numberWithDouble:VAL_INT];
+  [NSNumber numberWithDouble:VAL_UINT];
+
+  [NSNumber numberWithBool:'a'];
+  [NSNumber numberWithBool:L'a'];
+  [NSNumber numberWithBool:2];
+  [NSNumber numberWithBool:2U];
+  [NSNumber numberWithBool:2u];
+  [NSNumber numberWithBool:2L];
+  [NSNumber numberWithBool:2l];
+  [NSNumber numberWithBool:2LL];
+  [NSNumber numberWithBool:2ll];
+  [NSNumber numberWithBool:2ul];
+  [NSNumber numberWithBool:2lu];
+  [NSNumber numberWithBool:2ull];
+  [NSNumber numberWithBool:2llu];
+  [NSNumber numberWithBool:2.0];
+  [NSNumber numberWithBool:2.0f];
+  [NSNumber numberWithBool:2.0F];
+  [NSNumber numberWithBool:2.0l];
+  [NSNumber numberWithBool:2.0L];
+  [NSNumber numberWithBool:0x2f];
+  [NSNumber numberWithBool:04];
+  [NSNumber numberWithBool:0];
+  [NSNumber numberWithBool:0.0];
+  @YES;
+  @NO;
+  @true;
+  @false;
+  [NSNumber numberWithBool:VAL_INT];
+  [NSNumber numberWithBool:VAL_UINT];
+
+  [NSNumber numberWithInteger:'a'];
+  [NSNumber numberWithInteger:L'a'];
+  @2;
+  @2;
+  @2;
+  @2L;
+  @2l;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  @2;
+  [NSNumber numberWithInteger:2.0];
+  [NSNumber numberWithInteger:2.0f];
+  [NSNumber numberWithInteger:2.0F];
+  [NSNumber numberWithInteger:2.0l];
+  [NSNumber numberWithInteger:2.0L];
+  @0x2f;
+  @04;
+  @0;
+  [NSNumber numberWithInteger:0.0];
+  [NSNumber numberWithInteger:YES];
+  [NSNumber numberWithInteger:NO];
+  [NSNumber numberWithInteger:true];
+  [NSNumber numberWithInteger:false];
+  [NSNumber numberWithInteger:VAL_INT];
+  [NSNumber numberWithInteger:VAL_UINT];
+
+  [NSNumber numberWithUnsignedInteger:'a'];
+  [NSNumber numberWithUnsignedInteger:L'a'];
+  @2U;
+  @2U;
+  @2u;
+  @2U;
+  @2u;
+  @2U;
+  @2u;
+  @2ul;
+  @2lu;
+  @2u;
+  @2u;
+  [NSNumber numberWithUnsignedInteger:2.0];
+  [NSNumber numberWithUnsignedInteger:2.0f];
+  [NSNumber numberWithUnsignedInteger:2.0F];
+  [NSNumber numberWithUnsignedInteger:2.0l];
+  [NSNumber numberWithUnsignedInteger:2.0L];
+  @0x2fU;
+  @04U;
+  @0U;
+  [NSNumber numberWithUnsignedInteger:0.0];
+  [NSNumber numberWithUnsignedInteger:YES];
+  [NSNumber numberWithUnsignedInteger:NO];
+  [NSNumber numberWithUnsignedInteger:true];
+  [NSNumber numberWithUnsignedInteger:false];
+  [NSNumber numberWithUnsignedInteger:VAL_INT];
+  [NSNumber numberWithUnsignedInteger:VAL_UINT];
+}
diff --git a/test/ARCMT/objcmt-subscripting-literals.m b/test/ARCMT/objcmt-subscripting-literals.m
new file mode 100644 (file)
index 0000000..1632bf9
--- /dev/null
@@ -0,0 +1,137 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+@interface I
+@end
+@implementation I
+-(void) foo {
+  NSString *str;
+  NSArray *arr;
+  NSDictionary *dict;
+
+  arr = [NSArray array];
+  arr = [NSArray arrayWithObject:str];
+  arr = [NSArray arrayWithObjects:str, str, nil];
+  dict = [NSDictionary dictionary];
+  dict = [NSDictionary dictionaryWithObject:arr forKey:str];
+  dict = [NSDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
+  dict = [NSDictionary dictionaryWithObjectsAndKeys: PAIR(1), PAIR(2), nil];
+  dict = [NSDictionary dictionaryWithObjectsAndKeys:
+                                               @"value1", @"key1",
+#ifdef BLAH
+                                               @"value2", @"key2",
+#else
+                                               @"value3", @"key3",
+#endif
+                                               nil ];
+
+  id o = [arr objectAtIndex:2];
+  o = [dict objectForKey:@"key"];
+  o = TWO([dict objectForKey:@"key"]);
+  o = [NSDictionary dictionaryWithObject:[NSDictionary dictionary] forKey:@"key"];
+  NSMutableArray *marr = 0;
+  NSMutableDictionary *mdict = 0;
+  [marr replaceObjectAtIndex:2 withObject:@"val"];
+  [mdict setObject:@"value" forKey:@"key"];
+  [marr replaceObjectAtIndex:2 withObject:[arr objectAtIndex:4]];
+  [mdict setObject:[dict objectForKey:@"key2"] forKey:@"key"];
+  [mdict setObject:[dict objectForKey:@"key2"] forKey:
+#if 1
+                     @"key1"
+#else
+                     @"key2"
+#endif
+                    ];
+  [mdict setObject:[dict objectForKey:
+#if 2
+                     @"key3"
+#else
+                     @"key4"
+#endif
+                   ] forKey:@"key"];
+  [mdict setObject:@"value" forKey:[dict objectForKey:
+#if 3
+                     @"key5"
+#else
+                     @"key6"
+#endif
+                   ] ];
+  [mdict setObject:@"val" forKey:[dict objectForKey:@"key2"]];
+  [mdict setObject:[dict objectForKey:@"key1"] forKey:[dict objectForKey:[NSArray arrayWithObject:@"arrkey"]]];
+  __strong NSArray **parr = 0;
+  o = [*parr objectAtIndex:2];
+}
+@end
diff --git a/test/ARCMT/objcmt-subscripting-literals.m.result b/test/ARCMT/objcmt-subscripting-literals.m.result
new file mode 100644 (file)
index 0000000..cc93cb4
--- /dev/null
@@ -0,0 +1,137 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c 
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+
+typedef signed char BOOL;
+#define nil ((void*) 0)
+
+@interface NSObject
++ (id)alloc;
+@end
+
+@interface NSString : NSObject
++ (id)stringWithString:(NSString *)string;
+- (id)initWithString:(NSString *)aString;
+@end
+
+@interface NSArray : NSObject
+- (id)objectAtIndex:(unsigned long)index;
+- (id)objectAtIndexedSubscript:(int)index;
+@end
+
+@interface NSArray (NSArrayCreation)
++ (id)array;
++ (id)arrayWithObject:(id)anObject;
++ (id)arrayWithObjects:(const id [])objects count:(unsigned long)cnt;
++ (id)arrayWithObjects:(id)firstObj, ...;
++ (id)arrayWithArray:(NSArray *)array;
+
+- (id)initWithObjects:(const id [])objects count:(unsigned long)cnt;
+- (id)initWithObjects:(id)firstObj, ...;
+- (id)initWithArray:(NSArray *)array;
+
+- (id)objectAtIndex:(unsigned long)index;
+@end
+
+@interface NSMutableArray : NSArray
+- (void)replaceObjectAtIndex:(unsigned long)index withObject:(id)anObject;
+- (void)setObject:(id)object atIndexedSubscript:(int)index;
+@end
+
+@interface NSDictionary : NSObject
+- (id)objectForKeyedSubscript:(id)key;
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
++ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
++ (id)dictionaryWithDictionary:(NSDictionary *)dict;
++ (id)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
+- (id)initWithObjectsAndKeys:(id)firstObject, ...;
+- (id)initWithDictionary:(NSDictionary *)otherDictionary;
+- (id)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+
+- (id)objectForKey:(id)aKey;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+- (void)setObject:(id)anObject forKey:(id)aKey;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+#define M(x) (x)
+#define PAIR(x) @#x, [NSNumber numberWithInt:(x)]
+#define TWO(x) ((x), (x))
+
+@interface I
+@end
+@implementation I
+-(void) foo {
+  NSString *str;
+  NSArray *arr;
+  NSDictionary *dict;
+
+  arr = @[];
+  arr = @[str];
+  arr = @[str, str];
+  dict = @{};
+  dict = @{str: arr};
+  dict = @{@"key1": @"value1", @"key2": @"value2"};
+  dict = [NSDictionary dictionaryWithObjectsAndKeys: PAIR(1), PAIR(2), nil];
+  dict = [NSDictionary dictionaryWithObjectsAndKeys:
+                                               @"value1", @"key1",
+#ifdef BLAH
+                                               @"value2", @"key2",
+#else
+                                               @"value3", @"key3",
+#endif
+                                               nil ];
+
+  id o = arr[2];
+  o = dict[@"key"];
+  o = TWO(dict[@"key"]);
+  o = @{@"key": @{}};
+  NSMutableArray *marr = 0;
+  NSMutableDictionary *mdict = 0;
+  marr[2] = @"val";
+  mdict[@"key"] = @"value";
+  marr[2] = arr[4];
+  mdict[@"key"] = dict[@"key2"];
+  [mdict setObject:dict[@"key2"] forKey:
+#if 1
+                     @"key1"
+#else
+                     @"key2"
+#endif
+                    ];
+  mdict[@"key"] = [dict objectForKey:
+#if 2
+                     @"key3"
+#else
+                     @"key4"
+#endif
+                   ];
+  mdict[[dict objectForKey:
+#if 3
+                     @"key5"
+#else
+                     @"key6"
+#endif
+                   ]] = @"value";
+  mdict[dict[@"key2"]] = @"val";
+  mdict[dict[@[@"arrkey"]]] = dict[@"key1"];
+  __strong NSArray **parr = 0;
+  o = (*parr)[2];
+}
+@end
index 32bcad1950422124a5fa9e3756142143be450d3f..468859478eb0fd56a8a1402745f88516da787c07 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s
-// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
 // RUN: rm -rf %t
 
 @protocol NSObject
index f060793f6eb4fa505d82eea808c405987674f9e7..dd34b99908783387013587375cd4124b05fe651b 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t
 // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -x objective-c %s.result
-// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -fsyntax-only -fobjc-arc %s
-// RUN: c-arcmt-test -arcmt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t -fsyntax-only -fobjc-arc %s
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
 // RUN: rm -rf %t
 
 @protocol NSObject
index 9227f8ee63c70cd3fce5235a00fd68b412431dc4..a0029b416f292b5f39519e47894a8ed7a066f811 100644 (file)
@@ -1,5 +1,6 @@
 set(LLVM_USED_LIBS
   clangARCMigrate
+  clangEdit
   clangRewrite
   )
 
index c143e27f33e28fa3243ae69add202e64bd25cc37..f5ca81a6d1176902546a323b5bbe5616a79d0b20 100644 (file)
@@ -19,6 +19,6 @@ NO_INSTALL = 1
 LINK_COMPONENTS := support mc
 USEDLIBS = clangIndex.a clangARCMigrate.a clangRewrite.a \
                 clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
-                clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+                clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile
index 881a058c2c4b6ee3c82b807604a02d782a3846cc..2dc8034e329b86252d6e3e47dfbb8b0493b2a63b 100644 (file)
@@ -135,9 +135,8 @@ static bool checkForMigration(StringRef resourcesPath,
 }
 
 static void printResult(FileRemapper &remapper, raw_ostream &OS) {
-  CompilerInvocation CI;
-  remapper.applyMappings(CI);
-  PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+  PreprocessorOptions PPOpts;
+  remapper.applyMappings(PPOpts);
   // 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;
index 5522b33e23a5e8ffec1fff8a5239e24c9a0a3218..b91d3e1b9862b6a24e65cdfd8fc045b903b081dd 100644 (file)
@@ -34,22 +34,51 @@ static int print_remappings(const char *path) {
   return 0;
 }
 
+static int print_remappings_filelist(const char **files, unsigned numFiles) {
+  CXRemapping remap;
+  unsigned i, N;
+  CXString origFname;
+  CXString transFname;
+
+  remap = clang_getRemappingsFromFileList(files, numFiles);
+  if (!remap)
+    return 1;
+
+  N = clang_remap_getNumFiles(remap);
+  for (i = 0; i != N; ++i) {
+    clang_remap_getFilenames(remap, i, &origFname, &transFname);
+
+    fprintf(stdout, "%s\n", clang_getCString(origFname));
+    fprintf(stdout, "%s\n", clang_getCString(transFname));
+
+    clang_disposeString(origFname);
+    clang_disposeString(transFname);
+  }
+
+  clang_remap_dispose(remap);
+  return 0;
+}
+
 /******************************************************************************/
 /* Command line processing.                                                   */
 /******************************************************************************/
 
 static void print_usage(void) {
   fprintf(stderr,
-    "usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n");
+    "usage: c-arcmt-test -mt-migrate-directory <path>\n"
+    "       c-arcmt-test <remap-file-path1> <remap-file-path2> ...\n\n\n");
 }
 
 /***/
 
 int carcmttest_main(int argc, const char **argv) {
   clang_enableStackTraces();
-  if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0)
+  if (argc == 3 && strncmp(argv[1], "-mt-migrate-directory", 21) == 0)
     return print_remappings(argv[2]);
 
+  if (argc > 1)
+    return print_remappings_filelist(argv+1, argc-1);
+  
   print_usage();
   return 1;
 }
index 539ae80058762733150e65972608189edd63fe57..c4c864bdbf5bc302d5269d55c27e9b895fb0a369 100644 (file)
@@ -5,10 +5,12 @@ set( LLVM_USED_LIBS
   clangBasic
   clangCodeGen
   clangDriver
+  clangEdit
   clangFrontend
   clangIndex
   clangLex
   clangParse
+  clangEdit
   clangARCMigrate
   clangRewrite
   clangSema
index c7d91a728d22a6670a6a032ec5f2ba8825ce18b9..d828f67868309a3affb7cdcd93d288de8b3aac35 100644 (file)
@@ -36,7 +36,7 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
            clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
            clangStaticAnalyzerCore.a \
            clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \
-           clangAST.a clangLex.a clangBasic.a
+           clangEdit.a clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile
 
index 58f8ba454db728ff0c1b808388ad2e02bd7a5b19..5ee5cf6e4ef89fab57187fe97543c74b4bb64d0b 100644 (file)
@@ -74,6 +74,47 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
   return remap.take();
 }
 
+CXRemapping clang_getRemappingsFromFileList(const char **filePaths,
+                                            unsigned numFiles) {
+  bool Logging = ::getenv("LIBCLANG_LOGGING");
+
+  OwningPtr<Remap> remap(new Remap());
+
+  if (numFiles == 0) {
+    if (Logging)
+      llvm::errs() << "clang_getRemappingsFromFileList was called with "
+                      "numFiles=0\n";
+    return remap.take();
+  }
+
+  if (!filePaths) {
+    if (Logging)
+      llvm::errs() << "clang_getRemappingsFromFileList was called with "
+                      "NULL filePaths\n";
+    return 0;
+  }
+
+  TextDiagnosticBuffer diagBuffer;
+  SmallVector<StringRef, 32> Files;
+  for (unsigned i = 0; i != numFiles; ++i)
+    Files.push_back(filePaths[i]);
+
+  bool err = arcmt::getFileRemappingsFromFileList(remap->Vec, Files,
+                                                  &diagBuffer);
+
+  if (err) {
+    if (Logging) {
+      llvm::errs() << "Error by clang_getRemappingsFromFileList\n";
+      for (TextDiagnosticBuffer::const_iterator
+             I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I)
+        llvm::errs() << I->second << '\n';
+    }
+    return remap.take();
+  }
+
+  return remap.take();
+}
+
 unsigned clang_remap_getNumFiles(CXRemapping map) {
   return static_cast<Remap *>(map)->Vec.size();
   
index 742448d2ea0ce5209c8b5f593b29de25d3fe0715..66a1710bac1428c6abfe5f087908c9faa77f157e 100644 (file)
@@ -6,6 +6,7 @@ set(LLVM_USED_LIBS
   clangSerialization
   clangIndex
   clangSema
+  clangEdit
   clangAST
   clangLex
   clangBasic)
index 375f7f20fe0060e5e291ebadf0928fcedd51d1bf..1fff166bbf8ff7c3b0701361b3e506ae69e0a830 100644 (file)
@@ -18,7 +18,8 @@ SHARED_LIBRARY = 1
 LINK_COMPONENTS := support mc
 USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
      clangSerialization.a \
-                clangParse.a clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+                clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
+                clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/Makefile
 
index 8645b15f7b2f1ab1298e0bc2211114aef23cf1a6..1900ac86c058f2863b9bf201a0ac92c910e42a7a 100644 (file)
@@ -132,6 +132,7 @@ clang_getRange
 clang_getRangeEnd
 clang_getRangeStart
 clang_getRemappings
+clang_getRemappingsFromFileList
 clang_getResultType
 clang_getSpecializedCursorTemplate
 clang_getSpellingLocation
index 7ec2b894a04b84966e46e3d13134645637bdd917..7c282d6b47f1aeed0fc48ff9dd93dc5683b0191e 100644 (file)
@@ -13,7 +13,7 @@ LINK_COMPONENTS := support mc
 USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
            clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
            clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
-           clangIndex.a clangARCMigrate.a clangRewrite.a \
+           clangIndex.a clangARCMigrate.a clangRewrite.a clangEdit.a \
            clangAnalysis.a clangAST.a clangLex.a clangBasic.a
 
 include $(CLANG_LEVEL)/unittests/Makefile
index 584ca10365d879484f28615a58f74b04ab321d6e..56581fcc638d94aabbc7bdc865f3937af22cc9e9 100644 (file)
@@ -66,10 +66,10 @@ TEST_F(LexerTest, LexAPI) {
     "N(INN(val)) N(NOF1) N(NOF2) N(val)";
 
   MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
-  SourceMgr.createMainFileIDForMemBuffer(buf);
+  FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
 
   VoidModuleLoader ModLoader;
-  HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
+  HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
   Preprocessor PP(Diags, LangOpts,
                   Target.getPtr(),
                   SourceMgr, HeaderInfo, ModLoader,