diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -25,7 +25,13 @@ namespace sys { namespace path { -enum class Style { windows, posix, native }; +enum class Style { + native, + posix, + windows_slash, + windows_backslash, + windows = windows_backslash, // deprecated +}; /// Check if \p S uses POSIX path rules. constexpr bool is_style_posix(Style S) { @@ -262,6 +268,17 @@ /// @param path A path that is transformed to native format. void native(SmallVectorImpl &path, Style style = Style::native); +/// For Windows path styles, convert path to use the preferred path separators. +/// For other styles, do nothing. +/// +/// @param path A path that is transformed to preferred format. +inline void make_preferred(SmallVectorImpl &path, + Style style = Style::native) { + if (!is_style_windows(style)) + return; + native(path, style); +} + /// Replaces backslashes with slashes if Windows. /// /// @param path processed path diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -37,9 +37,12 @@ using llvm::sys::path::Style; inline Style real_style(Style style) { - if (is_style_posix(style)) - return Style::posix; - return Style::windows; + if (style == Style::native) { + if (is_style_posix(style)) + return Style::posix; + return Style::windows; + } + return style; } inline const char *separators(Style style) { @@ -547,7 +550,9 @@ if (Path.empty()) return; if (is_style_windows(style)) { - std::replace(Path.begin(), Path.end(), '/', '\\'); + for (char &Ch : Path) + if (is_separator(Ch, style)) + Ch = preferred_separator(style); if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) { SmallString<128> PathHome; home_directory(PathHome); diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -99,6 +99,7 @@ EXPECT_FALSE(path::is_separator(' ')); EXPECT_TRUE(path::is_separator('\\', path::Style::windows)); + EXPECT_TRUE(path::is_separator('\\', path::Style::windows_slash)); EXPECT_FALSE(path::is_separator('\\', path::Style::posix)); EXPECT_EQ(path::is_style_windows(path::Style::native), @@ -387,6 +388,8 @@ testing::ElementsAre("/", ".c", ".d", "..", ".")); EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows), testing::ElementsAre("c:", "\\", "c", "e", "foo.txt")); + EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows_slash), + testing::ElementsAre("c:", "\\", "c", "e", "foo.txt")); EXPECT_THAT(GetComponents("//net/"), testing::ElementsAre("//net", "/")); EXPECT_THAT(GetComponents("//net/c/foo.txt"), testing::ElementsAre("//net", "/", "c", "foo.txt")); @@ -1429,10 +1432,25 @@ for (auto &T : Tests) { SmallString<64> Win(std::get<0>(T)); SmallString<64> Posix(Win); + SmallString<64> WinSlash(Win); path::native(Win, path::Style::windows); path::native(Posix, path::Style::posix); + path::native(WinSlash, path::Style::windows_slash); EXPECT_EQ(std::get<1>(T), Win); EXPECT_EQ(std::get<2>(T), Posix); + EXPECT_EQ(std::get<2>(T), WinSlash); + } + + for (auto &T : Tests) { + SmallString<64> WinBackslash(std::get<0>(T)); + SmallString<64> Posix(WinBackslash); + SmallString<64> WinSlash(WinBackslash); + path::make_preferred(WinBackslash, path::Style::windows_backslash); + path::make_preferred(Posix, path::Style::posix); + path::make_preferred(WinSlash, path::Style::windows_slash); + EXPECT_EQ(std::get<1>(T), WinBackslash); + EXPECT_EQ(std::get<0>(T), Posix); // Posix remains unchanged here + EXPECT_EQ(std::get<2>(T), WinSlash); } #if defined(_WIN32) @@ -1441,10 +1459,15 @@ const char *Path7a = "~/aaa"; SmallString<64> Path7(Path7a); - path::native(Path7); + path::native(Path7, path::Style::windows_backslash); EXPECT_TRUE(Path7.endswith("\\aaa")); EXPECT_TRUE(Path7.startswith(PathHome)); EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1)); + Path7 = Path7a; + path::native(Path7, path::Style::windows_slash); + EXPECT_TRUE(Path7.endswith("/aaa")); + EXPECT_TRUE(Path7.startswith(PathHome)); + EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1)); const char *Path8a = "~"; SmallString<64> Path8(Path8a); @@ -1458,7 +1481,7 @@ const char *Path10a = "aaa/~/b"; SmallString<64> Path10(Path10a); - path::native(Path10); + path::native(Path10, path::Style::windows_backslash); EXPECT_EQ(Path10, "aaa\\~\\b"); #endif }