#include "support/ThreadsafeFS.h"
#include "Logger.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <memory>
namespace clang {
namespace clangd {
namespace {
class VolatileFileSystem : public llvm::vfs::ProxyFileSystem {
public:
explicit VolatileFileSystem(llvm::IntrusiveRefCntPtr<FileSystem> FS)
: ProxyFileSystem(std::move(FS)) {}
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
openFileForRead(const llvm::Twine &InPath) override {
llvm::SmallString<128> Path;
InPath.toVector(Path);
auto File = getUnderlyingFS().openFileForRead(Path);
if (!File)
return File;
llvm::StringRef FileName = llvm::sys::path::filename(Path);
if (FileName.starts_with("preamble-") && FileName.ends_with(".pch"))
return File;
return std::make_unique<VolatileFile>(std::move(*File));
}
private:
class VolatileFile : public llvm::vfs::File {
public:
VolatileFile(std::unique_ptr<llvm::vfs::File> Wrapped)
: Wrapped(std::move(Wrapped)) {
assert(this->Wrapped);
}
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBuffer(const llvm::Twine &Name, int64_t FileSize,
bool RequiresNullTerminator, bool ) override {
return Wrapped->getBuffer(Name, FileSize, RequiresNullTerminator,
true);
}
llvm::ErrorOr<llvm::vfs::Status> status() override {
return Wrapped->status();
}
llvm::ErrorOr<std::string> getName() override { return Wrapped->getName(); }
std::error_code close() override { return Wrapped->close(); }
private:
std::unique_ptr<File> Wrapped;
};
};
}
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
ThreadsafeFS::view(PathRef CWD) const {
auto FS = view(std::nullopt);
if (auto EC = FS->setCurrentWorkingDirectory(CWD))
elog("VFS: failed to set CWD to {0}: {1}", CWD, EC.message());
return FS;
}
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
RealThreadsafeFS::viewImpl() const {
return new VolatileFileSystem(llvm::vfs::createPhysicalFileSystem());
}
}
}