Skip to content

Commit f388f19

Browse files
committed
[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).
1 parent 0e8208e commit f388f19

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed

clang/include/clang/AST/RecursiveASTVisitor.h

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

21452145
DEF_TRAVERSE_DECL(BindingDecl, {
2146-
if (getDerived().shouldVisitImplicitCode())
2146+
if (getDerived().shouldVisitImplicitCode()) {
21472147
TRY_TO(TraverseStmt(D->getBinding()));
2148+
if (const auto HoldingVar = D->getHoldingVar())
2149+
TRY_TO(TraverseDecl(HoldingVar));
2150+
}
21482151
})
21492152

21502153
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: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,15 @@ const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
143143
return cast<BoolValue>(Env.getValue(D))->formula();
144144
}
145145

146+
const BindingDecl *findBindingDecl(const char *Name, ASTContext &ASTCtx) {
147+
using ast_matchers::bindingDecl;
148+
using ast_matchers::hasName;
149+
auto TargetNodes =
150+
ast_matchers::match(bindingDecl(hasName(Name)).bind("v"), ASTCtx);
151+
assert(TargetNodes.size() == 1 && "Name must be unique");
152+
return ast_matchers::selectFirst<BindingDecl>("v", TargetNodes);
153+
}
154+
146155
TEST(TransferTest, CNotSupported) {
147156
TestInputs Inputs("void target() {}");
148157
Inputs.Language = TestLanguage::Lang_C89;
@@ -5515,10 +5524,10 @@ TEST(TransferTest, StructuredBindingAssignFromTupleLikeType) {
55155524
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
55165525
const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
55175526

5518-
const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
5527+
const ValueDecl *BoundFooDecl = findBindingDecl("BoundFoo", ASTCtx);
55195528
ASSERT_THAT(BoundFooDecl, NotNull());
55205529

5521-
const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
5530+
const ValueDecl *BoundBarDecl = findBindingDecl("BoundBar", ASTCtx);
55225531
ASSERT_THAT(BoundBarDecl, NotNull());
55235532

55245533
const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
@@ -5596,10 +5605,10 @@ TEST(TransferTest, StructuredBindingAssignRefFromTupleLikeType) {
55965605
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p1", "p2"));
55975606
const Environment &Env1 = getEnvironmentAtAnnotation(Results, "p1");
55985607

5599-
const ValueDecl *BoundFooDecl = findValueDecl(ASTCtx, "BoundFoo");
5608+
const ValueDecl *BoundFooDecl = findBindingDecl("BoundFoo", ASTCtx);
56005609
ASSERT_THAT(BoundFooDecl, NotNull());
56015610

5602-
const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
5611+
const ValueDecl *BoundBarDecl = findBindingDecl("BoundBar", ASTCtx);
56035612
ASSERT_THAT(BoundBarDecl, NotNull());
56045613

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

0 commit comments

Comments
 (0)