From 8fe2337421af15dee7f0d2af7ed27695e2967723 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Fri, 15 Feb 2019 11:32:09 -0800 Subject: [PATCH] llvm: Enhance path prefix mapping Upstream-Status: Submitted [https://reviews.llvm.org/D56769] Signed-off-by: Khem Raj --- llvm/include/llvm/Support/Path.h | 25 +++++++++++++++--- llvm/lib/Support/Path.cpp | 44 +++++++++++++++++++++++++------- llvm/unittests/Support/Path.cpp | 29 +++++++++++++++++++++ 3 files changed, 85 insertions(+), 13 deletions(-) diff --git a/llvm/include/llvm/Support/Path.h b/llvm/include/llvm/Support/Path.h index 5c0bee58f18..20332c09852 100644 --- a/llvm/include/llvm/Support/Path.h +++ b/llvm/include/llvm/Support/Path.h @@ -150,18 +150,35 @@ void replace_extension(SmallVectorImpl &path, const Twine &extension, /// /// @code /// /foo, /old, /new => /foo +/// /old, /old, /new => /new +/// /old, /old/, /new, false => /old +/// /old, /old/, /new, true => /new /// /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, , false => /foo +/// /old/foo, /old, , true => 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 if strict is true. /// @param NewPrefix The path prefix to replace \a NewPrefix with. -void replace_path_prefix(SmallVectorImpl &Path, +/// @param style The path separator style +/// @param strict Strict prefix path checking +/// @result true if \a Path begins with OldPrefix +bool replace_path_prefix(SmallVectorImpl &Path, const StringRef &OldPrefix, const StringRef &NewPrefix, - Style style = Style::native); + Style style = Style::native, bool strict = false); +static inline bool replace_path_prefix(SmallVectorImpl &Path, + const StringRef &OldPrefix, const StringRef &NewPrefix, + bool strict, Style style = Style::native) { + return replace_path_prefix(Path, OldPrefix, NewPrefix, style, strict); +} /// Append to path. /// diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp index c49260125db..89a1c193d14 100644 --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -496,27 +496,53 @@ void replace_extension(SmallVectorImpl &path, const Twine &extension, 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) { + Style style, bool strict) { if (OldPrefix.empty() && NewPrefix.empty()) - return; + return false; StringRef OrigPath(Path.begin(), Path.size()); - if (!OrigPath.startswith(OldPrefix)) - return; + StringRef OldPrefixDir; + + if (!strict && OldPrefix.size() > OrigPath.size()) + return false; + + if (!strict && OldPrefix.size() > OrigPath.size()) + return false; + + // 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 (OrigPath.size() > OldPrefixDir.size()) + if (!is_separator(OrigPath[OldPrefixDir.size()], style) && strict) + 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() && !strict) { 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 (!RelPath.empty()) { + if (!is_separator(RelPath[0], style) || !strict) + 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) { diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp index ccd72d7f176..13af998d8f8 100644 --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -1219,7 +1219,9 @@ TEST(Support, RemoveDots) { 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(""); @@ -1239,6 +1241,33 @@ TEST(Support, ReplacePathPrefix) { Path = Path2; path::replace_path_prefix(Path, OldPrefix, EmptyPrefix); EXPECT_EQ(Path, "/foo"); + Path = Path2; + path::replace_path_prefix(Path, OldPrefix, EmptyPrefix, true); + EXPECT_EQ(Path, "foo"); + Path = Path3; + path::replace_path_prefix(Path, OldPrefix, NewPrefix, false); + EXPECT_EQ(Path, "/newnew/foo"); + Path = Path3; + path::replace_path_prefix(Path, OldPrefix, NewPrefix, true); + EXPECT_EQ(Path, "/oldnew/foo"); + Path = Path3; + path::replace_path_prefix(Path, OldPrefixSep, NewPrefix, true); + 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, false); + EXPECT_EQ(Path, "/old"); + Path = OldPrefix; + path::replace_path_prefix(Path, OldPrefixSep, NewPrefix, true); + EXPECT_EQ(Path, "/new"); } TEST_F(FileSystemTest, OpenFileForRead) {