[Lldb-commits] [lldb] a3a8ed3 - [LLDB][NativePDB] Fix function decl creation for class methods
Zequan Wu via lldb-commits
lldb-commits at lists.llvm.org
Tue Dec 7 10:43:56 PST 2021
Author: Zequan Wu
Date: 2021-12-07T10:41:28-08:00
New Revision: a3a8ed33a1d6a5047aae29790e02f3c7955297af
URL: https://github.com/llvm/llvm-project/commit/a3a8ed33a1d6a5047aae29790e02f3c7955297af
DIFF: https://github.com/llvm/llvm-project/commit/a3a8ed33a1d6a5047aae29790e02f3c7955297af.diff
LOG: [LLDB][NativePDB] Fix function decl creation for class methods
This is a split of D113724. Calling `TypeSystemClang::AddMethodToCXXRecordType`
to create function decls for class methods.
Differential Revision: https://reviews.llvm.org/D113930
Added:
Modified:
lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
lldb/test/Shell/SymbolFile/NativePDB/ast-methods.cpp
lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp
Removed:
################################################################################
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index c29fc2230a674..7ce2f1451580f 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -30,6 +30,70 @@ using namespace lldb_private::npdb;
using namespace llvm::codeview;
using namespace llvm::pdb;
+namespace {
+struct CreateMethodDecl : public TypeVisitorCallbacks {
+ CreateMethodDecl(PdbIndex &m_index, TypeSystemClang &m_clang,
+ TypeIndex func_type_index,
+ 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), func_type_index(func_type_index),
+ function_decl(function_decl), parent_ty(parent_ty),
+ proc_name(proc_name), func_ct(func_ct) {}
+ PdbIndex &m_index;
+ TypeSystemClang &m_clang;
+ TypeIndex func_type_index;
+ 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<MethodOverloadListRecord>(
+ method_list_type, method_list));
+
+ for (const OneMethodRecord &method : method_list.Methods) {
+ if (method.getType().getIndex() == func_type_index.getIndex())
+ 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);
+ }
+};
+} // namespace
+
static llvm::Optional<PdbCompilandSymId> FindSymbolScope(PdbIndex &index,
PdbCompilandSymId id) {
CVSymbol sym = index.ReadSymbolRecord(id);
@@ -681,7 +745,8 @@ bool PdbAstBuilder::CompleteTagDecl(clang::TagDecl &tag) {
// Visit all members of this class, then perform any finalization necessary
// to complete the class.
CompilerType ct = ToCompilerType(tag_qt);
- UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index);
+ UdtRecordCompleter completer(best_ti, ct, tag, *this, m_index,
+ m_cxx_record_map);
auto error =
llvm::codeview::visitMemberRecordStream(field_list_cvt.data(), completer);
completer.complete();
@@ -1014,8 +1079,62 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
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()) {
+ clang::QualType parent_qt = llvm::dyn_cast<clang::TypeDecl>(parent)
+ ->getTypeForDecl()
+ ->getCanonicalTypeInternal();
+ lldb::opaque_compiler_type_t parent_opaque_ty =
+ ToCompilerType(parent_qt).GetOpaqueQualType();
+
+ auto iter = m_cxx_record_map.find(parent_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({proc_name, func_ct})) {
+ return nullptr;
+ }
+ }
+
+ CVType cvt = m_index.tpi().getType(type_id.index);
+ MemberFunctionRecord func_record(static_cast<TypeRecordKind>(cvt.kind()));
+ llvm::cantFail(TypeDeserializer::deserializeAs<MemberFunctionRecord>(
+ 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<TypeIndex> 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);
+ CreateMethodDecl process(m_index, m_clang, type_id.index, 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);
+ }
+
+ m_cxx_record_map[parent_opaque_ty].insert({proc_name, func_ct});
+ } 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 +1143,6 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
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/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
index 7bb2584d19a36..73accf5e5e681 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -137,6 +137,12 @@ class PdbAstBuilder {
llvm::DenseMap<clang::Decl *, DeclStatus> m_decl_to_status;
llvm::DenseMap<lldb::user_id_t, clang::Decl *> m_uid_to_decl;
llvm::DenseMap<lldb::user_id_t, clang::QualType> m_uid_to_type;
+
+ // From class/struct's opaque_compiler_type_t to a set containing the pairs of
+ // method's name and CompilerType.
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ m_cxx_record_map;
};
} // namespace npdb
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
index c8fb46c750342..d0b27bc5bf79a 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp
@@ -28,13 +28,15 @@ using namespace lldb_private::npdb;
using Error = llvm::Error;
-UdtRecordCompleter::UdtRecordCompleter(PdbTypeSymId id,
- CompilerType &derived_ct,
- clang::TagDecl &tag_decl,
- PdbAstBuilder &ast_builder,
- PdbIndex &index)
+UdtRecordCompleter::UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &cxx_record_map)
: m_id(id), m_derived_ct(derived_ct), m_tag_decl(tag_decl),
- m_ast_builder(ast_builder), m_index(index) {
+ m_ast_builder(ast_builder), m_index(index),
+ m_cxx_record_map(cxx_record_map) {
CVType cvt = m_index.tpi().getType(m_id.index);
switch (cvt.kind()) {
case LF_ENUM:
@@ -78,14 +80,24 @@ void UdtRecordCompleter::AddMethod(llvm::StringRef name, TypeIndex type_idx,
clang::QualType method_qt =
m_ast_builder.GetOrCreateType(PdbTypeSymId(type_idx));
m_ast_builder.CompleteType(method_qt);
+ CompilerType method_ct = m_ast_builder.ToCompilerType(method_qt);
+ lldb::opaque_compiler_type_t derived_opaque_ty = m_derived_ct.GetOpaqueQualType();
+ auto iter = m_cxx_record_map.find(derived_opaque_ty);
+ if (iter != m_cxx_record_map.end()) {
+ if (iter->getSecond().contains({name, method_ct})) {
+ return;
+ }
+ }
lldb::AccessType access_type = TranslateMemberAccess(access);
bool is_artificial = (options & MethodOptions::CompilerGenerated) ==
MethodOptions::CompilerGenerated;
m_ast_builder.clang().AddMethodToCXXRecordType(
- m_derived_ct.GetOpaqueQualType(), name.data(), nullptr,
- m_ast_builder.ToCompilerType(method_qt), access_type, attrs.isVirtual(),
- attrs.isStatic(), false, false, false, is_artificial);
+ derived_opaque_ty, name.data(), nullptr, method_ct,
+ access_type, attrs.isVirtual(), attrs.isStatic(), false, false, false,
+ is_artificial);
+
+ m_cxx_record_map[derived_opaque_ty].insert({name, method_ct});
}
Error UdtRecordCompleter::visitKnownMember(CVMemberRecord &cvr,
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
index ae7e47c82fe55..9c6b5ed28bc28 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h
@@ -54,11 +54,17 @@ class UdtRecordCompleter : public llvm::codeview::TypeVisitorCallbacks {
PdbIndex &m_index;
std::vector<IndexedBase> m_bases;
ClangASTImporter::LayoutInfo m_layout;
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
+ &m_cxx_record_map;
public:
- UdtRecordCompleter(PdbTypeSymId id, CompilerType &derived_ct,
- clang::TagDecl &tag_decl, PdbAstBuilder &ast_builder,
- PdbIndex &index);
+ UdtRecordCompleter(
+ PdbTypeSymId id, CompilerType &derived_ct, clang::TagDecl &tag_decl,
+ PdbAstBuilder &ast_builder, PdbIndex &index,
+ llvm::DenseMap<lldb::opaque_compiler_type_t,
+ llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>,
+ 8>> &cxx_record_map);
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
llvm::Error visitKnownMember(llvm::codeview::CVMemberRecord &CVR, \
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-methods.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-methods.cpp
index fb1c8e116af41..f2be33aae8163 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/ast-methods.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-methods.cpp
@@ -4,7 +4,9 @@
// RUN: %clang_cl --target=x86_64-windows-msvc -Od -Z7 -GR- -c /Fo%t.obj -- %s
// RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb
// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
-// RUN: %p/Inputs/ast-methods.lldbinit 2>&1 | FileCheck %s
+// RUN: %p/Inputs/ast-methods.lldbinit 2>&1 | FileCheck %s --check-prefix=AST
+
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb-test symbols --dump-ast %t.exe | FileCheck %s --check-prefix=SYMBOL
struct Struct {
void simple_method() {}
@@ -21,17 +23,33 @@ struct Struct {
Struct s;
int main(int argc, char **argv) {
+ s.simple_method();
+ s.static_method();
+ s.virtual_method();
+ s.overloaded_method();
+ s.overloaded_method('a');
+ s.overloaded_method('a', 1);
return 0;
}
-// CHECK: TranslationUnitDecl
-// CHECK: |-CXXRecordDecl {{.*}} struct Struct definition
-// CHECK: | |-CXXMethodDecl {{.*}} simple_method 'void (){{.*}}'
-// CHECK: | |-CXXMethodDecl {{.*}} virtual_method 'void (){{.*}}' virtual
-// CHECK: | |-CXXMethodDecl {{.*}} static_method 'void ()' static
-// CHECK: | |-CXXMethodDecl {{.*}} overloaded_method 'int (){{.*}}'
-// CHECK: | |-CXXMethodDecl {{.*}} overloaded_method 'int (char){{.*}}'
-// CHECK: | | `-ParmVarDecl {{.*}} 'char'
-// CHECK: | `-CXXMethodDecl {{.*}} overloaded_method 'int (char, int, ...)'
-// CHECK: | |-ParmVarDecl {{.*}} 'char'
-// CHECK: | `-ParmVarDecl {{.*}} 'int'
+// AST: TranslationUnitDecl
+// AST: |-CXXRecordDecl {{.*}} struct Struct definition
+// AST: | |-CXXMethodDecl {{.*}} simple_method 'void (){{.*}}'
+// AST: | |-CXXMethodDecl {{.*}} virtual_method 'void (){{.*}}' virtual
+// AST: | |-CXXMethodDecl {{.*}} static_method 'void ()' static
+// AST: | |-CXXMethodDecl {{.*}} overloaded_method 'int (){{.*}}'
+// AST: | |-CXXMethodDecl {{.*}} overloaded_method 'int (char){{.*}}'
+// AST: | | `-ParmVarDecl {{.*}} 'char'
+// AST: | `-CXXMethodDecl {{.*}} overloaded_method 'int (char, int, ...)'
+// AST: | |-ParmVarDecl {{.*}} 'char'
+// AST: | `-ParmVarDecl {{.*}} 'int'
+
+// SYMBOL: int main(int argc, char **argv);
+// SYMBOL-NEXT: struct Struct {
+// SYMBOL-NEXT: void simple_method();
+// SYMBOL-NEXT: static void static_method();
+// SYMBOL-NEXT: virtual void virtual_method();
+// SYMBOL-NEXT: int overloaded_method();
+// SYMBOL-NEXT: int overloaded_method(char);
+// SYMBOL-NEXT: int overloaded_method(char, int, ...);
+// SYMBOL-NEXT: };
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp b/lldb/test/Shell/SymbolFile/NativePDB/find-functions.cpp
index 5c2332bea66cf..5ebef61bdbfef 100644
--- 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 varargs_fn(int x, int y, ...) {
}
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 @@ int main(int argc, char **argv) {
// 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, ...)"
More information about the lldb-commits
mailing list