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( + m_ast_builder.clang().GetSymbolFile()->GetBackingSymbolFile()); + std::optional 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 definition // CHECK: | | `-FieldDecl {{.*}} AnonymousMember 'int' // CHECK: | `-CXXRecordDecl {{.*}} struct Anonymous> 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 definition +// CHECK: | |-CXXRecordDecl {{.*}} struct W definition +// CHECK: | | |-FieldDecl {{.*}} M 'int' +// CHECK: | | `-FieldDecl {{.*}} N 'int' +// CHECK: | |-TypedefDecl {{.*}} Y 'U::V' +// CHECK: | | `-RecordType {{.*}} 'U::V' canonical +// CHECK: | | `-CXXRecord {{.*}} 'U::V' +// CHECK: | |-TypedefDecl {{.*}} Z 'U::V' +// CHECK: | | `-RecordType {{.*}} 'U::V' canonical +// CHECK: | | `-CXXRecord {{.*}} 'U::V' // 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::V definition +// CHECK: | |-TypedefDecl {{.*}}> W 'int' +// CHECK: | | `-BuiltinType {{.*}} 'int' +// CHECK: | |-TypedefDecl {{.*}} X 'U' +// CHECK: | | `-RecordType {{.*}} 'U' canonical +// CHECK: | | `-CXXRecord {{.*}} 'U' // CHECK: | |-FieldDecl {{.*}} I 'int' // CHECK: | `-FieldDecl {{.*}} J 'int'