[Lldb-commits] [lldb] 6cdfa29 - [lldb][ClangExpression] Filter out non-root namespaces in FindNamespace
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Fri Apr 14 09:12:21 PDT 2023
Author: Michael Buch
Date: 2023-04-14T17:11:30+01:00
New Revision: 6cdfa295743729178ff6f15a8dcd36f8f7d27c2c
URL: https://github.com/llvm/llvm-project/commit/6cdfa295743729178ff6f15a8dcd36f8f7d27c2c
DIFF: https://github.com/llvm/llvm-project/commit/6cdfa295743729178ff6f15a8dcd36f8f7d27c2c.diff
LOG: [lldb][ClangExpression] Filter out non-root namespaces in FindNamespace
**Summary**
In a program such as:
```
namespace A {
namespace B {
struct Bar {};
}
}
namespace B {
struct Foo {};
}
```
...LLDB would run into issues such as:
```
(lldb) expr ::B::Foo f
error: expression failed to parse:
error: <user expression 0>:1:6: no type named 'Foo' in namespace 'A::B'
::B::Foo f
~~~~~^
```
This is because the `SymbolFileDWARF::FindNamespace` implementation
will return *any* namespace it finds if the `parent_decl_ctx` provided
is empty. In `FindExternalVisibleDecls` we use this API to find the
namespace that symbol `B` refers to. If `A::B` happened to be the one
that `SymbolFileDWARF::FindNamespace` looked at first, we would try
to find `struct Foo` in `A::B`. Hence the error.
This patch proposes a new `SymbolFileDWARF::FindNamespace` API that
will only find a match for top-level namespaces, which is what
`FindExternalVisibleDecls` is attempting anyway; it just never
accounted for multiple namespaces of the same name.
**Testing**
* Added API test-case
Differential Revision: https://reviews.llvm.org/D147436
Added:
Modified:
lldb/include/lldb/Symbol/SymbolFile.h
lldb/include/lldb/Symbol/SymbolFileOnDemand.h
lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
lldb/source/Symbol/SymbolFileOnDemand.cpp
lldb/test/API/lang/cpp/namespace/TestNamespace.py
lldb/test/API/lang/cpp/namespace/main.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h
index 90162b7827d3..8de752816cf9 100644
--- a/lldb/include/lldb/Symbol/SymbolFile.h
+++ b/lldb/include/lldb/Symbol/SymbolFile.h
@@ -327,8 +327,17 @@ class SymbolFile : public PluginInterface {
virtual llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) = 0;
+ /// Finds a namespace of name \ref name and whose parent
+ /// context is \ref parent_decl_ctx.
+ ///
+ /// If \code{.cpp} !parent_decl_ctx.IsValid() \endcode
+ /// then this function will consider all namespaces that
+ /// match the name. If \ref only_root_namespaces is
+ /// true, only consider in the search those DIEs that
+ /// represent top-level namespaces.
virtual CompilerDeclContext
- FindNamespace(ConstString name, const CompilerDeclContext &parent_decl_ctx) {
+ FindNamespace(ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces = false) {
return CompilerDeclContext();
}
diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
index 825fba755e99..adf1017ce73c 100644
--- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
+++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h
@@ -171,9 +171,10 @@ class SymbolFileOnDemand : public lldb_private::SymbolFile {
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override;
- lldb_private::CompilerDeclContext FindNamespace(
- lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx) override;
+ lldb_private::CompilerDeclContext
+ FindNamespace(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
std::vector<std::unique_ptr<lldb_private::CallEdge>>
ParseCallEdgesInFunction(UserID func_id) override;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
index 108566b066d7..76cbfc4c05f8 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -700,7 +700,18 @@ void ClangASTSource::FillNamespaceMap(
if (!symbol_file)
continue;
- found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl);
+ // If namespace_decl is not valid, 'FindNamespace' would look for
+ // any namespace called 'name' (ignoring parent contexts) and return
+ // the first one it finds. Thus if we're doing a qualified lookup only
+ // consider root namespaces. E.g., in an expression ::A::B::Foo, the
+ // lookup of ::A will result in a qualified lookup. Note, namespace
+ // disambiguation for function calls are handled separately in
+ // SearchFunctionsInSymbolContexts.
+ const bool find_root_namespaces =
+ context.m_decl_context &&
+ context.m_decl_context->shouldUseQualifiedLookup();
+ found_namespace_decl = symbol_file->FindNamespace(
+ name, namespace_decl, /* only root namespaces */ find_root_namespaces);
if (found_namespace_decl) {
context.m_namespace_map->push_back(
diff --git a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
index 6d9336966517..3942f4f7ae24 100644
--- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ b/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -134,9 +134,9 @@ class SymbolFileBreakpad : public SymbolFileCommon {
llvm::inconvertibleErrorCode());
}
- CompilerDeclContext
- FindNamespace(ConstString name,
- const CompilerDeclContext &parent_decl_ctx) override {
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override {
return CompilerDeclContext();
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 837d87cdebbb..0bde202f280f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2324,12 +2324,19 @@ bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
}
bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext &decl_ctx,
- const DWARFDIE &die) {
+ const DWARFDIE &die,
+ bool only_root_namespaces) {
// If we have no parent decl context to match this DIE matches, and if the
// parent decl context isn't valid, we aren't trying to look for any
// particular decl context so any die matches.
- if (!decl_ctx.IsValid())
+ if (!decl_ctx.IsValid()) {
+ // ...But if we are only checking root decl contexts, confirm that the
+ // 'die' is a top-level context.
+ if (only_root_namespaces)
+ return die.GetParent().Tag() == dwarf::DW_TAG_compile_unit;
+
return true;
+ }
if (die) {
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) {
@@ -2632,7 +2639,8 @@ void SymbolFileDWARF::FindTypes(
CompilerDeclContext
SymbolFileDWARF::FindNamespace(ConstString name,
- const CompilerDeclContext &parent_decl_ctx) {
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
Log *log = GetLog(DWARFLog::Lookups);
@@ -2648,7 +2656,7 @@ SymbolFileDWARF::FindNamespace(ConstString name,
return namespace_decl_ctx;
m_index->GetNamespaces(name, [&](DWARFDIE die) {
- if (!DIEInDeclContext(parent_decl_ctx, die))
+ if (!DIEInDeclContext(parent_decl_ctx, die, only_root_namespaces))
return true; // The containing decl contexts don't match
DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU());
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 0616846d8dc6..d685e4df6d85 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -214,9 +214,10 @@ class SymbolFileDWARF : public lldb_private::SymbolFileCommon {
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override;
- lldb_private::CompilerDeclContext FindNamespace(
- lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx) override;
+ lldb_private::CompilerDeclContext
+ FindNamespace(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
void PreloadSymbols() override;
@@ -274,7 +275,7 @@ class SymbolFileDWARF : public lldb_private::SymbolFileCommon {
static bool
DIEInDeclContext(const lldb_private::CompilerDeclContext &parent_decl_ctx,
- const DWARFDIE &die);
+ const DWARFDIE &die, bool only_root_namespaces = false);
std::vector<std::unique_ptr<lldb_private::CallEdge>>
ParseCallEdgesInFunction(lldb_private::UserID func_id) override;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
index a07807241deb..1d79b13a6633 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1256,13 +1256,14 @@ void SymbolFileDWARFDebugMap::FindTypes(
}
CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace(
- lldb_private::ConstString name,
- const CompilerDeclContext &parent_decl_ctx) {
+ lldb_private::ConstString name, const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
CompilerDeclContext matching_namespace;
ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool {
- matching_namespace = oso_dwarf->FindNamespace(name, parent_decl_ctx);
+ matching_namespace =
+ oso_dwarf->FindNamespace(name, parent_decl_ctx, only_root_namespaces);
return (bool)matching_namespace;
});
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
index 0313063119c7..881fd4c45ff0 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -136,9 +136,10 @@ class SymbolFileDWARFDebugMap : public lldb_private::SymbolFileCommon {
lldb_private::LanguageSet languages,
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
lldb_private::TypeMap &types) override;
- lldb_private::CompilerDeclContext FindNamespace(
- lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx) override;
+ lldb_private::CompilerDeclContext
+ FindNamespace(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
void GetTypes(lldb_private::SymbolContextScope *sc_scope,
lldb::TypeClass type_mask,
lldb_private::TypeList &type_list) override;
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index df558c842f9c..01756e47e917 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -2133,9 +2133,8 @@ 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) {
+CompilerDeclContext SymbolFileNativePDB::FindNamespace(
+ ConstString name, const CompilerDeclContext &parent_decl_ctx, bool) {
return {};
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
index 90cd5251679e..bf64cd330c1f 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -152,9 +152,9 @@ class SymbolFileNativePDB : public SymbolFileCommon {
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override;
- CompilerDeclContext
- FindNamespace(ConstString name,
- const CompilerDeclContext &parent_decl_ctx) override;
+ CompilerDeclContext FindNamespace(ConstString name,
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index 613e36207127..7f07eec1e464 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -1697,7 +1697,7 @@ PDBASTParser *SymbolFilePDB::GetPDBAstParser() {
lldb_private::CompilerDeclContext
SymbolFilePDB::FindNamespace(lldb_private::ConstString name,
- const CompilerDeclContext &parent_decl_ctx) {
+ const CompilerDeclContext &parent_decl_ctx, bool) {
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
auto type_system_or_err =
GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus);
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
index 992bafd6a377..5b98c6e8b486 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -157,9 +157,10 @@ class SymbolFilePDB : public lldb_private::SymbolFileCommon {
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override;
- lldb_private::CompilerDeclContext FindNamespace(
- lldb_private::ConstString name,
- const lldb_private::CompilerDeclContext &parent_decl_ctx) override;
+ lldb_private::CompilerDeclContext
+ FindNamespace(lldb_private::ConstString name,
+ const lldb_private::CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) override;
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
diff --git a/lldb/source/Symbol/SymbolFileOnDemand.cpp b/lldb/source/Symbol/SymbolFileOnDemand.cpp
index aa3d23ccbf4d..d3694580194f 100644
--- a/lldb/source/Symbol/SymbolFileOnDemand.cpp
+++ b/lldb/source/Symbol/SymbolFileOnDemand.cpp
@@ -483,13 +483,16 @@ SymbolFileOnDemand::GetTypeSystemForLanguage(LanguageType language) {
CompilerDeclContext
SymbolFileOnDemand::FindNamespace(ConstString name,
- const CompilerDeclContext &parent_decl_ctx) {
+ const CompilerDeclContext &parent_decl_ctx,
+ bool only_root_namespaces) {
if (!m_debug_info_enabled) {
LLDB_LOG(GetLog(), "[{0}] {1}({2}) is skipped", GetSymbolFileName(),
__FUNCTION__, name);
- return SymbolFile::FindNamespace(name, parent_decl_ctx);
+ return SymbolFile::FindNamespace(name, parent_decl_ctx,
+ only_root_namespaces);
}
- return m_sym_file_impl->FindNamespace(name, parent_decl_ctx);
+ return m_sym_file_impl->FindNamespace(name, parent_decl_ctx,
+ only_root_namespaces);
}
std::vector<std::unique_ptr<lldb_private::CallEdge>>
diff --git a/lldb/test/API/lang/cpp/namespace/TestNamespace.py b/lldb/test/API/lang/cpp/namespace/TestNamespace.py
index 114d70dc0ec9..ad534cd58ac0 100644
--- a/lldb/test/API/lang/cpp/namespace/TestNamespace.py
+++ b/lldb/test/API/lang/cpp/namespace/TestNamespace.py
@@ -225,3 +225,11 @@ def test_with_run_command(self):
self.expect("expression variadic_sum", patterns=[
'\(anonymous namespace\)::variadic_sum\(int, ...\)'])
+
+ self.expect_expr("::B::Bar b; b.x()", result_type="int", result_value="42")
+ self.expect_expr("A::B::Bar b; b.y()", result_type="int", result_value="137")
+ self.expect_expr("::NS1::NS2::Foo{}.bar() == -2 && ::NS2::Foo{}.bar() == -3",
+ result_type="bool", result_value="true")
+ # FIXME: C++ unqualified namespace lookups currently not supported when instantiating types.
+ self.expect_expr("NS2::Foo{}.bar() == -3", result_type="bool", result_value="false")
+ self.expect_expr("((::B::Bar*)&::B::bar)->x()", result_type="int", result_value="42")
diff --git a/lldb/test/API/lang/cpp/namespace/main.cpp b/lldb/test/API/lang/cpp/namespace/main.cpp
index fc5dacdaf8f5..6a8efa160766 100644
--- a/lldb/test/API/lang/cpp/namespace/main.cpp
+++ b/lldb/test/API/lang/cpp/namespace/main.cpp
@@ -102,6 +102,31 @@ int Foo::myfunc(int a)
return myfunc2(3) + j + i + a + 2 + anon_uint + a_uint + b_uint + y_uint; // Set break point at this line.
}
+namespace B {
+struct Bar {
+ int x() { return 42; }
+};
+Bar bar;
+} // namespace B
+
+namespace A::B {
+struct Bar {
+ int y() { return 137; }
+};
+} // namespace A::B
+
+namespace NS1::NS2 {
+struct Foo {
+ int bar() { return -2; }
+};
+} // namespace NS1::NS2
+
+namespace NS2 {
+struct Foo {
+ int bar() { return -3; }
+};
+} // namespace NS2
+
int
main (int argc, char const *argv[])
{
@@ -112,5 +137,8 @@ main (int argc, char const *argv[])
A::B::test_lookup_at_nested_ns_scope_after_using();
test_lookup_before_using_directive();
test_lookup_after_using_directive();
- return Foo::myfunc(12);
+ ::B::Bar bb;
+ A::B::Bar ab;
+ return Foo::myfunc(12) + bb.x() + ab.y() + NS1::NS2::Foo{}.bar() +
+ NS2::Foo{}.bar();
}
More information about the lldb-commits
mailing list