[Lldb-commits] [lldb] 9de41ee - [LLDB][NativePDB] Create typedefs in structs (#169248)
via lldb-commits
lldb-commits at lists.llvm.org
Sun Dec 14 06:43:01 PST 2025
Author: nerix
Date: 2025-12-14T15:42:57+01:00
New Revision: 9de41eef6e4cd3c96ef0dba56e875e01b8e378c8
URL: https://github.com/llvm/llvm-project/commit/9de41eef6e4cd3c96ef0dba56e875e01b8e378c8
DIFF: https://github.com/llvm/llvm-project/commit/9de41eef6e4cd3c96ef0dba56e875e01b8e378c8.diff
LOG: [LLDB][NativePDB] Create typedefs in structs (#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.
Added:
Modified:
lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp
lldb/test/Shell/SymbolFile/NativePDB/nested-types.cpp
Removed:
################################################################################
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index 8ab06e09b024e..f3d6fbf1e27d8 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -229,6 +229,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 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) {
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'
More information about the lldb-commits
mailing list