From: Yitzhak Mandelbaum Date: Tue, 3 Mar 2020 20:04:08 +0000 (-0500) Subject: [AST Matchers] Restrict `optionally` matcher to a single argument. X-Git-Tag: llvmorg-12-init~12809 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c359f9537ffb17c4f40a933980ddb515d7ee923b;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index f8c56d7..dca7aa5 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -4793,14 +4793,12 @@ Usable as: Any Matcher -Matcher<*>optionallyMatcher<*>, ..., Matcher<*> -
Matches any node regardless of the submatchers.
+Matcher<*>optionallyMatcher<*>
+
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 d45825d..da7e230 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::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::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 6f4132c..033a5f1 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 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::max()>
     allOf = {internal::DynTypedMatcher::VO_AllOf};
-const internal::VariadicOperatorMatcherFunc<
-    1, std::numeric_limits::max()>
-    optionally = {internal::DynTypedMatcher::VO_Optionally};
+const internal::VariadicOperatorMatcherFunc<1, 1> optionally = {
+    internal::DynTypedMatcher::VO_Optionally};
 const internal::VariadicFunction, StringRef,
                                  internal::hasAnyNameFunc>
     hasAnyName = {};
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index edfd1c3..c3c770a 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>("v")));
+      recordDecl(optionally(has(fieldDecl(hasName("c")).bind("c")))),
+      std::make_unique>("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>("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>("v", 2)));
+      recordDecl(optionally(has(fieldDecl(hasName("a")).bind("v")))),
+      std::make_unique>("v")));
 }
 
 TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {