diff --git a/resect.h b/resect.h index 10bed9e..79341a0 100644 --- a/resect.h +++ b/resect.h @@ -231,6 +231,12 @@ typedef enum { RESECT_CONSTRUCTOR_KIND_OTHER = 5, } resect_constructor_kind; +typedef enum { + RESECT_REF_QUALIFIER_NONE = 0, + RESECT_REF_QUALIFIER_LVALUE = 1, + RESECT_REF_QUALIFIER_RVALUE = 2 +} resect_ref_qualifier; + typedef struct P_resect_translation_unit *resect_translation_unit; typedef struct P_resect_collection *resect_collection; typedef struct P_resect_iterator *resect_iterator; @@ -496,6 +502,8 @@ RESECT_API resect_bool resect_method_is_const(resect_decl decl); RESECT_API resect_bool resect_method_is_deleted(resect_decl decl); +RESECT_API resect_bool resect_method_is_constructor(resect_decl decl); + /* * MACRO */ diff --git a/src/decl.c b/src/decl.c index 6e0976e..bc4472c 100644 --- a/src/decl.c +++ b/src/decl.c @@ -189,13 +189,19 @@ struct P_resect_decl { resect_data_deallocator data_deallocator; }; -resect_decl_kind convert_cursor_kind(CXCursor cursor) { +enum CXCursorKind get_cursor_kind(CXCursor cursor) { enum CXCursorKind clang_kind = clang_getTemplateCursorKind(cursor); if (clang_kind == CXCursor_NoDeclFound) { clang_kind = clang_getCursorKind(cursor); } + return clang_kind; +} + +resect_decl_kind convert_cursor_kind(CXCursor cursor) { + enum CXCursorKind clang_kind = get_cursor_kind(cursor); + switch (clang_kind) { case CXCursor_MacroDefinition: return RESECT_DECL_KIND_MACRO; @@ -947,6 +953,7 @@ typedef struct P_resect_function_data { resect_function_calling_convention calling_convention; resect_type result_type; resect_bool inlined; + resect_ref_qualifier ref_qualifier; } *resect_function_data; resect_type resect_function_get_result_type(resect_decl decl) { @@ -1097,10 +1104,22 @@ resect_function_data resect_function_data_create(resect_visit_context visit_cont data->variadic = clang_isFunctionTypeVariadic(functionType) != 0 ? resect_true : resect_false; data->result_type = resect_type_create(visit_context, context, clang_getResultType(functionType)); data->inlined = convert_bool_from_uint(clang_Cursor_isFunctionInlined(cursor)); + data->ref_qualifier = convert_ref_qualifier(clang_Type_getCXXRefQualifier(functionType)); return data; } +resect_ref_qualifier convert_ref_qualifier(enum CXRefQualifierKind qual) { + switch (qual) { + case CXRefQualifier_LValue: + return RESECT_REF_QUALIFIER_LVALUE; + case CXRefQualifier_RValue: + return RESECT_REF_QUALIFIER_RVALUE; + default: + return RESECT_REF_QUALIFIER_NONE; + } +} + void resect_function_init(resect_visit_context visit_context, resect_translation_context context, resect_decl decl, CXCursor cursor) { resect_function_data function_data = resect_function_data_create(visit_context, context, cursor); @@ -1376,6 +1395,9 @@ typedef struct P_resect_method_data { resect_bool virtual; resect_bool non_mutating; resect_bool deleted; + resect_bool constructor; + resect_bool copy_constructor; + resect_bool copy_assign; } *resect_method_data; resect_type resect_method_get_result_type(resect_decl decl) { @@ -1420,12 +1442,40 @@ resect_bool resect_method_is_deleted(resect_decl decl) { return data->deleted; } +resect_bool resect_method_is_constructor(resect_decl decl) { + assert(decl->kind == RESECT_DECL_KIND_METHOD); + resect_method_data data = decl->data; + return data->constructor; +} + +resect_bool resect_method_is_copy_constructor(resect_decl decl) { + if (decl->kind != RESECT_DECL_KIND_METHOD || decl->data == NULL) { + return resect_false; + } + resect_method_data data = decl->data; + return data->copy_constructor; +} + +resect_bool resect_method_is_copy_assignment(resect_decl decl) { + if (decl->kind != RESECT_DECL_KIND_METHOD || decl->data == NULL) { + return resect_false; + } + resect_method_data data = decl->data; + return data->copy_assign; +} + resect_collection resect_method_parameters(resect_decl decl) { assert(decl->kind == RESECT_DECL_KIND_METHOD); resect_method_data data = decl->data; return data->function_data->parameters; } +resect_ref_qualifier resect_method_get_ref_qualifier(resect_decl decl) { + assert(decl->kind == RESECT_DECL_KIND_METHOD); + resect_method_data data = decl->data; + return data->function_data->ref_qualifier; +} + enum CXChildVisitResult resect_visit_method_parameter(CXCursor cursor, CXCursor parent, CXClientData data) { resect_decl_child_visit_data visit_data = data; resect_method_data method_data = visit_data->parent->data; @@ -1454,6 +1504,9 @@ void resect_method_init(resect_visit_context visit_context, resect_translation_c data->pure_virtual = clang_CXXMethod_isPureVirtual(cursor) > 0; data->non_mutating = clang_CXXMethod_isConst(cursor) > 0; data->deleted = clang_CXXMethod_isDeleted(cursor) > 0; + data->constructor = get_cursor_kind(cursor) == CXCursor_Constructor; + data->copy_constructor = (data->constructor && clang_CXXConstructor_isCopyConstructor(cursor)); + data->copy_assign = clang_CXXMethod_isCopyAssignmentOperator(cursor); decl->data_deallocator = resect_method_data_free; decl->data = data; diff --git a/src/resect_private.h b/src/resect_private.h index 414e8a3..2dc23d6 100644 --- a/src/resect_private.h +++ b/src/resect_private.h @@ -276,6 +276,8 @@ resect_bool resect_is_forward_declaration(CXCursor cursor); resect_bool resect_is_specialized(CXCursor cursor); +enum CXCursorKind get_cursor_kind(CXCursor cursor); + resect_decl_kind convert_cursor_kind(CXCursor cursor); bool is_cursor_anonymous(CXCursor cursor); @@ -286,6 +288,12 @@ resect_decl_visit_data resect_decl_visit_data_create(resect_translation_context void resect_visit_decl_data_free(resect_decl_visit_data data); +resect_ref_qualifier convert_ref_qualifier(enum CXRefQualifierKind qual); + +resect_bool resect_method_is_copy_assignment(resect_decl decl); + +resect_bool resect_method_is_copy_constructor(resect_decl decl); + /* * TEMPLATE ARGUMENT */ diff --git a/src/shaking.c b/src/shaking.c index 07a29fe..54b1207 100644 --- a/src/shaking.c +++ b/src/shaking.c @@ -267,9 +267,6 @@ static void resect_investigate_owner(resect_visit_context visit_context, resect_ CXCursor cursor); static resect_access_level convert_access_level(CXCursor cursor) { - if (clang_getCursorKind(cursor) == CXCursor_CXXMethod && clang_CXXMethod_isDeleted(cursor)) { - return RESECT_ACCESS_LEVEL_INACCESSIBLE; - } CXType cursor_type = clang_getCursorType(cursor); // libclang cannot handle templated member-pointers diff --git a/src/type.c b/src/type.c index 2af12f2..4b0cecd 100644 --- a/src/type.c +++ b/src/type.c @@ -31,6 +31,10 @@ struct P_resect_type { resect_bool const_qualified; resect_bool pod; resect_bool undeclared; + resect_bool has_copy_constructor; + resect_bool copy_constructor_deleted; + resect_bool has_copy_assignment; + resect_bool copy_assignment_deleted; resect_collection template_arguments; resect_decl decl; @@ -306,6 +310,22 @@ static enum CXVisitorResult visit_type_method(CXCursor cursor, CXClientData data resect_type_method type_method = resect_method_create(visit_data->visit_context, visit_data->context, cursor); if (type_method != NULL) { resect_collection_add(visit_data->type->methods, type_method); + if (type_method->decl != NULL) { + if (resect_method_is_copy_constructor(type_method->decl)) { + if (resect_method_is_deleted(type_method->decl)) { + visit_data->type->copy_constructor_deleted = resect_true; + } else { + visit_data->type->has_copy_constructor = resect_true; + } + } + if (resect_method_is_copy_assignment(type_method->decl)) { + if (resect_method_is_deleted(type_method->decl)) { + visit_data->type->copy_assignment_deleted = resect_true; + } else { + visit_data->type->has_copy_assignment = resect_true; + } + } + } } return CXVisit_Continue; @@ -603,9 +623,22 @@ resect_type_category get_type_category(resect_type_kind kind) { */ resect_type resect_type_create(resect_visit_context visit_context, resect_translation_context context, CXType clang_type) { + resect_type type = resect_find_type(context, clang_type); + if (type != NULL) { + return type; + } + + CXType original_clang_type = clang_type; + resect_bool is_const = false; + // Not sure this can be true more than once -- but just in case, we loop + while (clang_type.kind == CXType_Elaborated) { + if (clang_isConstQualifiedType(clang_type)) { + is_const = true; + } + // Can unwrap to an Unexposed + clang_type = clang_Type_getNamedType(clang_type); + } switch (clang_type.kind) { - case CXType_Elaborated: - return resect_type_create(visit_context, context, clang_Type_getNamedType(clang_type)); case CXType_Unexposed: { CXType canonical_type = clang_getCanonicalType(clang_type); if (CXType_Unexposed != canonical_type.kind) { @@ -619,11 +652,6 @@ resect_type resect_type_create(resect_visit_context visit_context, resect_transl default: ; } - resect_type type = resect_find_type(context, clang_type); - if (type != NULL) { - return type; - } - type = malloc(sizeof(struct P_resect_type)); type->initialized = false; type->kind = convert_type_kind(clang_type.kind); @@ -646,11 +674,15 @@ resect_type resect_type_create(resect_visit_context visit_context, resect_transl type->pod = convert_bool_from_uint(clang_isPODType(clang_type)); type->template_arguments = resect_collection_create(); type->decl = NULL; + type->has_copy_constructor = resect_false; + type->copy_constructor_deleted = resect_false; + type->has_copy_assignment = resect_false; + type->copy_assignment_deleted = resect_false; type->data_deallocator = NULL; type->data = NULL; - resect_register_type(context, clang_type, type); + resect_register_type(context, original_clang_type, type); CXCursor declaration_cursor = clang_getTypeDeclaration(clang_type); if (declaration_cursor.kind == CXCursor_NoDeclFound) { @@ -699,6 +731,9 @@ resect_type resect_type_create(resect_visit_context visit_context, resect_transl } type->initialized = true; + if (is_const) { + type->const_qualified = true; + } if (type->decl != NULL) { if (resect_context_diagnostics_level(context) >= RESECT_DIAGNOSTICS_WARNING @@ -764,6 +799,14 @@ resect_decl resect_type_get_declaration(resect_type type) { return type->decl; } resect_type_category resect_type_get_category(resect_type type) { return type->category; } +resect_bool resect_type_has_copy_constructor(resect_type type) { return type->has_copy_constructor; } + +resect_bool resect_type_copy_constructor_deleted(resect_type type) { return type->copy_constructor_deleted; } + +resect_bool resect_type_has_copy_assignment(resect_type type) { return type->has_copy_assignment; } + +resect_bool resect_type_copy_assignment_deleted(resect_type type) { return type->copy_assignment_deleted; } + resect_collection resect_type_template_arguments(resect_type type) { return type->template_arguments; } resect_string resect_type_pretty_print(resect_translation_context context, CXType type) {