diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2586,13 +2586,11 @@ 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 @@ /// 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 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -346,18 +346,11 @@ 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< 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 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2007,9 +2007,8 @@ 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, 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) {