Skip to content

[lldb][TypeSystemClang][NFCI] Factor completion logic for individual types out of GetCompleteQualType #95402

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

Merged
Merged
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
210 changes: 133 additions & 77 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2574,6 +2574,128 @@ TypeSystemClang::GetDeclContextForType(clang::QualType type) {
return nullptr;
}

/// Returns the clang::RecordType of the specified \ref qual_type. This
/// function will try to complete the type if necessary (and allowed
/// by the specified \ref allow_completion). If we fail to return a *complete*
/// type, returns nullptr.
static const clang::RecordType *GetCompleteRecordType(clang::ASTContext *ast,
clang::QualType qual_type,
bool allow_completion) {
assert(qual_type->isRecordType());

const auto *tag_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr());

clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();

// RecordType with no way of completing it, return the plain
// TagType.
if (!cxx_record_decl || !cxx_record_decl->hasExternalLexicalStorage())
return tag_type;

const bool is_complete = cxx_record_decl->isCompleteDefinition();
const bool fields_loaded =
cxx_record_decl->hasLoadedFieldsFromExternalStorage();

// Already completed this type, nothing to be done.
if (is_complete && fields_loaded)
return tag_type;

if (!allow_completion)
return nullptr;

// Call the field_begin() accessor to for it to use the external source
// to load the fields...
//
// TODO: if we need to complete the type but have no external source,
// shouldn't we error out instead?
clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
if (external_ast_source) {
external_ast_source->CompleteType(cxx_record_decl);
if (cxx_record_decl->isCompleteDefinition()) {
cxx_record_decl->field_begin();
cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
}
}

return tag_type;
}

/// Returns the clang::EnumType of the specified \ref qual_type. This
/// function will try to complete the type if necessary (and allowed
/// by the specified \ref allow_completion). If we fail to return a *complete*
/// type, returns nullptr.
static const clang::EnumType *GetCompleteEnumType(clang::ASTContext *ast,
clang::QualType qual_type,
bool allow_completion) {
assert(qual_type->isEnumeralType());
assert(ast);

const clang::EnumType *enum_type =
llvm::cast<clang::EnumType>(qual_type.getTypePtr());

auto *tag_decl = enum_type->getAsTagDecl();
assert(tag_decl);

// Already completed, nothing to be done.
if (tag_decl->getDefinition())
return enum_type;

if (!allow_completion)
return nullptr;

// No definition but can't complete it, error out.
if (!tag_decl->hasExternalLexicalStorage())
return nullptr;

// We can't complete the type without an external source.
clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
if (!external_ast_source)
return nullptr;

external_ast_source->CompleteType(tag_decl);
return enum_type;
}

/// Returns the clang::ObjCObjectType of the specified \ref qual_type. This
/// function will try to complete the type if necessary (and allowed
/// by the specified \ref allow_completion). If we fail to return a *complete*
/// type, returns nullptr.
static const clang::ObjCObjectType *
GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type,
bool allow_completion) {
assert(qual_type->isObjCObjectType());
assert(ast);

const clang::ObjCObjectType *objc_class_type =
llvm::cast<clang::ObjCObjectType>(qual_type);

clang::ObjCInterfaceDecl *class_interface_decl =
objc_class_type->getInterface();
// We currently can't complete objective C types through the newly added
// ASTContext because it only supports TagDecl objects right now...
if (!class_interface_decl)
return objc_class_type;

// Already complete, nothing to be done.
if (class_interface_decl->getDefinition())
return objc_class_type;

if (!allow_completion)
return nullptr;

// No definition but can't complete it, error out.
if (!class_interface_decl->hasExternalLexicalStorage())
return nullptr;

// We can't complete the type without an external source.
clang::ExternalASTSource *external_ast_source = ast->getExternalSource();
if (!external_ast_source)
return nullptr;

external_ast_source->CompleteType(class_interface_decl);
return objc_class_type;
}

static bool GetCompleteQualType(clang::ASTContext *ast,
clang::QualType qual_type,
bool allow_completion = true) {
Expand All @@ -2591,92 +2713,26 @@ static bool GetCompleteQualType(clang::ASTContext *ast,
allow_completion);
} break;
case clang::Type::Record: {
clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
if (cxx_record_decl) {
if (cxx_record_decl->hasExternalLexicalStorage()) {
const bool is_complete = cxx_record_decl->isCompleteDefinition();
const bool fields_loaded =
cxx_record_decl->hasLoadedFieldsFromExternalStorage();
if (is_complete && fields_loaded)
return true;
if (const auto *RT =
GetCompleteRecordType(ast, qual_type, allow_completion))
return !RT->isIncompleteType();

if (!allow_completion)
return false;

// Call the field_begin() accessor to for it to use the external source
// to load the fields...
clang::ExternalASTSource *external_ast_source =
ast->getExternalSource();
if (external_ast_source) {
external_ast_source->CompleteType(cxx_record_decl);
if (cxx_record_decl->isCompleteDefinition()) {
cxx_record_decl->field_begin();
cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true);
}
}
}
}
const clang::TagType *tag_type =
llvm::cast<clang::TagType>(qual_type.getTypePtr());
return !tag_type->isIncompleteType();
return false;
} break;

case clang::Type::Enum: {
const clang::TagType *tag_type =
llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr());
if (tag_type) {
clang::TagDecl *tag_decl = tag_type->getDecl();
if (tag_decl) {
if (tag_decl->getDefinition())
return true;

if (!allow_completion)
return false;

if (tag_decl->hasExternalLexicalStorage()) {
if (ast) {
clang::ExternalASTSource *external_ast_source =
ast->getExternalSource();
if (external_ast_source) {
external_ast_source->CompleteType(tag_decl);
return !tag_type->isIncompleteType();
}
}
}
return false;
}
}
if (const auto *ET = GetCompleteEnumType(ast, qual_type, allow_completion))
return !ET->isIncompleteType();

return false;
} break;
case clang::Type::ObjCObject:
case clang::Type::ObjCInterface: {
const clang::ObjCObjectType *objc_class_type =
llvm::dyn_cast<clang::ObjCObjectType>(qual_type);
if (objc_class_type) {
clang::ObjCInterfaceDecl *class_interface_decl =
objc_class_type->getInterface();
// We currently can't complete objective C types through the newly added
// ASTContext because it only supports TagDecl objects right now...
if (class_interface_decl) {
if (class_interface_decl->getDefinition())
return true;

if (!allow_completion)
return false;
if (const auto *OT =
GetCompleteObjCObjectType(ast, qual_type, allow_completion))
return !OT->isIncompleteType();

if (class_interface_decl->hasExternalLexicalStorage()) {
if (ast) {
clang::ExternalASTSource *external_ast_source =
ast->getExternalSource();
if (external_ast_source) {
external_ast_source->CompleteType(class_interface_decl);
return !objc_class_type->isIncompleteType();
}
}
}
return false;
}
}
return false;
} break;

case clang::Type::Attributed:
Expand Down
Loading