mirror of
https://github.com/intel/llvm.git
synced 2026-01-22 23:49:22 +08:00
[lldb][TypeSystemClang][NFCI] Factor completion logic for individual types out of GetCompleteQualType (#95402)
This patch factors out the completion logic for individual clang::Type's into their own helper functions. During the process I cleaned up a few assumptions (e.g., unnecessary if-guards that could be asserts because these conditions are guaranteed by the `clang::Type::TypeClass` switch in `GetCompleteQualType`). This is mainly motivated by the type-completion rework proposed in https://github.com/llvm/llvm-project/pull/95100.
This commit is contained in:
@@ -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) {
|
||||
@@ -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 (const auto *OT =
|
||||
GetCompleteObjCObjectType(ast, qual_type, allow_completion))
|
||||
return !OT->isIncompleteType();
|
||||
|
||||
if (!allow_completion)
|
||||
return false;
|
||||
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user