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

Typedef/using declarations in structs and classes were not created with the 
native PDB plugin. The following would only create `Foo` and `Foo::Bar`:
```cpp
struct Foo {
    struct Bar {};
    using Baz = Bar;
    using Int = int;
};
```

With this PR, they're created. One complication is that typedefs and nested 
types show up identical. The example from above gives:
```
  0x1006 | LF_FIELDLIST [size = 40, hash = 0x2E844]
           - LF_NESTTYPE [name = `Bar`, parent = 0x1002]
           - LF_NESTTYPE [name = `Baz`, parent = 0x1002]
           - LF_NESTTYPE [name = `Int`, parent = 0x0074 (int)]
```

To distinguish nested types and typedefs, we check if the parent of a type is 
equal to the current one (`parent(0x1002) == 0x1006`) and if the basename 
matches the nested type name.

>From 66148315c58efd99056b91fd8984da33048052e0 Mon Sep 17 00:00:00 2001
From: Nerixyz <[email protected]>
Date: Sun, 23 Nov 2025 23:01:12 +0100
Subject: [PATCH] [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'

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to