brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.2 KiB · 7398e42 Raw
91 lines · cpp
1//===--- ThreadsafeFS.cpp -------------------------------------------------===//2//3// 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-exception6//7//===----------------------------------------------------------------------===//8 9#include "support/ThreadsafeFS.h"10#include "Logger.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 17namespace clang {18namespace clangd {19 20namespace {21/// Always opens files in the underlying filesystem as "volatile", meaning they22/// won't be memory-mapped. Memory-mapping isn't desirable for clangd:23///   - edits to the underlying files change contents MemoryBuffers owned by24//      SourceManager, breaking its invariants and leading to crashes25///   - it locks files on windows, preventing edits26class VolatileFileSystem : public llvm::vfs::ProxyFileSystem {27public:28  explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr<FileSystem> FS)29      : ProxyFileSystem(std::move(FS)) {}30 31  llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>32  openFileForRead(const llvm::Twine &InPath) override {33    llvm::SmallString<128> Path;34    InPath.toVector(Path);35 36    auto File = getUnderlyingFS().openFileForRead(Path);37    if (!File)38      return File;39    // Try to guess preamble files, they can be memory-mapped even on Windows as40    // clangd has exclusive access to those and nothing else should touch them.41    llvm::StringRef FileName = llvm::sys::path::filename(Path);42    if (FileName.starts_with("preamble-") && FileName.ends_with(".pch"))43      return File;44    return std::make_unique<VolatileFile>(std::move(*File));45  }46 47private:48  class VolatileFile : public llvm::vfs::File {49  public:50    VolatileFile(std::unique_ptr<llvm::vfs::File> Wrapped)51        : Wrapped(std::move(Wrapped)) {52      assert(this->Wrapped);53    }54 55    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>56    getBuffer(const llvm::Twine &Name, int64_t FileSize,57              bool RequiresNullTerminator, bool /*IsVolatile*/) override {58      return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator,59                                /*IsVolatile=*/true);60    }61 62    llvm::ErrorOr<llvm::vfs::Status> status() override {63      return Wrapped->status();64    }65    llvm::ErrorOr<std::string> getName() override { return Wrapped->getName(); }66    std::error_code close() override { return Wrapped->close(); }67 68  private:69    std::unique_ptr<File> Wrapped;70  };71};72} // namespace73 74llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>75ThreadsafeFS::view(PathRef CWD) const {76  auto FS = view(std::nullopt);77  if (auto EC = FS->setCurrentWorkingDirectory(CWD))78    elog("VFS: failed to set CWD to {0}: {1}", CWD, EC.message());79  return FS;80}81 82llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>83RealThreadsafeFS::viewImpl() const {84  // Avoid using memory-mapped files.85  // FIXME: Try to use a similar approach in Sema instead of relying on86  //        propagation of the 'isVolatile' flag through all layers.87  return new VolatileFileSystem(llvm::vfs::createPhysicalFileSystem());88}89} // namespace clangd90} // namespace clang91