diff options
Diffstat (limited to 'lib/Tooling/Core/Replacement.cpp')
-rw-r--r-- | lib/Tooling/Core/Replacement.cpp | 84 |
1 files changed, 71 insertions, 13 deletions
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp index 47bbdeb470ee0..4f130709ac16d 100644 --- a/lib/Tooling/Core/Replacement.cpp +++ b/lib/Tooling/Core/Replacement.cpp @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +#include "clang/Tooling/Core/Replacement.h" + #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticOptions.h" @@ -18,7 +20,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "clang/Rewrite/Core/Rewriter.h" -#include "clang/Tooling/Core/Replacement.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_os_ostream.h" @@ -57,14 +58,8 @@ bool Replacement::apply(Rewriter &Rewrite) const { const FileEntry *Entry = SM.getFileManager().getFile(FilePath); if (!Entry) return false; - FileID ID; - // FIXME: Use SM.translateFile directly. - SourceLocation Location = SM.translateFileLineCol(Entry, 1, 1); - ID = Location.isValid() ? - SM.getFileID(Location) : - SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User); - // FIXME: We cannot check whether Offset + Length is in the file, as - // the remapping API is not public in the RewriteBuffer. + + FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User); const SourceLocation Start = SM.getLocForStartOfFile(ID). getLocWithOffset(ReplacementRange.getOffset()); @@ -254,7 +249,11 @@ bool applyAllReplacements(const std::vector<Replacement> &Replaces, return Result; } -std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) { +llvm::Expected<std::string> applyAllReplacements(StringRef Code, + const Replacements &Replaces) { + if (Replaces.empty()) + return Code.str(); + IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( new vfs::InMemoryFileSystem); FileManager Files(FileSystemOptions(), InMemoryFileSystem); @@ -272,7 +271,9 @@ std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) { Replacement Replace("<stdin>", I->getOffset(), I->getLength(), I->getReplacementText()); if (!Replace.apply(Rewrite)) - return ""; + return llvm::make_error<llvm::StringError>( + "Failed to apply replacement: " + Replace.toString(), + llvm::inconvertibleErrorCode()); } std::string Result; llvm::raw_string_ostream OS(Result); @@ -281,6 +282,55 @@ std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) { return Result; } +// Merge and sort overlapping ranges in \p Ranges. +static std::vector<Range> mergeAndSortRanges(std::vector<Range> Ranges) { + std::sort(Ranges.begin(), Ranges.end(), + [](const Range &LHS, const Range &RHS) { + if (LHS.getOffset() != RHS.getOffset()) + return LHS.getOffset() < RHS.getOffset(); + return LHS.getLength() < RHS.getLength(); + }); + std::vector<Range> Result; + for (const auto &R : Ranges) { + if (Result.empty() || + Result.back().getOffset() + Result.back().getLength() < R.getOffset()) { + Result.push_back(R); + } else { + unsigned NewEnd = + std::max(Result.back().getOffset() + Result.back().getLength(), + R.getOffset() + R.getLength()); + Result[Result.size() - 1] = + Range(Result.back().getOffset(), NewEnd - Result.back().getOffset()); + } + } + return Result; +} + +std::vector<Range> calculateChangedRanges(const Replacements &Replaces) { + std::vector<Range> ChangedRanges; + int Shift = 0; + for (const Replacement &R : Replaces) { + unsigned Offset = R.getOffset() + Shift; + unsigned Length = R.getReplacementText().size(); + Shift += Length - R.getLength(); + ChangedRanges.push_back(Range(Offset, Length)); + } + return mergeAndSortRanges(ChangedRanges); +} + +std::vector<Range> +calculateRangesAfterReplacements(const Replacements &Replaces, + const std::vector<Range> &Ranges) { + auto MergedRanges = mergeAndSortRanges(Ranges); + tooling::Replacements FakeReplaces; + for (const auto &R : MergedRanges) + FakeReplaces.insert(Replacement(Replaces.begin()->getFilePath(), + R.getOffset(), R.getLength(), + std::string(R.getLength(), ' '))); + tooling::Replacements NewReplaces = mergeReplacements(FakeReplaces, Replaces); + return calculateChangedRanges(NewReplaces); +} + namespace { // Represents a merged replacement, i.e. a replacement consisting of multiple // overlapping replacements from 'First' and 'Second' in mergeReplacements. @@ -314,7 +364,7 @@ public: // Merges the next element 'R' into this merged element. As we always merge // from 'First' into 'Second' or vice versa, the MergedReplacement knows what - // set the next element is coming from. + // set the next element is coming from. void merge(const Replacement &R) { if (MergeSecond) { unsigned REnd = R.getOffset() + Delta + R.getLength(); @@ -377,6 +427,15 @@ private: }; } // namespace +std::map<std::string, Replacements> +groupReplacementsByFile(const Replacements &Replaces) { + std::map<std::string, Replacements> FileToReplaces; + for (const auto &Replace : Replaces) { + FileToReplaces[Replace.getFilePath()].insert(Replace); + } + return FileToReplaces; +} + Replacements mergeReplacements(const Replacements &First, const Replacements &Second) { if (First.empty() || Second.empty()) @@ -416,4 +475,3 @@ Replacements mergeReplacements(const Replacements &First, } // end namespace tooling } // end namespace clang - |