blob: 81a1adab6b97c399da2cda1a0784cf4ba0dc1997 [file] [log] [blame]
Ilya Biryukov1712bc72018-12-03 15:21:49 +00001//===--- FSProvider.cpp - VFS provider for ClangdServer -------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "FSProvider.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/SmallString.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/Path.h"
15#include "llvm/Support/VirtualFileSystem.h"
16#include <memory>
17
Ilya Biryukov1712bc72018-12-03 15:21:49 +000018namespace clang {
19namespace clangd {
20
21namespace {
22/// Always opens files in the underlying filesystem as "volatile", meaning they
23/// won't be memory-mapped. This avoid locking the files on Windows.
24class VolatileFileSystem : public llvm::vfs::ProxyFileSystem {
25public:
26 explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr<FileSystem> FS)
27 : ProxyFileSystem(std::move(FS)) {}
28
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000029 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
30 openFileForRead(const llvm::Twine &InPath) override {
31 llvm::SmallString<128> Path;
Ilya Biryukov1712bc72018-12-03 15:21:49 +000032 InPath.toVector(Path);
33
34 auto File = getUnderlyingFS().openFileForRead(Path);
35 if (!File)
36 return File;
37 // Try to guess preamble files, they can be memory-mapped even on Windows as
38 // clangd has exclusive access to those.
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000039 llvm::StringRef FileName = llvm::sys::path::filename(Path);
Ilya Biryukov1712bc72018-12-03 15:21:49 +000040 if (FileName.startswith("preamble-") && FileName.endswith(".pch"))
41 return File;
Ilya Biryukov22fa4652019-01-03 13:28:05 +000042 return std::unique_ptr<VolatileFile>(new VolatileFile(std::move(*File)));
Ilya Biryukov1712bc72018-12-03 15:21:49 +000043 }
44
45private:
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000046 class VolatileFile : public llvm::vfs::File {
Ilya Biryukov1712bc72018-12-03 15:21:49 +000047 public:
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000048 VolatileFile(std::unique_ptr<llvm::vfs::File> Wrapped)
Ilya Biryukov1712bc72018-12-03 15:21:49 +000049 : Wrapped(std::move(Wrapped)) {
50 assert(this->Wrapped);
51 }
52
53 virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000054 getBuffer(const llvm::Twine &Name, int64_t FileSize,
55 bool RequiresNullTerminator, bool /*IsVolatile*/) override {
Ilya Biryukov1712bc72018-12-03 15:21:49 +000056 return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator,
57 /*IsVolatile=*/true);
58 }
59
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000060 llvm::ErrorOr<llvm::vfs::Status> status() override {
61 return Wrapped->status();
62 }
Ilya Biryukov1712bc72018-12-03 15:21:49 +000063 llvm::ErrorOr<std::string> getName() override { return Wrapped->getName(); }
64 std::error_code close() override { return Wrapped->close(); }
65
66 private:
67 std::unique_ptr<File> Wrapped;
68 };
69};
70} // namespace
71
72llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
73clang::clangd::RealFileSystemProvider::getFileSystem() const {
74// Avoid using memory-mapped files on Windows, they cause file locking issues.
75// FIXME: Try to use a similar approach in Sema instead of relying on
76// propagation of the 'isVolatile' flag through all layers.
77#ifdef _WIN32
Amara Emersoncadf4b62019-01-14 18:59:17 +000078 return new VolatileFileSystem(llvm::vfs::getRealFileSystem());
Ilya Biryukov1712bc72018-12-03 15:21:49 +000079#else
Amara Emersoncadf4b62019-01-14 18:59:17 +000080 return llvm::vfs::getRealFileSystem();
Ilya Biryukov1712bc72018-12-03 15:21:49 +000081#endif
82}
83} // namespace clangd
84} // namespace clang