Correctly look up declarations in inline namespaces

Summary:
This patch marks the inline namespaces from DWARF as inline and also ensures that looking
up declarations now follows the lookup rules for inline namespaces.

Reviewers: aprantl, shafik, serge-sans-paille

Reviewed By: aprantl

Subscribers: eraman, jdoerfert, lldb-commits

Tags: #c_modules_in_lldb, #lldb

Differential Revision: https://reviews.llvm.org/D59198

llvm-svn: 355897
This commit is contained in:
Raphael Isemann 2019-03-12 07:45:04 +00:00
parent 21347b2901
commit a946997c24
10 changed files with 108 additions and 11 deletions

View File

@ -354,11 +354,13 @@ public:
//------------------------------------------------------------------
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 @@ public:
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
//----------------------------------------------------------------------

View File

@ -75,6 +75,21 @@ public:
bool *is_instance_method_ptr,
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
//----------------------------------------------------------------------

View File

@ -132,6 +132,9 @@ public:
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
//----------------------------------------------------------------------

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -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'])

View File

@ -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();
}

View File

@ -3798,8 +3798,11 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) {
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) {

View File

@ -2239,7 +2239,7 @@ bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext *decl_ctx,
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;

View File

@ -1893,9 +1893,8 @@ ClangASTContext::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl,
#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 @@ ClangASTContext::GetUniqueNamespaceDeclaration(const char *name,
}
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 @@ ClangASTContext::GetUniqueNamespaceDeclaration(const char *name,
}
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 @@ bool ClangASTContext::DeclContextIsClassMethod(
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())

View File

@ -59,6 +59,19 @@ bool CompilerDeclContext::IsClassMethod(lldb::LanguageType *language_ptr,
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() &&