From 1ba6ec0ba906472661506ef7bd2f0bf4efe4657e Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Mon, 6 Feb 2023 13:54:32 +0000 Subject: [PATCH] [lldb][DWARFASTParserClang] Correctly resolve imported namespaces during expression evaluation **Summary** This patch makes the expression evaluator understand namespace aliases. This will become important once `std::ranges` become more widespread since `std::views` is defined as: ``` namespace std { namespace ranges::views {} namespace views = ranges::views; } ``` **Testing** * Added API test Differential Revision: https://reviews.llvm.org/D143398 --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 41 ++++++++++++++++++++++ .../Plugins/SymbolFile/DWARF/DWARFASTParserClang.h | 11 ++++++ .../commands/expression/namespace-alias/Makefile | 3 ++ .../namespace-alias/TestInlineNamespaceAlias.py | 29 +++++++++++++++ .../commands/expression/namespace-alias/main.cpp | 21 +++++++++++ 5 files changed, 105 insertions(+) create mode 100644 lldb/test/API/commands/expression/namespace-alias/Makefile create mode 100644 lldb/test/API/commands/expression/namespace-alias/TestInlineNamespaceAlias.py create mode 100644 lldb/test/API/commands/expression/namespace-alias/main.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 4429b4f..7174566 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3304,6 +3304,11 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) { 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; @@ -3465,6 +3470,42 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) { 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/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 0733d22..a4613af 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -132,6 +132,17 @@ protected: 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/test/API/commands/expression/namespace-alias/Makefile b/lldb/test/API/commands/expression/namespace-alias/Makefile new file mode 100644 index 0000000..99998b2 --- /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 index 0000000..9d014da --- /dev/null +++ b/lldb/test/API/commands/expression/namespace-alias/TestInlineNamespaceAlias.py @@ -0,0 +1,29 @@ +""" +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 test(self): + 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") 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 index 0000000..b35efda --- /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; } -- 2.7.4