Index: clangd/CMakeLists.txt =================================================================== --- clangd/CMakeLists.txt +++ clangd/CMakeLists.txt @@ -23,6 +23,7 @@ FindSymbols.cpp FileDistance.cpp FS.cpp + FSProvider.cpp FuzzyMatch.cpp GlobalCompilationDatabase.cpp Headers.cpp Index: clangd/FSProvider.h =================================================================== --- clangd/FSProvider.h +++ clangd/FSProvider.h @@ -33,9 +33,7 @@ public: // FIXME: returns the single real FS instance, which is not threadsafe. llvm::IntrusiveRefCntPtr - getFileSystem() const override { - return llvm::vfs::getRealFileSystem(); - } + getFileSystem() const override; }; } // namespace clangd Index: clangd/FSProvider.cpp =================================================================== --- clangd/FSProvider.cpp +++ 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 + +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 FS) + : ProxyFileSystem(std::move(FS)) {} + + llvm::ErrorOr> + 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( + new VolatileFile(std::move(*File))); + } + +private: + class VolatileFile : public vfs::File { + public: + VolatileFile(std::unique_ptr Wrapped) + : Wrapped(std::move(Wrapped)) { + assert(this->Wrapped); + } + + virtual llvm::ErrorOr> + getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, + bool /*IsVolatile*/) override { + return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator, + /*IsVolatile=*/true); + } + + llvm::ErrorOr status() override { return Wrapped->status(); } + llvm::ErrorOr getName() override { return Wrapped->getName(); } + std::error_code close() override { return Wrapped->close(); } + + private: + std::unique_ptr Wrapped; + }; +}; +} // namespace + +llvm::IntrusiveRefCntPtr +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