[llvm] 4125524 - [VFS] Add print/dump to the whole FileSystem hierarchy

Ben Barham via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 17 13:03:13 PDT 2022


Author: Ben Barham
Date: 2022-03-17T13:02:40-07:00
New Revision: 4125524112e00c61547e83804279ef7889c8636a

URL: https://github.com/llvm/llvm-project/commit/4125524112e00c61547e83804279ef7889c8636a
DIFF: https://github.com/llvm/llvm-project/commit/4125524112e00c61547e83804279ef7889c8636a.diff

LOG: [VFS] Add print/dump to the whole FileSystem hierarchy

For now most are implemented by printing out the name of the filesystem,
but this can be expanded in the future. Only `OverlayFileSystem` and
`RedirectingFileSystem` are properly implemented in this patch.
  - `OverlayFileSystem`: Prints each filesystem in the order that any
    operations are actually run on them. Optionally prints recursively.
  - `RedirectingFileSystem`: Prints out all mappings, as well as the
    `ExternalFS`. Most of this was already implemented other than the
    handling for the `DirectoryRemap` case and to actually print out the
    mapping.

Each FS should implement `printImpl` rather than `print`, where the
latter just fowards to the former. This is to avoid spreading the
default arguments through to the subclasses (where we may miss updating
in the future).

Differential Revision: https://reviews.llvm.org/D121421

Added: 
    

Modified: 
    llvm/include/llvm/Support/VirtualFileSystem.h
    llvm/lib/Support/VirtualFileSystem.cpp
    llvm/unittests/Support/VirtualFileSystemTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h
index 64b4d4dcd35af..7e93a2146286d 100644
--- a/llvm/include/llvm/Support/VirtualFileSystem.h
+++ b/llvm/include/llvm/Support/VirtualFileSystem.h
@@ -306,6 +306,28 @@ class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> {
   /// \returns success if \a path has been made absolute, otherwise a
   ///          platform-specific error_code.
   virtual std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
+
+  enum class PrintType { Summary, Contents, RecursiveContents };
+  void print(raw_ostream &OS, PrintType Type = PrintType::Contents,
+             unsigned IndentLevel = 0) const {
+    printImpl(OS, Type, IndentLevel);
+  }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  LLVM_DUMP_METHOD void dump() const;
+#endif
+
+protected:
+  virtual void printImpl(raw_ostream &OS, PrintType Type,
+                         unsigned IndentLevel) const {
+    printIndent(OS, IndentLevel);
+    OS << "FileSystem\n";
+  }
+
+  void printIndent(raw_ostream &OS, unsigned IndentLevel) const {
+    for (unsigned i = 0; i < IndentLevel; ++i)
+      OS << "  ";
+  }
 };
 
 /// Gets an \p vfs::FileSystem for the 'real' file system, as seen by
@@ -357,6 +379,8 @@ class OverlayFileSystem : public FileSystem {
   using const_iterator = FileSystemList::const_reverse_iterator;
   using reverse_iterator = FileSystemList::iterator;
   using const_reverse_iterator = FileSystemList::const_iterator;
+  using range = iterator_range<iterator>;
+  using const_range = iterator_range<const_iterator>;
 
   /// Get an iterator pointing to the most recently added file system.
   iterator overlays_begin() { return FSList.rbegin(); }
@@ -373,6 +397,13 @@ class OverlayFileSystem : public FileSystem {
   /// Get an iterator pointing one-past the most recently added file system.
   reverse_iterator overlays_rend() { return FSList.end(); }
   const_reverse_iterator overlays_rend() const { return FSList.end(); }
+
+  range overlays_range() { return llvm::reverse(FSList); }
+  const_range overlays_range() const { return llvm::reverse(FSList); }
+
+protected:
+  void printImpl(raw_ostream &OS, PrintType Type,
+                 unsigned IndentLevel) const override;
 };
 
 /// By default, this delegates all calls to the underlying file system. This
@@ -520,6 +551,10 @@ class InMemoryFileSystem : public FileSystem {
                               SmallVectorImpl<char> &Output) const override;
   std::error_code isLocal(const Twine &Path, bool &Result) override;
   std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
+
+protected:
+  void printImpl(raw_ostream &OS, PrintType Type,
+                 unsigned IndentLevel) const override;
 };
 
 /// Get a globally unique ID for a virtual file or directory.
