[Lldb-commits] [lldb] [lldb][NativePDB] Find namespaces that only contain typedefs (PR #233460)

Charles Zablit via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 30 12:02:08 PDT 2026


https://github.com/charles-zablit updated https://github.com/llvm/llvm-project/pull/233460

>From 04cf7dc3d65036223aa9c5e520d9bc9c60a592b0 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Mon, 19 Oct 2026 17:20:03 +0200
Subject: [PATCH 1/3] [lldb][NativePDB] Find namespaces that only contain
 typedefs

---
 .../NativePDB/SymbolFileNativePDB.cpp         | 25 +++++++++++
 .../NativePDB/SymbolFileNativePDB.h           |  3 ++
 .../SymbolFile/NativePDB/typedef-lookup.test  | 44 +++++++++++++++++++
 3 files changed, 72 insertions(+)
 create mode 100644 lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test

diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 816d06dd346aa3..146b1978b36bd9 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -2927,6 +2927,20 @@ SymbolFileNativePDB::FindNamespace(ConstString name,
   if (!ast_builder)
     return {};
 
+  if (CompilerDeclContext ns =
+          ast_builder->FindNamespaceDecl(parent_decl_ctx, name.GetStringRef()))
+    return ns;
+
+  // The AST builder only knows the namespaces of the decls it created so far.
+  BuildParentMap();
+  std::string qualified_name;
+  if (parent_decl_ctx.IsValid())
+    qualified_name = parent_decl_ctx.GetScopeQualifiedName().GetString() + "::";
+  qualified_name += name.GetStringRef();
+  auto it = m_typedef_scopes.find(qualified_name);
+  if (it == m_typedef_scopes.end())
+    return {};
+  GetOrCreateTypedef(PdbGlobalSymId{it->second, false});
   return ast_builder->FindNamespaceDecl(parent_decl_ctx, name.GetStringRef());
 }
 
@@ -3055,6 +3069,17 @@ void SymbolFileNativePDB::BuildParentMap() {
     llvm::StringRef base_name =
         MSVCUndecoratedNameParser::DropScope(udt_or_err->Name);
     m_typedef_base_names.Append(ConstString(base_name), gid);
+
+    if (std::optional<Type::ParsedName> parsed_name =
+            Type::GetTypeScopeAndBasename(udt_or_err->Name)) {
+      std::string scope_name;
+      for (llvm::StringRef scope : parsed_name->scope) {
+        if (!scope_name.empty())
+          scope_name += "::";
+        scope_name += scope;
+        m_typedef_scopes.try_emplace(scope_name, gid);
+      }
+    }
   }
   m_typedef_base_names.Sort(std::less<uint32_t>());
 
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index edd08e8407ee98..7d2308db073376 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -13,6 +13,7 @@
 #include "lldb/Symbol/SymbolFile.h"
 
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/DebugInfo/CodeView/CVRecord.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
 #include "llvm/DebugInfo/PDB/PDBTypes.h"
@@ -358,6 +359,8 @@ class SymbolFileNativePDB : public SymbolFileCommon {
   lldb_private::UniqueCStringMap<uint32_t> m_type_base_names;
   /// typedef basename -> Global ID(s) of its S_UDT
   lldb_private::UniqueCStringMap<uint32_t> m_typedef_base_names;
+  /// Qualified name of a scope of a typedef -> Global ID of a typedef in it.
+  llvm::StringMap<uint32_t> m_typedef_scopes;
 
   /// mangled name/full function name -> Global ID(s)
   lldb_private::UniqueCStringMap<uint32_t> m_func_full_names;
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test b/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test
new file mode 100644
index 00000000000000..5c9f79352807a8
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test
@@ -0,0 +1,44 @@
+# REQUIRES: target-windows
+
+# Test that typedefs are found by name. They are only S_UDT records, not type
+# records, and "ns" isn't the scope of anything but a typedef. Evaluate the
+# expressions first, since looking up the type also creates the namespace.
+# RUN: split-file %s %t
+# RUN: %build --nodefaultlib -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN:     %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+struct S {
+  char a[3];
+};
+
+typedef S GlobalTypedef;
+
+namespace ns {
+typedef S NamespaceTypedef;
+} // namespace ns
+
+int main() {
+  GlobalTypedef g;
+  ns::NamespaceTypedef n;
+  return sizeof(g) + sizeof(n);
+}
+
+#--- commands.input
+
+expr sizeof(ns::NamespaceTypedef)
+expr sizeof(GlobalTypedef)
+type lookup ns::NamespaceTypedef
+type lookup GlobalTypedef
+quit
+
+# CHECK:      (lldb) expr sizeof(ns::NamespaceTypedef)
+# CHECK-NEXT: ({{.*}}) $0 = 3
+# CHECK:      (lldb) expr sizeof(GlobalTypedef)
+# CHECK-NEXT: ({{.*}}) $1 = 3
+# CHECK:      (lldb) type lookup ns::NamespaceTypedef
+# CHECK-NEXT: struct S {
+# CHECK:      (lldb) type lookup GlobalTypedef
+# CHECK-NEXT: struct S {

>From bf9ddffbdff18ed07fce7652d7d4b12bb9b58048 Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Thu, 29 Oct 2026 21:46:08 +0000
Subject: [PATCH 2/3] address comments

---
 .../SymbolFile/NativePDB/typedef-lookup.test  | 22 +++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test b/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test
index 5c9f79352807a8..c4573c5533b635 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test
+++ b/lldb/test/Shell/SymbolFile/NativePDB/typedef-lookup.test
@@ -1,8 +1,9 @@
 # REQUIRES: target-windows
 
 # Test that typedefs are found by name. They are only S_UDT records, not type
-# records, and "ns" isn't the scope of anything but a typedef. Evaluate the
-# expressions first, since looking up the type also creates the namespace.
+# records, and "ns", "outer" and "outer::inner" aren't the scope of anything but
+# a typedef. Evaluate the expressions first, since looking up the type also
+# creates the namespace.
 # RUN: split-file %s %t
 # RUN: %build --nodefaultlib -o %t.exe -- %t/main.cpp
 # RUN: %lldb -f %t.exe -s \
@@ -20,25 +21,38 @@ namespace ns {
 typedef S NamespaceTypedef;
 } // namespace ns
 
+namespace outer {
+namespace inner {
+typedef S NestedTypedef;
+} // namespace inner
+} // namespace outer
+
 int main() {
   GlobalTypedef g;
   ns::NamespaceTypedef n;
-  return sizeof(g) + sizeof(n);
+  outer::inner::NestedTypedef i;
+  return sizeof(g) + sizeof(n) + sizeof(i);
 }
 
 #--- commands.input
 
 expr sizeof(ns::NamespaceTypedef)
+expr sizeof(outer::inner::NestedTypedef)
 expr sizeof(GlobalTypedef)
 type lookup ns::NamespaceTypedef
+type lookup outer::inner::NestedTypedef
 type lookup GlobalTypedef
 quit
 
 # CHECK:      (lldb) expr sizeof(ns::NamespaceTypedef)
 # CHECK-NEXT: ({{.*}}) $0 = 3
-# CHECK:      (lldb) expr sizeof(GlobalTypedef)
+# CHECK:      (lldb) expr sizeof(outer::inner::NestedTypedef)
 # CHECK-NEXT: ({{.*}}) $1 = 3
+# CHECK:      (lldb) expr sizeof(GlobalTypedef)
+# CHECK-NEXT: ({{.*}}) $2 = 3
 # CHECK:      (lldb) type lookup ns::NamespaceTypedef
 # CHECK-NEXT: struct S {
+# CHECK:      (lldb) type lookup outer::inner::NestedTypedef
+# CHECK-NEXT: struct S {
 # CHECK:      (lldb) type lookup GlobalTypedef
 # CHECK-NEXT: struct S {

>From 51443c5448b6612ee954675c6a3b7d34607daabe Mon Sep 17 00:00:00 2001
From: Charles Zablit <c_zablit at apple.com>
Date: Fri, 30 Oct 2026 11:57:20 -0700
Subject: [PATCH 3/3] Use MSVCUndecoratedNameParser to extract typedef scopes

---
 .../NativePDB/SymbolFileNativePDB.cpp         | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 146b1978b36bd9..b34f7694da7bac 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -3066,20 +3066,11 @@ void SymbolFileNativePDB::BuildParentMap() {
     }
     if (!IsTypedefUdt(*udt_or_err))
       continue;
-    llvm::StringRef base_name =
-        MSVCUndecoratedNameParser::DropScope(udt_or_err->Name);
-    m_typedef_base_names.Append(ConstString(base_name), gid);
-
-    if (std::optional<Type::ParsedName> parsed_name =
-            Type::GetTypeScopeAndBasename(udt_or_err->Name)) {
-      std::string scope_name;
-      for (llvm::StringRef scope : parsed_name->scope) {
-        if (!scope_name.empty())
-          scope_name += "::";
-        scope_name += scope;
-        m_typedef_scopes.try_emplace(scope_name, gid);
-      }
-    }
+    MSVCUndecoratedNameParser parser(udt_or_err->Name);
+    llvm::ArrayRef<MSVCUndecoratedNameSpecifier> specs = parser.GetSpecifiers();
+    m_typedef_base_names.Append(ConstString(specs.back().GetBaseName()), gid);
+    for (const MSVCUndecoratedNameSpecifier &scope : specs.drop_back())
+      m_typedef_scopes.try_emplace(scope.GetFullName(), gid);
   }
   m_typedef_base_names.Sort(std::less<uint32_t>());
 



More information about the lldb-commits mailing list