blob: 5d1434bf6f0bf1673bd23f890c2f1de4a9a5a60e [file] [log] [blame]
Ilya Biryukov1712bc72018-12-03 15:21:49 +00001//===--- FSProvider.cpp - VFS provider for ClangdServer -------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Ilya Biryukov1712bc72018-12-03 15:21:49 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "FSProvider.h"
10#include "llvm/ADT/STLExtras.h"
11#include "llvm/ADT/SmallString.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/Support/Path.h"
14#include "llvm/Support/VirtualFileSystem.h"
15#include <memory>
16
Ilya Biryukov1712bc72018-12-03 15:21:49 +000017namespace clang {
18namespace clangd {
19
20namespace {
21/// Always opens files in the underlying filesystem as "volatile", meaning they
22/// won't be memory-mapped. This avoid locking the files on Windows.
23class VolatileFileSystem : public llvm::vfs::ProxyFileSystem {
24public:
25 explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr<FileSystem> FS)
26 : ProxyFileSystem(std::move(FS)) {}
27
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000028 llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
29 openFileForRead(const llvm::Twine &InPath) override {
30 llvm::SmallString<128> Path;
Ilya Biryukov1712bc72018-12-03 15:21:49 +000031 InPath.toVector(Path);
32
33 auto File = getUnderlyingFS().openFileForRead(Path);
34 if (!File)
35 return File;
36 // Try to guess preamble files, they can be memory-mapped even on Windows as
37 // clangd has exclusive access to those.
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000038 llvm::StringRef FileName = llvm::sys::path::filename(Path);
Ilya Biryukov1712bc72018-12-03 15:21:49 +000039 if (FileName.startswith("preamble-") && FileName.endswith(".pch"))
40 return File;
Ilya Biryukov22fa4652019-01-03 13:28:05 +000041 return std::unique_ptr<VolatileFile>(new VolatileFile(std::move(*File)));
Ilya Biryukov1712bc72018-12-03 15:21:49 +000042 }
43
44private:
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000045 class VolatileFile : public llvm::vfs::File {
Ilya Biryukov1712bc72018-12-03 15:21:49 +000046 public:
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000047 VolatileFile(std::unique_ptr<llvm::vfs::File> Wrapped)
Ilya Biryukov1712bc72018-12-03 15:21:49 +000048 : Wrapped(std::move(Wrapped)) {
49 assert(this->Wrapped);
50 }
51
52 virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000053 getBuffer(const llvm::Twine &Name, int64_t FileSize,
54 bool RequiresNullTerminator, bool /*IsVolatile*/) override {
Ilya Biryukov1712bc72018-12-03 15:21:49 +000055 return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator,
56 /*IsVolatile=*/true);
57 }
58
Ilya Biryukovf2001aa2019-01-07 15:45:19 +000059 llvm::ErrorOr<llvm::vfs::Status> status() override {
60 return Wrapped->status();
61 }
Ilya Biryukov1712bc72018-12-03 15:21:49 +000062 llvm::ErrorOr<std::string> getName() override { return Wrapped->getName(); }
63 std::error_code close() override { return Wrapped->close(); }
64
65 private:
66 std::unique_ptr<File> Wrapped;
67 };
68};
69} // namespace
70
71llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
72clang::clangd::RealFileSystemProvider::getFileSystem() const {
73// Avoid using memory-mapped files on Windows, they cause file locking issues.
74// FIXME: Try to use a similar approach in Sema instead of relying on
75// propagation of the 'isVolatile' flag through all layers.
76#ifdef _WIN32
Sam McCall0446b402019-02-15 11:04:25 +000077 return new VolatileFileSystem(
78 llvm::vfs::createPhysicalFileSystem().release());
Ilya Biryukov1712bc72018-12-03 15:21:49 +000079#else
Sam McCall0446b402019-02-15 11:04:25 +000080 return llvm::vfs::createPhysicalFileSystem().release();
Ilya Biryukov1712bc72018-12-03 15:21:49 +000081#endif
82}
83} // namespace clangd
84} // namespace clang