diff options
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(SourceLoca |