[llvm] 577adda - [Support/Path] Add path::is_absolute_gnu

Renato Golin via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 10:03:18 PDT 2020


Author: Vinicius Tinti
Date: 2020-09-23T18:01:32+01:00
New Revision: 577adda54f075b256007ed4fa80c9988a0642a87

URL: https://github.com/llvm/llvm-project/commit/577adda54f075b256007ed4fa80c9988a0642a87
DIFF: https://github.com/llvm/llvm-project/commit/577adda54f075b256007ed4fa80c9988a0642a87.diff

LOG: [Support/Path] Add path::is_absolute_gnu

Implements IS_ABSOLUTE_PATH from GNU tools.

C++17 is_absolute behavior is different the from the behavior defined by GNU
tools.

According to cppreference.com, C++17 states: "An absolute path is a path
that unambiguously identifies the location of a file without reference
to an additional starting location."

In other words, the rules are:
 1. POSIX style paths with nonempty root directory are absolute.
 2. Windows style paths with nonempty root name and root directory are
    absolute.
 3. No other paths are absolute.

GNU rules are:
 1. Paths starting with a path separator are absolute.
 2. Windows style paths are also absolute if they start with a character
    followed by ':'.
 3. No other paths are absolute.

On Windows style the path "C:\Users\Default" has "C:" as root name and "\"
as root directory.

Hence "C:" on Windows is absolute under GNU rules and not absolute under
C++17 because it has no root directory. Likewise "/" and "\" on Windows are
absolute under GNU and are not absolute under C++17 due to empty root name.

Related to PR46368.

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

Added: 
    

Modified: 
    llvm/include/llvm/Support/Path.h
    llvm/lib/Support/Path.cpp
    llvm/unittests/Support/Path.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h
index 83bca5b70bc2..af70e086a1b6 100644
--- a/llvm/include/llvm/Support/Path.h
+++ b/llvm/include/llvm/Support/Path.h
@@ -451,10 +451,48 @@ bool has_extension(const Twine &path, Style style = Style::native);
 
 /// Is path absolute?
 ///
+/// According to cppreference.com, C++17 states: "An absolute path is a path
+/// that unambiguously identifies the location of a file without reference to
+/// an additional starting location."
+///
+/// In other words, the rules are:
+/// 1) POSIX style paths with nonempty root directory are absolute.
+/// 2) Windows style paths with nonempty root name and root directory are
+///    absolute.
+/// 3) No other paths are absolute.
+///
+/// \see has_root_name
+/// \see has_root_directory
+///
 /// @param path Input path.
 /// @result True if the path is absolute, false if it is not.
 bool is_absolute(const Twine &path, Style style = Style::native);
 
+/// Is path absolute using GNU rules?
+///
+/// GNU rules are:
+/// 1) Paths starting with a path separator are absolute.
+/// 2) Windows style paths are also absolute if they start with a character
+///    followed by ':'.
+/// 3) No other paths are absolute.
+///
+/// On Windows style the path "C:\Users\Default" has "C:" as root name and "\"
+/// as root directory.
+///
+/// Hence "C:" on Windows is absolute under GNU rules and not absolute under
+/// C++17 because it has no root directory. Likewise "/" and "\" on Windows are
+/// absolute under GNU and are not absolute under C++17 due to empty root name.
+///
+/// \see has_root_name
+/// \see has_root_directory
+///
+/// @param path Input path.
+/// @param style The style of \p path (e.g. Windows or POSIX). "native" style
+/// means to derive the style from the host.
+/// @result True if the path is absolute following GNU rules, false if it is
+/// not.
+bool is_absolute_gnu(const Twine &path, Style style = Style::native);
+
 /// Is path relative?
 ///
 /// @param path Input path.

diff  --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp
index 37b3086fddf5..bbc02a246a50 100644
--- a/llvm/lib/Support/Path.cpp
+++ b/llvm/lib/Support/Path.cpp
@@ -683,6 +683,24 @@ bool is_absolute(const Twine &path, Style style) {
   return rootDir && rootName;
 }
 
+bool is_absolute_gnu(const Twine &path, Style style) {
+  SmallString<128> path_storage;
+  StringRef p = path.toStringRef(path_storage);
+
+  // Handle '/' which is absolute for both Windows and POSIX systems.
+  // Handle '\\' on Windows.
+  if (!p.empty() && is_separator(p.front(), style))
+    return true;
+
+  if (real_style(style) == Style::windows) {
+    // Handle drive letter pattern (a character followed by ':') on Windows.
+    if (p.size() >= 2 && (p[0] && p[1] == ':'))
+      return true;
+  }
+
+  return false;
+}
+
 bool is_relative(const Twine &path, Style style) {
   return !is_absolute(path, style);
 }

diff  --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp
index 9d7ab1a60090..10ebea7940af 100644
--- a/llvm/unittests/Support/Path.cpp
+++ b/llvm/unittests/Support/Path.cpp
@@ -85,6 +85,23 @@ TEST(is_separator, Works) {
 #endif
 }
 
+TEST(is_absolute_gnu, Works) {
+  // Test tuple <Path, ExpectedPosixValue, ExpectedWindowsValue>.
+  const std::tuple<StringRef, bool, bool> Paths[] = {
+      {"", false, false},  {"/", true, true},      {"/foo", true, true},
+      {"\\", false, true}, {"\\foo", false, true}, {"foo", false, false},
+      {"c", false, false}, {"c:", false, true},    {"c:\\", false, true},
+      {"!:", false, true}, {"xx:", false, false},  {"c:abc\\", false, true},
+      {":", false, false}};
+
+  for (const auto &Path : Paths) {
+    EXPECT_EQ(path::is_absolute_gnu(std::get<0>(Path), path::Style::posix),
+              std::get<1>(Path));
+    EXPECT_EQ(path::is_absolute_gnu(std::get<0>(Path), path::Style::windows),
+              std::get<2>(Path));
+  }
+}
+
 TEST(Support, Path) {
   SmallVector<StringRef, 40> paths;
   paths.push_back("");
@@ -171,6 +188,7 @@ TEST(Support, Path) {
     (void)path::has_extension(*i);
     (void)path::extension(*i);
     (void)path::is_absolute(*i);
+    (void)path::is_absolute_gnu(*i);
     (void)path::is_relative(*i);
 
     SmallString<128> temp_store;


        


More information about the llvm-commits mailing list