[Lldb-commits] [lldb] [lldb][TypeSystemClang][NFCI] Factor completion logic for individual types in GetCompleteQualType (PR #95402)
Michael Buch via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 13 07:07:01 PDT 2024
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 <michaelbuch12 at 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 <michaelbuch12 at 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();
More information about the lldb-commits
mailing list