Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cherry-pick][swift/release/6.0] [lldb][Type Completion] Lazy loading of C++ methods #8698

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/include/clang/AST/ExternalASTSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ class ExternalASTSource : public RefCountedBase<ExternalASTSource> {
virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);

virtual bool FindExternalVisibleMethodsByName(const DeclContext *DC,
DeclarationName Name) {
return false;
}

/// Ensures that the table of all visible declarations inside this
/// context is up to date.
///
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1878,7 +1878,7 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
continue;
}

if (Importer.hasLLDBRedeclCompletion()) {
if (!Importer.hasLLDBRedeclCompletion()) {
FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From);
Decl *ImportedDecl = *ImportedOrErr;
FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl);
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,13 @@ static bool LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
}
}

if (ExternalASTSource *Source =
DC->getParentASTContext().getExternalSource()) {
if (auto LookupName = R.getLookupName()) {
Source->FindExternalVisibleMethodsByName(DC, LookupName);
}
}

// The record definition is complete, now look up the member.
SemaRef.LookupQualifiedName(R, DC, SS);

Expand Down
63 changes: 34 additions & 29 deletions lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,23 +824,17 @@ bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
if (!decl_origin.Valid())
return false;

ImporterDelegateSP delegate_sp(
GetDelegate(&decl->getASTContext(), decl_origin.ctx));

ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
&decl->getASTContext());

