[clangd] Move non-clang base pieces into separate support/ lib. NFCI
Summary:
This enforces layering, reduces a sprawling clangd/ directory, and makes life
easier for embedders.
Reviewers: kbobyrev
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79014
diff --git a/clang-tools-extra/clangd/support/FSProvider.cpp b/clang-tools-extra/clangd/support/FSProvider.cpp
new file mode 100644
index 0000000..6474a3c
--- /dev/null
+++ b/clang-tools-extra/clangd/support/FSProvider.cpp
@@ -0,0 +1,83 @@
+//===--- FSProvider.cpp - VFS provider for ClangdServer -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/FSProvider.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include <memory>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+/// Always opens files in the underlying filesystem as "volatile", meaning they
+/// won't be memory-mapped. Memory-mapping isn't desirable for clangd:
+/// - edits to the underlying files change contents MemoryBuffers owned by
+// SourceManager, breaking its invariants and leading to crashes
+/// - it locks files on windows, preventing edits
+class VolatileFileSystem : public llvm::vfs::ProxyFileSystem {
+public:
+ explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr<FileSystem> FS)
+ : ProxyFileSystem(std::move(FS)) {}
+
+ llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
+ openFileForRead(const llvm::Twine &InPath) override {
+ llvm::SmallString<128> Path;
+ InPath.toVector(Path);
+
+ auto File = getUnderlyingFS().openFileForRead(Path);
+ if (!File)
+ return File;
+ // Try to guess preamble files, they can be memory-mapped even on Windows as
+ // clangd has exclusive access to those and nothing else should touch them.
+ llvm::StringRef FileName = llvm::sys::path::filename(Path);
+ if (FileName.startswith("preamble-") && FileName.endswith(".pch"))
+ return File;
+ return std::unique_ptr<VolatileFile>(new VolatileFile(std::move(*File)));
+ }
+
+private:
+ class VolatileFile : public llvm::vfs::File {
+ public:
+ VolatileFile(std::unique_ptr<llvm::vfs::File> Wrapped)
+ : Wrapped(std::move(Wrapped)) {
+ assert(this->Wrapped);
+ }
+
+ virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBuffer(const llvm::Twine &Name, int64_t FileSize,
+ bool RequiresNullTerminator, bool /*IsVolatile*/) override {
+ return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator,
+ /*IsVolatile=*/true);
+ }
+
+ llvm::ErrorOr<llvm::vfs::Status> status() override {
+ return Wrapped->status();
+ }
+ llvm::ErrorOr<std::string> getName() override { return Wrapped->getName(); }
+ std::error_code close() override { return Wrapped->close(); }
+
+ private:
+ std::unique_ptr<File> Wrapped;
+ };
+};
+} // namespace
+
+llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
+clang::clangd::RealFileSystemProvider::getFileSystem() const {
+ // Avoid using memory-mapped files.
+ // FIXME: Try to use a similar approach in Sema instead of relying on
+ // propagation of the 'isVolatile' flag through all layers.
+ return new VolatileFileSystem(
+ llvm::vfs::createPhysicalFileSystem().release());
+}
+} // namespace clangd
+} // namespace clang