@@ -910,12 +945,11 @@ class RedirectingFileSystem : public vfs::FileSystem {
 
   std::vector<llvm::StringRef> getRoots() const;
 
-  void print(raw_ostream &OS) const;
-  void printEntry(raw_ostream &OS, Entry *E, int NumSpaces = 0) const;
+  void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel = 0) const;
 
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-  LLVM_DUMP_METHOD void dump() const;
-#endif
+protected:
+  void printImpl(raw_ostream &OS, PrintType Type,
+                 unsigned IndentLevel) const override;
 };
 
 /// Collect all pairs of <virtual path, real path> entries from the

diff  --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 1ca18e4b82cb9..cb34fa60d8018 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -151,6 +151,10 @@ bool FileSystem::exists(const Twine &Path) {
   return Status && Status->exists();
 }
 
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void FileSystem::dump() const { print(dbgs(), PrintType::RecursiveContents); }
+#endif
+
 #ifndef NDEBUG
 static bool isTraversalComponent(StringRef Component) {
   return Component.equals("..") || Component.equals(".");
@@ -273,6 +277,10 @@ class RealFileSystem : public FileSystem {
   std::error_code getRealPath(const Twine &Path,
                               SmallVectorImpl<char> &Output) const override;
 
+protected:
+  void printImpl(raw_ostream &OS, PrintType Type,
+                 unsigned IndentLevel) const override;
+
 private:
   // If this FS has its own working dir, use it to make Path absolute.
   // The returned twine is safe to use as long as both Storage and Path live.
@@ -354,6 +362,17 @@ RealFileSystem::getRealPath(const Twine &Path,
   return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
 }
 
+void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+                               unsigned IndentLevel) const {
+  printIndent(OS, IndentLevel);
+  OS << "RealFileSystem using ";
+  if (WD)
+    OS << "own";
+  else
+    OS << "process";
+  OS << " CWD\n";
+}
+
 IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
   static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
   return FS;
@@ -459,6 +478,19 @@ OverlayFileSystem::getRealPath(const Twine &Path,
   return errc::no_such_file_or_directory;
 }
 
+void OverlayFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+                                  unsigned IndentLevel) const {
+  printIndent(OS, IndentLevel);
+  OS << "OverlayFileSystem\n";
+  if (Type == PrintType::Summary)
+    return;
+
+  if (Type == PrintType::Contents)
+    Type = PrintType::Summary;
+  for (auto FS : overlays_range())
+    FS->print(OS, Type, IndentLevel + 1);
+}
+
 llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
 
 namespace {
@@ -1047,6 +1079,12 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
   return {};
 }
 
+void InMemoryFileSystem::printImpl(raw_ostream &OS, PrintType PrintContents,
+                                   unsigned IndentLevel) const {
+  printIndent(OS, IndentLevel);
+  OS << "InMemoryFileSystem\n";
+}
+
 } // namespace vfs
 } // namespace llvm
 
@@ -1381,34 +1419,59 @@ std::vector<StringRef> RedirectingFileSystem::getRoots() const {
   return R;
 }
 
