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,112 @@ 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(PdbIndex &m_index, TypeSystemClang &m_clang, + clang::FunctionDecl *&function_decl, + lldb::opaque_compiler_type_t parent_ty, + llvm::StringRef proc_name, CompilerType func_ct) + : m_index(m_index), m_clang(m_clang), function_decl(function_decl), + parent_ty(parent_ty), proc_name(proc_name), func_ct(func_ct) {} + PdbIndex &m_index; + 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, + OverloadedMethodRecord &overloaded) override { + TypeIndex method_list_idx = overloaded.MethodList; + + CVType method_list_type = m_index.tpi().getType(method_list_idx); + assert(method_list_type.kind() == LF_METHODLIST); + + MethodOverloadListRecord method_list; + llvm::cantFail( + TypeDeserializer::deserializeAs( + method_list_type, method_list)); + + for (const OneMethodRecord &method : method_list.Methods) + AddMethod(overloaded.Name, method.getAccess(), method.getOptions(), + method.Attrs); + + return llvm::Error::success(); + } + + llvm::Error visitKnownMember(CVMemberRecord &cvr, + OneMethodRecord &Record) override { + AddMethod(Record.getName(), Record.getAccess(), Record.getOptions(), + Record.Attrs); + return llvm::Error::success(); + } + + void AddMethod(llvm::StringRef name, MemberAccess access, + MethodOptions options, MemberAttributes attrs) { + if (name != proc_name || function_decl) + return; + lldb::AccessType access_type = TranslateMemberAccess(access); + bool is_virtual = attrs.isVirtual(); + bool is_static = attrs.isStatic(); + bool is_artificial = (options & MethodOptions::CompilerGenerated) == + MethodOptions::CompilerGenerated; + function_decl = m_clang.AddMethodToCXXRecordType( + parent_ty, proc_name, + /*mangled_name=*/nullptr, func_ct, /*access=*/access_type, + /*is_virtual=*/is_virtual, /*is_static=*/is_static, + /*is_inline=*/false, /*is_explicit=*/false, + /*is_attr_used=*/false, /*is_artificial=*/is_artificial); + } + }; + + 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_index, 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 +1128,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,46 @@ // 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 + overloaded_method('a') + overloaded_method('a', 1); + } +protected: + virtual int overloaded_method(char c) { + return 5; + } +private: + static int overloaded_method(char c, int i, ...) { + return 6; + } +}; + +Struct s; + static int static_fn() { return 42; } @@ -22,7 +62,8 @@ } 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(); } // FIND-MAIN: Function: id = {{.*}}, name = "main" @@ -33,3 +74,17 @@ // FIND-VAR: Function: id = {{.*}}, name = "{{.*}}varargs_fn{{.*}}" // FIND-VAR-NEXT: FuncType: id = {{.*}}, compiler_type = "int (int, int, ...)" + +// FIND-SIMPLE: Function: id = {{.*}}, name = "{{.*}}Struct::simple_method{{.*}}" +// FIND-SIMPLE-NEXT: FuncType: id = {{.*}}, compiler_type = "int (void)" + +// FIND-VIRTUAL: Function: id = {{.*}}, name = "{{.*}}Struct::virtual_method{{.*}}" +// FIND-VIRTUAL-NEXT: FuncType: id = {{.*}}, compiler_type = "int (void)" + +// FIND-STATIC-METHOD: Function: id = {{.*}}, name = "{{.*}}Struct::static_method{{.*}}" +// FIND-STATIC-METHOD-NEXT: FuncType: id = {{.*}}, compiler_type = "int (void)" + +// FIND-OVERLOAD: Function: id = {{.*}}, name = "{{.*}}Struct::overloaded_method{{.*}}" +// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (void)" +// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (char)" +// FIND-OVERLOAD: FuncType: id = {{.*}}, compiler_type = "int (char, int, ...)"