LutsenkoDanil created this revision.
LutsenkoDanil added reviewers: sammccall, ilya-biryukov.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, MaskRay,
ioeric.
Patch changes behavior of preamble building. If headers was changed in editor,
preamble will be built with draft versions of them.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D54077
Files:
clangd/ClangdLSPServer.cpp
clangd/ClangdLSPServer.h
clangd/DraftStore.cpp
clangd/DraftStore.h
clangd/FS.h
clangd/FSProvider.h
unittests/clangd/DraftStoreTests.cpp
Index: unittests/clangd/DraftStoreTests.cpp
===
--- unittests/clangd/DraftStoreTests.cpp
+++ unittests/clangd/DraftStoreTests.cpp
@@ -53,7 +53,7 @@
Expected Result = DS.updateDraft(Path, {Event});
ASSERT_TRUE(!!Result);
EXPECT_EQ(*Result, SrcAfter.code());
-EXPECT_EQ(*DS.getDraft(Path), SrcAfter.code());
+EXPECT_EQ(DS.getDraft(Path)->Content, SrcAfter.code());
}
}
@@ -83,7 +83,7 @@
ASSERT_TRUE(!!Result) << toString(Result.takeError());
EXPECT_EQ(*Result, FinalSrc.code());
- EXPECT_EQ(*DS.getDraft(Path), FinalSrc.code());
+ EXPECT_EQ(DS.getDraft(Path)->Content, FinalSrc.code());
}
TEST(DraftStoreIncrementalUpdateTest, Simple) {
@@ -339,9 +339,9 @@
EXPECT_EQ(toString(Result.takeError()),
"UTF-16 offset 100 is invalid for line 0");
- Optional Contents = DS.getDraft(File);
- EXPECT_TRUE(Contents);
- EXPECT_EQ(*Contents, OriginalContents);
+ Optional NewDraft = DS.getDraft(File);
+ EXPECT_TRUE(NewDraft);
+ EXPECT_EQ(NewDraft->Content, OriginalContents);
}
} // namespace
Index: clangd/FSProvider.h
===
--- clangd/FSProvider.h
+++ clangd/FSProvider.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FSPROVIDER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FSPROVIDER_H
+#include "FS.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -38,6 +39,20 @@
}
};
+class DraftFileSystemProvider : public FileSystemProvider {
+ DraftStore &DS;
+
+public:
+ DraftFileSystemProvider(DraftStore &DS) : DS(DS) {}
+
+ llvm::IntrusiveRefCntPtr
+ getFileSystem() const override {
+static llvm::IntrusiveRefCntPtr Result(
+new DraftFileSystem(llvm::vfs::getRealFileSystem(), DS));
+return Result;
+ }
+};
+
} // namespace clangd
} // namespace clang
Index: clangd/FS.h
===
--- clangd/FS.h
+++ clangd/FS.h
@@ -10,13 +10,84 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_H
+#include "DraftStore.h"
+#include "Logger.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/VirtualFileSystem.h"
namespace clang {
namespace clangd {
+class DraftFile : public llvm::vfs::File {
+ std::unique_ptr F;
+ Draft DraftInfo;
+
+public:
+ DraftFile(std::unique_ptr F, Draft D)
+ : F(std::move(F)), DraftInfo(std::move(D)) {}
+
+ llvm::ErrorOr getName() override { return F->getName(); }
+
+ llvm::ErrorOr>
+ getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
+bool IsVolatile) override {
+(void)IsVolatile;
+(void)RequiresNullTerminator;
+
+if (FileSize < 0) {
+ FileSize = DraftInfo.Content.size();
+}
+
+return llvm::MemoryBuffer::getMemBufferCopy(
+llvm::StringRef(DraftInfo.Content).substr(0, FileSize), Name);
+ }
+
+ llvm::ErrorOr status() override {
+auto RealStatus = F->status();
+
+if (!RealStatus) {
+ return RealStatus;
+}
+
+llvm::vfs::Status Result(
+RealStatus->getName(), RealStatus->getUniqueID(), DraftInfo.ModifyTime,
+RealStatus->getUser(), RealStatus->getGroup(), DraftInfo.Content.size(),
+RealStatus->getType(), RealStatus->getPermissions());
+
+Result.IsVFSMapped = RealStatus->IsVFSMapped;
+return Result;
+ }
+
+ std::error_code close() override { return F->close(); }
+};
+
+/// Wrapper around real FS. If file was changed in the DraftStrore, returns
+/// changed content, instead of real
+class DraftFileSystem : public llvm::vfs::ProxyFileSystem {
+ DraftStore &DS;
+
+public:
+ DraftFileSystem(IntrusiveRefCntPtr FS, DraftStore &DS)
+ : llvm::vfs::ProxyFileSystem(FS), DS(DS) {}
+
+ llvm::ErrorOr>
+ openFileForRead(const Twine &Path) override {
+auto Result = getUnderlyingFS().openFileForRead(Path);
+
+if (!Result) {
+ return Result;
+}
+
+if (auto D = DS.getDraft(Path.str())) {
+ return std::unique_ptr(
+ new DraftFile(std::move(*Result), std::move(*D)));
+}
+
+return Result;
+ }
+};
+
/// Records status information for files open()ed or stat()ed during preamble
/// build (except for the main file), so we can avoid stat()s on the underlying
/// FS when reusing the preamble. For example, co