-void RedirectingFileSystem::print(raw_ostream &OS) const {
+void RedirectingFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+                                      unsigned IndentLevel) const {
+  printIndent(OS, IndentLevel);
+  OS << "RedirectingFileSystem (UseExternalNames: "
+     << (UseExternalNames ? "true" : "false") << ")\n";
+  if (Type == PrintType::Summary)
+    return;
+
   for (const auto &Root : Roots)
-    printEntry(OS, Root.get());
+    printEntry(OS, Root.get(), IndentLevel);
+
+  printIndent(OS, IndentLevel);
+  OS << "ExternalFS:\n";
+  ExternalFS->print(OS, Type == PrintType::Contents ? PrintType::Summary : Type,
+                    IndentLevel + 1);
 }
 
 void RedirectingFileSystem::printEntry(raw_ostream &OS,
                                        RedirectingFileSystem::Entry *E,
-                                       int NumSpaces) const {
-  StringRef Name = E->getName();
-  for (int i = 0, e = NumSpaces; i < e; ++i)
-    OS << " ";
-  OS << "'" << Name.str().c_str() << "'"
-     << "\n";
+                                       unsigned IndentLevel) const {
+  printIndent(OS, IndentLevel);
+  OS << "'" << E->getName() << "'";
 
-  if (E->getKind() == RedirectingFileSystem::EK_Directory) {
-    auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(E);
-    assert(DE && "Should be a directory");
+  switch (E->getKind()) {
+  case EK_Directory: {
+    auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
 
+    OS << "\n";
     for (std::unique_ptr<Entry> &SubEntry :
          llvm::make_range(DE->contents_begin(), DE->contents_end()))
-      printEntry(OS, SubEntry.get(), NumSpaces + 2);
+      printEntry(OS, SubEntry.get(), IndentLevel + 1);
+    break;
+  }
+  case EK_DirectoryRemap:
+  case EK_File: {
+    auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
+    OS << " -> '" << RE->getExternalContentsPath() << "'";
+    switch (RE->getUseName()) {
+    case NK_NotSet:
+      break;
+    case NK_External:
+      OS << " (UseExternalName: true)";
+      break;
+    case NK_Virtual:
+      OS << " (UseExternalName: false)";
+      break;
+    }
+    OS << "\n";
+    break;
+  }
   }
 }
 
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-void RedirectingFileSystem::dump() const { print(dbgs()); }
-#endif
-
 /// A helper class to hold the common YAML parsing state.
 class llvm::vfs::RedirectingFileSystemParser {
   yaml::Stream &Stream;

diff  --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index 657fc0afb7fc4..1eb7fe6b27611 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -171,6 +171,25 @@ class DummyFileSystem : public vfs::FileSystem {
                   sys::fs::file_type::symlink_file, sys::fs::all_all);
     addEntry(Path, S);
   }
+
+protected:
+  void printImpl(raw_ostream &OS, PrintType Type,
+                 unsigned IndentLevel) const override {
+    printIndent(OS, IndentLevel);
+    OS << "DummyFileSystem (";
+    switch (Type) {
+    case vfs::FileSystem::PrintType::Summary:
+      OS << "Summary";
+      break;
+    case vfs::FileSystem::PrintType::Contents:
+      OS << "Contents";
+      break;
+    case vfs::FileSystem::PrintType::RecursiveContents:
+      OS << "RecursiveContents";
+      break;
+    }
+    OS << ")\n";
+  }
 };
 
 class ErrorDummyFileSystem : public DummyFileSystem {
@@ -848,6 +867,36 @@ TEST(VirtualFileSystemTest, HiddenInIteration) {
   }
 }
 
+TEST(OverlayFileSystemTest, PrintOutput) {
+  auto Dummy = makeIntrusiveRefCnt<DummyFileSystem>();
+  auto Overlay1 = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(Dummy);
+  Overlay1->pushOverlay(Dummy);
+  auto Overlay2 = makeIntrusiveRefCnt<vfs::OverlayFileSystem>(Overlay1);
+  Overlay2->pushOverlay(Dummy);
+
+  SmallString<0> Output;
+  raw_svector_ostream OuputStream{Output};
+
+  Overlay2->print(OuputStream, vfs::FileSystem::PrintType::Summary);
+  ASSERT_EQ("OverlayFileSystem\n", Output);
+
+  Output.clear();
+  Overlay2->print(OuputStream, vfs::FileSystem::PrintType::Contents);
+  ASSERT_EQ("OverlayFileSystem\n"
+            "  DummyFileSystem (Summary)\n"
+            "  OverlayFileSystem\n",
+            Output);
+
+  Output.clear();
+  Overlay2->print(OuputStream, vfs::FileSystem::PrintType::RecursiveContents);
+  ASSERT_EQ("OverlayFileSystem\n"
+            "  DummyFileSystem (RecursiveContents)\n"
+            "  OverlayFileSystem\n"
+            "    DummyFileSystem (RecursiveContents)\n"
+            "    DummyFileSystem (RecursiveContents)\n",
+            Output);
+}
+
 TEST(ProxyFileSystemTest, Basic) {
   IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
       new vfs::InMemoryFileSystem());
