[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