diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -1014,8 +1014,87 @@ proc_name.consume_front(context_name); proc_name.consume_front("::"); - clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( - parent, OptionalClangModuleID(), proc_name, func_ct, storage, false); + clang::FunctionDecl *function_decl = nullptr; + if (parent->isRecord()) { + struct ProcessOneMethodRecord : public TypeVisitorCallbacks { + ProcessOneMethodRecord(TypeSystemClang &m_clang, + clang::FunctionDecl *&function_decl, + lldb::opaque_compiler_type_t parent_ty, + llvm::StringRef proc_name, CompilerType func_ct) + : m_clang(m_clang), function_decl(function_decl), + parent_ty(parent_ty), proc_name(proc_name), func_ct(func_ct) {} + TypeSystemClang &m_clang; + clang::FunctionDecl *&function_decl; + lldb::opaque_compiler_type_t parent_ty; + llvm::StringRef proc_name; + CompilerType func_ct; + + llvm::Error visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Record) override { + if (Record.getName() != proc_name) { + return llvm::Error::success(); + } + lldb::AccessType access = TranslateMemberAccess(Record.getAccess()); + bool is_virtual = Record.Attrs.isVirtual(); + bool is_static = Record.Attrs.isStatic(); + bool is_artificial = + (Record.getOptions() & MethodOptions::CompilerGenerated) == + MethodOptions::CompilerGenerated; + function_decl = m_clang.AddMethodToCXXRecordType( + parent_ty, proc_name, + /*mangled_name=*/nullptr, func_ct, /*access=*/access, + /*is_virtual=*/is_virtual, /*is_static=*/is_static, + /*is_inline=*/false, /*is_explicit=*/false, + /*is_attr_used=*/false, /*is_artificial=*/is_artificial); + return llvm::Error::success(); + } + }; + + clang::QualType parent_qt = llvm::dyn_cast(parent) + ->getTypeForDecl() + ->getCanonicalTypeInternal(); + lldb::opaque_compiler_type_t parent_opaque_ty = + ToCompilerType(parent_qt).GetOpaqueQualType(); + + CVType cvt = m_index.tpi().getType(type_id.index); + MemberFunctionRecord func_record(static_cast(cvt.kind())); + llvm::cantFail(TypeDeserializer::deserializeAs( + cvt, func_record)); + TypeIndex class_index = func_record.getClassType(); + CVType parent_cvt = m_index.tpi().getType(class_index); + ClassRecord class_record = CVTagRecord::create(parent_cvt).asClass(); + // If it's a forward reference, try to get the real TypeIndex. + if (class_record.isForwardRef()) { + llvm::Expected eti = + m_index.tpi().findFullDeclForForwardRef(class_index); + if (eti) { + class_record = + CVTagRecord::create(m_index.tpi().getType(*eti)).asClass(); + } + } + if (!class_record.FieldList.isSimple()) { + CVType field_list = m_index.tpi().getType(class_record.FieldList); + ProcessOneMethodRecord process(m_clang, function_decl, parent_opaque_ty, + proc_name, func_ct); + if (llvm::Error err = visitMemberRecordStream(field_list.data(), process)) + llvm::consumeError(std::move(err)); + } + + if (!function_decl) { + function_decl = m_clang.AddMethodToCXXRecordType( + parent_opaque_ty, proc_name, + /*mangled_name=*/nullptr, func_ct, + /*access=*/lldb::AccessType::eAccessPublic, + /*is_virtual=*/false, /*is_static=*/false, + /*is_inline=*/false, /*is_explicit=*/false, + /*is_attr_used=*/false, /*is_artificial=*/false); + } + } else { + function_decl = m_clang.CreateFunctionDeclaration( + parent, OptionalClangModuleID(), proc_name, func_ct, storage, false); + CreateFunctionParameters(func_id, *function_decl, + func_type->getNumParams()); + } lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; @@ -1024,8 +1103,6 @@ status.uid = toOpaqueUid(func_id); m_decl_to_status.insert({function_decl, status}); - CreateFunctionParameters(func_id, *function_decl, func_type->getNumParams()); - return function_decl; } diff --git a/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp b/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp --- a/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp +++ b/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp @@ -1,7 +1,7 @@ // clang-format off // REQUIRES: lld, x86 -// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -c /Fo%t.obj -- %s +// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -c /GR- /Fo%t.obj -- %s // RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb // RUN: lldb-test symbols --find=function --name=main --function-flags=full %t.exe \ @@ -13,6 +13,44 @@ // RUN: lldb-test symbols --find=function --name=varargs_fn --function-flags=full %t.exe \ // RUN: | FileCheck %s --check-prefix=FIND-VAR +// RUN: lldb-test symbols --find=function --name=Struct::simple_method --function-flags=full %t.exe \ +// RUN: | FileCheck %s --check-prefix=FIND-SIMPLE + +// RUN: lldb-test symbols --find=function --name=Struct::virtual_method --function-flags=full %t.exe \ +// RUN: | FileCheck %s --check-prefix=FIND-VIRTUAL + +// RUN: lldb-test symbols --find=function --name=Struct::static_method --function-flags=full %t.exe \ +// RUN: | FileCheck %s --check-prefix=FIND-STATIC-METHOD + +// RUN: lldb-test symbols --find=function --name=Struct::overloaded_method --function-flags=full %t.exe \ +// RUN: | FileCheck %s --check-prefix=FIND-OVERLOAD + +struct Struct { + int simple_method() { + return 1; + } + + virtual int virtual_method() { + return 2; + } + + static int static_method() { + return 3; + } + + int overloaded_method() { + return 4; + } + int overloaded_method(char c) { + return 5; + } + int overloaded_method(char c, int i, ...) { + return 6; + } +}; + +Struct s; + static int static_fn() { return 42; } @@ -22,7 +60,9 @@ } int main(int argc, char **argv) { - return static_fn() + varargs_fn(argc, argc); + return static_fn() + varargs_fn(argc, argc) + s.simple_method() + + Struct::static_method() + s.virtual_method() + s.overloaded_method() + + s.overloaded_method('c') + s.overloaded_method('a', 1); } // FIND-MAIN: Function: id = {{.*}}, name = "main" @@ -33,3 +73,17 @@ // FIND-VAR: Function: id = {{.*}}, name = "varargs_fn" // FIND-VAR-NEXT: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (int, int, ...)" + +// FIND-SIMPLE: Function: id = {{.*}}, name = "Struct::simple_method" +// FIND-SIMPLE-NEXT: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (void)" + +// FIND-VIRTUAL: Function: id = {{.*}}, name = "Struct::virtual_method" +// FIND-VIRTUAL-NEXT: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (void)" + +// FIND-STATIC-METHOD: Function: id = {{.*}}, name = "Struct::static_method" +// FIND-STATIC-METHOD-NEXT: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (void)" + +// FIND-OVERLOAD: Function: id = {{.*}}, name = "Struct::overloaded_method" +// FIND-OVERLOAD: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (void)" +// FIND-OVERLOAD: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (char)" +// FIND-OVERLOAD: FuncType: id = {{.*}}, byte-size = 0, compiler_type = "int (char, int, ...)"