Allow objective-c procedures to have their @objc_name attribute inferred.

The `@objc_name` is automatically inferred if it is not specified and
the procedure name is prefixed with type name specified in `@objc_type`,
followed by an `_`. What followed the `_` is interpreted as the `@objc_name`.
This commit is contained in:
Harold Brenes
2025-07-16 17:14:57 -04:00
parent e8b2f1eeaa
commit edc01293b2
+20 -12
View File
@@ -1001,27 +1001,36 @@ gb_internal String handle_link_name(CheckerContext *ctx, Token token, String lin
gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) { gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) {
if (!(ac.objc_name.len || ac.objc_is_class_method || ac.objc_type)) { if (!ac.objc_type) {
return; return;
} }
if (ac.objc_name.len == 0 && ac.objc_is_class_method) {
error(e->token, "@(objc_name) is required with @(objc_is_class_method)");
} else if (ac.objc_type == nullptr) {
error(e->token, "@(objc_name) requires that @(objc_type) to be set");
} else if (ac.objc_name.len == 0 && ac.objc_type) {
error(e->token, "@(objc_name) is required with @(objc_type)");
} else {
Type *t = ac.objc_type; Type *t = ac.objc_type;
GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage. GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage.
Entity *tn = t->Named.type_name;
// Attempt to infer th objc_name automatically if the proc name contains
// the type name objc_type's name, followed by an underscore, as a prefix.
if (ac.objc_name.len == 0) {
String proc_name = e->token.string;
String type_name = t->Named.name;
if (proc_name.len > type_name.len + 1 &&
proc_name[type_name.len] == '_' &&
str_eq(type_name, substring(proc_name, 0, type_name.len))
) {
ac.objc_name = substring(proc_name, type_name.len+1, proc_name.len);
} else {
error(e->token, "@(objc_name) requires that @(objc_type) be set or inferred "
"by prefixing the proc name with the type and underscore: MyObjcType_myProcName :: proc().");
}
}
Entity *tn = t->Named.type_name;
GB_ASSERT(tn->kind == Entity_TypeName); GB_ASSERT(tn->kind == Entity_TypeName);
if (tn->scope != e->scope) { if (tn->scope != e->scope) {
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope"); error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
} else { } else {
// Enable implementation by default if the class is an implementer too and // Enable implementation by default if the class is an implementer too and
// @objc_implement was not set to false explicitly in this proc. // @objc_implement was not set to false explicitly in this proc.
bool implement = tn->TypeName.objc_is_implementation; bool implement = tn->TypeName.objc_is_implementation;
@@ -1116,7 +1125,6 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
} }
} }
} }
}
} }
gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) { gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {