aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2012-03-06 20:06:33 +0000
committerTed Kremenek <kremenek@apple.com>2012-03-06 20:06:33 +0000
commit30660a898545416f0fea2d717f16f75640001e38 (patch)
treea8408d8c12d992b4110fca1bfe78f337b48f5d11
parent2a253960f0312c9759965a1defb9326d6b2764a4 (diff)
Add new code migrator support for migrating existing Objective-C code to use
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
-rw-r--r--include/clang-c/Index.h14
-rw-r--r--include/clang/ARCMigrate/ARCMT.h9
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h26
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h9
-rw-r--r--include/clang/Basic/Diagnostic.h25
-rw-r--r--include/clang/Driver/Action.h12
-rw-r--r--include/clang/Driver/CC1Options.td11
-rw-r--r--include/clang/Driver/Options.td12
-rw-r--r--include/clang/Driver/Types.def1
-rw-r--r--include/clang/Edit/Commit.h140
-rw-r--r--include/clang/Edit/EditedSource.h87
-rw-r--r--include/clang/Edit/EditsReceiver.h35
-rw-r--r--include/clang/Edit/FileOffset.h65
-rw-r--r--include/clang/Edit/Rewriters.h33
-rw-r--r--include/clang/Frontend/FrontendOptions.h13
-rw-r--r--include/clang/Rewrite/FixItRewriter.h3
-rw-r--r--lib/ARCMigrate/ARCMT.cpp46
-rw-r--r--lib/ARCMigrate/CMakeLists.txt1
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp26
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp226
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp94
-rw-r--r--lib/Basic/DiagnosticIDs.cpp13
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/Driver/Action.cpp7
-rw-r--r--lib/Driver/Driver.cpp3
-rw-r--r--lib/Driver/ToolChain.cpp2
-rw-r--r--lib/Driver/ToolChains.cpp2
-rw-r--r--lib/Driver/Tools.cpp25
-rw-r--r--lib/Driver/WindowsToolChain.cpp1
-rw-r--r--lib/Edit/CMakeLists.txt7
-rw-r--r--lib/Edit/Commit.cpp345
-rw-r--r--lib/Edit/EditedSource.cpp329
-rw-r--r--lib/Edit/Makefile14
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp589
-rw-r--r--lib/Frontend/CompilerInvocation.cpp31
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp57
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp9
-rwxr-xr-xlib/Makefile2
-rw-r--r--lib/Rewrite/FixItRewriter.cpp69
-rw-r--r--test/ARCMT/dispatch.m29
-rw-r--r--test/ARCMT/dispatch.m.result25
-rw-r--r--test/ARCMT/driver-migrate.m2
-rw-r--r--test/ARCMT/migrate-emit-errors.m2
-rw-r--r--test/ARCMT/migrate-plist-output.m2
-rw-r--r--test/ARCMT/migrate-space-in-path.m6
-rw-r--r--test/ARCMT/migrate.m6
-rw-r--r--test/ARCMT/objcmt-numeric-literals.m501
-rw-r--r--test/ARCMT/objcmt-numeric-literals.m.result501
-rw-r--r--test/ARCMT/objcmt-subscripting-literals.m137
-rw-r--r--test/ARCMT/objcmt-subscripting-literals.m.result137
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m4
-rw-r--r--test/ARCMT/with-arc-mode-migrate.m.result4
-rw-r--r--tools/arcmt-test/CMakeLists.txt1
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp5
-rw-r--r--tools/c-arcmt-test/c-arcmt-test.c33
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/Makefile2
-rw-r--r--tools/libclang/ARCMigrate.cpp41
-rw-r--r--tools/libclang/CMakeLists.txt1
-rw-r--r--tools/libclang/Makefile3
-rw-r--r--tools/libclang/libclang.exports1
-rw-r--r--unittests/Frontend/Makefile2
-rw-r--r--unittests/Lex/LexerTest.cpp4
64 files changed, 3748 insertions, 99 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 746490be88..fd7a9f3a01 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -3983,6 +3983,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.
*/
CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping);
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index 738a00dcd0..86a6cbb22a 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -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,
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h
index 4eac4facdd..e075252137 100644
--- a/include/clang/ARCMigrate/ARCMTActions.h
+++ b/include/clang/ARCMigrate/ARCMTActions.h
@@ -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);
+};
+
}
}
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
index a451988f93..fe7cfadb49 100644
--- a/include/clang/ARCMigrate/FileRemapper.h
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -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());
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index 3e54b4352b..2b71d445cc 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -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;
}
diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h
index 41ce4d92c4..6e317a0726 100644
--- a/include/clang/Driver/Action.h
+++ b/include/clang/Driver/Action.h
@@ -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:
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 93e63dee61..2fe4eba205 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -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=">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index b269ddb045..51c5e020e1 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -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]>;
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index 8449d639e6..bba888ca4a 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -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
index 0000000000..aaf6b18384
--- /dev/null
+++ b/include/clang/Edit/Commit.h
@@ -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
index 0000000000..273921cee5
--- /dev/null
+++ b/include/clang/Edit/EditedSource.h
@@ -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
index 0000000000..600ac28ea9
--- /dev/null
+++ b/include/clang/Edit/EditsReceiver.h
@@ -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
index 0000000000..675ad18fcd
--- /dev/null
+++ b/include/clang/Edit/FileOffset.h
@@ -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
index 0000000000..aa7a5b2320
--- /dev/null
+++ b/include/clang/Edit/Rewriters.h
@@ -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
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index f18fdebba7..0ec2f6b1ef 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -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
diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/FixItRewriter.h
index 0ebd62c560..44f0611b17 100644
--- a/include/clang/Rewrite/FixItRewriter.h
+++ b/include/clang/Rewrite/FixItRewriter.h
@@ -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;
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index 61753074e8..07f22c4f36 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -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;
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index 1a64b12721..fcb7f72ee2 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -4,6 +4,7 @@ add_clang_library(clangARCMigrate
ARCMT.cpp
ARCMTActions.cpp
FileRemapper.cpp
+ ObjCMT.cpp
PlistReporter.cpp
TransAPIUses.cpp
TransARCAssign.cpp
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 0e6e35c748..1e97c9eed5 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -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
index 0000000000..497377a394
--- /dev/null
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -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);
+}
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 7bb7b5eeea..15669ac973 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -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,
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index f0e0c9c778..8c33a963c9 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -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()) {
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 7b46c6040a..54d296c3ab 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -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)
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index a9dc17b320..d7b4bc7053 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -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)
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index e71f5a6065..30b7eccc8a 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -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)) {
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index c0c9c504b6..b4f5d0b421 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -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;
}
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 5ff82c7600..a45722315e 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -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;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 38f21c0882..076311a78e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -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.
//
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index 8a32db2fca..70bd4f1fc3 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -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
index 0000000000..c87478cf7d
--- /dev/null
+++ b/lib/Edit/CMakeLists.txt
@@ -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
index 0000000000..e0250ccf05
--- /dev/null
+++ b/lib/Edit/Commit.cpp
@@ -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
index 0000000000..5b7fa4ad1b
--- /dev/null
+++ b/lib/Edit/EditedSource.cpp
@@ -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
index 0000000000..92a67ebc82
--- /dev/null
+++ b/lib/Edit/Makefile
@@ -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
index 0000000000..a092768034
--- /dev/null
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -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;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 43ac475211..9391eea32d 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -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);
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index 29f9ed5a7d..6c3bb1d695 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -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)
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 0841b2cef8..07d2b8d19f 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -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())
diff --git a/lib/Makefile b/lib/Makefile
index 74df7abcef..69c5cd5d83 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp
index caa7d06ac2..3863adb4f1 100644
--- a/lib/Rewrite/FixItRewriter.cpp
+++ b/lib/Rewrite/FixItRewriter.cpp
@@ -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
index 0000000000..75c4a83459
--- /dev/null
+++ b/test/ARCMT/dispatch.m
@@ -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
index 0000000000..e897672a26
--- /dev/null
+++ b/test/ARCMT/dispatch.m.result
@@ -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) {
+}
diff --git a/test/ARCMT/driver-migrate.m b/test/ARCMT/driver-migrate.m
index a2b1a7dc27..a912ad95b1 100644
--- a/test/ARCMT/driver-migrate.m
+++ b/test/ARCMT/driver-migrate.m
@@ -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
diff --git a/test/ARCMT/migrate-emit-errors.m b/test/ARCMT/migrate-emit-errors.m
index 6a4a3963ca..95c0d2f8f0 100644
--- a/test/ARCMT/migrate-emit-errors.m
+++ b/test/ARCMT/migrate-emit-errors.m
@@ -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
diff --git a/test/ARCMT/migrate-plist-output.m b/test/ARCMT/migrate-plist-output.m
index b9e3ceff86..12efa93f07 100644
--- a/test/ARCMT/migrate-plist-output.m
+++ b/test/ARCMT/migrate-plist-output.m
@@ -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
diff --git a/test/ARCMT/migrate-space-in-path.m b/test/ARCMT/migrate-space-in-path.m
index e454fae642..89dfe1475c 100644
--- a/test/ARCMT/migrate-space-in-path.m
+++ b/test/ARCMT/migrate-space-in-path.m
@@ -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
diff --git a/test/ARCMT/migrate.m b/test/ARCMT/migrate.m
index beaf8e5b15..6f41258e59 100644
--- a/test/ARCMT/migrate.m
+++ b/test/ARCMT/migrate.m
@@ -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
index 0000000000..b86af4d056
--- /dev/null
+++ b/test/ARCMT/objcmt-numeric-literals.m
@@ -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
index 0000000000..1c4187aaef
--- /dev/null
+++ b/test/ARCMT/objcmt-numeric-literals.m.result
@@ -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
index 0000000000..1632bf91ad
--- /dev/null
+++ b/test/ARCMT/objcmt-subscripting-literals.m
@@ -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
index 0000000000..cc93cb4906
--- /dev/null
+++ b/test/ARCMT/objcmt-subscripting-literals.m.result
@@ -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
diff --git a/test/ARCMT/with-arc-mode-migrate.m b/test/ARCMT/with-arc-mode-migrate.m
index 32bcad1950..468859478e 100644
--- a/test/ARCMT/with-arc-mode-migrate.m
+++ b/test/ARCMT/with-arc-mode-migrate.m
@@ -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
diff --git a/test/ARCMT/with-arc-mode-migrate.m.result b/test/ARCMT/with-arc-mode-migrate.m.result
index f060793f6e..dd34b99908 100644
--- a/test/ARCMT/with-arc-mode-migrate.m.result
+++ b/test/ARCMT/with-arc-mode-migrate.m.result
@@ -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
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index 9227f8ee63..a0029b416f 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_USED_LIBS
clangARCMigrate
+ clangEdit
clangRewrite
)
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index c143e27f33..f5ca81a6d1 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -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
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index 881a058c2c..2dc8034e32 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -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;
diff --git a/tools/c-arcmt-test/c-arcmt-test.c b/tools/c-arcmt-test/c-arcmt-test.c
index 5522b33e23..b91d3e1b98 100644
--- a/tools/c-arcmt-test/c-arcmt-test.c
+++ b/tools/c-arcmt-test/c-arcmt-test.c
@@ -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;
}
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 539ae80058..c4c864bdbf 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -5,10 +5,12 @@ set( LLVM_USED_LIBS
clangBasic
clangCodeGen
clangDriver
+ clangEdit
clangFrontend
clangIndex
clangLex
clangParse
+ clangEdit
clangARCMigrate
clangRewrite
clangSema
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index c7d91a728d..d828f67868 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -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
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index 58f8ba454d..5ee5cf6e4e 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -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();
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 742448d2ea..66a1710bac 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_USED_LIBS
clangSerialization
clangIndex
clangSema
+ clangEdit
clangAST
clangLex
clangBasic)
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 375f7f20fe..1fff166bbf 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -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
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 8645b15f7b..1900ac86c0 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -132,6 +132,7 @@ clang_getRange
clang_getRangeEnd
clang_getRangeStart
clang_getRemappings
+clang_getRemappingsFromFileList
clang_getResultType
clang_getSpecializedCursorTemplate
clang_getSpellingLocation
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index 7ec2b894a0..7c282d6b47 100644
--- a/unittests/Frontend/Makefile
+++ b/unittests/Frontend/Makefile
@@ -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
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index 584ca10365..56581fcc63 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -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,