diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -328,7 +328,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(); } diff --git a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h --- a/lldb/include/lldb/Symbol/SymbolFileOnDemand.h +++ b/lldb/include/lldb/Symbol/SymbolFileOnDemand.h @@ -171,9 +171,10 @@ llvm::Expected 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> ParseCallEdgesInFunction(UserID func_id) override; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -700,7 +700,15 @@ if (!symbol_file) continue; - found_namespace_decl = symbol_file->FindNamespace(name, namespace_decl); + // 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 --- a/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/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(); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -214,9 +214,18 @@ llvm::Expected 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> ParseCallEdgesInFunction(lldb_private::UserID func_id) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/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 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()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -136,9 +136,10 @@ lldb_private::LanguageSet languages, llvm::DenseSet &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/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/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 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/NativePDB/SymbolFileNativePDB.h b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -152,9 +152,9 @@ llvm::Expected 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/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/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 {}; } diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -157,9 +157,10 @@ llvm::Expected 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/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/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 guard(GetModuleMutex()); auto type_system_or_err = GetTypeSystemForLanguage(lldb::eLanguageTypeC_plus_plus); diff --git a/lldb/source/Symbol/SymbolFileOnDemand.cpp b/lldb/source/Symbol/SymbolFileOnDemand.cpp --- a/lldb/source/Symbol/SymbolFileOnDemand.cpp +++ b/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> diff --git a/lldb/test/API/commands/expression/inline-namespace/TestInlineNamespace.py b/lldb/test/API/commands/expression/inline-namespace/TestInlineNamespace.py --- a/lldb/test/API/commands/expression/inline-namespace/TestInlineNamespace.py +++ b/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) diff --git a/lldb/test/API/lang/cpp/namespace/TestNamespace.py b/lldb/test/API/lang/cpp/namespace/TestNamespace.py --- a/lldb/test/API/lang/cpp/namespace/TestNamespace.py +++ b/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") diff --git a/lldb/test/API/lang/cpp/namespace/main.cpp b/lldb/test/API/lang/cpp/namespace/main.cpp --- a/lldb/test/API/lang/cpp/namespace/main.cpp +++ b/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(); }