if (!TypeSystemClang::UseRedeclCompletion()) {
if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
return false;

if (delegate_sp)
delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
} else {
if (TypeSystemClang::UseRedeclCompletion()) {
auto *origin_def = llvm::cast<TagDecl>(decl_origin.decl)->getDefinition();
if (!origin_def)
return false;

ImporterDelegateSP delegate_sp(
GetDelegate(&decl->getASTContext(), decl_origin.ctx));

ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
&decl->getASTContext());

// This is expected to pull in a definition for result_decl (if in redecl
// completion mode)
llvm::Expected<Decl *> result = delegate_sp->Import(origin_def);
Expand All @@ -859,6 +853,18 @@ bool ClangASTImporter::CompleteTagDecl(clang::TagDecl *decl) {
if (!decl->isThisDeclarationADefinition() && result_decl != decl)
if (result_decl->getPreviousDecl() == nullptr)
result_decl->setPreviousDecl(decl);
} else {
if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
return false;

ImporterDelegateSP delegate_sp(
GetDelegate(&decl->getASTContext(), decl_origin.ctx));

ASTImporterDelegate::CxxModuleScope std_scope(*delegate_sp,
&decl->getASTContext());

if (delegate_sp)
delegate_sp->ImportDefinitionTo(decl, decl_origin.decl);
}

return true;
Expand All @@ -880,27 +886,15 @@ bool ClangASTImporter::CompleteObjCInterfaceDecl(
if (!decl_origin.Valid())
return false;

ImporterDelegateSP delegate_sp(
GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));

if (!TypeSystemClang::UseRedeclCompletion()) {
if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
return false;

if (delegate_sp)
delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);

if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));
} else {
if (TypeSystemClang::UseRedeclCompletion()) {
ObjCInterfaceDecl *origin_decl =
llvm::cast<ObjCInterfaceDecl>(decl_origin.decl);

origin_decl = origin_decl->getDefinition();
if (!origin_decl)
return false;

auto delegate_sp(
ImporterDelegateSP delegate_sp(
GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));

llvm::Expected<Decl *> result = delegate_sp->Import(origin_decl);
Expand All @@ -915,6 +909,18 @@ bool ClangASTImporter::CompleteObjCInterfaceDecl(
return false;
}

if (!TypeSystemClang::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
return false;

ImporterDelegateSP delegate_sp(
GetDelegate(&interface_decl->getASTContext(), decl_origin.ctx));

if (delegate_sp)
delegate_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);

if (ObjCInterfaceDecl *super_class = interface_decl->getSuperClass())
RequireCompleteType(clang::QualType(super_class->getTypeForDecl(), 0));

return true;
}

Expand Down Expand Up @@ -1204,15 +1210,14 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) {
DeclContext::lookup_result lr = dc->lookup(*dn_or_err);
for (clang::Decl *candidate : lr) {
if (candidate->getKind() == From->getKind()) {
RegisterImportedDecl(From, candidate);

// If we're dealing with redecl chains. We want to find the definition,
// so skip if the decl is actually just a forwad decl.
if (TypeSystemClang::UseRedeclCompletion())
if (auto *tag_decl = llvm::dyn_cast<TagDecl>(candidate);
!tag_decl || !tag_decl->getDefinition())
continue;

RegisterImportedDecl(From, candidate);
m_decls_to_ignore.insert(candidate);
return candidate;
}
Expand Down
121 changes: 121 additions & 0 deletions lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "ClangDeclVendor.h"
#include "ClangModulesDeclVendor.h"

#include "NameSearchContext.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Symbol/CompilerDeclContext.h"
Expand All @@ -21,6 +22,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/SourceManager.h"

#include "Plugins/ExpressionParser/Clang/ClangUtil.h"
Expand Down Expand Up @@ -615,6 +617,125 @@ bool ClangASTSource::IgnoreName(const ConstString name,
name_string_ref.startswith("_$");
}

bool ClangASTSource::FindExternalVisibleMethodsByName(
const clang::DeclContext *DC, clang::DeclarationName Name) {
if (!TypeSystemClang::UseRedeclCompletion())
return true;

SmallVector<clang::NamedDecl *> decls;
NameSearchContext context(*m_clang_ast_context, decls, Name, DC);
FindExternalVisibleMethods(context);

return true;
}

void ClangASTSource::FindExternalVisibleMethods(NameSearchContext &context) {
assert(m_ast_context);

const ConstString name(context.m_decl_name.getAsString().c_str());
CompilerDeclContext namespace_decl;
FindExternalVisibleMethods(context, lldb::ModuleSP(), namespace_decl);
}

bool ClangASTSource::CompilerDeclContextsMatch(
CompilerDeclContext candidate_decl_ctx, DeclContext const *context,
TypeSystemClang &ts) {
auto CDC1 = candidate_decl_ctx.GetTypeSystem()->DeclContextGetCompilerContext(
candidate_decl_ctx.GetOpaqueDeclContext());

// Member functions have at least 2 entries (1
// for method name, 1 for parent class)
assert(CDC1.size() > 1);

// drop last entry (which is function name)
CDC1.pop_back();

const auto CDC2 = ts.DeclContextGetCompilerContext(
const_cast<clang::DeclContext *>(context));

// Quick by-name check of the entire context hierarchy.
if (CDC1 == CDC2)
return true;

// Otherwise, check whether the 'candidate_decl_ctx' is a base class of
// 'context'.
auto const *candidate_context =
(static_cast<clang::DeclContext *>(
candidate_decl_ctx.GetOpaqueDeclContext()))
->getParent();

auto const *candidate_cxx_record =
dyn_cast<clang::CXXRecordDecl>(candidate_context);
if (!candidate_cxx_record)
return false;

auto const *cxx_record = dyn_cast<clang::CXXRecordDecl>(context);
if (!cxx_record)
return false;

// cxx_record comes from user expression AST. So we need to get origin
// to compare against candidate_context.
auto orig = GetDeclOrigin(cxx_record);
if (!orig.Valid())
return false;

if (llvm::cast<CXXRecordDecl>(orig.decl)->isDerivedFrom(candidate_cxx_record))
return true;

return false;
}

void ClangASTSource::FindExternalVisibleMethods(
NameSearchContext &context, lldb::ModuleSP module_sp,
CompilerDeclContext &namespace_decl) {
assert(m_ast_context);

SymbolContextList sc_list;
const ConstString name(context.m_decl_name.getAsString().c_str());
if (!m_target)
return;

if (context.m_found_type)
return;

ModuleFunctionSearchOptions function_options;
function_options.include_inlines = false;
function_options.include_symbols = false;
m_target->GetImages().FindFunctions(name, lldb::eFunctionNameTypeMethod,
function_options, sc_list);

auto num_matches = sc_list.GetSize();
if (num_matches == 0)
return;

for (const SymbolContext &sym_ctx : sc_list) {
assert(sym_ctx.function);
CompilerDeclContext decl_ctx = sym_ctx.function->GetDeclContext();
if (!decl_ctx)
continue;

assert(decl_ctx.IsClassMethod());

if (!CompilerDeclContextsMatch(decl_ctx, context.m_decl_context,
context.m_clang_ts))
continue;

clang::CXXMethodDecl *src_method = llvm::cast<CXXMethodDecl>(
static_cast<clang::DeclContext *>(decl_ctx.GetOpaqueDeclContext()));
Decl *copied_decl = CopyDecl(src_method);

if (!copied_decl)
continue;

CXXMethodDecl *copied_method_decl = dyn_cast<CXXMethodDecl>(copied_decl);

if (!copied_method_decl)
continue;

context.AddNamedDecl(copied_method_decl);
}
}

void ClangASTSource::FindExternalVisibleDecls(
NameSearchContext &context, lldb::ModuleSP module_sp,
CompilerDeclContext &namespace_decl) {
Expand Down
19 changes: 18 additions & 1 deletion lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class ClangASTSource : public ImporterBackedASTSource,
bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
clang::DeclarationName Name) override;

bool FindExternalVisibleMethodsByName(const clang::DeclContext *DC,
clang::DeclarationName Name) override;

/// Enumerate all Decls in a given lexical context.
///
/// \param[in] DC
Expand Down Expand Up @@ -197,6 +200,7 @@ class ClangASTSource : public ImporterBackedASTSource,
/// \param[in] context
/// The NameSearchContext to use when filing results.
virtual void FindExternalVisibleDecls(NameSearchContext &context);
virtual void FindExternalVisibleMethods(NameSearchContext &context);

clang::Sema *getSema();

Expand All @@ -210,7 +214,7 @@ class ClangASTSource : public ImporterBackedASTSource,
///
/// Clang AST contexts like to own their AST sources, so this is a state-
/// free proxy object.
class ClangASTSourceProxy : public clang::ExternalASTSource {
class ClangASTSourceProxy : public ImporterBackedASTSource {
public:
ClangASTSourceProxy(ClangASTSource &original) : m_original(original) {}

Expand All @@ -219,6 +223,12 @@ class ClangASTSource : public ImporterBackedASTSource,
return m_original.FindExternalVisibleDeclsByName(DC, Name);
}

bool
FindExternalVisibleMethodsByName(const clang::DeclContext *DC,
clang::DeclarationName Name) override {
return m_original.FindExternalVisibleMethodsByName(DC, Name);
}

void FindExternalLexicalDecls(
const clang::DeclContext *DC,
llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
Expand Down Expand Up @@ -288,6 +298,9 @@ class ClangASTSource : public ImporterBackedASTSource,
void FindExternalVisibleDecls(NameSearchContext &context,
lldb::ModuleSP module,
CompilerDeclContext &namespace_decl);
void FindExternalVisibleMethods(NameSearchContext &context,
lldb::ModuleSP module,
CompilerDeclContext &namespace_decl);

/// Find all Objective-C methods matching a given selector.
///
Expand Down Expand Up @@ -364,6 +377,10 @@ class ClangASTSource : public ImporterBackedASTSource,
NameSearchContext &context,
DeclFromUser<const clang::ObjCInterfaceDecl> &origin_iface_decl);

bool CompilerDeclContextsMatch(CompilerDeclContext candidate_decl_ctx,
clang::DeclContext const *context,
TypeSystemClang &ts);

protected:
bool FindObjCMethodDeclsWithOrigin(
NameSearchContext &context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,13 @@ void ClangExpressionDeclMap::LookupFunction(
}
}

void ClangExpressionDeclMap::FindExternalVisibleMethods(
NameSearchContext &context) {
assert(m_ast_context);

ClangASTSource::FindExternalVisibleMethods(context);
}

void ClangExpressionDeclMap::FindExternalVisibleDecls(
NameSearchContext &context, lldb::ModuleSP module_sp,
const CompilerDeclContext &namespace_decl) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "ClangASTSource.h"
#include "ClangExpressionVariable.h"

#include "Plugins/ExpressionParser/Clang/NameSearchContext.h"
#include "lldb/Core/Value.h"
#include "lldb/Expression/Materializer.h"
#include "lldb/Symbol/SymbolContext.h"
Expand Down Expand Up @@ -266,6 +267,7 @@ class ClangExpressionDeclMap : public ClangASTSource {
/// \param[in] context
/// The NameSearchContext that can construct Decls for this name.
void FindExternalVisibleDecls(NameSearchContext &context) override;
void FindExternalVisibleMethods(NameSearchContext &context) override;

/// Find all entities matching a given name in a given module/namespace,
/// using a NameSearchContext to make Decls for them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ class ClangExternalASTSourceCallbacks : public ImporterBackedASTSource {
bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
clang::DeclarationName Name) override;

bool FindExternalVisibleMethodsByName(const clang::DeclContext *DC,
clang::DeclarationName Name) override {
return false;
}

void CompleteType(clang::TagDecl *tag_decl) override;

void CompleteType(clang::ObjCInterfaceDecl *objc_decl) override;
Expand Down
Loading