Skip to content

Commit 9de41ee

Browse files
authored
[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.
1 parent 8a53c01 commit 9de41ee

File tree

3 files changed

+74
-19
lines changed

3 files changed

+74
-19
lines changed

lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,32 @@ Error UdtRecordCompleter::visitKnownMember(
229229

230230
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
231231
NestedTypeRecord &nested) {
232+
// Typedefs can only be added on structs.
233+
if (m_record.record.kind != Member::Struct)
234+
return Error::success();
235+
236+
clang::QualType qt =
237+
m_ast_builder.GetOrCreateType(PdbTypeSymId(nested.Type, false));
238+
if (qt.isNull())
239+
return Error::success();
240+
CompilerType ct = m_ast_builder.ToCompilerType(qt);
241+
242+
// There's no distinction between nested types and typedefs, so check if we
243+
// encountered a nested type.
244+
auto *pdb = static_cast<SymbolFileNativePDB *>(
245+
m_ast_builder.clang().GetSymbolFile()->GetBackingSymbolFile());
246+
std::optional<TypeIndex> parent = pdb->GetParentType(nested.Type);
247+
if (parent && *parent == m_id.index && ct.GetTypeName(true) == nested.Name)
248+
return Error::success();
249+
250+
clang::DeclContext *decl_ctx =
251+
m_ast_builder.GetOrCreateDeclContextForUid(m_id);
252+
if (!decl_ctx)
253+
return Error::success();
254+
255+
std::string name = nested.Name.str();
256+
ct.CreateTypedef(name.c_str(), m_ast_builder.ToCompilerDeclContext(*decl_ctx),
257+
0);
232258
return Error::success();
233259
}
234260

lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,15 @@ int SI::*mp9 = nullptr;
183183
// CHECK: | |-CXXRecordDecl {{.*}} struct Anonymous<int> definition
184184
// CHECK: | | `-FieldDecl {{.*}} AnonymousMember 'int'
185185
// CHECK: | `-CXXRecordDecl {{.*}} struct Anonymous<A::B::C<void>> definition
186-
// CHECK: | |-FieldDecl {{.*}} AnonymousMember 'int'
187186
// CHECK: | |-CXXRecordDecl {{.*}} struct D definition
188187
// CHECK: | | |-VarDecl {{.*}} StaticMember 'const int' static cinit
189188
// CHECK: | | | `-IntegerLiteral {{.*}} 'int' 1
190189
// CHECK: | | `-FieldDecl {{.*}} AnonymousDMember 'int'
191-
// CHECK: | `-CXXRecordDecl {{.*}} union U definition
192-
// CHECK: | |-VarDecl {{.*}} StaticMember 'const int' static
193-
// CHECK: | | `-IntegerLiteral {{.*}} 'int' 2
194-
// CHECK: | `-FieldDecl {{.*}} AnonymousUMember 'int'
190+
// CHECK: | |-CXXRecordDecl {{.*}} union U definition
191+
// CHECK: | | |-VarDecl {{.*}} StaticMember 'const int' static
192+
// CHECK: | | | `-IntegerLiteral {{.*}} 'int' 2
193+
// CHECK: | | `-FieldDecl {{.*}} AnonymousUMember 'int'
194+
// CHECK: | `-FieldDecl {{.*}} AnonymousMember 'int'
195195

196196

197197
int main(int argc, char **argv) {

lldb/test/Shell/SymbolFile/NativePDB/nested-types.cpp

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,30 +126,59 @@ int main(int argc, char **argv) {
126126
// CHECK: (lldb) target modules dump ast
127127
// CHECK: Dumping clang ast for 1 modules.
128128
// CHECK: TranslationUnitDecl {{.*}}
129+
129130
// CHECK: |-CXXRecordDecl {{.*}} struct S definition
130-
// CHECK: | |-FieldDecl {{.*}} C 'int'
131-
// CHECK: | |-FieldDecl {{.*}} D 'int'
132-
// CHECK: | |-FieldDecl {{.*}} DD 'void *'
133131
// CHECK: | |-CXXRecordDecl {{.*}} struct NestedStruct definition
134132
// CHECK: | | |-FieldDecl {{.*}} A 'int'
135133
// CHECK: | | `-FieldDecl {{.*}} B 'int'
136-
// CHECK: | `-EnumDecl {{.*}} NestedEnum
137-
// CHECK: | |-EnumConstantDecl {{.*}} EnumValue1 'S::NestedEnum'
138-
// CHECK: | `-EnumConstantDecl {{.*}} EnumValue2 'S::NestedEnum'
134+
// CHECK: | |-EnumDecl {{.*}} NestedEnum
135+
// CHECK: | | |-EnumConstantDecl {{.*}} EnumValue1 'S::NestedEnum'
136+
// CHECK: | | `-EnumConstantDecl {{.*}} EnumValue2 'S::NestedEnum'
137+
// CHECK: | |-TypedefDecl {{.*}} VoidPtrT 'void *'
138+
// CHECK: | | `-PointerType {{.*}} 'void *'
139+
// CHECK: | | `-BuiltinType {{.*}} 'void'
140+
// CHECK: | |-FieldDecl {{.*}} C 'int'
141+
// CHECK: | |-FieldDecl {{.*}} D 'int'
142+
// CHECK: | `-FieldDecl {{.*}} DD 'void *'
143+
139144
// CHECK: |-CXXRecordDecl {{.*}} struct T definition
140-
// CHECK: | |-FieldDecl {{.*}} NT 'int'
145+
// CHECK: | |-TypedefDecl {{.*}} NestedTypedef 'int'
146+
// CHECK: | | `-BuiltinType {{.*}} 'int'
147+
// CHECK: | |-TypedefDecl {{.*}} NestedTypedef2 'S'
148+
// CHECK: | | `-RecordType {{.*}} 'S' canonical
149+
// CHECK: | | `-CXXRecord {{.*}} 'S'
141150
// CHECK: | |-CXXRecordDecl {{.*}} struct NestedStruct definition
142151
// CHECK: | | |-FieldDecl {{.*}} E 'int'
143152
// CHECK: | | `-FieldDecl {{.*}} F 'int'
144-
// CHECK: | `-CXXRecordDecl {{.*}} struct U definition
145-
// CHECK: | |-FieldDecl {{.*}} G 'int'
146-
// CHECK: | `-FieldDecl {{.*}} H 'int'
153+
// CHECK: | |-TypedefDecl {{.*}} NestedStructAlias 'T::NestedStruct'
154+
// CHECK: | | `-RecordType {{.*}} 'T::NestedStruct' canonical
155+
// CHECK: | | `-CXXRecord {{.*}} 'NestedStruct'
156+
// CHECK: | |-TypedefDecl {{.*}} NST 'S::NestedStruct'
157+
// CHECK: | | `-RecordType {{.*}} 'S::NestedStruct' canonical
158+
// CHECK: | | `-CXXRecord {{.*}} 'NestedStruct'
159+
// CHECK: | |-CXXRecordDecl {{.*}} struct U definition
160+
// CHECK: | | |-FieldDecl {{.*}} G 'int'
161+
// CHECK: | | `-FieldDecl {{.*}} H 'int'
162+
// CHECK: | `-FieldDecl {{.*}} NT 'int'
163+
147164
// CHECK: |-CXXRecordDecl {{.*}} class U<int> definition
165+
// CHECK: | |-CXXRecordDecl {{.*}} struct W definition
166+
// CHECK: | | |-FieldDecl {{.*}} M 'int'
167+
// CHECK: | | `-FieldDecl {{.*}} N 'int'
168+
// CHECK: | |-TypedefDecl {{.*}} Y 'U<int>::V<int>'
169+
// CHECK: | | `-RecordType {{.*}} 'U<int>::V<int>' canonical
170+
// CHECK: | | `-CXXRecord {{.*}} 'U<int>::V<int>'
171+
// CHECK: | |-TypedefDecl {{.*}} Z 'U<int>::V<T>'
172+
// CHECK: | | `-RecordType {{.*}} 'U<int>::V<T>' canonical
173+
// CHECK: | | `-CXXRecord {{.*}} 'U<int>::V<T>'
148174
// CHECK: | |-FieldDecl {{.*}} K 'int'
149-
// CHECK: | |-FieldDecl {{.*}} L 'int'
150-
// CHECK: | `-CXXRecordDecl {{.*}} struct W definition
151-
// CHECK: | |-FieldDecl {{.*}} M 'int'
152-
// CHECK: | `-FieldDecl {{.*}} N 'int'
175+
// CHECK: | `-FieldDecl {{.*}} L 'int'
176+
153177
// CHECK: |-CXXRecordDecl {{.*}} struct U<int>::V<int> definition
178+
// CHECK: | |-TypedefDecl {{.*}}> W 'int'
179+
// CHECK: | | `-BuiltinType {{.*}} 'int'
180+
// CHECK: | |-TypedefDecl {{.*}} X 'U<int>'
181+
// CHECK: | | `-RecordType {{.*}} 'U<int>' canonical
182+
// CHECK: | | `-CXXRecord {{.*}} 'U<int>'
154183
// CHECK: | |-FieldDecl {{.*}} I 'int'
155184
// CHECK: | `-FieldDecl {{.*}} J 'int'

0 commit comments

Comments
 (0)