[clang] [Index] Report references through UsingType (PR #228823)

Fangrui Song via cfe-commits cfe-commits at lists.llvm.org
Sat Oct 3 22:03:36 PDT 2026


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/228823

In

    namespace ns2 { using ns1::A; }
    ns2::A a;

`ns2::A` is a UsingType. TypeIndexer has no VisitUsingTypeLoc and
RecursiveASTVisitor only traverses the qualifier, so the reference to A
has been dropped since UsingType was introduced (af27466c5039). This
affects clangd's find-references and index, as well as other
clangIndex users like ccls.

Report the target declaration, similar to DeclRefExpr. For a typedef
target used as a base specifier, also report the implicit reference to
the class, like VisitTypedefTypeLoc.

Aided by Opus 5.5

>From 1314a757bbc47b2735b7a95d6bbfa6355f7cc26e Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 3 Oct 2026 21:52:18 -0700
Subject: [PATCH] [Index] Report references through UsingType

In

    namespace ns2 { using ns1::A; }
    ns2::A a;

`ns2::A` is a UsingType. TypeIndexer has no VisitUsingTypeLoc and
RecursiveASTVisitor only traverses the qualifier, so the reference to A
has been dropped since UsingType was introduced (af27466c5039). This
affects clangd's find-references and index, as well as other
clangIndex users like ccls.

Report the target declaration, similar to DeclRefExpr. For a typedef
target used as a base specifier, also report the implicit reference to
the class, like VisitTypedefTypeLoc.

Aided by Opus 5.5
---
 clang/lib/Index/IndexTypeSourceInfo.cpp | 20 ++++++++++++++++++++
 clang/test/Index/Core/index-source.cpp  | 25 +++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/clang/lib/Index/IndexTypeSourceInfo.cpp b/clang/lib/Index/IndexTypeSourceInfo.cpp
index 6f599ababcaf5..220f067b34a27 100644
--- a/clang/lib/Index/IndexTypeSourceInfo.cpp
+++ b/clang/lib/Index/IndexTypeSourceInfo.cpp
@@ -81,6 +81,26 @@ class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
     return true;
   }
 
+  bool VisitUsingTypeLoc(UsingTypeLoc TL) {
+    // A type found via a using-declaration, e.g. `ns2::A` after
+    // `namespace ns2 { using ns1::A; }`. Like DeclRefExpr, report the target
+    // declaration rather than the UsingShadowDecl.
+    SourceLocation Loc = TL.getNameLoc();
+    NamedDecl *ND = TL.getDecl()->getTargetDecl();
+    if (IsBase && !isa<TagDecl>(ND)) {
+      TRY_TO(
+          IndexCtx.handleReference(ND, Loc, Parent, ParentDC, SymbolRoleSet()));
+      if (auto *CD = TL.getType()->getAsCXXRecordDecl()) {
+        TRY_TO(IndexCtx.handleReference(CD, Loc, Parent, ParentDC,
+                                        (unsigned)SymbolRole::Implicit,
+                                        Relations));
+      }
+      return true;
+    }
+    return IndexCtx.handleReference(ND, Loc, Parent, ParentDC, SymbolRoleSet(),
+                                    Relations);
+  }
+
   bool VisitAutoTypeLoc(AutoTypeLoc TL) {
     if (auto *C = TL.getNamedConcept().getAsTemplateDecl())
       return IndexCtx.handleReference(C, TL.getConceptNameLoc(), Parent,
diff --git a/clang/test/Index/Core/index-source.cpp b/clang/test/Index/Core/index-source.cpp
index e376523a58f7c..de474b80b3425 100644
--- a/clang/test/Index/Core/index-source.cpp
+++ b/clang/test/Index/Core/index-source.cpp
@@ -570,3 +570,28 @@ class C : B<A> {};
 // CHECK: [[@LINE-1]]:13 | class/C++ | A | c:@N at clangd_issue_504@S at A | <no-cgname> | Ref,RelCont | rel: 1
 // CHECK-NEXT: RelCont | C | c:@N at clangd_issue_504@S at C
 } // namespace clangd_issue_504
+
+namespace using_type {
+namespace ns1 {
+struct A {};
+typedef A T;
+}
+namespace ns2 {
+using ns1::A;
+using ns1::T;
+}
+void foo() {
+  ns2::A a;
+// CHECK: [[@LINE-1]]:8 | struct/C | A | c:@N at using_type@N at ns1@S at A | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK-NEXT: RelCont | foo | c:@N at using_type@F at foo#
+  ns2::T t;
+// CHECK: [[@LINE-1]]:8 | type-alias/using-struct/C | T | c:index-source.cpp at N@using_type at N@ns1 at T@T | <no-cgname> | Ref,RelCont | rel: 1
+}
+struct B : ns2::A {};
+// CHECK: [[@LINE-1]]:17 | struct/C | A | c:@N at using_type@N at ns1@S at A | <no-cgname> | Ref,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | B | c:@N at using_type@S at B
+struct C : ns2::T {};
+// CHECK: [[@LINE-1]]:17 | type-alias/using-struct/C | T | c:index-source.cpp at N@using_type at N@ns1 at T@T | <no-cgname> | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:17 | struct/C | A | c:@N at using_type@N at ns1@S at A | <no-cgname> | Ref,Impl,RelBase,RelCont | rel: 1
+// CHECK-NEXT: RelBase,RelCont | C | c:@N at using_type@S at C
+} // namespace using_type



More information about the cfe-commits mailing list