[Lldb-commits] [lldb] [lldb][NativePDB] Use decl context from a method's class (PR #199221)

via lldb-commits lldb-commits at lists.llvm.org
Thu May 28 02:11:26 PDT 2026


https://github.com/Nerixyz updated https://github.com/llvm/llvm-project/pull/199221

>From 735985fc154ca5b24e653ed29ee4f231f5da8f0f Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Fri, 22 May 2026 15:15:51 +0200
Subject: [PATCH 1/3] [lldb][NativePDB] Use decl context from method's class

---
 .../NativePDB/PdbAstBuilderClang.cpp          | 76 ++++++++++++++++++-
 .../SymbolFile/NativePDB/PdbAstBuilderClang.h |  3 +
 .../Plugins/SymbolFile/NativePDB/PdbUtil.cpp  | 26 +++++++
 .../Plugins/SymbolFile/NativePDB/PdbUtil.h    |  2 +
 .../SymbolFile/NativePDB/ast-lambdas-msvc.cpp | 46 +++++++++++
 .../SymbolFile/NativePDB/ast-lambdas.cpp      | 45 +++++++++++
 6 files changed, 196 insertions(+), 2 deletions(-)
 create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp
 create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp

diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
index e70e69f5f697d..d316b1e3cabf6 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
@@ -360,6 +360,79 @@ PdbAstBuilderClang::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
   return {context, std::string(uname)};
 }
 
+std::pair<clang::DeclContext *, std::string>
+PdbAstBuilderClang::CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid) {
+  SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
+      m_clang.GetSymbolFile()->GetBackingSymbolFile());
+  PdbIndex &index = pdb->GetIndex();
+  CVSymbol sym = index.ReadSymbolRecord(uid);
+
+  llvm::StringRef symbol_name = getSymbolName(sym);
+
+  std::optional<PdbTypeSymId> func_id = GetFunctionType(sym);
+  if (!func_id || !symbol_name.contains("::"))
+    return CreateDeclInfoForUndecoratedName(symbol_name);
+
+  // Try to get the context from class type of an LF_MFUNCTION.
+  // For some types, we might not find a class type.
+  auto get_member_fn_context = [&]() -> clang::DeclContext * {
+    TypeIndex id = func_id->index;
+
+    if (func_id->is_ipi) {
+      // Type from IPI, for example from S_INLINESITE
+      std::optional<CVType> func_id_type =
+          index.ipi().tryGetType(func_id->index);
+      if (!func_id_type || func_id_type->kind() != LF_MFUNC_ID)
+        return nullptr;
+
+      MemberFuncIdRecord record;
+      llvm::Error err = TypeDeserializer::deserializeAs<MemberFuncIdRecord>(
+          *func_id_type, record);
+      if (err) {
+        llvm::consumeError(std::move(err));
+        return nullptr;
+      }
+
+      id = record.FunctionType;
+    }
+
+    std::optional<CVType> func_type = index.tpi().tryGetType(id);
+    if (!func_type || func_type->kind() != LF_MFUNCTION)
+      return nullptr;
+
+    MemberFunctionRecord mfr(TypeRecordKind::MemberFunction);
+
+    llvm::Error err =
+        TypeDeserializer::deserializeAs<MemberFunctionRecord>(*func_type, mfr);
+    if (err || mfr.ClassType.isNoneType()) {
+      llvm::consumeError(std::move(err));
+      return nullptr;
+    }
+
+    clang::QualType qt = GetOrCreateClangType(mfr.ClassType);
+    if (qt.isNull())
+      return nullptr;
+    clang::TagDecl *tag = qt->getAsTagDecl();
+    if (!tag)
+      return nullptr;
+
+    return clang::TagDecl::castToDeclContext(tag);
+  };
+
+  clang::DeclContext *context = get_member_fn_context();
+  if (!context)
+    return CreateDeclInfoForUndecoratedName(symbol_name);
+
+  MSVCUndecoratedNameParser parser(symbol_name);
+  llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specifiers =
+      parser.GetSpecifiers();
+  if (specifiers.size() < 2) {
+    assert(false && "Member function name with less than two scopes");
+    return CreateDeclInfoForUndecoratedName(symbol_name);
+  }
+  return {context, std::string(specifiers.back().GetFullName())};
+}
+
 clang::DeclContext *
 PdbAstBuilderClang::GetParentClangDeclContext(PdbSymUid uid) {
   // We must do this *without* calling GetOrCreate on the current uid, as
@@ -374,8 +447,7 @@ PdbAstBuilderClang::GetParentClangDeclContext(PdbSymUid uid) {
     if (scope)
       return GetOrCreateClangDeclContextForUid(*scope);
 
-    CVSymbol sym = index.ReadSymbolRecord(uid.asCompilandSym());
-    return CreateDeclInfoForUndecoratedName(getSymbolName(sym)).first;
+    return CreateDeclInfoForCompilandSymbol(uid.asCompilandSym()).first;
   }
   case PdbSymUidKind::Type: {
     // It could be a namespace, class, or global.  We don't support nested
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h
index fb338e5f8244e..486fd6b5a23ca 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h
@@ -150,6 +150,9 @@ class PdbAstBuilderClang : public PdbAstBuilder {
   CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti);
   std::pair<clang::DeclContext *, std::string>
   CreateDeclInfoForUndecoratedName(llvm::StringRef uname);
+  std::pair<clang::DeclContext *, std::string>
+  CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid);
+
   clang::QualType CreateSimpleType(TypeIndex ti);
 
   TypeSystemClang &m_clang;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index 5860d90eca689..bd6b19eea6ff3 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -1194,3 +1194,29 @@ size_t lldb_private::npdb::GetSizeOfType(PdbTypeSymId id,
   }
   return 0;
 }
+
+std::optional<PdbTypeSymId>
+lldb_private::npdb::GetFunctionType(llvm::codeview::CVSymbol symbol) {
+  switch (symbol.kind()) {
+  case SymbolKind::S_GPROC32:
+  case SymbolKind::S_LPROC32:
+  case SymbolKind::S_LPROC32_ID:
+  case SymbolKind::S_GPROC32_ID: {
+    ProcSym reg(SymbolRecordKind::ProcSym);
+    llvm::Error err = SymbolDeserializer::deserializeAs<ProcSym>(symbol, reg);
+    if (err)
+      return std::nullopt;
+    return PdbTypeSymId(reg.FunctionType, /*is_ipi=*/false);
+  }
+  case SymbolKind::S_INLINESITE: {
+    InlineSiteSym reg(SymbolRecordKind::InlineesSym);
+    llvm::Error err =
+        SymbolDeserializer::deserializeAs<InlineSiteSym>(symbol, reg);
+    if (err)
+      return std::nullopt;
+    return PdbTypeSymId(reg.Inlinee, /*is_ipi=*/true);
+  }
+  default:
+    return std::nullopt;
+  }
+}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
index 36e075b04f26f..bfe82db208b91 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -161,6 +161,8 @@ PdbTypeSymId GetBestPossibleDecl(PdbTypeSymId id, llvm::pdb::TpiStream &tpi);
 
 size_t GetSizeOfType(PdbTypeSymId id, llvm::pdb::TpiStream &tpi);
 
