From 9011903e3613af360c3a1d05c106e464538efd08 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 20 Jan 2022 15:07:39 +0100 Subject: [PATCH] [llvm][vfs] Abstract in-memory node creation The creation of in-memory VFS nodes happens in a single function that deduces what kind of node to create from the arguments. This leads to complicated if-then-else logic that's difficult to cleanly extend. This patch abstracts away in-memory node creation via a type-erased factory function that's passed instead. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D117648 --- llvm/include/llvm/Support/VirtualFileSystem.h | 24 +++++-- llvm/lib/Support/VirtualFileSystem.cpp | 65 +++++++++++-------- 2 files changed, 58 insertions(+), 31 deletions(-) diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index 9b5ff8f20ae2..305096dff67e 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -419,6 +419,21 @@ namespace detail { class InMemoryDirectory; class InMemoryFile; +class InMemoryNode; + +struct NewInMemoryNodeInfo { + llvm::sys::fs::UniqueID DirUID; + StringRef Path; + StringRef Name; + time_t ModificationTime; + std::unique_ptr Buffer; + uint32_t User; + uint32_t Group; + llvm::sys::fs::file_type Type; + llvm::sys::fs::perms Perms; + + Status makeStatus() const; +}; } // namespace detail @@ -428,14 +443,15 @@ class InMemoryFileSystem : public FileSystem { std::string WorkingDirectory; bool UseNormalizedPaths = true; - /// If HardLinkTarget is non-null, a hardlink is created to the To path which - /// must be a file. If it is null then it adds the file as the public addFile. + using MakeNodeFn = llvm::function_ref( + detail::NewInMemoryNodeInfo)>; + + /// Create node with \p MakeNode and add it into this filesystem at \p Path. bool addFile(const Twine &Path, time_t ModificationTime, std::unique_ptr Buffer, Optional User, Optional Group, Optional Type, - Optional Perms, - const detail::InMemoryFile *HardLinkTarget); + Optional Perms, MakeNodeFn MakeNode); public: explicit InMemoryFileSystem(bool UseNormalizedPaths = true); diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 1536f4de2e26..a963beb180ba 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -729,6 +729,16 @@ static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, return getUniqueID(llvm::hash_combine(Parent.getFile(), Name)); } +Status detail::NewInMemoryNodeInfo::makeStatus() const { + UniqueID UID = + (Type == sys::fs::file_type::directory_file) + ? getDirectoryID(DirUID, Name) + : getFileID(DirUID, Name, Buffer ? Buffer->getBuffer() : ""); + + return Status(Path, UID, llvm::sys::toTimePoint(ModificationTime), User, + Group, Buffer ? Buffer->getBufferSize() : 0, Type, Perms); +} + InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) : Root(new detail::InMemoryDirectory( Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""), @@ -749,7 +759,7 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, Optional Group, Optional Type, Optional Perms, - const detail::InMemoryFile *HardLinkTarget) { + MakeNodeFn MakeNode) { SmallString<128> Path; P.toVector(Path); @@ -770,7 +780,6 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, const auto ResolvedGroup = Group.getValueOr(0); const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file); const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all); - assert(!(HardLinkTarget && Buffer) && "HardLink cannot have a buffer"); // Any intermediate directories we create should be accessible by // the owner, even if Perms says otherwise for the final path. const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all; @@ -781,27 +790,10 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, if (!Node) { if (I == E) { // End of the path. - std::unique_ptr Child; - if (HardLinkTarget) - Child.reset(new detail::InMemoryHardLink(P.str(), *HardLinkTarget)); - else { - // Create a new file or directory. - Status Stat( - P.str(), - (ResolvedType == sys::fs::file_type::directory_file) - ? getDirectoryID(Dir->getUniqueID(), Name) - : getFileID(Dir->getUniqueID(), Name, Buffer->getBuffer()), - llvm::sys::toTimePoint(ModificationTime), ResolvedUser, - ResolvedGroup, Buffer->getBufferSize(), ResolvedType, - ResolvedPerms); - if (ResolvedType == sys::fs::file_type::directory_file) { - Child.reset(new detail::InMemoryDirectory(std::move(Stat))); - } else { - Child.reset( - new detail::InMemoryFile(std::move(Stat), std::move(Buffer))); - } - } - Dir->addChild(Name, std::move(Child)); + Dir->addChild( + Name, MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime, + std::move(Buffer), ResolvedUser, ResolvedGroup, + ResolvedType, ResolvedPerms})); return true; } @@ -845,7 +837,15 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, Optional Type, Optional Perms) { return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type, - Perms, /*HardLinkTarget=*/nullptr); + Perms, + [](detail::NewInMemoryNodeInfo NNI) + -> std::unique_ptr { + Status Stat = NNI.makeStatus(); + if (Stat.getType() == sys::fs::file_type::directory_file) + return std::make_unique(Stat); + return std::make_unique( + Stat, std::move(NNI.Buffer)); + }); } bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime, @@ -856,7 +856,15 @@ bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime, Optional Perms) { return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer), std::move(User), std::move(Group), std::move(Type), - std::move(Perms)); + std::move(Perms), + [](detail::NewInMemoryNodeInfo NNI) + -> std::unique_ptr { + Status Stat = NNI.makeStatus(); + if (Stat.getType() == sys::fs::file_type::directory_file) + return std::make_unique(Stat); + return std::make_unique( + Stat, std::move(NNI.Buffer)); + }); } static ErrorOr @@ -911,8 +919,11 @@ bool InMemoryFileSystem::addHardLink(const Twine &FromPath, // before. Resolved ToPath must be a File. if (!ToNode || FromNode || !isa(*ToNode)) return false; - return this->addFile(FromPath, 0, nullptr, None, None, None, None, - cast(*ToNode)); + return addFile(FromPath, 0, nullptr, None, None, None, None, + [&](detail::NewInMemoryNodeInfo NNI) { + return std::make_unique( + NNI.Path.str(), *cast(*ToNode)); + }); } llvm::ErrorOr InMemoryFileSystem::status(const Twine &Path) {