[clang] c359f95 - [AST Matchers] Restrict `optionally` matcher to a single argument.
Yitzhak Mandelbaum via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 5 11:49:30 PST 2020
Author: Yitzhak Mandelbaum
Date: 2020-03-05T14:48:40-05:00
New Revision: c359f9537ffb17c4f40a933980ddb515d7ee923b
URL: https://github.com/llvm/llvm-project/commit/c359f9537ffb17c4f40a933980ddb515d7ee923b
DIFF: https://github.com/llvm/llvm-project/commit/c359f9537ffb17c4f40a933980ddb515d7ee923b.diff
LOG: [AST Matchers] Restrict `optionally` matcher to a single argument.
Summary:
Currently, `optionally` can take multiple arguments, which commits it to a
particular strategy for those arguments (in this case, "for each"). We limit the
matcher to a single argument, which avoids any potential confusion and
simplifies the implementation. The user can retrieve multiple-argument
optionality, by explicitly using the desired operator (like `forEach`, `anyOf`,
`allOf`, etc.) with all children wrapped in `optionally`.
Reviewers: sbenza, aaron.ballman
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75556
Added:
Modified:
clang/docs/LibASTMatchersReference.html
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/lib/ASTMatchers/ASTMatchersInternal.cpp
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index f8c56d7d9efc..dca7aa5c2cf7 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -4793,14 +4793,12 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>
-<tr><td>Matcher<*></td><td class="name" onclick="toggle('optionally0')"><a name="optionally0Anchor">optionally</a></td><td>Matcher<*>, ..., Matcher<*></td></tr>
-<tr><td colspan="4" class="doc" id="optionally0"><pre>Matches any node regardless of the submatchers.
+<tr><td>Matcher<*></td><td class="name" onclick="toggle('optionally0')"><a name="optionally0Anchor">optionally</a></td><td>Matcher<*></td></tr>
+<tr><td colspan="4" class="doc" id="optionally0"><pre>Matches any node regardless of the submatcher.
-However, optionally will generate a result binding for each matching
-submatcher.
-
-Useful when additional information which may or may not present about a
-main matching node is desired.
+However, optionally will retain any bindings generated by the submatcher.
+Useful when additional information which may or may not present about a main
+matching node is desired.
For example, in:
class Foo {
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index d45825de67db..da7e23052b28 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2586,13 +2586,11 @@ extern const internal::VariadicOperatorMatcherFunc<
2, std::numeric_limits<unsigned>::max()>
allOf;
-/// Matches any node regardless of the submatchers.
+/// Matches any node regardless of the submatcher.
///
-/// However, \c optionally will generate a result binding for each matching
-/// submatcher.
-///
-/// Useful when additional information which may or may not present about a
-/// main matching node is desired.
+/// However, \c optionally will retain any bindings generated by the submatcher.
+/// Useful when additional information which may or may not present about a main
+/// matching node is desired.
///
/// For example, in:
/// \code
@@ -2612,9 +2610,7 @@ extern const internal::VariadicOperatorMatcherFunc<
/// member named "bar" in that class.
///
/// Usable as: Any Matcher
-extern const internal::VariadicOperatorMatcherFunc<
- 1, std::numeric_limits<unsigned>::max()>
- optionally;
+extern const internal::VariadicOperatorMatcherFunc<1, 1> optionally;
/// Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
///
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 6f4132c19aed..033a5f19fd8c 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -346,18 +346,11 @@ bool OptionallyVariadicOperator(const DynTypedNode &DynNode,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder,
ArrayRef<DynTypedMatcher> InnerMatchers) {
- BoundNodesTreeBuilder Result;
- bool Matched = false;
- for (const DynTypedMatcher &InnerMatcher : InnerMatchers) {
- BoundNodesTreeBuilder BuilderInner(*Builder);
- if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) {
- Matched = true;
- Result.addMatch(BuilderInner);
- }
- }
- // If there were no matches, we can't assign to `*Builder`; we'd (incorrectly)
- // clear it because `Result` is empty.
- if (Matched)
+ if (InnerMatchers.size() != 1)
+ return false;
+
+ BoundNodesTreeBuilder Result(*Builder);
+ if (InnerMatchers[0].matches(DynNode, Finder, &Result))
*Builder = std::move(Result);
return true;
}
@@ -859,9 +852,8 @@ const internal::VariadicOperatorMatcherFunc<
const internal::VariadicOperatorMatcherFunc<
2, std::numeric_limits<unsigned>::max()>
allOf = {internal::DynTypedMatcher::VO_AllOf};
-const internal::VariadicOperatorMatcherFunc<
- 1, std::numeric_limits<unsigned>::max()>
- optionally = {internal::DynTypedMatcher::VO_Optionally};
+const internal::VariadicOperatorMatcherFunc<1, 1> optionally = {
+ internal::DynTypedMatcher::VO_Optionally};
const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
internal::hasAnyNameFunc>
hasAnyName = {};
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index edfd1c3fbd91..c3c770a7dffd 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2007,9 +2007,8 @@ TEST(EachOf, BehavesLikeAnyOfUnlessBothMatch) {
TEST(Optionally, SubmatchersDoNotMatch) {
EXPECT_TRUE(matchAndVerifyResultFalse(
"class A { int a; int b; };",
- recordDecl(optionally(has(fieldDecl(hasName("c")).bind("v")),
- has(fieldDecl(hasName("d")).bind("v")))),
- std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v")));
+ recordDecl(optionally(has(fieldDecl(hasName("c")).bind("c")))),
+ std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("c")));
}
// Regression test.
@@ -2028,14 +2027,8 @@ TEST(Optionally, SubmatchersDoNotMatchButPreserveBindings) {
TEST(Optionally, SubmatchersMatch) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class A { int a; int c; };",
- recordDecl(optionally(has(fieldDecl(hasName("a")).bind("v")),
- has(fieldDecl(hasName("b")).bind("v")))),
- std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v", 1)));
- EXPECT_TRUE(matchAndVerifyResultTrue(
- "class A { int c; int b; };",
- recordDecl(optionally(has(fieldDecl(hasName("c")).bind("v")),
- has(fieldDecl(hasName("b")).bind("v")))),
- std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v", 2)));
+ recordDecl(optionally(has(fieldDecl(hasName("a")).bind("v")))),
+ std::make_unique<VerifyIdIsBoundTo<FieldDecl>>("v")));
}
TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
More information about the cfe-commits
mailing list