@@ -2928,3 +2977,80 @@ TEST(VFSFromRemappedFilesTest, LastMappingWins) {
   EXPECT_EQ("contents of c", (*BufferKeepA)->getBuffer());
   EXPECT_EQ("contents of c", (*BufferExternalA)->getBuffer());
 }
+
+TEST(RedirectingFileSystemTest, PrintOutput) {
+  auto Buffer =
+      MemoryBuffer::getMemBuffer("{\n"
+                                 "  'version': 0,\n"
+                                 "  'roots': [\n"
+                                 "    {\n"
+                                 "      'type': 'directory-remap',\n"
+                                 "      'name': '/dremap',\n"
+                                 "      'external-contents': '/a',\n"
+                                 "    },"
+                                 "    {\n"
+                                 "      'type': 'directory',\n"
+                                 "      'name': '/vdir',\n"
+                                 "      'contents': ["
+                                 "        {\n"
+                                 "          'type': 'directory-remap',\n"
+                                 "          'name': 'dremap',\n"
+                                 "          'external-contents': '/b'\n"
+                                 "          'use-external-name': 'true'\n"
+                                 "        },\n"
+                                 "        {\n"
+                                 "          'type': 'file',\n"
+                                 "          'name': 'vfile',\n"
+                                 "          'external-contents': '/c'\n"
+                                 "          'use-external-name': 'false'\n"
+                                 "        }]\n"
+                                 "    }]\n"
+                                 "}");
+
+  auto Dummy = makeIntrusiveRefCnt<DummyFileSystem>();
+  auto Redirecting = vfs::RedirectingFileSystem::create(
+      std::move(Buffer), nullptr, "", nullptr, Dummy);
+
+  SmallString<0> Output;
+  raw_svector_ostream OuputStream{Output};
+
+  Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Summary);
+  ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n", Output);
+
+  Output.clear();
+  Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Contents);
+  ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n"
+            "'/'\n"
+            "  'dremap' -> '/a'\n"
+            "  'vdir'\n"
+            "    'dremap' -> '/b' (UseExternalName: true)\n"
+            "    'vfile' -> '/c' (UseExternalName: false)\n"
+            "ExternalFS:\n"
+            "  DummyFileSystem (Summary)\n",
+            Output);
+
+  Output.clear();
+  Redirecting->print(OuputStream, vfs::FileSystem::PrintType::Contents, 1);
+  ASSERT_EQ("  RedirectingFileSystem (UseExternalNames: true)\n"
+            "  '/'\n"
+            "    'dremap' -> '/a'\n"
+            "    'vdir'\n"
+            "      'dremap' -> '/b' (UseExternalName: true)\n"
+            "      'vfile' -> '/c' (UseExternalName: false)\n"
+            "  ExternalFS:\n"
+            "    DummyFileSystem (Summary)\n",
+            Output);
+
+  Output.clear();
+  Redirecting->print(OuputStream,
+                     vfs::FileSystem::PrintType::RecursiveContents);
+  ASSERT_EQ("RedirectingFileSystem (UseExternalNames: true)\n"
+            "'/'\n"
+            "  'dremap' -> '/a'\n"
+            "  'vdir'\n"
+            "    'dremap' -> '/b' (UseExternalName: true)\n"
+            "    'vfile' -> '/c' (UseExternalName: false)\n"
+            "ExternalFS:\n"
+            "  DummyFileSystem (RecursiveContents)\n",
+            Output);
+}


        


More information about the llvm-commits mailing list