diff options
author | Kadir Cetinkaya <kadircet@google.com> | 2019-09-09 12:28:44 +0000 |
---|---|---|
committer | Kadir Cetinkaya <kadircet@google.com> | 2019-09-09 12:28:44 +0000 |
commit | 5b270932cc6ee39d977d397bafc363e9c5df040f (patch) | |
tree | 5d55df28fdce1d6ad01e26152a66541c4f797316 /clang-tools-extra/clangd/SourceCode.cpp | |
parent | 7c5697c8b24c6a1288f9682ba627182bdfb914f7 (diff) | |
download | bcm5719-llvm-5b270932cc6ee39d977d397bafc363e9c5df040f.tar.gz bcm5719-llvm-5b270932cc6ee39d977d397bafc363e9c5df040f.zip |
[clangd] Support multifile edits as output of Tweaks
Summary:
First patch for propogating multifile changes from tweak outputs to LSP
WorkspaceEdits.
Uses SM to convert tooling::Replacements to TextEdits.
Errors out if there are any inconsistencies between the draft version and the
version generated the edits.
Reviewers: sammccall
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D66637
llvm-svn: 371392
Diffstat (limited to 'clang-tools-extra/clangd/SourceCode.cpp')
-rw-r--r-- | clang-tools-extra/clangd/SourceCode.cpp | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp index 812e42a7a2a..95f250c9d6a 100644 --- a/clang-tools-extra/clangd/SourceCode.cpp +++ b/clang-tools-extra/clangd/SourceCode.cpp @@ -11,6 +11,7 @@ #include "FuzzyMatch.h" #include "Logger.h" #include "Protocol.h" +#include "refactor/Tweak.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" @@ -19,14 +20,21 @@ #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SHA1.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/xxhash.h" #include <algorithm> @@ -562,7 +570,7 @@ llvm::Optional<std::string> getCanonicalPath(const FileEntry *F, } // Handle the symbolic link path case where the current working directory - // (getCurrentWorkingDirectory) is a symlink./ We always want to the real + // (getCurrentWorkingDirectory) is a symlink. We always want to the real // file path (instead of the symlink path) for the C++ symbols. // // Consider the following example: @@ -908,5 +916,57 @@ llvm::Optional<DefinedMacro> locateMacroAt(SourceLocation Loc, return None; } +llvm::Expected<std::string> Edit::apply() const { + return tooling::applyAllReplacements(InitialCode, Replacements); +} + +std::vector<TextEdit> Edit::asTextEdits() const { + return replacementsToEdits(InitialCode, Replacements); +} + +bool Edit::canApplyTo(llvm::StringRef Code) const { + // Create line iterators, since line numbers are important while applying our + // edit we cannot skip blank lines. + auto LHS = llvm::MemoryBuffer::getMemBuffer(Code); + llvm::line_iterator LHSIt(*LHS, /*SkipBlanks=*/false); + + auto RHS = llvm::MemoryBuffer::getMemBuffer(InitialCode); + llvm::line_iterator RHSIt(*RHS, /*SkipBlanks=*/false); + + // Compare the InitialCode we prepared the edit for with the Code we received + // line by line to make sure there are no differences. + // FIXME: This check is too conservative now, it should be enough to only + // check lines around the replacements contained inside the Edit. + while (!LHSIt.is_at_eof() && !RHSIt.is_at_eof()) { + if (*LHSIt != *RHSIt) + return false; + ++LHSIt; + ++RHSIt; + } + + // After we reach EOF for any of the files we make sure the other one doesn't + // contain any additional content except empty lines, they should not + // interfere with the edit we produced. + while (!LHSIt.is_at_eof()) { + if (!LHSIt->empty()) + return false; + ++LHSIt; + } + while (!RHSIt.is_at_eof()) { + if (!RHSIt->empty()) + return false; + ++RHSIt; + } + return true; +} + +llvm::Error reformatEdit(Edit &E, const format::FormatStyle &Style) { + if (auto NewEdits = cleanupAndFormat(E.InitialCode, E.Replacements, Style)) + E.Replacements = std::move(*NewEdits); + else + return NewEdits.takeError(); + return llvm::Error::success(); +} + } // namespace clangd } // namespace clang |