Hello,

this patch fixes loading files on Windows with a path without
subdirectories (like 'C:\foo.cpp'). Without the patch, the trailing path
separator is stripped and stat() fails for 'C:'.

-- Nico

From c2142af3102060a7105ec9ef9432f12c5308f7dc Mon Sep 17 00:00:00 2001
From: Nico Rieck <[email protected]>
Date: Sun, 12 Feb 2012 02:10:30 +0100
Subject: [PATCH] Support/FileSystem: Add path::is_root_path

Used by clang to not strip trailing path separators from Windows drives.
---
 include/llvm/Support/PathV2.h |    6 ++++++
 lib/Support/PathV2.cpp        |   14 ++++++++++++++
 unittests/Support/Path.cpp    |    1 +
 3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/include/llvm/Support/PathV2.h b/include/llvm/Support/PathV2.h
index 6d38c95..78fac8f 100644
--- a/include/llvm/Support/PathV2.h
+++ b/include/llvm/Support/PathV2.h
@@ -283,6 +283,12 @@ void system_temp_directory(bool erasedOnReboot, 
SmallVectorImpl<char> &result);
 /// @result True if the path has a root name, false otherwise.
 bool has_root_name(const Twine &path);
 
+/// @brief Check whether the path is a root path (excludes network paths).
+///
+/// @param path Input path.
+/// @result True if \a path is a root path, false otherwise.
+bool is_root_path(StringRef path);
+
 /// @brief Has root directory?
 ///
 /// root_directory != ""
diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp
index 3ef13e2..0901945 100644
--- a/lib/Support/PathV2.cpp
+++ b/lib/Support/PathV2.cpp
@@ -519,6 +519,20 @@ void system_temp_directory(bool erasedOnReboot, 
SmallVectorImpl<char> &result) {
   result.append(DefaultResult, DefaultResult + strlen(DefaultResult));
 }
 
+bool is_root_path(StringRef path) {
+  switch (path.size()) {
+     // POSIX style
+    case 1:  return is_separator(path[0]);
+#ifdef LLVM_ON_WIN32
+    // C:
+    case 2:  return path.endswith(":");
+    // C:/
+    case 3:  return path[1] == ':' && is_separator(path[2]);
+#endif
+    default: return false;
+  }
+}
+
 bool has_root_name(const Twine &path) {
   SmallString<128> path_storage;
   StringRef p = path.toStringRef(path_storage);
diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp
index 358dad0..9107bb1 100644
--- a/unittests/Support/Path.cpp
+++ b/unittests/Support/Path.cpp
@@ -108,6 +108,7 @@ TEST(Support, Path) {
 #endif
 
     path::has_root_path(*i);
+    path::is_root_path(*i);
     path::root_path(*i);
     path::has_root_name(*i);
     path::root_name(*i);
-- 
1.7.8.msysgit.0

From c44d558a045828b23b4c481321c110cc995a3ba4 Mon Sep 17 00:00:00 2001
From: Nico Rieck <[email protected]>
Date: Sun, 12 Feb 2012 01:48:21 +0100
Subject: [PATCH] Basic: Handle windows drives in FileManager::getDirectory

---
 lib/Basic/FileManager.cpp           |    5 +++--
 unittests/Basic/FileManagerTest.cpp |   21 +++++++++++++++++++++
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index fd6d334..768931c 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -267,8 +267,9 @@ const DirectoryEntry *FileManager::getDirectory(StringRef 
DirName,
                                                 bool CacheFailure) {
   // stat doesn't like trailing separators.
   // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
-  // (though it can strip '\\')
-  if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back()))
+  // (though it can strip '\\') Do not strip it for root paths like 'C:/'.
+  if (DirName.size() > 1 && llvm::sys::path::is_separator(DirName.back())
+      && !llvm::sys::path::is_root_path(DirName))
     DirName = DirName.substr(0, DirName.size()-1);
 
   ++NumDirLookups;
diff --git a/unittests/Basic/FileManagerTest.cpp 
b/unittests/Basic/FileManagerTest.cpp
index 91998b6..a2f0839 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -218,6 +218,27 @@ TEST_F(FileManagerTest, 
getFileReturnsSameFileEntryForAliasedVirtualFiles) {
   EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
 }
 
+#else
+
+// The following tests apply to Windows only.
+
+// getDirectory() accepts drive names.
+TEST_F(FileManagerTest, getDirectoryAcceptsWindowsDrive) {
+  // Inject two real files with the same inode.
+  FakeStatCache *statCache = new FakeStatCache;
+  // Path separators are not normalized, so both variants could occur.
+  statCache->InjectDirectory("c:\\", 41);
+  statCache->InjectDirectory("d:/", 42);
+  manager.addStatCache(statCache);
+
+  const DirectoryEntry *drive_c = manager.getDirectory("c:\\");
+  const DirectoryEntry *drive_d = manager.getDirectory("d:/");
+  ASSERT_TRUE(drive_c != NULL);
+  ASSERT_TRUE(drive_d != NULL);
+  EXPECT_STREQ("c:\\", drive_c->getName());
+  EXPECT_STREQ("d:/", drive_d->getName());
+}
+
 #endif  // !_WIN32
 
 } // anonymous namespace
-- 
1.7.8.msysgit.0

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to