diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -132,6 +132,17 @@ clang::NamespaceDecl *ResolveNamespaceDIE(const DWARFDIE &die); + /// Returns the namespace decl that a DW_TAG_imported_declaration imports. + /// + /// \param[in] die The import declaration to resolve. If the DIE is not a + /// DW_TAG_imported_declaration the behaviour is undefined. + /// + /// \returns The decl corresponding to the namespace that the specified + /// 'die' imports. If the imported entity is not a namespace + /// or another import declaration, returns nullptr. If an error + /// occurs, returns nullptr. + clang::NamespaceDecl *ResolveImportedDeclarationDIE(const DWARFDIE &die); + bool ParseTemplateDIE(const DWARFDIE &die, lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3347,6 +3347,11 @@ try_parsing_type = false; break; + case DW_TAG_imported_declaration: + decl_ctx = ResolveImportedDeclarationDIE(die); + try_parsing_type = false; + break; + case DW_TAG_lexical_block: decl_ctx = GetDeclContextForBlock(die); try_parsing_type = false; @@ -3508,6 +3513,42 @@ return nullptr; } +clang::NamespaceDecl * +DWARFASTParserClang::ResolveImportedDeclarationDIE(const DWARFDIE &die) { + assert(die && die.Tag() == DW_TAG_imported_declaration); + + // See if we cached a NamespaceDecl for this imported declaration + // already + auto it = m_die_to_decl_ctx.find(die.GetDIE()); + if (it != m_die_to_decl_ctx.end()) + return static_cast(it->getSecond()); + + clang::NamespaceDecl *namespace_decl = nullptr; + + const DWARFDIE imported_uid = + die.GetAttributeValueAsReferenceDIE(DW_AT_import); + if (!imported_uid) + return nullptr; + + switch (imported_uid.Tag()) { + case DW_TAG_imported_declaration: + namespace_decl = ResolveImportedDeclarationDIE(imported_uid); + break; + case DW_TAG_namespace: + namespace_decl = ResolveNamespaceDIE(imported_uid); + break; + default: + return nullptr; + } + + if (!namespace_decl) + return nullptr; + + LinkDeclContextToDIE(namespace_decl, die); + + return namespace_decl; +} + clang::DeclContext *DWARFASTParserClang::GetClangDeclContextContainingDIE( const DWARFDIE &die, DWARFDIE *decl_ctx_die_copy) { SymbolFileDWARF *dwarf = die.GetDWARF(); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -208,6 +208,7 @@ case DW_TAG_enumeration_type: case DW_TAG_inlined_subroutine: case DW_TAG_namespace: + case DW_TAG_imported_declaration: case DW_TAG_string_type: case DW_TAG_structure_type: case DW_TAG_subprogram: @@ -354,6 +355,7 @@ break; case DW_TAG_namespace: + case DW_TAG_imported_declaration: if (name) set.namespaces.Insert(ConstString(name), ref); break; diff --git a/lldb/test/API/commands/expression/namespace-alias/Makefile b/lldb/test/API/commands/expression/namespace-alias/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/expression/namespace-alias/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/expression/namespace-alias/TestInlineNamespaceAlias.py b/lldb/test/API/commands/expression/namespace-alias/TestInlineNamespaceAlias.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/expression/namespace-alias/TestInlineNamespaceAlias.py @@ -0,0 +1,37 @@ +""" +Test that we correctly handle namespace +expression evaluation through namespace +aliases. +""" + +import lldb + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestInlineNamespace(TestBase): + def do_test(self, params): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "return A::B::C::a", lldb.SBFileSpec("main.cpp")) + + self.expect_expr("A::C::a", result_type="int", result_value="-1") + self.expect_expr("A::D::a", result_type="int", result_value="-1") + + self.expect_expr("A::C::func()", result_type="int", result_value="0") + self.expect_expr("A::D::func()", result_type="int", result_value="0") + + self.expect_expr("E::C::a", result_type="int", result_value="-1") + self.expect_expr("E::D::a", result_type="int", result_value="-1") + self.expect_expr("F::a", result_type="int", result_value="-1") + self.expect_expr("G::a", result_type="int", result_value="-1") + + @skipIf(debug_info=no_match(["dsym"])) + def test_dsym(self): + self.do_test({}) + + @skipIf(debug_info="dsym") + def test_dwarf(self): + self.do_test(dict(CFLAGS_EXTRAS="-gdwarf-5 -gpubnames")) diff --git a/lldb/test/API/commands/expression/namespace-alias/main.cpp b/lldb/test/API/commands/expression/namespace-alias/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/commands/expression/namespace-alias/main.cpp @@ -0,0 +1,21 @@ +namespace A { +inline namespace _A { +namespace B { +namespace C { +int a = -1; + +int func() { return 0; } +} // namespace C +} // namespace B + +namespace C = B::C; +namespace D = B::C; + +} // namespace _A +} // namespace A + +namespace E = A; +namespace F = E::C; +namespace G = F; + +int main(int argc, char **argv) { return A::B::C::a; }