Skip to content

Commit 4aacafd

Browse files
authored
[clang][ASTVisitor] Visit HoldingVar from BindingDecl. (llvm#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).
1 parent e5371ed commit 4aacafd

File tree

3 files changed

+67
-5
lines changed

3 files changed

+67
-5
lines changed

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2151,8 +2151,11 @@ DEF_TRAVERSE_DECL(DecompositionDecl, {
21512151
})
21522152

21532153
DEF_TRAVERSE_DECL(BindingDecl, {
2154-
if (getDerived().shouldVisitImplicitCode())
2154+
if (getDerived().shouldVisitImplicitCode()) {
21552155
TRY_TO(TraverseStmt(D->getBinding()));
2156+
if (const auto HoldingVar = D->getHoldingVar())
2157+
TRY_TO(TraverseDecl(HoldingVar));
2158+
}
21562159
})
21572160

21582161
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })

clang/unittests/AST/ASTContextParentMapTest.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,54 @@ TEST(GetParents, FriendTypeLoc) {
148148
ElementsAre(DynTypedNode::create(FrA)));
149149
}
150150

151+
TEST(GetParents, UserDefinedTupleLikeTypes) {
152+
MatchVerifier<VarDecl> Verifier;
153+
EXPECT_TRUE(Verifier.match(
154+
R"(
155+
namespace std {
156+
157+
using size_t = __typeof(sizeof(int));
158+
159+
template <typename T>
160+
struct tuple_size;
161+
162+
template <typename T>
163+
struct tuple_size<T&> : tuple_size<T>{};
164+
165+
template <typename T>
166+
requires requires { tuple_size<T>::value; }
167+
struct tuple_size<const T> : tuple_size<T>{};
168+
169+
170+
template<size_t i, typename T>
171+
struct tuple_element;
172+
173+
174+
} // namespace std
175+
176+
struct Decomposable {};
177+
178+
template<> struct std::tuple_size<Decomposable> {
179+
static constexpr size_t value = 2;
180+
};
181+
182+
template<std::size_t i> struct std::tuple_element<i, Decomposable> {
183+
using type = int;
184+
};
185+
186+
template<std::size_t i> struct std::tuple_element<i, const Decomposable> {
187+
using type = const int;
188+
};
189+
190+
template<std::size_t i>
191+
const int& get(const Decomposable& d);
192+
193+
void F(const Decomposable& d) {
194+
const auto& [x, y] = d;
195+
}
196+
)",
197+
varDecl(hasName("x"), hasAncestor(decompositionDecl())), Lang_CXX20));
198+
}
199+
151200
} // end namespace ast_matchers
152201
} // end namespace clang

clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "gtest/gtest.h"
2626
#include <optional>
2727
#include <string>
28+
#include <string_view>
2829
#include <utility>
2930

3031
namespace clang {
@@ -143,6 +144,15 @@ const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
143144
return cast<BoolValue>(Env.getValue(D))->formula();
144145
}
145146

147+
const BindingDecl *findBindingDecl(ASTContext &ASTCtx, std::string_view Name) {
148+
using ast_matchers::bindingDecl;
149+
using ast_matchers::hasName;
150+
auto TargetNodes =
151+
ast_matchers::match(bindingDecl(hasName(Name)).bind("v"), ASTCtx);
152+
assert(TargetNodes.size() == 1 && "Name must be unique");
153+
return ast_matchers::selectFirst<BindingDecl>("v", TargetNodes);
154+
}
155+
146156
TEST(TransferTest, CNotSupported) {
147157
TestInputs Inputs("void target() {}");
148158
Inputs.Language = TestLanguage::Lang_C89;
@@ -5515,10 +5525,10 @@ TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
55155525
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
55165526
const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
55175527

5518-
const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
5528+
const ValueDecl *BoundFooDecl = findBindingDecl(ASTCtx, "BoundFoo");
55195529
ASSERT_THAT(BoundFooDecl, NotNull());
55205530

5521-
const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
5531+
const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar");
55225532
ASSERT_THAT(BoundBarDecl, NotNull());
55235533

55245534
const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
@@ -5596,10 +5606,10 @@ TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
55965606
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
55975607
const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
55985608

5599-
const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
5609+
const ValueDecl *BoundFooDecl = findBindingDecl(ASTCtx, "BoundFoo");
56005610
ASSERT_THAT(BoundFooDecl, NotNull());
56015611

5602-
const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
5612+
const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar");
56035613
ASSERT_THAT(BoundBarDecl, NotNull());
56045614

56055615
const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");

0 commit comments

Comments
 (0)