Index: include/llvm/Support/Path.h =================================================================== --- include/llvm/Support/Path.h +++ include/llvm/Support/Path.h @@ -160,7 +160,8 @@ /// start with \a NewPrefix. /// @param OldPrefix The path prefix to strip from \a Path. /// @param NewPrefix The path prefix to replace \a NewPrefix with. -void replace_path_prefix(SmallVectorImpl &Path, +/// @result true if \a Path begins with OldPrefix +bool replace_path_prefix(SmallVectorImpl &Path, const StringRef &OldPrefix, const StringRef &NewPrefix, Style style = Style::native); Index: lib/Support/Path.cpp =================================================================== --- lib/Support/Path.cpp +++ lib/Support/Path.cpp @@ -521,27 +521,44 @@ path.append(ext.begin(), ext.end()); } -void replace_path_prefix(SmallVectorImpl &Path, +bool replace_path_prefix(SmallVectorImpl &Path, const StringRef &OldPrefix, const StringRef &NewPrefix, Style style) { if (OldPrefix.empty() && NewPrefix.empty()) - return; + return false; StringRef OrigPath(Path.begin(), Path.size()); - if (!OrigPath.startswith(OldPrefix)) - return; + StringRef Prefix; + if (!OldPrefix.empty() && is_separator(OldPrefix.back())) { + Prefix = parent_path(OldPrefix, style); + } else { + Prefix = OldPrefix; + } + + if (!OrigPath.startswith(Prefix)) + return false; + + if (!is_separator(OrigPath[Prefix.size()], style) && + OrigPath.size() > Prefix.size()) + return false; + // If prefixes have the same size we can simply copy the new one over. - if (OldPrefix.size() == NewPrefix.size()) { + if (Prefix.size() == NewPrefix.size()) { llvm::copy(NewPrefix, Path.begin()); - return; + return true; } - StringRef RelPath = OrigPath.substr(OldPrefix.size()); + StringRef RelPath = OrigPath.substr(Prefix.size()); SmallString<256> NewPath; path::append(NewPath, style, NewPrefix); - path::append(NewPath, style, RelPath); + if (!is_separator(RelPath[0], style)) + path::append(NewPath, style, RelPath); + else + path::append(NewPath, style, relative_path(RelPath, style)); Path.swap(NewPath); + + return true; } void native(const Twine &path, SmallVectorImpl &result, Style style) { Index: unittests/Support/Path.cpp =================================================================== --- unittests/Support/Path.cpp +++ unittests/Support/Path.cpp @@ -1208,7 +1208,9 @@ TEST(Support, ReplacePathPrefix) { SmallString<64> Path1("/foo"); SmallString<64> Path2("/old/foo"); + SmallString<64> Path3("/oldnew/foo"); SmallString<64> OldPrefix("/old"); + SmallString<64> OldPrefix2("/old/"); SmallString<64> NewPrefix("/new"); SmallString<64> NewPrefix2("/longernew"); SmallString<64> EmptyPrefix(""); @@ -1227,7 +1229,22 @@ EXPECT_EQ(Path, "/new/foo"); Path = Path2; path::replace_path_prefix(Path, OldPrefix, EmptyPrefix); - EXPECT_EQ(Path, "/foo"); + EXPECT_EQ(Path, "foo"); + Path = Path3; + path::replace_path_prefix(Path, OldPrefix, NewPrefix); + EXPECT_EQ(Path, "/oldnew/foo"); + Path = Path3; + path::replace_path_prefix(Path, OldPrefix2, NewPrefix); + EXPECT_EQ(Path, "/oldnew/foo"); + Path = Path1; + path::replace_path_prefix(Path, EmptyPrefix, NewPrefix); + EXPECT_EQ(Path, "/new/foo"); + Path = OldPrefix; + path::replace_path_prefix(Path, OldPrefix, NewPrefix); + EXPECT_EQ(Path, "/new"); + Path = OldPrefix2; + path::replace_path_prefix(Path, OldPrefix, NewPrefix); + EXPECT_EQ(Path, "/new/"); } TEST_F(FileSystemTest, OpenFileForRead) {