summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/FSProvider.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/FSProvider.cpp')
-rw-r--r--clang-tools-extra/clangd/FSProvider.cpp85
1 files changed, 85 insertions, 0 deletions
diff --git a/clang-tools-extra/clangd/FSProvider.cpp b/clang-tools-extra/clangd/FSProvider.cpp
new file mode 100644
index 00000000000..d94be5bb12c
--- /dev/null
+++ b/clang-tools-extra/clangd/FSProvider.cpp
@@ -0,0 +1,85 @@
+//===--- FSProvider.cpp - VFS provider for ClangdServer -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "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>
+
+using namespace llvm;
+
+namespace clang {
+namespace clangd {
+
+namespace {
+/// Always opens files in the underlying filesystem as "volatile", meaning they
+/// won't be memory-mapped. This avoid locking the files on Windows.
+class VolatileFileSystem : public llvm::vfs::ProxyFileSystem {
+public:
+ explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr<FileSystem> FS)
+ : ProxyFileSystem(std::move(FS)) {}
+
+ llvm::ErrorOr<std::unique_ptr<vfs::File>>
+ openFileForRead(const Twine &InPath) override {
+ 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.
+ 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 vfs::File {
+ public:
+ VolatileFile(std::unique_ptr<vfs::File> Wrapped)
+ : Wrapped(std::move(Wrapped)) {
+ assert(this->Wrapped);
+ }
+
+ virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
+ bool /*IsVolatile*/) override {
+ return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator,
+ /*IsVolatile=*/true);
+ }
+
+ llvm::ErrorOr<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 on Windows, they cause file locking issues.
+// FIXME: Try to use a similar approach in Sema instead of relying on
+// propagation of the 'isVolatile' flag through all layers.
+#ifdef _WIN32
+ return new VolatileFSProvider(vfs::getRealFileSystem());
+#else
+ return vfs::getRealFileSystem();
+#endif
+}
+} // namespace clangd
+} // namespace clang
OpenPOWER on IntegriCloud