https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/95402
>From e3ecb1e686e16d90f860126c3ede758196df8f31 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 13 Jun 2024 13:22:04 +0100 Subject: [PATCH 1/2] [lldb][TypeSystemClang][NFC] Factor completion logic for individual types in GetCompleteQualType 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. --- .../TypeSystem/Clang/TypeSystemClang.cpp | 210 +++++++++++------- 1 file changed, 133 insertions(+), 77 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 369ae46cf264a..bef9263eaeafc 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 clang::RecordType const *GetCompleteRecordType(clang::ASTContext *ast, + clang::QualType qual_type, + bool allow_completion) { + assert(qual_type->isRecordType()); + + auto const *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 clang::EnumType const *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 clang::ObjCObjectType const * +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 (auto const *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 (auto const *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 (auto const *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: >From c085adcf1ca1cdba2f63e0be7e8b40b200414453 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Thu, 13 Jun 2024 15:06:35 +0100 Subject: [PATCH 2/2] fixup! fix const-placement style --- .../Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index bef9263eaeafc..dbe6238d4fe5a 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -2578,12 +2578,12 @@ TypeSystemClang::GetDeclContextForType(clang::QualType type) { /// 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 clang::RecordType const *GetCompleteRecordType(clang::ASTContext *ast, +static const clang::RecordType *GetCompleteRecordType(clang::ASTContext *ast, clang::QualType qual_type, bool allow_completion) { assert(qual_type->isRecordType()); - auto const *tag_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const auto *tag_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); @@ -2624,7 +2624,7 @@ static clang::RecordType const *GetCompleteRecordType(clang::ASTContext *ast, /// 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 clang::EnumType const *GetCompleteEnumType(clang::ASTContext *ast, +static const clang::EnumType *GetCompleteEnumType(clang::ASTContext *ast, clang::QualType qual_type, bool allow_completion) { assert(qual_type->isEnumeralType()); @@ -2660,7 +2660,7 @@ static clang::EnumType const *GetCompleteEnumType(clang::ASTContext *ast, /// 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 clang::ObjCObjectType const * +static const clang::ObjCObjectType * GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type, bool allow_completion) { assert(qual_type->isObjCObjectType()); @@ -2713,7 +2713,7 @@ static bool GetCompleteQualType(clang::ASTContext *ast, allow_completion); } break; case clang::Type::Record: { - if (auto const *RT = + if (const auto *RT = GetCompleteRecordType(ast, qual_type, allow_completion)) return !RT->isIncompleteType(); @@ -2721,14 +2721,14 @@ static bool GetCompleteQualType(clang::ASTContext *ast, } break; case clang::Type::Enum: { - if (auto const *ET = GetCompleteEnumType(ast, qual_type, allow_completion)) + if (const auto *ET = GetCompleteEnumType(ast, qual_type, allow_completion)) return !ET->isIncompleteType(); return false; } break; case clang::Type::ObjCObject: case clang::Type::ObjCInterface: { - if (auto const *OT = + if (const auto *OT = GetCompleteObjCObjectType(ast, qual_type, allow_completion)) return !OT->isIncompleteType(); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits