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 @@ -3293,13 +3293,10 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher, InnerMatcher) { BoundNodesTreeBuilder Result(*Builder); - auto MatchIt = matchesFirstInPointerRange(InnerMatcher, Node.method_begin(), - Node.method_end(), Finder, &Result); + auto MatchIt = matchesFirstInPointerRangeIgnoreUnspelled( + InnerMatcher, Node.method_begin(), Node.method_end(), Finder, &Result); if (MatchIt == Node.method_end()) return false; - - if (Finder->isTraversalIgnoringImplicitNodes() && (*MatchIt)->isImplicit()) - return false; *Builder = std::move(Result); return true; } @@ -4358,11 +4355,9 @@ /// record matches Foo, hasAnyConstructorInitializer matches foo_(1) AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer, internal::Matcher, InnerMatcher) { - auto MatchIt = matchesFirstInPointerRange(InnerMatcher, Node.init_begin(), - Node.init_end(), Finder, Builder); - if (MatchIt == Node.init_end()) - return false; - return (*MatchIt)->isWritten() || !Finder->isTraversalIgnoringImplicitNodes(); + const auto *MatchIt = matchesFirstInPointerRangeIgnoreUnspelled( + InnerMatcher, Node.init_begin(), Node.init_end(), Finder, Builder); + return MatchIt != Node.init_end(); } /// Matches the field declaration of a constructor initializer. diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -792,6 +792,12 @@ return End; } +inline bool isSpelledInSource(const Decl *Node) { return !Node->isImplicit(); } + +inline bool isSpelledInSource(const CXXCtorInitializer *Node) { + return Node->isWritten(); +} + /// Finds the first node in a pointer range that matches the given /// matcher. template @@ -808,6 +814,26 @@ return End; } +/// Finds the first node in a pointer range that matches the given +/// matcher. Ignores any nodes that aren't spelled in source if Finder is +/// ignoring implicit nodes. +template +IteratorT matchesFirstInPointerRangeIgnoreUnspelled( + const MatcherT &Matcher, IteratorT Start, IteratorT End, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) { + bool IgnoreIsSpelledInSource = Finder->isTraversalIgnoringImplicitNodes(); + for (IteratorT I = Start; I != End; ++I) { + if (IgnoreIsSpelledInSource && !isSpelledInSource(*I)) + continue; + BoundNodesTreeBuilder Result(*Builder); + if (Matcher.matches(**I, Finder, &Result)) { + *Builder = std::move(Result); + return I; + } + } + return End; +} + template ::value> * = nullptr> inline bool isDefaultedHelper(const T *) { diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3276,6 +3276,18 @@ hasExplicitSpecifier(callExpr(has(declRefExpr()))))), true, {"-std=c++20"})); } + Code = R"cpp( + struct Foo{ + int A = 4, B; + Foo() : B(5) {} + }; + )cpp"; + { + auto M = + cxxConstructorDecl(hasAnyConstructorInitializer(cxxCtorInitializer())); + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); + EXPECT_TRUE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); + } } template