Re: [PATCH] D13430: [VFS] Add an in-memory file system implementation.

2015-10-05 Thread Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL249316: [VFS] Add working directories to every virtual file 
system. (authored by d0k).

Changed prior to commit:
  http://reviews.llvm.org/D13430?vs=36509&id=36515#toc

Repository:
  rL LLVM

http://reviews.llvm.org/D13430

Files:
  cfe/trunk/include/clang/Basic/VirtualFileSystem.h
  cfe/trunk/lib/Basic/VirtualFileSystem.cpp
  cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp

Index: cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp
===
--- cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp
+++ cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp
@@ -43,6 +43,12 @@
   openFileForRead(const Twine &Path) override {
 llvm_unreachable("unimplemented");
   }
+  llvm::ErrorOr getCurrentWorkingDirectory() const override {
+return std::string();
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+return std::error_code();
+  }
 
   struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
 std::map &FilesAndDirs;
Index: cfe/trunk/include/clang/Basic/VirtualFileSystem.h
===
--- cfe/trunk/include/clang/Basic/VirtualFileSystem.h
+++ cfe/trunk/include/clang/Basic/VirtualFileSystem.h
@@ -199,6 +199,25 @@
   /// \note The 'end' iterator is directory_iterator().
   virtual directory_iterator dir_begin(const Twine &Dir,
std::error_code &EC) = 0;
+
+  /// Set the working directory. This will affect all following operations on
+  /// this file system and may propagate down for nested file systems.
+  virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0;
+  /// Get the working directory of this file system.
+  virtual llvm::ErrorOr getCurrentWorkingDirectory() const = 0;
+
+  /// Make \a Path an absolute path.
+  ///
+  /// Makes \a Path absolute using the current directory if it is not already.
+  /// An empty \a Path will result in the current directory.
+  ///
+  /// /absolute/path   => /absolute/path
+  /// relative/../path => /relative/../path
+  ///
+  /// \param Path A path that is modified to be an absolute path.
+  /// \returns success if \a path has been made absolute, otherwise a
+  ///  platform-specific error_code.
+  std::error_code makeAbsolute(SmallVectorImpl &Path) const;
 };
 
 /// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by
@@ -230,6 +249,8 @@
   llvm::ErrorOr>
   openFileForRead(const Twine &Path) override;
   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+  llvm::ErrorOr getCurrentWorkingDirectory() const override;
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
 
   typedef FileSystemList::reverse_iterator iterator;
   
@@ -248,6 +269,7 @@
 /// An in-memory file system.
 class InMemoryFileSystem : public FileSystem {
   std::unique_ptr Root;
+  std::string WorkingDirectory;
 
 public:
   InMemoryFileSystem();
@@ -260,6 +282,13 @@
   llvm::ErrorOr>
   openFileForRead(const Twine &Path) override;
   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+  llvm::ErrorOr getCurrentWorkingDirectory() const override {
+return WorkingDirectory;
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+WorkingDirectory = Path.str();
+return std::error_code();
+  }
 };
 
 /// \brief Get a globally unique ID for a virtual file or directory.
Index: cfe/trunk/lib/Basic/VirtualFileSystem.cpp
===
--- cfe/trunk/lib/Basic/VirtualFileSystem.cpp
+++ cfe/trunk/lib/Basic/VirtualFileSystem.cpp
@@ -89,6 +89,14 @@
   return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
 }
 
+std::error_code FileSystem::makeAbsolute(SmallVectorImpl &Path) const {
+  auto WorkingDir = getCurrentWorkingDirectory();
+  if (!WorkingDir)
+return WorkingDir.getError();
+
+  return llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
+}
+
 //===---===/
 // RealFileSystem implementation
 //===---===/
@@ -160,6 +168,9 @@
   ErrorOr status(const Twine &Path) override;
   ErrorOr> openFileForRead(const Twine &Path) override;
   directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+
+  llvm::ErrorOr getCurrentWorkingDirectory() const override;
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
 };
 } // end anonymous namespace
 
@@ -178,6 +189,28 @@
   return std::unique_ptr(new RealFile(FD, Name.str()));
 }
 
+llvm::ErrorOr RealFileSystem::getCurrentWorkingDirectory() const {
+  SmallString<256> Dir;
+  if (std::error_code EC = llvm::sys::fs::current_path(Dir))
+return EC;
+  return Dir.str().st

Re: [PATCH] D13430: [VFS] Add an in-memory file system implementation.

2015-10-05 Thread Manuel Klimek via cfe-commits
klimek accepted this revision.
klimek added a comment.
This revision is now accepted and ready to land.

lg



Comment at: lib/Basic/VirtualFileSystem.cpp:1263-1265
@@ -957,5 +1262,5 @@
 
   if (!F->useExternalName(UseExternalNames)) {
 // Provide a file wrapper that returns the external name when asked.
 class NamedFileAdaptor : public File {
   std::unique_ptr InnerFile;

Optional: I'd put this into an anonymous namespace. But I'm also fine with 
waiting how others think about this :)


http://reviews.llvm.org/D13430



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D13430: [VFS] Add an in-memory file system implementation.

2015-10-05 Thread Benjamin Kramer via cfe-commits
bkramer marked 10 inline comments as done.


Comment at: include/clang/Basic/VirtualFileSystem.h:286-288
@@ +285,5 @@
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+WorkingDirectory = Path.str();
+return std::error_code();
+  }

klimek wrote:
> Return errc::success?
There is no errc::success, the preferred way is to just use error_code(). Fixed 
the comment.


Comment at: lib/Basic/VirtualFileSystem.cpp:80
@@ -79,1 +79,3 @@
 
+// FIXME: This is copypasted from LLVM's file system implementation.
+std::error_code FileSystem::make_absolute(SmallVectorImpl &path) const {

klimek wrote:
> What's the proposed fix? :)
Moving it to LLVM. That's done now :)


Comment at: lib/Basic/VirtualFileSystem.cpp:312-316
@@ -229,4 +311,7 @@
 
 void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr FS) {
   FSList.push_back(FS);
+  // Synchronize added file systems by duplicating the working directory from
+  // the first one in the list.
+  FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
 }

klimek wrote:
> If I read this correctly, it gets and sets the pwd from FS for the first one? 
> That seems superfluous.
> (perhaps change the constructor to not use pushOverlay)
Good catch!


Comment at: lib/Basic/VirtualFileSystem.cpp:476
@@ +475,3 @@
+  std::error_code close() override { return std::error_code(); }
+  void setName(StringRef Name) override { Parent.getStatus().setName(Name); }
+};

klimek wrote:
> Is this used in the File interface? It seems - strange... is this really a 
> "mv" implementation?
Gone it is.


