diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -438,6 +438,8 @@ } void VisitBindingDecl(const BindingDecl *D) { + if (Traversal == TK_IgnoreUnlessSpelledInSource) + return; if (const auto *E = D->getBinding()) Visit(E); } diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -1216,6 +1216,8 @@ ScopedChildren = true; if (FD->isTemplateInstantiation()) ScopedTraversal = true; + } else if (isa(DeclNode)) { + ScopedChildren = true; } ASTNodeNotSpelledInSourceScope RAII1(this, ScopedTraversal); diff --git a/clang/unittests/AST/ASTTraverserTest.cpp b/clang/unittests/AST/ASTTraverserTest.cpp --- a/clang/unittests/AST/ASTTraverserTest.cpp +++ b/clang/unittests/AST/ASTTraverserTest.cpp @@ -1148,6 +1148,15 @@ { hasDefaultArg(42); } + +void decomposition() +{ + int arr[3]; + auto &[f, s, t] = arr; + + f = 42; +} + )cpp", {"-std=c++20"}); @@ -1443,6 +1452,46 @@ CallExpr |-DeclRefExpr 'hasDefaultArg' `-IntegerLiteral +)cpp"); + } + + { + auto FN = ast_matchers::match( + functionDecl(hasName("decomposition"), + hasDescendant(decompositionDecl().bind("decomp"))), + AST2->getASTContext()); + EXPECT_EQ(FN.size(), 1u); + + EXPECT_EQ( + dumpASTString(TK_AsIs, FN[0].getNodeAs("decomp")), + R"cpp( +DecompositionDecl '' +|-DeclRefExpr 'arr' +|-BindingDecl 'f' +| `-ArraySubscriptExpr +| |-ImplicitCastExpr +| | `-DeclRefExpr '' +| `-IntegerLiteral +|-BindingDecl 's' +| `-ArraySubscriptExpr +| |-ImplicitCastExpr +| | `-DeclRefExpr '' +| `-IntegerLiteral +`-BindingDecl 't' + `-ArraySubscriptExpr + |-ImplicitCastExpr + | `-DeclRefExpr '' + `-IntegerLiteral +)cpp"); + + EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, + FN[0].getNodeAs("decomp")), + R"cpp( +DecompositionDecl '' +|-DeclRefExpr 'arr' +|-BindingDecl 'f' +|-BindingDecl 's' +`-BindingDecl 't' )cpp"); } } 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 @@ -2591,6 +2591,31 @@ Code, traverse(TK_IgnoreUnlessSpelledInSource, M), std::make_unique>("allExprs", 1))); } + + Code = R"cpp( +void foo() +{ + int arr[3]; + auto &[f, s, t] = arr; + + f = 42; +} + )cpp"; + { + auto M = bindingDecl(hasName("f"), has(expr())); + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); + EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); + } + { + auto M = integerLiteral(hasAncestor(bindingDecl(hasName("f")))); + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); + EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); + } + { + auto M = declRefExpr(hasAncestor(bindingDecl(hasName("f")))); + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, M))); + EXPECT_FALSE(matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, M))); + } } TEST(Traversal, traverseNoImplicit) {