Author: Michael Buch Date: 2024-06-14T07:20:50+01:00 New Revision: f2d215f572affc9ad73da07763ce1831de7f2d4d
URL: https://github.com/llvm/llvm-project/commit/f2d215f572affc9ad73da07763ce1831de7f2d4d DIFF: https://github.com/llvm/llvm-project/commit/f2d215f572affc9ad73da07763ce1831de7f2d4d.diff LOG: [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. Added: Modified: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp Removed: ################################################################################ diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 369ae46cf264a..dbe6238d4fe5a 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -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 (!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: _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits