diff options
Diffstat (limited to 'clang-tools-extra/clangd/FSProvider.cpp')
| -rw-r--r-- | clang-tools-extra/clangd/FSProvider.cpp | 85 |
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 |

