[clang] 4aacafd - [clang][ASTVisitor] Visit `HoldingVar` from `BindingDecl`. (#117858)

via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 12 08:02:03 PST 2024


Author: Clement Courbet
Date: 2024-12-12T17:01:59+01:00
New Revision: 4aacafd49b74dc168e0d99018b4c8289ce9c923e

URL: https://github.com/llvm/llvm-project/commit/4aacafd49b74dc168e0d99018b4c8289ce9c923e
DIFF: https://github.com/llvm/llvm-project/commit/4aacafd49b74dc168e0d99018b4c8289ce9c923e.diff

LOG: [clang][ASTVisitor] Visit `HoldingVar` from `BindingDecl`. (#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).

Added: 
    

Modified: 
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/unittests/AST/ASTContextParentMapTest.cpp
    clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 33363072c716f2..5d5c91ff91d553 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2151,8 +2151,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..0f731f4532535e 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -25,6 +25,7 @@
 #include "gtest/gtest.h"
 #include <optional>
 #include <string>
+#include <string_view>
 #include <utility>
 
 namespace clang {
@@ -143,6 +144,15 @@ const Formula &getFormula(const ValueDecl &D, const Environment &Env) {
   return cast<BoolValue>(Env.getValue(D))->formula();
 }
 
+const BindingDecl *findBindingDecl(ASTContext &ASTCtx, std::string_view Name) {
+  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 +5525,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(ASTCtx, "BoundFoo");
         ASSERT_THAT(BoundFooDecl, NotNull());
 
-        const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
+        const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar");
         ASSERT_THAT(BoundBarDecl, NotNull());
 
         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
@@ -5596,10 +5606,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(ASTCtx, "BoundFoo");
         ASSERT_THAT(BoundFooDecl, NotNull());
 
-        const ValueDecl *BoundBarDecl = findValueDecl(ASTCtx, "BoundBar");
+        const ValueDecl *BoundBarDecl = findBindingDecl(ASTCtx, "BoundBar");
         ASSERT_THAT(BoundBarDecl, NotNull());
 
         const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");


        


More information about the cfe-commits mailing list