[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