+std::optional<PdbTypeSymId> GetFunctionType(llvm::codeview::CVSymbol symbol);
+
 } // namespace npdb
 } // namespace lldb_private
 
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp
new file mode 100644
index 0000000000000..4b9b7b058d495
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp
@@ -0,0 +1,46 @@
+// clang-format off
+// REQUIRES: msvc
+
+// RUN: %build --compiler=msvc --nodefaultlib --std c++20 -o %t.exe -- %s
+// RUN: lldb-test symbols --dump-ast %t.exe | FileCheck %s
+
+class Foo {
+public:
+  void fun() {
+    auto f = [this]() {
+      int c = a;
+      int d = b;
+      return a + b;
+    };
+    f();
+    int local = 42;
+    auto g = [=]() mutable {
+      return local + 1;
+    };
+    g();
+  }
+
+private:
+  int a = 1;
+  int b = 2;
+};
+
+int main() {
+  Foo f;
+  f.fun();
+  return 0;
+}
+
+// CHECK:      namespace `public: void __cdecl Foo::fun(void)'::`{{.*}}' {
+// CHECK-NEXT:     class <lambda_1> {
+// CHECK:              int `Foo::fun'::`{{.*}}'::<lambda_1>::operator()() const;
+// CHECK:              int operator()() const;
+// CHECK:              Foo *__this;
+// CHECK-NEXT:     };
+// CHECK-NEXT:     class <lambda_2> {
+// CHECK:              int `Foo::fun'::`{{.*}}'::<lambda_2>::operator()();
+// CHECK:              int operator()();
+// CHECK:              int local;
+// CHECK-NEXT:     };
+// CHECK-NEXT: }
+
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp
new file mode 100644
index 0000000000000..833b92d668213
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp
@@ -0,0 +1,45 @@
+// clang-format off
+// REQUIRES: lld, x86
+
+// RUN: %clang_cl --target=x86_64-windows-msvc -Od -GS- -std:c++20 -Z7 -c /Fo%t.obj -- %s
+// RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe -pdb:%t.pdb
+// RUN: lldb-test symbols --dump-ast %t.exe | FileCheck %s
+
+class Foo {
+public:
+  void fun() {
+    auto f = [this]() {
+      int c = a;
+      int d = b;
+      return a + b;
+    };
+    f();
+    int local = 42;
+    auto g = [=]() mutable {
+      return local + 1;
+    };
+    g();
+  }
+
+private:
+  int a = 1;
+  int b = 2;
+};
+
+int main() {
+  Foo f;
+  f.fun();
+  return 0;
+}
+
+// CHECK:      namespace `public: void __cdecl Foo::fun(void)'::`1' {
+// CHECK-NEXT:     class <lambda_1> {
+// CHECK-NEXT:         int Foo::fun::<lambda_1>::operator()() const;
+// CHECK-NEXT:         Foo *__this;
+// CHECK-NEXT:     };
+// CHECK-NEXT:     class <lambda_2> {
+// CHECK-NEXT:         int Foo::fun::<lambda_2>::operator()();
+// CHECK-NEXT:         int local;
+// CHECK-NEXT:     };
+// CHECK-NEXT: }
+

>From 22a6e5c2121932247fa60cba1688c69d4f2289a3 Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 28 May 2026 10:30:43 +0200
Subject: [PATCH 2/3] refactor: Only get the decl context

---
 .../NativePDB/PdbAstBuilderClang.cpp          | 22 +++++++------------
 .../SymbolFile/NativePDB/PdbAstBuilderClang.h |  5 +++--
 2 files changed, 11 insertions(+), 16 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
index d316b1e3cabf6..aecfa6e2d0f09 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
@@ -360,8 +360,9 @@ PdbAstBuilderClang::CreateDeclInfoForUndecoratedName(llvm::StringRef name) {
   return {context, std::string(uname)};
 }
 
