summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/SourceCode.cpp
diff options
context:
space:
mode:
authorKadir Cetinkaya <kadircet@google.com>2019-09-09 12:28:44 +0000
committerKadir Cetinkaya <kadircet@google.com>2019-09-09 12:28:44 +0000
commit5b270932cc6ee39d977d397bafc363e9c5df040f (patch)
tree5d55df28fdce1d6ad01e26152a66541c4f797316 /clang-tools-extra/clangd/SourceCode.cpp
parent7c5697c8b24c6a1288f9682ba627182bdfb914f7 (diff)
downloadbcm5719-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.cpp62
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
OpenPOWER on IntegriCloud