brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.6 KiB · 5729b93 Raw
124 lines · cpp
1//===--- FS.cpp - File system related utils ----------------------*- C++-*-===//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 "FS.h"10#include "clang/Basic/LLVM.h"11#include "llvm/Support/Path.h"12#include "llvm/Support/VirtualFileSystem.h"13#include <optional>14#include <utility>15 16namespace clang {17namespace clangd {18 19PreambleFileStatusCache::PreambleFileStatusCache(llvm::StringRef MainFilePath){20  assert(llvm::sys::path::is_absolute(MainFilePath));21  llvm::SmallString<256> MainFileCanonical(MainFilePath);22  llvm::sys::path::remove_dots(MainFileCanonical, /*remove_dot_dot=*/true);23  this->MainFilePath = std::string(MainFileCanonical);24}25 26void PreambleFileStatusCache::update(const llvm::vfs::FileSystem &FS,27                                     llvm::vfs::Status S,28                                     llvm::StringRef File) {29  // Canonicalize path for later lookup, which is usually by absolute path.30  llvm::SmallString<32> PathStore(File);31  if (FS.makeAbsolute(PathStore))32    return;33  llvm::sys::path::remove_dots(PathStore, /*remove_dot_dot=*/true);34  // Do not cache status for the main file.35  if (PathStore == MainFilePath)36    return;37  // Stores the latest status in cache as it can change in a preamble build.38  StatCache.insert({PathStore, std::move(S)});39}40 41std::optional<llvm::vfs::Status>42PreambleFileStatusCache::lookup(llvm::StringRef File) const {43  // Canonicalize to match the cached form.44  // Lookup tends to be first by absolute path, so no need to make absolute.45  llvm::SmallString<256> PathLookup(File);46  llvm::sys::path::remove_dots(PathLookup, /*remove_dot_dot=*/true);47 48  auto I = StatCache.find(PathLookup);49  if (I != StatCache.end())50    // Returned Status name should always match the requested File.51    return llvm::vfs::Status::copyWithNewName(I->getValue(), File);52  return std::nullopt;53}54 55llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>56PreambleFileStatusCache::getProducingFS(57    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {58  // This invalidates old status in cache if files are re-`open()`ed or59  // re-`stat()`ed in case file status has changed during preamble build.60  class CollectFS : public llvm::vfs::ProxyFileSystem {61  public:62    CollectFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,63              PreambleFileStatusCache &StatCache)64        : ProxyFileSystem(std::move(FS)), StatCache(StatCache) {}65 66    llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>67    openFileForRead(const llvm::Twine &Path) override {68      auto File = getUnderlyingFS().openFileForRead(Path);69      if (!File || !*File)70        return File;71      // Eagerly stat opened file, as the followup `status` call on the file72      // doesn't necessarily go through this FS. This puts some extra work on73      // preamble build, but it should be worth it as preamble can be reused74      // many times (e.g. code completion) and the repeated status call is75      // likely to be cached in the underlying file system anyway.76      if (auto S = File->get()->status())77        StatCache.update(getUnderlyingFS(), std::move(*S), Path.str());78      return File;79    }80 81    llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine &Path) override {82      auto S = getUnderlyingFS().status(Path);83      if (S)84        StatCache.update(getUnderlyingFS(), *S, Path.str());85      return S;86    }87 88  private:89    PreambleFileStatusCache &StatCache;90  };91  return llvm::IntrusiveRefCntPtr<CollectFS>(92      new CollectFS(std::move(FS), *this));93}94 95llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>96PreambleFileStatusCache::getConsumingFS(97    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) const {98  class CacheVFS : public llvm::vfs::ProxyFileSystem {99  public:100    CacheVFS(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,101             const PreambleFileStatusCache &StatCache)102        : ProxyFileSystem(std::move(FS)), StatCache(StatCache) {}103 104    llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine &Path) override {105      if (auto S = StatCache.lookup(Path.str()))106        return *S;107      return getUnderlyingFS().status(Path);108    }109 110  private:111    const PreambleFileStatusCache &StatCache;112  };113  return llvm::IntrusiveRefCntPtr<CacheVFS>(new CacheVFS(std::move(FS), *this));114}115 116Path removeDots(PathRef File) {117  llvm::SmallString<128> CanonPath(File);118  llvm::sys::path::remove_dots(CanonPath, /*remove_dot_dot=*/true);119  return CanonPath.str().str();120}121 122} // namespace clangd123} // namespace clang124