Skip to content

Commit bf284fe

Browse files
committed
MatchFilePath: Add support for double asterisk patterns
1 parent 3ea55d3 commit bf284fe

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

clang/lib/Format/MatchFilePath.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,29 @@ bool matchFilePath(StringRef Pattern, StringRef FilePath) {
4949
return false;
5050
break;
5151
case '*': {
52-
while (++I < EOP && Pattern[I] == '*') { // Skip consecutive stars.
52+
if (I + 1 < EOP && Pattern[I + 1] == '*') {
53+
// Handle '**' pattern
54+
while (++I < EOP && Pattern[I] == '*') { // Skip consecutive stars.
55+
}
56+
if (I == EOP)
57+
return true; // '**' at the end matches everything
58+
if (Pattern[I] == Separator) {
59+
// Try to match the rest of the pattern without consuming the
60+
// separator for the case where we want to match "zero" directories
61+
// e.g. "a/**/b" matches "a/b"
62+
if (matchFilePath(Pattern.substr(I + 1), FilePath.substr(J)))
63+
return true;
64+
}
65+
while (J < End) {
66+
if (matchFilePath(Pattern.substr(I), FilePath.substr(J)))
67+
return true;
68+
++J;
69+
}
70+
return false;
5371
}
5472
const auto K = FilePath.find(Separator, J); // Index of next `Separator`.
5573
const bool NoMoreSeparatorsInFilePath = K == StringRef::npos;
56-
if (I == EOP) // `Pattern` ends with a star.
74+
if (++I == EOP) // `Pattern` ends with a star.
5775
return NoMoreSeparatorsInFilePath;
5876
// `Pattern` ends with a lone backslash.
5977
if (Pattern[I] == '\\' && ++I == EOP)

clang/unittests/Format/MatchFilePathTest.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,40 @@ TEST_F(MatchFilePathTest, Path) {
164164
EXPECT_FALSE(match("foo\\", R"(foo*\)"));
165165
}
166166

167+
TEST_F(MatchFilePathTest, DoubleAsterisk) {
168+
EXPECT_TRUE(match("a/b/c/d.cpp", "**b**"));
169+
EXPECT_TRUE(match("a/b/c/d.cpp", "**/b/**"));
170+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "**d_*"));
171+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "**/d_*"));
172+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "**d_**"));
173+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "**/d_**"));
174+
175+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "**/b/c/**"));
176+
177+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "a/**/b/c/d_e.cpp"));
178+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "a/**/c/d_e.cpp"));
179+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "a/**/b/**/d_e.cpp"));
180+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "**/b/**/d_e.cpp"));
181+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "a/**/**/b/**"));
182+
183+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "**/d"));
184+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "**/b/d"));
185+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "**/b/d/**"));
186+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "**/b/c/"));
187+
188+
// Multiple consecutive asterisks are treated as **
189+
EXPECT_TRUE(match("a/b/c/d.cpp", "***b****"));
190+
EXPECT_TRUE(match("a/b/c/d.cpp", "****/b/***"));
191+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "***d_**"));
192+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "****/d_*"));
193+
EXPECT_TRUE(match("a/b/c/d_e.cpp", "***/b/c/*****"));
194+
195+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "*****/d"));
196+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "***/b/d"));
197+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "*****/b/d/***"));
198+
EXPECT_FALSE(match("a/b/c/d_e.cpp", "***/b/c"));
199+
}
200+
167201
} // namespace
168202
} // namespace format
169203
} // namespace clang

0 commit comments

Comments
 (0)