-std::pair<clang::DeclContext *, std::string>
-PdbAstBuilderClang::CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid) {
+clang::DeclContext *
+PdbAstBuilderClang::GetOrCreateDeclContextForCompilandSymbol(
+    PdbCompilandSymId uid) {
   SymbolFileNativePDB *pdb = static_cast<SymbolFileNativePDB *>(
       m_clang.GetSymbolFile()->GetBackingSymbolFile());
   PdbIndex &index = pdb->GetIndex();
@@ -371,7 +372,7 @@ PdbAstBuilderClang::CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid) {
 
   std::optional<PdbTypeSymId> func_id = GetFunctionType(sym);
   if (!func_id || !symbol_name.contains("::"))
-    return CreateDeclInfoForUndecoratedName(symbol_name);
+    return CreateDeclInfoForUndecoratedName(symbol_name).first;
 
   // Try to get the context from class type of an LF_MFUNCTION.
   // For some types, we might not find a class type.
@@ -421,16 +422,9 @@ PdbAstBuilderClang::CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid) {
 
   clang::DeclContext *context = get_member_fn_context();
   if (!context)
-    return CreateDeclInfoForUndecoratedName(symbol_name);
-
-  MSVCUndecoratedNameParser parser(symbol_name);
-  llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specifiers =
-      parser.GetSpecifiers();
-  if (specifiers.size() < 2) {
-    assert(false && "Member function name with less than two scopes");
-    return CreateDeclInfoForUndecoratedName(symbol_name);
-  }
-  return {context, std::string(specifiers.back().GetFullName())};
+    return CreateDeclInfoForUndecoratedName(symbol_name).first;
+
+  return context;
 }
 
 clang::DeclContext *
@@ -447,7 +441,7 @@ PdbAstBuilderClang::GetParentClangDeclContext(PdbSymUid uid) {
     if (scope)
       return GetOrCreateClangDeclContextForUid(*scope);
 
-    return CreateDeclInfoForCompilandSymbol(uid.asCompilandSym()).first;
+    return GetOrCreateDeclContextForCompilandSymbol(uid.asCompilandSym());
   }
   case PdbSymUidKind::Type: {
     // It could be a namespace, class, or global.  We don't support nested
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h
index 486fd6b5a23ca..0d214cb57f820 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.h
@@ -150,8 +150,9 @@ class PdbAstBuilderClang : public PdbAstBuilder {
   CreateDeclInfoForType(const llvm::codeview::TagRecord &record, TypeIndex ti);
   std::pair<clang::DeclContext *, std::string>
   CreateDeclInfoForUndecoratedName(llvm::StringRef uname);
-  std::pair<clang::DeclContext *, std::string>
-  CreateDeclInfoForCompilandSymbol(PdbCompilandSymId uid);
+
+  clang::DeclContext *
+  GetOrCreateDeclContextForCompilandSymbol(PdbCompilandSymId uid);
 
   clang::QualType CreateSimpleType(TypeIndex ti);
 

>From 26b0b7406a15fcff210631e40d9871f0ddfe583b Mon Sep 17 00:00:00 2001
From: Nerixyz <nerixdev at outlook.de>
Date: Thu, 28 May 2026 11:07:01 +0200
Subject: [PATCH 3/3] fix: Use basename if the context name doesn't match

---
 .../SymbolFile/NativePDB/PdbAstBuilderClang.cpp       | 11 +++++++++--
 .../Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp   |  2 --
 lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp  |  4 ++--
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
index aecfa6e2d0f09..83b937f92eeec 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilderClang.cpp
@@ -1152,8 +1152,15 @@ PdbAstBuilderClang::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) {
   CompilerType func_ct = ToCompilerType(qt);
 
   llvm::StringRef proc_name = proc.Name;
-  proc_name.consume_front(context_name);
-  proc_name.consume_front("::");
+  if (!context_name.empty() && !(proc_name.consume_front(context_name) &&
+                                 proc_name.consume_front("::"))) {
+    // If we have some context, but the function name doesn't start with it, use
+    // the basename.
+    MSVCUndecoratedNameParser parser(proc.Name);
+    llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs(parser.GetSpecifiers());
+    if (!specs.empty())
+      proc_name = specs.back().GetBaseName();
+  }
   clang::FunctionDecl *function_decl =
       CreateFunctionDecl(func_id, proc_name, proc.FunctionType, func_ct,
                          func_type->getNumParams(), storage, false, parent);
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp
index 4b9b7b058d495..d38cdcf22f4df 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas-msvc.cpp
@@ -33,12 +33,10 @@ int main() {
 
 // CHECK:      namespace `public: void __cdecl Foo::fun(void)'::`{{.*}}' {
 // CHECK-NEXT:     class <lambda_1> {
-// CHECK:              int `Foo::fun'::`{{.*}}'::<lambda_1>::operator()() const;
 // CHECK:              int operator()() const;
 // CHECK:              Foo *__this;
 // CHECK-NEXT:     };
 // CHECK-NEXT:     class <lambda_2> {
-// CHECK:              int `Foo::fun'::`{{.*}}'::<lambda_2>::operator()();
 // CHECK:              int operator()();
 // CHECK:              int local;
 // CHECK-NEXT:     };
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp
index 833b92d668213..78f9856f44559 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-lambdas.cpp
@@ -34,11 +34,11 @@ int main() {
 
 // CHECK:      namespace `public: void __cdecl Foo::fun(void)'::`1' {
 // CHECK-NEXT:     class <lambda_1> {
-// CHECK-NEXT:         int Foo::fun::<lambda_1>::operator()() const;
+// CHECK-NEXT:         int operator()() const;
 // CHECK-NEXT:         Foo *__this;
 // CHECK-NEXT:     };
 // CHECK-NEXT:     class <lambda_2> {
-// CHECK-NEXT:         int Foo::fun::<lambda_2>::operator()();
+// CHECK-NEXT:         int operator()();
 // CHECK-NEXT:         int local;
 // CHECK-NEXT:     };
 // CHECK-NEXT: }



More information about the lldb-commits mailing list