Comment at: lib/Basic/VirtualFileSystem.cpp:546-550
@@ +545,7 @@
+// End of the path, create a new file.
+Status Stat(Path, "", getNextVirtualUniqueID(),
+llvm::sys::TimeValue(ModificationTime), 0, 0,
+Buffer->getBufferSize(),
+llvm::sys::fs::file_type::regular_file,
+llvm::sys::fs::all_all);
+Dir->addChild(Name, llvm::make_unique(

klimek wrote:
> I think we'll want to get some of these into the interface. But that's fine 
> in a follow-up patch. Add a FIXME though.
FIXME added.


Comment at: lib/Basic/VirtualFileSystem.cpp:800
@@ -455,1 +799,3 @@
 
+  std::string WorkingDirectory;
+

klimek wrote:
> Doesn't the YAML FS work on the same pwd as the current process?
Changed the methods to forward to the inner FS of the yaml overlay.


http://reviews.llvm.org/D13430



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D13430: [VFS] Add an in-memory file system implementation.

2015-10-05 Thread Benjamin Kramer via cfe-commits
bkramer updated this revision to Diff 36509.
bkramer added a comment.

Rebased and addressed review comments.


http://reviews.llvm.org/D13430

Files:
  include/clang/Basic/VirtualFileSystem.h
  lib/Basic/VirtualFileSystem.cpp
  unittests/Basic/VirtualFileSystemTest.cpp
  unittests/Tooling/RewriterTestContext.h

Index: unittests/Tooling/RewriterTestContext.h
===
--- unittests/Tooling/RewriterTestContext.h
+++ unittests/Tooling/RewriterTestContext.h
@@ -34,25 +34,30 @@
 /// methods, which help with writing tests that change files.
 class RewriterTestContext {
  public:
-  RewriterTestContext()
-  : DiagOpts(new DiagnosticOptions()),
-Diagnostics(IntrusiveRefCntPtr(new DiagnosticIDs),
-&*DiagOpts),
-DiagnosticPrinter(llvm::outs(), &*DiagOpts),
-Files((FileSystemOptions())),
-Sources(Diagnostics, Files),
-Rewrite(Sources, Options) {
+   RewriterTestContext()
+   : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(IntrusiveRefCntPtr(new DiagnosticIDs),
+ &*DiagOpts),
+ DiagnosticPrinter(llvm::outs(), &*DiagOpts),
+ InMemoryFileSystem(new vfs::InMemoryFileSystem),
+ OverlayFileSystem(
+ new vfs::OverlayFileSystem(vfs::getRealFileSystem())),
+ Files(FileSystemOptions(), OverlayFileSystem),
+ Sources(Diagnostics, Files), Rewrite(Sources, Options) {
 Diagnostics.setClient(&DiagnosticPrinter, false);
+// FIXME: To make these tests truly in-memory, we need to overlay the
+// builtin headers.
+OverlayFileSystem->pushOverlay(InMemoryFileSystem);
   }
 
   ~RewriterTestContext() {}
 
   FileID createInMemoryFile(StringRef Name, StringRef Content) {
 std::unique_ptr Source =
 llvm::MemoryBuffer::getMemBuffer(Content);
-const FileEntry *Entry =
-  Files.getVirtualFile(Name, Source->getBufferSize(), 0);
-Sources.overrideFileContents(Entry, std::move(Source));
+InMemoryFileSystem->addFile(Name, 0, std::move(Source));
+
+const FileEntry *Entry = Files.getFile(Name);
 assert(Entry != nullptr);
 return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
   }
@@ -109,6 +114,8 @@
   IntrusiveRefCntPtr DiagOpts;
   DiagnosticsEngine Diagnostics;
   TextDiagnosticPrinter DiagnosticPrinter;
+  IntrusiveRefCntPtr InMemoryFileSystem;
+  IntrusiveRefCntPtr OverlayFileSystem;
   FileManager Files;
   SourceManager Sources;
   LangOptions Options;
Index: unittests/Basic/VirtualFileSystemTest.cpp
===
--- unittests/Basic/VirtualFileSystemTest.cpp
+++ unittests/Basic/VirtualFileSystemTest.cpp
@@ -43,6 +43,12 @@
   openFileForRead(const Twine &Path) override {
 llvm_unreachable("unimplemented");
   }
+  llvm::ErrorOr getCurrentWorkingDirectory() const override {
+return std::string();
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+return std::error_code();
+  }
 
   struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
 std::map &FilesAndDirs;
@@ -515,6 +521,73 @@
   }
 }
 
+class InMemoryFileSystemTest : public ::testing::Test {
+protected:
+  clang::vfs::InMemoryFileSystem FS;
+};
+
+TEST_F(InMemoryFileSystemTest, IsEmpty) {
+  auto Stat = FS.status("/a");
+  ASSERT_EQ(errc::no_such_file_or_directory, Stat.getError()) << FS.toString();
+  Stat = FS.status("/");
+  ASSERT_EQ(errc::no_such_file_or_directory, Stat.getError()) << FS.toString();
+}
+
+TEST_F(InMemoryFileSystemTest, WindowsPath) {
+  FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
+  auto Stat = FS.status("c:");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  Stat = FS.status("c:/windows/system128/foo.cpp");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
+  Stat = FS.status("d:/windows/foo.cpp");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+}
+
+TEST_F(InMemoryFileSystemTest, OverlayFile) {
+  FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+  auto Stat = FS.status("/");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  Stat = FS.status("/a");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
+  ASSERT_EQ("/a", Stat->getName());
+}
+
+TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
+  FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+  auto File = FS.openFileForRead("/a");
+  ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
+  File = FS.openFileForRead("/a"); // Open again.
+  ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
+  File = FS.openFileForRead("/");
+  ASSERT_EQ(errc::invalid_argument, File.getError()) << FS.toString();
+  File = FS.openFileForRead("/b");
+  ASSERT_EQ(errc::no_such_file_or_directory, File.getE

Re: [PATCH] D13430: [VFS] Add an in-memory file system implementation.

2015-10-05 Thread Manuel Klimek via cfe-commits
klimek added inline comments.


Comment at: include/clang/Basic/VirtualFileSystem.h:286-288
@@ +285,5 @@
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+WorkingDirectory = Path.str();
+return std::error_code();
+  }

Return errc::success?


Comment at: lib/Basic/VirtualFileSystem.cpp:80
@@ -79,1 +79,3 @@
 
+// FIXME: This is copypasted from LLVM's file system implementation.
+std::error_code FileSystem::make_absolute(SmallVectorImpl &path) const {

What's the proposed fix? :)


Comment at: lib/Basic/VirtualFileSystem.cpp:312-316
@@ -229,4 +311,7 @@
 
 void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr FS) {
   FSList.push_back(FS);
+  // Synchronize added file systems by duplicating the working directory from
+  // the first one in the list.
+  FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
 }

If I read this correctly, it gets and sets the pwd from FS for the first one? 
That seems superfluous.
(perhaps change the constructor to not use pushOverlay)


Comment at: lib/Basic/VirtualFileSystem.cpp:437
@@ +436,3 @@
+  virtual ~InMemoryNode() {}
+  Status &getStatus() { return Stat; }
+  InMemoryNodeKind getKind() const { return Kind; }

Do we want to make this const?


Comment at: lib/Basic/VirtualFileSystem.cpp:439
@@ +438,3 @@
+  InMemoryNodeKind getKind() const { return Kind; }
+  virtual std::string toString(unsigned Indent) = 0;
+};

This probably wants to be const.


Comment at: lib/Basic/VirtualFileSystem.cpp:461
@@ +460,3 @@
+class InMemoryFileAdaptor : public File {
+  InMemoryFile &Parent;
+

I think parent is a misleading name here (parent implies a hierarchy, but this 
is a simple adapter). Perhaps "Node".


Comment at: lib/Basic/VirtualFileSystem.cpp:476
@@ +475,3 @@
+  std::error_code close() override { return std::error_code(); }
+  void setName(StringRef Name) override { Parent.getStatus().setName(Name); }
+};

Is this used in the File interface? It seems - strange... is this really a "mv" 
implementation?


Comment at: lib/Basic/VirtualFileSystem.cpp:546-550
@@ +545,7 @@
+// End of the path, create a new file.
+Status Stat(Path, "", getNextVirtualUniqueID(),
+llvm::sys::TimeValue(ModificationTime), 0, 0,
+Buffer->getBufferSize(),
+llvm::sys::fs::file_type::regular_file,
+llvm::sys::fs::all_all);
+Dir->addChild(Name, llvm::make_unique(

I think we'll want to get some of these into the interface. But that's fine in 
a follow-up patch. Add a FIXME though.


Comment at: lib/Basic/VirtualFileSystem.cpp:800
@@ -455,1 +799,3 @@
 
+  std::string WorkingDirectory;
+

Doesn't the YAML FS work on the same pwd as the current process?


Comment at: unittests/Tooling/RewriterTestContext.h:42-45
@@ +41,6 @@
+ DiagnosticPrinter(llvm::outs(), &*DiagOpts),
+ InMemoryFileSystem(new vfs::InMemoryFileSystem),
+ OverlayFileSystem(
+ new vfs::OverlayFileSystem(vfs::getRealFileSystem())),
+ Files(FileSystemOptions(), OverlayFileSystem),
+ Sources(Diagnostics, Files), Rewrite(Sources, Options) {

Perhaps add a FIXME: To make these tests truly in-memory, we need to overlay 
the builtin headers.


http://reviews.llvm.org/D13430



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D13430: [VFS] Add an in-memory file system implementation.

2015-10-05 Thread Benjamin Kramer via cfe-commits
bkramer created this revision.
bkramer added a reviewer: klimek.
bkramer added a subscriber: cfe-commits.
Herald added a subscriber: klimek.

This is a simple file system tree of memory buffers that can be filled by a
client. In conjunction with an OverlayFS it can be used to make virtual
files accessible right next to physical files. This can be used as a
replacement for the virtual file handling in FileManager and which I intend
to remove eventually.

[VFS] Add working directories to every virtual file system.

For RealFileSystem this is getcwd()/chdir(), the synthetic file systems can
make up one for themselves. OverlayFileSystem now synchronizes the working
directories when a new FS is added to the overlay or the overlay working
directory is set. This allows purely artificial file systems that have zero
ties to the underlying disks.

http://reviews.llvm.org/D13430

Files:
  include/clang/Basic/VirtualFileSystem.h
  lib/Basic/VirtualFileSystem.cpp
  unittests/Basic/VirtualFileSystemTest.cpp
  unittests/Tooling/RewriterTestContext.h

Index: unittests/Tooling/RewriterTestContext.h
===
--- unittests/Tooling/RewriterTestContext.h
+++ unittests/Tooling/RewriterTestContext.h
@@ -34,25 +34,28 @@
 /// methods, which help with writing tests that change files.
 class RewriterTestContext {
  public:
-  RewriterTestContext()
-  : DiagOpts(new DiagnosticOptions()),
-Diagnostics(IntrusiveRefCntPtr(new DiagnosticIDs),
-&*DiagOpts),
-DiagnosticPrinter(llvm::outs(), &*DiagOpts),
-Files((FileSystemOptions())),
-Sources(Diagnostics, Files),
-Rewrite(Sources, Options) {
+   RewriterTestContext()
+   : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(IntrusiveRefCntPtr(new DiagnosticIDs),
+ &*DiagOpts),
+ DiagnosticPrinter(llvm::outs(), &*DiagOpts),
+ InMemoryFileSystem(new vfs::InMemoryFileSystem),
+ OverlayFileSystem(
+ new vfs::OverlayFileSystem(vfs::getRealFileSystem())),
+ Files(FileSystemOptions(), OverlayFileSystem),
+ Sources(Diagnostics, Files), Rewrite(Sources, Options) {
 Diagnostics.setClient(&DiagnosticPrinter, false);
+OverlayFileSystem->pushOverlay(InMemoryFileSystem);
   }
 
   ~RewriterTestContext() {}
 
   FileID createInMemoryFile(StringRef Name, StringRef Content) {
 std::unique_ptr Source =
 llvm::MemoryBuffer::getMemBuffer(Content);
-const FileEntry *Entry =
-  Files.getVirtualFile(Name, Source->getBufferSize(), 0);
-Sources.overrideFileContents(Entry, std::move(Source));
+InMemoryFileSystem->addFile(Name, 0, std::move(Source));
+
+const FileEntry *Entry = Files.getFile(Name);
 assert(Entry != nullptr);
 return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
   }
@@ -109,6 +112,8 @@
   IntrusiveRefCntPtr DiagOpts;
   DiagnosticsEngine Diagnostics;
   TextDiagnosticPrinter DiagnosticPrinter;
+  IntrusiveRefCntPtr InMemoryFileSystem;
+  IntrusiveRefCntPtr OverlayFileSystem;
   FileManager Files;
   SourceManager Sources;
   LangOptions Options;
Index: unittests/Basic/VirtualFileSystemTest.cpp
===
--- unittests/Basic/VirtualFileSystemTest.cpp
+++ unittests/Basic/VirtualFileSystemTest.cpp
@@ -43,6 +43,12 @@
   openFileForRead(const Twine &Path) override {
 llvm_unreachable("unimplemented");
   }
+  llvm::ErrorOr getCurrentWorkingDirectory() const override {
+return std::string();
+  }
+  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+return std::error_code();
+  }
 
   struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
 std::map &FilesAndDirs;
@@ -515,6 +521,73 @@
   }
 }
 
+class InMemoryFileSystemTest : public ::testing::Test {
+protected:
+  clang::vfs::InMemoryFileSystem FS;
+};
+
+TEST_F(InMemoryFileSystemTest, IsEmpty) {
+  auto Stat = FS.status("/a");
+  ASSERT_EQ(errc::no_such_file_or_directory, Stat.getError()) << FS.toString();
+  Stat = FS.status("/");
+  ASSERT_EQ(errc::no_such_file_or_directory, Stat.getError()) << FS.toString();
+}
+
+TEST_F(InMemoryFileSystemTest, WindowsPath) {
+  FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
+  auto Stat = FS.status("c:");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  Stat = FS.status("c:/windows/system128/foo.cpp");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
+  Stat = FS.status("d:/windows/foo.cpp");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+}
+
+TEST_F(InMemoryFileSystemTest, OverlayFile) {
+  FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+  auto Stat = FS.status("/");
+  ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  Stat = FS.status("/a");
+  ASSERT_FA