diff --git a/llvm/include/llvm/Support/GlobPattern.h b/llvm/include/llvm/Support/GlobPattern.h index 62ed4a0f23fd9..c1b44849b9794 100644 --- a/llvm/include/llvm/Support/GlobPattern.h +++ b/llvm/include/llvm/Support/GlobPattern.h @@ -65,13 +65,19 @@ class GlobPattern { bool isTrivialMatchAll() const { if (!Prefix.empty()) return false; + if (!Suffix.empty()) + return false; if (SubGlobs.size() != 1) return false; return SubGlobs[0].getPat() == "*"; } + StringRef prefix() const { return Prefix; } + StringRef suffix() const { return Suffix; } + private: StringRef Prefix; + StringRef Suffix; struct SubGlobPattern { /// \param Pat the pattern to match against diff --git a/llvm/lib/Support/GlobPattern.cpp b/llvm/lib/Support/GlobPattern.cpp index 7004adf461a0c..0ecf47dc1d3d1 100644 --- a/llvm/lib/Support/GlobPattern.cpp +++ b/llvm/lib/Support/GlobPattern.cpp @@ -143,6 +143,15 @@ GlobPattern::create(StringRef S, std::optional MaxSubPatterns) { return Pat; S = S.substr(PrefixSize); + // Just in case we stop on unmatched opening brackets. + size_t SuffixStart = S.find_last_of("?*[]{}\\"); + assert(SuffixStart != std::string::npos); + if (S[SuffixStart] == '\\') + ++SuffixStart; + ++SuffixStart; + Pat.Suffix = S.substr(SuffixStart); + S = S.substr(0, SuffixStart); + SmallVector SubPats; if (auto Err = parseBraceExpansions(S, MaxSubPatterns).moveInto(SubPats)) return std::move(Err); @@ -193,6 +202,8 @@ GlobPattern::SubGlobPattern::create(StringRef S) { bool GlobPattern::match(StringRef S) const { if (!S.consume_front(Prefix)) return false; + if (!S.consume_back(Suffix)) + return false; if (SubGlobs.empty() && S.empty()) return true; for (auto &Glob : SubGlobs) diff --git a/llvm/unittests/Support/GlobPatternTest.cpp b/llvm/unittests/Support/GlobPatternTest.cpp index e4f1025b00956..58fd7678131c6 100644 --- a/llvm/unittests/Support/GlobPatternTest.cpp +++ b/llvm/unittests/Support/GlobPatternTest.cpp @@ -257,6 +257,78 @@ TEST_F(GlobPatternTest, NUL) { } } +TEST_F(GlobPatternTest, PrefixSuffix) { + auto Pat = GlobPattern::create(""); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("", Pat->prefix()); + EXPECT_EQ("", Pat->suffix()); + + Pat = GlobPattern::create("abcd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("abcd", Pat->prefix()); + EXPECT_EQ("", Pat->suffix()); + + Pat = GlobPattern::create("*abcd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("", Pat->prefix()); + EXPECT_EQ("abcd", Pat->suffix()); + + Pat = GlobPattern::create("abcd*"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("abcd", Pat->prefix()); + EXPECT_EQ("", Pat->suffix()); + + Pat = GlobPattern::create("ab*cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("cd", Pat->suffix()); + + Pat = GlobPattern::create("ab?cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("cd", Pat->suffix()); + + Pat = GlobPattern::create("ab[n]cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("cd", Pat->suffix()); + + Pat = GlobPattern::create("ab{}cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("cd", Pat->suffix()); + + Pat = GlobPattern::create("ab{cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("cd", Pat->suffix()); + + Pat = GlobPattern::create("ab]cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab]cd", Pat->prefix()); + EXPECT_EQ("", Pat->suffix()); + + Pat = GlobPattern::create("ab\\cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("d", Pat->suffix()); + + Pat = GlobPattern::create("ab\\\\cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("d", Pat->suffix()); + + Pat = GlobPattern::create("ab?cd?"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("ab", Pat->prefix()); + EXPECT_EQ("", Pat->suffix()); + + Pat = GlobPattern::create("?ab?cd"); + ASSERT_TRUE((bool)Pat); + EXPECT_EQ("", Pat->prefix()); + EXPECT_EQ("cd", Pat->suffix()); +} + TEST_F(GlobPatternTest, Pathological) { std::string P, S(40, 'a'); StringRef Pieces[] = {"a*", "[ba]*", "{b*,a*}*"};