-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[LLDB][NativePDB] Create typedefs in structs #169248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-lldb Author: nerix (Nerixyz) ChangesTypedef/using declarations in structs and classes were not created with the native PDB plugin. The following would only create 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: To distinguish nested types and typedefs, we check if the parent of a type is equal to the current one ( Full diff: https://github.com/llvm/llvm-project/pull/169248.diff 3 Files Affected:
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'
|
Typedef/using declarations in structs and classes were not created with the native PDB plugin. The following would only create
FooandFoo::Bar:With this PR, they're created. One complication is that typedefs and nested types show up identical. The example from above gives:
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.