Michael137 created this revision.
Michael137 added reviewers: aprantl, labath.
Herald added a project: All.
Michael137 updated this revision to Diff 510478.
Michael137 added a comment.
Michael137 updated this revision to Diff 510482.
Michael137 edited the summary of this revision.
Michael137 updated this revision to Diff 510489.
Michael137 published this revision for review.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
- Add docs
Michael137 added a comment.
- Merge into single API
Michael137 added a comment.
- Adjust test-case. Add FIXME
**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 flag to `SymbolFileDWARF::FindNamespace`
allows us to only consider top-level namespaces in our search, which is what
`FindExternalVisibleDecls` is attempting anyway; it just never
accounted for multiple namespaces of the same name.
**Testing**
- Added API test-case
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D147436
Files:
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/commands/expression/inline-namespace/TestInlineNamespace.py
lldb/test/API/lang/cpp/namespace/TestNamespace.py
lldb/test/API/lang/cpp/namespace/TestNamespaceLookup.py
lldb/test/API/lang/cpp/namespace/main.cpp
Index: lldb/test/API/lang/cpp/namespace/main.cpp
===================================================================
--- lldb/test/API/lang/cpp/namespace/main.cpp
+++ lldb/test/API/lang/cpp/namespace/main.cpp
@@ -102,6 +102,18 @@
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; }
+};
+} // namespace B
+
+namespace A::B {
+struct Bar {
+ int y() { return 137; }
+};
+} // namespace A::B
+
int
main (int argc, char const *argv[])
{
@@ -112,5 +124,7 @@
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();
}
Index: lldb/test/API/lang/cpp/namespace/TestNamespaceLookup.py
===================================================================
--- lldb/test/API/lang/cpp/namespace/TestNamespaceLookup.py
+++ lldb/test/API/lang/cpp/namespace/TestNamespaceLookup.py
@@ -159,8 +159,8 @@
self.runToBkpt("continue")
# Evaluate func(10) - should call A::func(int)
self.expect_expr("func(10)", result_type="int", result_value="13")
- # Evaluate B::func() - should call B::func()
- self.expect_expr("B::func()", result_type="int", result_value="4")
+ # FIXME: under C++ rules this should call A::B::func() since we're at namespace scope of 'A'.
+ self.expect("expr B::func()", error=True, substrs=["no member named 'func' in namespace 'B'"])
# Evaluate func() - should call A::func()
self.expect_expr("func()", result_type="int", result_value="3")
@@ -187,14 +187,14 @@
# Continue to BP_before_using_directive at global scope before using
# declaration
self.runToBkpt("continue")
- # Evaluate B::func() - should call B::func()
- self.expect_expr("B::func()", result_type="int", result_value="4")
+ # Evaluate B::func() - should error out since there is no definition for it
+ self.expect("expr B::func()", error=True, substrs=["no member named 'func' in namespace 'B'"])
# Continue to BP_after_using_directive at global scope after using
# declaration
self.runToBkpt("continue")
- # Evaluate B::func() - should call B::func()
- self.expect_expr("B::func()", result_type="int", result_value="4")
+ # FIXME: under C++ rules this should call A::B::func() since we imported namespace 'A'
+ self.expect("expr B::func()", error=True, substrs=["no member named 'func' in namespace 'B'"])
@expectedFailure("lldb scope lookup of functions bugs")
def test_function_scope_lookup_with_run_command(self):
Index: lldb/test/API/lang/cpp/namespace/TestNamespace.py
===================================================================
--- lldb/test/API/lang/cpp/namespace/TestNamespace.py
+++ lldb/test/API/lang/cpp/namespace/TestNamespace.py
@@ -225,3 +225,6 @@
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")
Index: lldb/test/API/commands/expression/inline-namespace/TestInlineNamespace.py
===================================================================
--- lldb/test/API/commands/expression/inline-namespace/TestInlineNamespace.py
+++ lldb/test/API/commands/expression/inline-namespace/TestInlineNamespace.py
@@ -46,7 +46,7 @@
self.expect("expr A::other_var", error=True, substrs=["no member named 'other_var' in namespace 'A'"])
self.expect("expr A::B::other_var", error=True, substrs=["no member named 'other_var' in namespace 'A::B'"])
- self.expect("expr B::other_var", error=True, substrs=["no member named 'other_var' in namespace 'A::B'"])
+ self.expect("expr B::other_var", error=True, substrs=["use of undeclared identifier 'B'"])
# 'frame variable' can correctly distinguish between A::B::global_var and A::global_var
gvars = self.target().FindGlobalVariables("A::global_var", 10)
Index: lldb/source/Symbol/SymbolFileOnDemand.cpp
===================================================================
--- lldb/source/Symbol/SymbolFileOnDemand.cpp
+++ lldb/source/Symbol/SymbolFileOnDemand.cpp
@@ -483,13 +483,16 @@
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>>
Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -157,9 +157,10 @@
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(); }
Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -1697,7 +1697,7 @@
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);
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -152,9 +152,9 @@
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(); }
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -2133,9 +2133,8 @@
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 {};
}
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -136,9 +136,10 @@
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;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -1256,13 +1256,14 @@
}
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;
});
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -214,9 +214,18 @@
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;
+ /// Checks the DWARF index for 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.
+ 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 +283,7 @@
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;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2324,12 +2324,17 @@
}
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.
+ //
+ // But if we are only checking root decl contexts, confirm that the
+ // 'die' is a top-level context.
if (!decl_ctx.IsValid())
- return true;
+ return !only_root_namespaces ||
+ die.GetParent().Tag() == dwarf::DW_TAG_compile_unit;
if (die) {
if (DWARFASTParser *dwarf_ast = GetDWARFParser(*die.GetCU())) {
@@ -2632,7 +2637,8 @@
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 +2654,7 @@
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());
Index: lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
===================================================================
--- lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -134,9 +134,9 @@
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();
}
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
@@ -700,7 +700,8 @@
if (!symbol_file)
continue;
- found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl);
+ found_namespace_decl = symbol_file->FindNamespace(
+ name, namespace_decl, /* only root namespaces */ true);
if (found_namespace_decl) {
context.m_namespace_map->push_back(
@@ -1673,8 +1674,8 @@
if (!symbol_file)
continue;
- found_namespace_decl =
- symbol_file->FindNamespace(name, null_namespace_decl);
+ found_namespace_decl = symbol_file->FindNamespace(
+ name, null_namespace_decl, /* only root namespaces */ true);
if (!found_namespace_decl)
continue;
Index: lldb/include/lldb/Symbol/SymbolFileOnDemand.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolFileOnDemand.h
+++ lldb/include/lldb/Symbol/SymbolFileOnDemand.h
@@ -171,9 +171,10 @@
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;
Index: lldb/include/lldb/Symbol/SymbolFile.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolFile.h
+++ lldb/include/lldb/Symbol/SymbolFile.h
@@ -327,7 +327,8 @@
GetTypeSystemForLanguage(lldb::LanguageType language) = 0;
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();
}
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits