Skip to content

[LLDB][NativePDB] Implement FindNamespace #151950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 5, 2025

Conversation

Nerixyz
Copy link
Contributor

@Nerixyz Nerixyz commented Aug 4, 2025

FindNamespace was not implemented for SymbolFileNativePDB. Without it, it wasn't possible to lookup items through namespaces when evaluating expressions.

This is mostly the same as in SymbolFilePDB as well as PDBAstParser: The AST parser/builder saves the created namespaces in a map to lookup when a namespace is requested.

This is working towards making Shell/SymbolFile/PDB/expressions.test pass with the native PDB plugin.

@Nerixyz Nerixyz requested a review from JDevlieghere as a code owner August 4, 2025 12:16
@llvmbot llvmbot added the lldb label Aug 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 4, 2025

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

Changes

FindNamespace was not implemented for SymbolFileNativePDB. Without it, it wasn't possible to lookup items through namespaces when evaluating expressions.

This is mostly the same as in SymbolFilePDB as well as PDBAstParser: The AST parser/builder saves the created namespaces in a map to lookup when a namespace is requested.

This is working towards making Shell/SymbolFile/PDB/expressions.test pass with the native PDB plugin.


Full diff: https://github.com/llvm/llvm-project/pull/151950.diff

4 Files Affected:

  • (modified) lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp (+31-1)
  • (modified) lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h (+12-1)
  • (modified) lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp (+30-3)
  • (modified) lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test (+29-1)
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
index 8137622842253..92a102bbc92a8 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp
@@ -644,9 +644,12 @@ clang::Decl *PdbAstBuilder::TryGetDecl(PdbSymUid uid) const {
 clang::NamespaceDecl *
 PdbAstBuilder::GetOrCreateNamespaceDecl(const char *name,
                                         clang::DeclContext &context) {
-  return m_clang.GetUniqueNamespaceDeclaration(
+  clang::NamespaceDecl *ns = m_clang.GetUniqueNamespaceDeclaration(
       IsAnonymousNamespaceName(name) ? nullptr : name, &context,
       OptionalClangModuleID());
+  m_known_namespaces.insert(ns);
+  m_parent_to_namespaces[&context].insert(ns);
+  return ns;
 }
 
 clang::BlockDecl *
@@ -1452,3 +1455,30 @@ PdbAstBuilder::FromCompilerDeclContext(CompilerDeclContext context) {
 void PdbAstBuilder::Dump(Stream &stream, llvm::StringRef filter) {
   m_clang.Dump(stream.AsRawOstream(), filter);
 }
+
+clang::NamespaceDecl *
+PdbAstBuilder::FindNamespaceDecl(const clang::DeclContext *parent,
+                                 llvm::StringRef name) {
+  NamespaceSet *set;
+  if (parent) {
+    auto it = m_parent_to_namespaces.find(parent);
+    if (it == m_parent_to_namespaces.end())
+      return nullptr;
+
+    set = &it->second;
+  } else {
+    // In this case, search through all known namespaces
+    set = &m_known_namespaces;
+  }
+  assert(set);
+
+  for (clang::NamespaceDecl *namespace_decl : *set)
+    if (namespace_decl->getName() == name)
+      return namespace_decl;
+
+  for (clang::NamespaceDecl *namespace_decl : *set)
+    if (namespace_decl->isAnonymousNamespace())
+      return FindNamespaceDecl(namespace_decl, name);
+
+  return nullptr;
+}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
index 66a3836fac053..fef65227bc8f5 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h
@@ -89,6 +89,9 @@ class PdbAstBuilder {
 
   void Dump(Stream &stream, llvm::StringRef filter);
 
+  clang::NamespaceDecl *FindNamespaceDecl(const clang::DeclContext *parent,
+                                          llvm::StringRef name);
+
 private:
   clang::Decl *TryGetDecl(PdbSymUid uid) const;
 
@@ -150,7 +153,15 @@ class PdbAstBuilder {
   llvm::DenseMap<lldb::opaque_compiler_type_t,
                  llvm::SmallSet<std::pair<llvm::StringRef, CompilerType>, 8>>
       m_cxx_record_map;
-  llvm::DenseSet<clang::NamespaceDecl *> m_parsed_namespaces;
+
+  using NamespaceSet = llvm::DenseSet<clang::NamespaceDecl *>;
+
+  // These namespaces are fully parsed
+  NamespaceSet m_parsed_namespaces;
+
+  // We know about these namespaces, but they might not be completely parsed yet
+  NamespaceSet m_known_namespaces;
+  llvm::DenseMap<clang::DeclContext *, NamespaceSet> m_parent_to_namespaces;
 };
 
 } // namespace npdb
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 7af53e16ce9d5..0fe411e598545 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -2164,9 +2164,36 @@ void SymbolFileNativePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope,
                                    TypeClass type_mask,
                                    lldb_private::TypeList &type_list) {}
 
-CompilerDeclContext SymbolFileNativePDB::FindNamespace(
-    ConstString name, const CompilerDeclContext &parent_decl_ctx, bool) {
-  return {};
+CompilerDeclContext
+SymbolFileNativePDB::FindNamespace(ConstString name,
+                                   const CompilerDeclContext &parent_decl_ctx,
+                                   bool /* only_root_namespaces */) {
+  std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
+  auto ts_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
+  if (auto err = ts_or_err.takeError())
+    return {};
+  auto ts = *ts_or_err;
+  if (!ts)
+    return {};
+  auto *clang = llvm::dyn_cast_or_null<TypeSystemClang>(ts.get());
+  if (!clang)
+    return {};
+
+  PdbAstBuilder *ast_builder = clang->GetNativePDBParser();
+  if (!ast_builder)
+    return {};
+
+  clang::DeclContext *decl_context = nullptr;
+  if (parent_decl_ctx)
+    decl_context = static_cast<clang::DeclContext *>(
+        parent_decl_ctx.GetOpaqueDeclContext());
+
+  auto *namespace_decl =
+      ast_builder->FindNamespaceDecl(decl_context, name.GetStringRef());
+  if (!namespace_decl)
+    return CompilerDeclContext();
+
+  return clang->CreateDeclContext(namespace_decl);
 }
 
 llvm::Expected<lldb::TypeSystemSP>
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
index f6c1ccf22fa18..22ecfa16a11fb 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
+++ b/lldb/test/Shell/SymbolFile/NativePDB/namespace-access.test
@@ -77,8 +77,18 @@ type lookup Outer::Inner2::S
 type lookup Outer::A
 type lookup A
 type lookup ::A
+# Test that Clang can find the namespaces as well
 expr sizeof(S)
+expr sizeof(::S)
+expr sizeof(Outer::S)
+expr sizeof(Outer::Inner1::S)
+expr sizeof(Inner1::S)
+expr sizeof(Outer::Inner1::Inner2::S)
+expr sizeof(Inner2::S)
+expr sizeof(Outer::Inner2::S)
+expr sizeof(Outer::A)
 expr sizeof(A)
+expr sizeof(::A)
 
 quit
 
@@ -131,5 +141,23 @@ quit
 # CHECK-NEXT: }
 # CHECK-NEXT: (lldb) expr sizeof(S) 
 # CHECK-NEXT: (__size_t) $0 = 1
+# CHECK-NEXT: (lldb) expr sizeof(::S)
+# CHECK-NEXT: (__size_t) $1 = 1
+# CHECK-NEXT: (lldb) expr sizeof(Outer::S)
+# CHECK-NEXT: (__size_t) $2 = 2
+# CHECK-NEXT: (lldb) expr sizeof(Outer::Inner1::S)
+# CHECK-NEXT: (__size_t) $3 = 3
+# CHECK-NEXT: (lldb) expr sizeof(Inner1::S)
+# CHECK-NEXT: (__size_t) $4 = 3
+# CHECK-NEXT: (lldb) expr sizeof(Outer::Inner1::Inner2::S)
+# CHECK-NEXT: (__size_t) $5 = 4
+# CHECK-NEXT: (lldb) expr sizeof(Inner2::S)
+# CHECK-NEXT: (__size_t) $6 = 5
+# CHECK-NEXT: (lldb) expr sizeof(Outer::Inner2::S)
+# CHECK-NEXT: (__size_t) $7 = 5
+# CHECK-NEXT: (lldb) expr sizeof(Outer::A)
+# CHECK-NEXT: (__size_t) $8 = 6
 # CHECK-NEXT: (lldb) expr sizeof(A)
-# CHECK-NEXT: (__size_t) $1 = 7
+# CHECK-NEXT: (__size_t) $9 = 7
+# CHECK-NEXT: (lldb) expr sizeof(::A)
+# CHECK-NEXT: (__size_t) $10 = 7

@JDevlieghere JDevlieghere requested a review from Michael137 August 4, 2025 22:00
Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

Would be nice to share code between the PDB plugins, but then again, if we're going to get rid of the PDB plugin, duplicating this bit isn't that big of a deal

@Michael137 Michael137 merged commit 852cc92 into llvm:main Aug 5, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants