Index: include/llvm/Support/Path.h =================================================================== --- include/llvm/Support/Path.h +++ include/llvm/Support/Path.h @@ -152,15 +152,21 @@ /// @code /// /foo, /old, /new => /foo /// /old/foo, /old, /new => /new/foo +/// /old/foo, /old/, /new => /new/foo +/// /old/foo, /old/, /new/ => /new/foo +/// /oldfoo, /old, /new => /oldfoo /// /foo, , /new => /new/foo -/// /old/foo, /old, => /foo +/// /foo, , new => new/foo +/// /old/foo, /old, => foo /// @endcode /// /// @param Path If \a Path starts with \a OldPrefix modify to instead /// start with \a NewPrefix. -/// @param OldPrefix The path prefix to strip from \a Path. +/// @param OldPrefix The path prefix to strip from \a Path. Any trailing +/// path separator is ignored. /// @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 OldPrefixDir; + // Ensure OldPrefixDir does not have a trailing separator. + if (!OldPrefix.empty() && is_separator(OldPrefix.back())) + OldPrefixDir = parent_path(OldPrefix, style); + else + OldPrefixDir = OldPrefix; + + if (!OrigPath.startswith(OldPrefixDir)) + return false; + + if (!is_separator(OrigPath[OldPrefixDir.size()], style) && + OrigPath.size() > OldPrefixDir.size()) + return false; + // If prefixes have the same size we can simply copy the new one over. - if (OldPrefix.size() == NewPrefix.size()) { + if (OldPrefixDir.size() == NewPrefix.size()) { llvm::copy(NewPrefix, Path.begin()); - return; + return true; } - StringRef RelPath = OrigPath.substr(OldPrefix.size()); + StringRef RelPath = OrigPath.substr(OldPrefixDir.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> OldPrefixSep("/old/"); SmallString<64> NewPrefix("/new"); SmallString<64> NewPrefix2("/longernew"); SmallString<64> EmptyPrefix(""); @@ -1227,7 +1229,25 @@ 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, OldPrefixSep, 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 = OldPrefixSep; + path::replace_path_prefix(Path, OldPrefix, NewPrefix); + EXPECT_EQ(Path, "/new/"); + Path = OldPrefix; + path::replace_path_prefix(Path, OldPrefixSep, NewPrefix); + EXPECT_EQ(Path, "/new"); } TEST_F(FileSystemTest, OpenFileForRead) {