[Lldb-commits] [lldb] [LLDB][NativePDB] Create typedefs in structs (PR #169248)

via lldb-commits lldb-commits at lists.llvm.org
Fri Dec 12 12:19:44 PST 2025


https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/169248

>From 66148315c58efd99056b91fd8984da33048052e0 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Sun, 23 Nov 2025 23:01:12 +0100
Subject: [PATCH 1/2] [LLDB][NativePDB] Create typedefs in structs

---
 .../NativePDB/UdtRecordCompleter.cpp          | 26 +++++++++
 .../Shell/SymbolFile/NativePDB/ast-types.cpp  |  6 +-
 .../SymbolFile/NativePDB/nested-types.cpp     | 57 ++++++++++++++-----
 3 files changed, 72 insertions(+), 17 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 46cf9b8524ede..d8e4255b4823f 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -233,6 +233,32 @@ Error UdtRecordCompleter::visitKnownMember(
 
 Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
                                            NestedTypeRecord &nested) {
+  // Typedefs can only be added on structs.
+  if (m_record.record.kind != Member::Struct)
+    return Error::success();
+
+  clang::QualType qt =
+      m_ast_builder.GetOrCreateType(PdbTypeSymId(nested.Type, false));
+  if (qt.isNull())
+    return Error::success();
+  CompilerType ct = m_ast_builder.ToCompilerType(qt);
+
+  // There's no distinction between nested types and typedefs, so check if we
+  // encountered a nested type.
+  auto *pdb = static_cast<SymbolFileNativePDB *>(
+      m_ast_builder.clang().GetSymbolFile()->GetBackingSymbolFile());
+  std::optional<TypeIndex> parent = pdb->GetParentType(nested.Type);
+  if (parent && *parent == m_id.index && ct.GetTypeName(true) == nested.Name)
+    return Error::success();
+
+  clang::DeclContext *decl_ctx =
+      m_ast_builder.GetOrCreateDeclContextForUid(m_id);
+  if (!decl_ctx)
+    return Error::success();
+
+  std::string name = nested.Name.str();
+  ct.CreateTypedef(name.c_str(), m_ast_builder.ToCompilerDeclContext(*decl_ctx),
+                   0);
   return Error::success();
 }
 
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
index ac0d87e95dbf9..dea124c6d6145 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
@@ -175,9 +175,9 @@ int SI::*mp9 = nullptr;
 // CHECK: | |-CXXRecordDecl {{.*}} struct Anonymous<int> definition
 // CHECK: | | `-FieldDecl {{.*}} AnonymousMember 'int'
 // CHECK: | `-CXXRecordDecl {{.*}} struct Anonymous<A::B::C<void>> definition
-// CHECK: |   |-FieldDecl {{.*}} AnonymousMember 'int'
-// CHECK: |   `-CXXRecordDecl {{.*}} struct D definition
-// CHECK: |     `-FieldDecl {{.*}} AnonymousDMember 'int'
+// CHECK: |   |-CXXRecordDecl {{.*}} struct D definition
+// CHECK: |   |  `-FieldDecl {{.*}} AnonymousDMember 'int'
+// CHECK: |   `-FieldDecl {{.*}} AnonymousMember 'int'
 
 int main(int argc, char **argv) {
   AnonInt.AnonymousMember = 1;
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/nested-types.cpp b/lldb/test/Shell/SymbolFile/NativePDB/nested-types.cpp
index f725037a220d9..a4b07cdb1b1b7 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/nested-types.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/nested-types.cpp
@@ -126,30 +126,59 @@ int main(int argc, char **argv) {
 // CHECK: (lldb) target modules dump ast
 // CHECK: Dumping clang ast for 1 modules.
 // CHECK: TranslationUnitDecl {{.*}}
+
 // CHECK: |-CXXRecordDecl {{.*}} struct S definition
-// CHECK: | |-FieldDecl {{.*}} C 'int'
-// CHECK: | |-FieldDecl {{.*}} D 'int'
-// CHECK: | |-FieldDecl {{.*}} DD 'void *'
 // CHECK: | |-CXXRecordDecl {{.*}} struct NestedStruct definition
 // CHECK: | | |-FieldDecl {{.*}} A 'int'
 // CHECK: | | `-FieldDecl {{.*}} B 'int'
-// CHECK: | `-EnumDecl {{.*}} NestedEnum
-// CHECK: |   |-EnumConstantDecl {{.*}} EnumValue1 'S::NestedEnum'
-// CHECK: |   `-EnumConstantDecl {{.*}} EnumValue2 'S::NestedEnum'
+// CHECK: | |-EnumDecl {{.*}} NestedEnum
+// CHECK: | | |-EnumConstantDecl {{.*}} EnumValue1 'S::NestedEnum'
+// CHECK: | | `-EnumConstantDecl {{.*}} EnumValue2 'S::NestedEnum'
+// CHECK: | |-TypedefDecl {{.*}} VoidPtrT 'void *'
+// CHECK: | | `-PointerType {{.*}} 'void *'
+// CHECK: | |   `-BuiltinType {{.*}} 'void'
+// CHECK: | |-FieldDecl {{.*}} C 'int'
+// CHECK: | |-FieldDecl {{.*}} D 'int'
+// CHECK: | `-FieldDecl {{.*}} DD 'void *'
+
 // CHECK: |-CXXRecordDecl {{.*}} struct T definition
-// CHECK: | |-FieldDecl {{.*}} NT 'int'
+// CHECK: | |-TypedefDecl {{.*}} NestedTypedef 'int'
+// CHECK: | | `-BuiltinType {{.*}} 'int'
+// CHECK: | |-TypedefDecl {{.*}} NestedTypedef2 'S'
+// CHECK: | | `-RecordType {{.*}} 'S' canonical
+// CHECK: | |   `-CXXRecord {{.*}} 'S'
 // CHECK: | |-CXXRecordDecl {{.*}} struct NestedStruct definition
 // CHECK: | | |-FieldDecl {{.*}} E 'int'
 // CHECK: | | `-FieldDecl {{.*}} F 'int'
-// CHECK: | `-CXXRecordDecl {{.*}} struct U definition
-// CHECK: |   |-FieldDecl {{.*}} G 'int'
-// CHECK: |   `-FieldDecl {{.*}} H 'int'
+// CHECK: | |-TypedefDecl {{.*}} NestedStructAlias 'T::NestedStruct'
+// CHECK: | | `-RecordType {{.*}} 'T::NestedStruct' canonical
+// CHECK: | |   `-CXXRecord {{.*}} 'NestedStruct'
+// CHECK: | |-TypedefDecl {{.*}} NST 'S::NestedStruct'
+// CHECK: | | `-RecordType {{.*}} 'S::NestedStruct' canonical
+// CHECK: | |   `-CXXRecord {{.*}} 'NestedStruct'
+// CHECK: | |-CXXRecordDecl {{.*}} struct U definition
+// CHECK: | | |-FieldDecl {{.*}} G 'int'
+// CHECK: | | `-FieldDecl {{.*}} H 'int'
+// CHECK: | `-FieldDecl {{.*}} NT 'int'
+
 // CHECK: |-CXXRecordDecl {{.*}} class U<int> definition
+// CHECK: | |-CXXRecordDecl {{.*}} struct W definition
+// CHECK: | | |-FieldDecl {{.*}} M 'int'
+// CHECK: | | `-FieldDecl {{.*}} N 'int'
+// CHECK: | |-TypedefDecl {{.*}} Y 'U<int>::V<int>'
+// CHECK: | | `-RecordType {{.*}} 'U<int>::V<int>' canonical
+// CHECK: | |   `-CXXRecord {{.*}} 'U<int>::V<int>'
+// CHECK: | |-TypedefDecl {{.*}} Z 'U<int>::V<T>'
+// CHECK: | | `-RecordType {{.*}} 'U<int>::V<T>' canonical
+// CHECK: | |   `-CXXRecord {{.*}} 'U<int>::V<T>'
 // CHECK: | |-FieldDecl {{.*}} K 'int'
-// CHECK: | |-FieldDecl {{.*}} L 'int'
-// CHECK: | `-CXXRecordDecl {{.*}} struct W definition
-// CHECK: |   |-FieldDecl {{.*}} M 'int'
-// CHECK: |   `-FieldDecl {{.*}} N 'int'
+// CHECK: | `-FieldDecl {{.*}} L 'int'
+
 // CHECK: |-CXXRecordDecl {{.*}} struct U<int>::V<int> definition
+// CHECK: | |-TypedefDecl {{.*}}> W 'int'
+// CHECK: | | `-BuiltinType {{.*}} 'int'
+// CHECK: | |-TypedefDecl {{.*}} X 'U<int>'
+// CHECK: | | `-RecordType {{.*}} 'U<int>' canonical
+// CHECK: | |   `-CXXRecord {{.*}} 'U<int>'
 // CHECK: | |-FieldDecl {{.*}} I 'int'
 // CHECK: | `-FieldDecl {{.*}} J 'int'

>From e19984600ae12c58c093af82e72d06edb9373591 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Fri, 12 Dec 2025 21:19:23 +0100
Subject: [PATCH 2/2] fix: test (fields are now at the bottom)

---
 lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
index e3af6d21893a7..4cc0b376d3ef9 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
@@ -183,15 +183,15 @@ int SI::*mp9 = nullptr;
 // CHECK: | |-CXXRecordDecl {{.*}} struct Anonymous<int> definition
 // CHECK: | | `-FieldDecl {{.*}} AnonymousMember 'int'
 // CHECK: | `-CXXRecordDecl {{.*}} struct Anonymous<A::B::C<void>> definition
-// CHECK: |   |-FieldDecl {{.*}} AnonymousMember 'int'
 // CHECK: |   |-CXXRecordDecl {{.*}} struct D definition
 // CHECK: |   | |-VarDecl {{.*}} StaticMember 'const int' static cinit
 // CHECK: |   | | `-IntegerLiteral {{.*}} 'int' 1
 // CHECK: |   | `-FieldDecl {{.*}} AnonymousDMember 'int'
-// CHECK: |   `-CXXRecordDecl {{.*}} union U definition
-// CHECK: |     |-VarDecl {{.*}} StaticMember 'const int' static
-// CHECK: |     | `-IntegerLiteral {{.*}} 'int' 2
-// CHECK: |     `-FieldDecl {{.*}} AnonymousUMember 'int'
+// CHECK: |   |-CXXRecordDecl {{.*}} union U definition
+// CHECK: |   | |-VarDecl {{.*}} StaticMember 'const int' static
+// CHECK: |   | | `-IntegerLiteral {{.*}} 'int' 2
+// CHECK: |   | `-FieldDecl {{.*}} AnonymousUMember 'int'
+// CHECK: |   `-FieldDecl {{.*}} AnonymousMember 'int'
 
 
 int main(int argc, char **argv) {



More information about the lldb-commits mailing list