#pragma once #include #include "Assert.h" #include "llvm/Support/Path.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/MemoryBuffer.h" namespace clice { namespace path { using namespace llvm::sys::path; template std::string join(Args&&... args) { llvm::SmallString<128> path; ((path::append(path, std::forward(args))), ...); return path.str().str(); } /// Get the real path of the given file. The file must exist. If the file does not exist, inline std::string real_path(llvm::StringRef file) { llvm::SmallString<128> path; auto error = llvm::sys::fs::real_path(file, path); ASSERT(!error, "Failed to get real path of {0}, because {1}", file, error.message()); return path.str().str(); } } // namespace path namespace fs { using namespace llvm::sys::fs; inline std::string resource_dir = ""; inline llvm::Error init_resource_dir(llvm::StringRef execute) { llvm::SmallString<128> path; path::append(path, path::parent_path(execute), ".."); path::append(path, "lib", "clang", "20"); if(auto error = real_path(path, path)) { return llvm::make_error(error.message(), error); } resource_dir = path.str(); return llvm::Error::success(); } } // namespace fs namespace vfs = llvm::vfs; class ThreadSafeFS : public vfs::ProxyFileSystem { public: explicit ThreadSafeFS() : ProxyFileSystem(vfs::createPhysicalFileSystem()) {} class VolatileFile : public vfs::File { public: VolatileFile(std::unique_ptr Wrapped) : wrapped(std::move(Wrapped)) { assert(this->wrapped); } llvm::ErrorOr> getBuffer(const llvm::Twine& Name, int64_t FileSize, bool RequiresNullTerminator, bool /*IsVolatile*/) override { return wrapped->getBuffer(Name, FileSize, RequiresNullTerminator, /*IsVolatile=*/true); } llvm::ErrorOr status() override { return wrapped->status(); } llvm::ErrorOr getName() override { return wrapped->getName(); } std::error_code close() override { return wrapped->close(); } private: std::unique_ptr wrapped; }; llvm::ErrorOr> openFileForRead(const llvm::Twine& InPath) override { llvm::SmallString<128> Path; InPath.toVector(Path); auto file = getUnderlyingFS().openFileForRead(Path); if(!file) return file; // Try to guess preamble files, they can be memory-mapped even on Windows as // clangd has exclusive access to those and nothing else should touch them. llvm::StringRef filename = path::filename(Path); if(filename.starts_with("preamble-") && filename.ends_with(".pch")) { return file; } return std::make_unique(std::move(*file)); } }; } // namespace clice