aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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,