This revision was automatically updated to reflect the committed changes.
Closed by commit rL250060: [VFS] Let the user decide if they want path 
normalization. (authored by d0k).

Changed prior to commit:
  http://reviews.llvm.org/D13658?vs=37124&id=37125#toc

Repository:
  rL LLVM

http://reviews.llvm.org/D13658

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

Index: cfe/trunk/include/clang/Basic/VirtualFileSystem.h
===================================================================
--- cfe/trunk/include/clang/Basic/VirtualFileSystem.h
+++ cfe/trunk/include/clang/Basic/VirtualFileSystem.h
@@ -273,17 +273,24 @@
 class InMemoryFileSystem : public FileSystem {
   std::unique_ptr<detail::InMemoryDirectory> Root;
   std::string WorkingDirectory;
+  bool UseNormalizedPaths = true;
 
 public:
-  InMemoryFileSystem();
+  explicit InMemoryFileSystem(bool UseNormalizedPaths = true);
   ~InMemoryFileSystem() override;
   /// Add a buffer to the VFS with a path. The VFS owns the buffer.
-  void addFile(const Twine &Path, time_t ModificationTime,
+  /// \return true if the file was successfully added, false if the file already
+  /// exists in the file system with different contents.
+  bool addFile(const Twine &Path, time_t ModificationTime,
                std::unique_ptr<llvm::MemoryBuffer> Buffer);
   /// Add a buffer to the VFS with a path. The VFS does not own the buffer.
-  void addFileNoOwn(const Twine &Path, time_t ModificationTime,
+  /// \return true if the file was successfully added, false if the file already
+  /// exists in the file system with different contents.
+  bool addFileNoOwn(const Twine &Path, time_t ModificationTime,
                     llvm::MemoryBuffer *Buffer);
   std::string toString() const;
+  /// Return true if this file system normalizes . and .. in paths.
+  bool useNormalizedPaths() const { return UseNormalizedPaths; }
 
   llvm::ErrorOr<Status> status(const Twine &Path) override;
   llvm::ErrorOr<std::unique_ptr<File>>
Index: cfe/trunk/lib/Basic/VirtualFileSystem.cpp
===================================================================
--- cfe/trunk/lib/Basic/VirtualFileSystem.cpp
+++ cfe/trunk/lib/Basic/VirtualFileSystem.cpp
@@ -10,6 +10,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/Basic/VirtualFileSystem.h"
+#include "clang/Basic/FileManager.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
@@ -474,19 +475,20 @@
 };
 }
 
-InMemoryFileSystem::InMemoryFileSystem()
+InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
     : Root(new detail::InMemoryDirectory(
           Status("", getNextVirtualUniqueID(), llvm::sys::TimeValue::MinTime(),
                  0, 0, 0, llvm::sys::fs::file_type::directory_file,
-                 llvm::sys::fs::perms::all_all))) {}
+                 llvm::sys::fs::perms::all_all))),
+      UseNormalizedPaths(UseNormalizedPaths) {}
 
 InMemoryFileSystem::~InMemoryFileSystem() {}
 
 std::string InMemoryFileSystem::toString() const {
   return Root->toString(/*Indent=*/0);
 }
 
-void InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
+bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
                                  std::unique_ptr<llvm::MemoryBuffer> Buffer) {
   SmallString<128> Path;
   P.toVector(Path);
@@ -496,14 +498,14 @@
   assert(!EC);
   (void)EC;
 
-  detail::InMemoryDirectory *Dir = Root.get();
-  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
-  if (*I == ".")
-    ++I;
+  if (useNormalizedPaths())
+    FileManager::removeDotPaths(Path, /*RemoveDotDot=*/true);
 
-  if (I == E)
-    return;
+  if (Path.empty())
+    return false;
 
+  detail::InMemoryDirectory *Dir = Root.get();
+  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
   while (true) {
     StringRef Name = *I;
     detail::InMemoryNode *Node = Dir->getChild(Name);
@@ -519,7 +521,7 @@
                     llvm::sys::fs::all_all);
         Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>(
                                 std::move(Stat), std::move(Buffer)));
-        return;
+        return true;
       }
 
       // Create a new directory. Use the path up to here.
@@ -534,12 +536,24 @@
       continue;
     }
 
-    if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node))
+    if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
       Dir = NewDir;
+    } else {
+      assert(isa<detail::InMemoryFile>(Node) &&
+             "Must be either file or directory!");
+
+      // Trying to insert a directory in place of a file.
+      if (I != E)
+        return false;
+
+      // Return false only if the new file is different from the existing one.
+      return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
+             Buffer->getBuffer();
+    }
   }
 }
 
-void InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
+bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
                                       llvm::MemoryBuffer *Buffer) {
   return addFile(P, ModificationTime,
                  llvm::MemoryBuffer::getMemBuffer(
@@ -557,13 +571,13 @@
   assert(!EC);
   (void)EC;
 
-  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
-  if (*I == ".")
-    ++I;
+  if (FS.useNormalizedPaths())
+    FileManager::removeDotPaths(Path, /*RemoveDotDot=*/true);
 
-  if (I == E)
+  if (Path.empty())
     return Dir;
 
+  auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
   while (true) {
     detail::InMemoryNode *Node = Dir->getChild(*I);
     ++I;
Index: cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp
===================================================================
--- cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp
+++ cfe/trunk/unittests/Basic/VirtualFileSystemTest.cpp
@@ -525,6 +525,11 @@
 class InMemoryFileSystemTest : public ::testing::Test {
 protected:
   clang::vfs::InMemoryFileSystem FS;
+  clang::vfs::InMemoryFileSystem NormalizedFS;
+
+  InMemoryFileSystemTest()
+      : FS(/*UseNormalizedPaths=*/false),
+        NormalizedFS(/*UseNormalizedPaths=*/true) {}
 };
 
 TEST_F(InMemoryFileSystemTest, IsEmpty) {
@@ -549,8 +554,13 @@
 
 TEST_F(InMemoryFileSystemTest, OverlayFile) {
   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+  NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
   auto Stat = FS.status("/");
   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
+  Stat = FS.status("/.");
+  ASSERT_FALSE(Stat);
+  Stat = NormalizedFS.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());
@@ -566,17 +576,36 @@
 
 TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
-  FS.addFile("./c", 0, MemoryBuffer::getMemBuffer("c"));
+  FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
+  FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
+  NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
+  NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
+  NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
   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 = NormalizedFS.openFileForRead("/././a"); // Open again.
+  ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
   File = FS.openFileForRead("/");
   ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
   File = FS.openFileForRead("/b");
   ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
-  File = FS.openFileForRead("c");
+  File = FS.openFileForRead("./c");
+  ASSERT_FALSE(File);
+  File = FS.openFileForRead("e/../d");
+  ASSERT_FALSE(File);
+  File = NormalizedFS.openFileForRead("./c");
   ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
+  File = NormalizedFS.openFileForRead("e/../d");
+  ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
+}
+
+TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
+  ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
+  ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
+  ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
+  ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
 }
 
 TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to