Index: include/lldb/Symbol/ClangASTContext.h =================================================================== --- include/lldb/Symbol/ClangASTContext.h +++ include/lldb/Symbol/ClangASTContext.h @@ -354,11 +354,13 @@ //------------------------------------------------------------------ clang::NamespaceDecl * - GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx); + GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx, + bool is_inline = false); static clang::NamespaceDecl * GetUniqueNamespaceDeclaration(clang::ASTContext *ast, const char *name, - clang::DeclContext *decl_ctx); + clang::DeclContext *decl_ctx, + bool is_inline = false); //------------------------------------------------------------------ // Function Types @@ -506,6 +508,9 @@ bool *is_instance_method_ptr, ConstString *language_object_name_ptr) override; + bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, + void *other_opaque_decl_ctx) override; + //---------------------------------------------------------------------- // Clang specific clang::DeclContext functions //---------------------------------------------------------------------- Index: include/lldb/Symbol/CompilerDeclContext.h =================================================================== --- include/lldb/Symbol/CompilerDeclContext.h +++ include/lldb/Symbol/CompilerDeclContext.h @@ -76,6 +76,21 @@ ConstString *language_object_name_ptr); //---------------------------------------------------------------------- + /// Check if the given other decl context is contained in the lookup + /// of this decl context (for example because the other context is a nested + /// inline namespace). + /// + /// @param[in] other + /// The other decl context for which we should check if it is contained + /// in the lookoup of this context. + /// + /// @return + /// Returns true iff the other decl context is contained in the lookup + /// of this decl context. + //---------------------------------------------------------------------- + bool IsContainedInLookup(CompilerDeclContext other) const; + + //---------------------------------------------------------------------- // Accessors //---------------------------------------------------------------------- Index: include/lldb/Symbol/TypeSystem.h =================================================================== --- include/lldb/Symbol/TypeSystem.h +++ include/lldb/Symbol/TypeSystem.h @@ -132,6 +132,9 @@ void *opaque_decl_ctx, lldb::LanguageType *language_ptr, bool *is_instance_method_ptr, ConstString *language_object_name_ptr) = 0; + virtual bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, + void *other_opaque_decl_ctx) = 0; + //---------------------------------------------------------------------- // Tests //---------------------------------------------------------------------- Index: packages/Python/lldbsuite/test/expression_command/inline-namespace/Makefile =================================================================== --- packages/Python/lldbsuite/test/expression_command/inline-namespace/Makefile +++ packages/Python/lldbsuite/test/expression_command/inline-namespace/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/expression_command/inline-namespace/TestInlineNamespace.py =================================================================== --- packages/Python/lldbsuite/test/expression_command/inline-namespace/TestInlineNamespace.py +++ packages/Python/lldbsuite/test/expression_command/inline-namespace/TestInlineNamespace.py @@ -0,0 +1,26 @@ +""" +Test that we correctly handle inline namespaces. +""" + +import lldb + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class TestInlineNamespace(TestBase): + mydir = TestBase.compute_mydir(__file__) + + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + # The 'A::B::f' function must be found via 'A::f' as 'B' is an inline + # namespace. + self.expect("expr A::f()", substrs=['$0 = 3']) + # But we should still find the function when we pretend the inline + # namespace is not inline. + self.expect("expr A::B::f()", substrs=['$1 = 3']) Index: packages/Python/lldbsuite/test/expression_command/inline-namespace/main.cpp =================================================================== --- packages/Python/lldbsuite/test/expression_command/inline-namespace/main.cpp +++ packages/Python/lldbsuite/test/expression_command/inline-namespace/main.cpp @@ -0,0 +1,10 @@ +namespace A { + inline namespace B { + int f() { return 3; } + }; +} + +int main(int argc, char **argv) { + // Set break point at this line. + return A::f(); +} Index: source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3798,8 +3798,11 @@ const char *namespace_name = die.GetName(); clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); - namespace_decl = m_ast.GetUniqueNamespaceDeclaration(namespace_name, - containing_decl_ctx); + bool is_inline = + die.GetAttributeValueAsUnsigned(DW_AT_export_symbols, 0) != 0; + + namespace_decl = m_ast.GetUniqueNamespaceDeclaration( + namespace_name, containing_decl_ctx, is_inline); Log *log = nullptr; // (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); if (log) { Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2239,7 +2239,7 @@ CompilerDeclContext actual_decl_ctx = dwarf_ast->GetDeclContextContainingUIDFromDWARF(die); if (actual_decl_ctx) - return actual_decl_ctx == *decl_ctx; + return decl_ctx->IsContainedInLookup(actual_decl_ctx); } } return false; Index: source/Symbol/ClangASTContext.cpp =================================================================== --- source/Symbol/ClangASTContext.cpp +++ source/Symbol/ClangASTContext.cpp @@ -1893,9 +1893,8 @@ #pragma mark Namespace Declarations -NamespaceDecl * -ClangASTContext::GetUniqueNamespaceDeclaration(const char *name, - DeclContext *decl_ctx) { +NamespaceDecl *ClangASTContext::GetUniqueNamespaceDeclaration( + const char *name, DeclContext *decl_ctx, bool is_inline) { NamespaceDecl *namespace_decl = nullptr; ASTContext *ast = getASTContext(); TranslationUnitDecl *translation_unit_decl = ast->getTranslationUnitDecl(); @@ -1913,7 +1912,7 @@ } namespace_decl = - NamespaceDecl::Create(*ast, decl_ctx, false, SourceLocation(), + NamespaceDecl::Create(*ast, decl_ctx, is_inline, SourceLocation(), SourceLocation(), &identifier_info, nullptr); decl_ctx->addDecl(namespace_decl); @@ -1954,12 +1953,13 @@ } NamespaceDecl *ClangASTContext::GetUniqueNamespaceDeclaration( - clang::ASTContext *ast, const char *name, clang::DeclContext *decl_ctx) { + clang::ASTContext *ast, const char *name, clang::DeclContext *decl_ctx, + bool is_inline) { ClangASTContext *ast_ctx = ClangASTContext::GetASTContext(ast); if (ast_ctx == nullptr) return nullptr; - return ast_ctx->GetUniqueNamespaceDeclaration(name, decl_ctx); + return ast_ctx->GetUniqueNamespaceDeclaration(name, decl_ctx, is_inline); } clang::BlockDecl * @@ -10264,6 +10264,23 @@ return false; } +bool ClangASTContext::DeclContextIsContainedInLookup( + void *opaque_decl_ctx, void *other_opaque_decl_ctx) { + auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; + auto *other = (clang::DeclContext *)other_opaque_decl_ctx; + + do { + // A decl context always includes its own contents in its lookup. + if (decl_ctx == other) + return true; + + // If we have an inline namespace, then the lookup of the parent context + // also includes the inline namespace contents. + } while (other->isInlineNamespace() && (other = other->getParent())); + + return false; +} + clang::DeclContext * ClangASTContext::DeclContextGetAsDeclContext(const CompilerDeclContext &dc) { if (dc.IsClang()) Index: source/Symbol/CompilerDeclContext.cpp =================================================================== --- source/Symbol/CompilerDeclContext.cpp +++ source/Symbol/CompilerDeclContext.cpp @@ -59,6 +59,19 @@ return false; } +bool CompilerDeclContext::IsContainedInLookup(CompilerDeclContext other) const { + if (!IsValid()) + return false; + + // If the other context is just the current context, we don't need to go + // over the type system to know that the lookup is identical. + if (this == &other) + return true; + + return m_type_system->DeclContextIsContainedInLookup(m_opaque_decl_ctx, + other.m_opaque_decl_ctx); +} + bool lldb_private::operator==(const lldb_private::CompilerDeclContext &lhs, const lldb_private::CompilerDeclContext &rhs) { return lhs.GetTypeSystem() == rhs.GetTypeSystem() &&