[clang] [clang][ASTVisitor] Visit `HoldingVar` from `BindingDecl`. (PR #117858)
Clement Courbet via cfe-commits
cfe-commits at lists.llvm.org
Wed Nov 27 00:57:58 PST 2024
https://github.com/legrosbuffle created https://github.com/llvm/llvm-project/pull/117858
Tuple-like types introduce `VarDecl`s in the AST for their "holding vars", but AST visitors do not visit those. As a result the `VarDecl` for the holding var is orphaned when trying to retreive its parents.
Fix a `FlowSensitive` test that assumes that only a `BindingDecl` is introduced with the given name (the matcher now can also reach the `VarDecl` for the holding var).
>From f388f19e26bdd7e45e874e4574e7d9196c2eaf0b Mon Sep 17 00:00:00 2001
From: Clement Courbet <courbet at google.com>
Date: Mon, 25 Nov 2024 15:52:18 +0000
Subject: [PATCH] [clang][ASTVisitor] Visit `HoldingVar` from `BindingDecl`.
Tuple-like types introduce `VarDecl`s in the AST for their "holding
vars", but AST visitors do not visit those. As a result the `VarDecl`
for the holding var is orphaned when trying to retreive its parents.
Fix a `FlowSensitive` test that assumes that only a `BindingDecl`
is introduced with the given name (the matcher now can also reach
the `VarDecl` for the holding var).
---
clang/include/clang/AST/RecursiveASTVisitor.h | 5 +-
.../unittests/AST/ASTContextParentMapTest.cpp | 49 +++++++++++++++++++
.../Analysis/FlowSensitive/TransferTest.cpp | 17 +++++--
3 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 2b35997bd539ac..3ff60555c7873c 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2143,8 +2143,11 @@ DEF_TRAVERSE_DECL(DecompositionDecl, {
})
DEF_TRAVERSE_DECL(BindingDecl, {
- if (getDerived().shouldVisitImplicitCode())
+ if (getDerived().shouldVisitImplicitCode()) {
TRY_TO(TraverseStmt(D->getBinding()));
+ if (const auto HoldingVar = D->getHoldingVar())
+ TRY_TO(TraverseDecl(HoldingVar));
+ }
})
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
diff --git a/clang/unittests/AST/ASTContextParentMapTest.cpp b/clang/unittests/AST/ASTContextParentMapTest.cpp
index 515dfb99e1126d..9af0a46817a25f 100644
--- a/clang/unittests/AST/ASTContextParentMapTest.cpp
+++ b/clang/unittests/AST/ASTContextParentMapTest.cpp
@@ -148,5 +148,54 @@ TEST(GetParents, FriendTypeLoc) {
ElementsAre(DynTypedNode::create(FrA)));
}
+TEST(GetParents, UserDefinedTupleLikeTypes) {
+ MatchVerifier<VarDecl> Verifier;
+ EXPECT_TRUE(Verifier.match(
+ R"(
+namespace std {
+
+using size_t = __typeof(sizeof(int));
+
+template <typename T>
+struct tuple_size;
+
+template <typename T>
+struct tuple_size<T&> : tuple_size<T>{};
+
+template <typename T>
+requires requires { tuple_size<T>::value; }
+struct tuple_size<const T> : tuple_size<T>{};
+
+
+template<size_t i, typename T>
+struct tuple_element;
+
+
+} // namespace std
+
+struct Decomposable {};
+
+template<> struct std::tuple_size<Decomposable> {
+ static constexpr size_t value = 2;
+};
+
+template<std::size_t i> struct std::tuple_element<i, Decomposable> {
+ using type = int;
+};
+
+template<std::size_t i> struct std::tuple_element<i, const Decomposable> {
+ using type = const int;
+};
+
+template<std::size_t i>
+const int& get(const Decomposable& d);
+
+void F(const Decomposable& d) {
+ const auto& [x, y] = d;
+}
+)",
+ varDecl(hasName("x"), hasAncestor(decompositionDecl())), Lang_CXX20));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index 39e7001393e5e9..e10e4611ab8c60 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -143,6 +143,15 @@ const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
return cast<BoolValue>(Env.getValue(D))->formula();
}
+const BindingDecl *findBindingDecl(const char *Name, ASTContext &ASTCtx) {
+ using ast_matchers::bindingDecl;
+ using ast_matchers::hasName;
+ auto TargetNodes =
+ ast_matchers::match(bindingDecl(hasName(Name)).bind("v"), ASTCtx);
+ assert(TargetNodes.size() == 1 && "Name must be unique");
+ return ast_matchers::selectFirst<BindingDecl>("v", TargetNodes);
+}
+
TEST(TransferTest, CNotSupported) {
TestInputs Inputs("void target() {}");
Inputs.Language = TestLanguage::Lang_C89;
@@ -5515,10 +5524,10 @@ TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
- const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
+ const ValueDecl *BoundFooDecl = findBindingDecl("BoundFoo", ASTCtx);
ASSERT_THAT(BoundFooDecl, NotNull());
- const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
+ const ValueDecl *BoundBarDecl = findBindingDecl("BoundBar", ASTCtx);
ASSERT_THAT(BoundBarDecl, NotNull());
const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
@@ -5596,10 +5605,10 @@ TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
- const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
+ const ValueDecl *BoundFooDecl = findBindingDecl("BoundFoo", ASTCtx);
ASSERT_THAT(BoundFooDecl, NotNull());
- const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
+ const ValueDecl *BoundBarDecl = findBindingDecl("BoundBar", ASTCtx);
ASSERT_THAT(BoundBarDecl, NotNull());
const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
More information about the cfe-commits
mailing list