Index: lldb/lit/SymbolFile/NativePDB/Inputs/struct-fields.lldbinit =================================================================== --- /dev/null +++ lldb/lit/SymbolFile/NativePDB/Inputs/struct-fields.lldbinit @@ -0,0 +1,32 @@ +b struct-fields.cpp:13 +b struct-fields.cpp:18 +b struct-fields.cpp:27 +b struct-fields.cpp:32 +b struct-fields.cpp:37 +b struct-fields.cpp:45 +b struct-fields.cpp:50 +b struct-fields.cpp:55 +b struct-fields.cpp:58 +b struct-fields.cpp:61 +run +p member +c +p inner_member +c +p member +c +p inner_member +c +p member +c +p member +c +p member +c +p member +c +p member +p t +c +p member +quit Index: lldb/lit/SymbolFile/NativePDB/struct-fields.cpp =================================================================== --- /dev/null +++ lldb/lit/SymbolFile/NativePDB/struct-fields.cpp @@ -0,0 +1,118 @@ +// clang-format off + +// REQUIRES: lld +// RUN: %build --compiler=clang-cl --nodefaultlib -o %t.exe -- %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \ +// RUN: %p/Inputs/struct-fields.lldbinit 2>&1 | FileCheck %s + +extern "C" int _fltused=0; + +struct Struct { + int member = 1; + int method(int i) { + return 0; + } + struct InnerStruct { + int inner_member = 2; + int method(float f, int i) { + return 0; + } + }; +}; + +namespace ns { + struct NsStruct { + int member = 3; + int method(int i...) { + return 0; + } + struct InnerStruct { + int inner_member = 4; + int method(Struct s) { + return 0; + } + }; + template + int template_method(T t) { + return 0; + } + }; + + template + struct TemplateStruct { + int member = 5; + int method(int i...) { + return 0; + } + struct InnerStruct { + int member = 6; + int method(Struct s) { + return 0; + } + }; + template + int template_method(T t) { + return 0; + } + int operator!() { + return 0; + } + TemplateStruct(int i) { + return; + } + }; + +} + +int main(int argc, char **argv) { + Struct s; + s.method(0); + Struct::InnerStruct is; + is.method(0.f, 0); + ns::NsStruct nss; + nss.method(0); + ns::NsStruct::InnerStruct nsis; + nsis.method(s); + nss.template_method("dssds"); + ns::TemplateStruct nsts(1); + nsts.method(0); + ns::TemplateStruct::InnerStruct nstis; + nstis.method(s); + nsts.template_method("dssds"); + return !nsts; +} + +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`Struct::method at struct-fields.cpp:13 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $0 = 1 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`Struct::InnerStruct::method at struct-fields.cpp:18 +// CHECK: (lldb) p inner_member +// CHECK-NEXT: (int) $1 = 2 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::NsStruct::method at struct-fields.cpp:27 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $2 = 3 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::NsStruct::InnerStruct::method at struct-fields.cpp:32 +// CHECK: (lldb) p inner_member +// CHECK-NEXT: (int) $3 = 4 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::NsStruct::template_method at struct-fields.cpp:37 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $4 = 3 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::TemplateStruct::TemplateStruct at struct-fields.cpp:61 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $5 = 5 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::TemplateStruct::method at struct-fields.cpp:45 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $6 = 5 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::TemplateStruct::InnerStruct::method at struct-fields.cpp:50 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $7 = 6 +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::TemplateStruct::template_method at struct-fields.cpp:55 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $8 = 5 +// CHECK-NEXT: (lldb) p t +// CHECK-NEXT: (const char *) $9 = {{.*}} "dssds" +// CHECK: frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::TemplateStruct::operator! at struct-fields.cpp:58 +// CHECK: (lldb) p member +// CHECK-NEXT: (int) $10 = 5 + + Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -109,6 +109,9 @@ clang::VarDecl *CreateVariableDecl(PdbSymUid uid, llvm::codeview::CVSymbol sym, clang::DeclContext &scope); + clang::CXXMethodDecl* LookupOrCreateMethodDecl(clang::CXXRecordDecl* parent, + const llvm::codeview::ProcSym& method_sym, + llvm::StringRef proc_name); clang::DeclContext * GetParentDeclContextForSymbol(const llvm::codeview::CVSymbol &sym); Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -983,19 +983,39 @@ return qt; } +clang::CXXMethodDecl * +PdbAstBuilder::LookupOrCreateMethodDecl(clang::CXXRecordDecl* parent, + const ProcSym& method_sym, + llvm::StringRef proc_name) { + + PdbTypeSymId type_id(method_sym.FunctionType); + clang::QualType qt = GetOrCreateType(type_id); + if (qt.isNull()) + return nullptr; + + CompilerType parent_tag = m_clang.GetTypeForDecl(parent); + if (parent_tag.GetCompleteType()) { + for (clang::CXXMethodDecl *method : parent->methods()) { + if (method->getNameAsString() == proc_name && method->getType() == qt) + return method; + } + } + + PdbTypeSymId type = PdbTypeSymId(method_sym.FunctionType); + clang::QualType method_qt = GetOrCreateType(type); + CompleteType(method_qt); + + return clang().AddMethodToCXXRecordType(parent_tag.GetOpaqueQualType(), + proc_name.data(),nullptr, ToCompilerType(method_qt), + lldb::eAccessPublic,false,false,false, + false,false,false); +} + clang::FunctionDecl * PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { if (clang::Decl *decl = TryGetDecl(func_id)) return llvm::dyn_cast(decl); - clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id)); - std::string context_name; - if (clang::NamespaceDecl *ns = llvm::dyn_cast(parent)) { - context_name = ns->getQualifiedNameAsString(); - } else if (clang::TagDecl *tag = llvm::dyn_cast(parent)) { - context_name = tag->getQualifiedNameAsString(); - } - CVSymbol cvs = m_index.ReadSymbolRecord(func_id); ProcSym proc(static_cast(cvs.kind())); llvm::cantFail(SymbolDeserializer::deserializeAs(cvs, proc)); @@ -1005,21 +1025,27 @@ if (qt.isNull()) return nullptr; - clang::StorageClass storage = clang::SC_None; - if (proc.Kind == SymbolRecordKind::ProcSym) - storage = clang::SC_Static; - - const clang::FunctionProtoType *func_type = - llvm::dyn_cast(qt); + clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id)); + + llvm::StringRef proc_name = proc.Name; + if (clang::NamedDecl *ns = llvm::dyn_cast(parent)) { + proc_name.consume_front(ns->getQualifiedNameAsString()); + proc_name.consume_front("::"); + } - CompilerType func_ct = ToCompilerType(qt); + clang::FunctionDecl *function_decl = nullptr; + if (clang::CXXRecordDecl *tag = llvm::dyn_cast(parent)) + function_decl = LookupOrCreateMethodDecl(tag, proc, proc_name); - llvm::StringRef proc_name = proc.Name; - proc_name.consume_front(context_name); - proc_name.consume_front("::"); + if (function_decl == nullptr) { + clang::StorageClass storage = clang::SC_None; + if (proc.Kind == SymbolRecordKind::ProcSym) + storage = clang::SC_Static; - clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( + CompilerType func_ct = ToCompilerType(qt); + function_decl = m_clang.CreateFunctionDeclaration( parent, proc_name.str().c_str(), func_ct, storage, false); + } lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; @@ -1028,7 +1054,9 @@ status.uid = toOpaqueUid(func_id); m_decl_to_status.insert({function_decl, status}); - CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams()); + int num_params = llvm::dyn_cast(qt)->getNumParams(); + if (function_decl->param_empty() && num_params != 0) + CreateFunctionParameters(func_id, *function_decl, num_params); return function_decl; }