zloyrobot created this revision.
zloyrobot added reviewers: amccarth, aleksandr.urakov, stella.stamenova.
zloyrobot added a project: LLDB.
Herald added subscribers: lldb-commits, teemperor.

This path implements member function support in 
PdbAstBuilder::GetOrCreateFunctionDecl. It allows to lookup and evaluate struct 
fields inside struct members


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D61886

Files:
  lldb/lit/SymbolFile/NativePDB/Inputs/struct-fields.lldbinit
  lldb/lit/SymbolFile/NativePDB/struct-fields.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h

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<clang::FunctionDecl>(decl);
 
-  clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id));
-  std::string context_name;
-  if (clang::NamespaceDecl *ns = llvm::dyn_cast<clang::NamespaceDecl>(parent)) {
-    context_name = ns->getQualifiedNameAsString();
-  } else if (clang::TagDecl *tag = llvm::dyn_cast<clang::TagDecl>(parent)) {
-    context_name = tag->getQualifiedNameAsString();
-  }
-
   CVSymbol cvs = m_index.ReadSymbolRecord(func_id);
   ProcSym proc(static_cast<SymbolRecordKind>(cvs.kind()));
   llvm::cantFail(SymbolDeserializer::deserializeAs<ProcSym>(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<clang::FunctionProtoType>(qt);
+  clang::DeclContext *parent = GetParentDeclContext(PdbSymUid(func_id));
+  
+  llvm::StringRef proc_name = proc.Name;
+  if (clang::NamedDecl *ns = llvm::dyn_cast<clang::NamedDecl>(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<clang::CXXRecordDecl>(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<clang::FunctionProtoType>(qt)->getNumParams();
+  if (function_decl->param_empty() && num_params != 0)
+    CreateFunctionParameters(func_id, *function_decl, num_params);
 
   return function_decl;
 }
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<typename T>
+    int template_method(T t) {
+      return 0;
+    }  
+  };
+
+  template<typename U>
+  struct TemplateStruct {
+    int member = 5;
+    int method(int i...) {
+      return 0;
+    }
+    struct InnerStruct {
+      int member = 6;
+      int method(Struct s) {
+        return 0;
+      }
+    };
+    template<typename T>
+    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<int> nsts(1);
+  nsts.method(0);
+  ns::TemplateStruct<int>::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<const char *> at struct-fields.cpp:37
+// CHECK: (lldb) p member
+// CHECK-NEXT: (int) $4 = 3
+// CHECK:     frame #0: {{.*}} struct-fields.cpp.tmp.exe`ns::TemplateStruct<int>::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<int>::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<int>::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<int>::template_method<const char *> 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<int>::operator! at struct-fields.cpp:58
+// CHECK: (lldb) p member
+// CHECK-NEXT: (int) $10 = 5
+
+
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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to