diff options
author | Torsten Schönfeld <kaffeetisch@gmx.de> | 2011-08-13 17:28:30 +0200 |
---|---|---|
committer | Torsten Schönfeld <kaffeetisch@gmx.de> | 2011-08-16 18:43:23 +0200 |
commit | 169b206cbb4b347e4b17854e8f0c62a40404f803 (patch) | |
tree | 929ddaefcedf7c9d4778ea355e58f0b1cc2f2f96 | |
parent | 64848acb817369436d629d153c5750789c0addc3 (diff) | |
download | gobject-introspection-169b206cbb4b347e4b17854e8f0c62a40404f803.tar.gz |
Allow enums and bitfields to have static methods
This uses the same backcompat machinery that was introduced for static
methods for non-class types, so this change does not break users of the
existing presentations.
New libgirepository API:
g_enum_info_get_n_methods
g_enum_info_get_method
https://bugzilla.gnome.org/show_bug.cgi?id=656499
-rw-r--r-- | docs/reference/gi-sections.txt | 2 | ||||
-rw-r--r-- | girepository/gienuminfo.c | 55 | ||||
-rw-r--r-- | girepository/gienuminfo.h | 3 | ||||
-rw-r--r-- | girepository/girnode.c | 18 | ||||
-rw-r--r-- | girepository/girnode.h | 1 | ||||
-rw-r--r-- | girepository/girparser.c | 17 | ||||
-rw-r--r-- | girepository/gitypelib-internal.h | 9 | ||||
-rw-r--r-- | girepository/gitypelib.c | 22 | ||||
-rw-r--r-- | giscanner/ast.py | 10 | ||||
-rw-r--r-- | giscanner/girparser.py | 3 | ||||
-rw-r--r-- | giscanner/girwriter.py | 4 | ||||
-rw-r--r-- | giscanner/maintransformer.py | 2 | ||||
-rw-r--r-- | tests/repository/gitypelibtest.c | 57 | ||||
-rw-r--r-- | tests/scanner/Foo-1.0-expected.gir | 37 | ||||
-rw-r--r-- | tests/scanner/Regress-1.0-expected.gir | 14 |
15 files changed, 237 insertions, 17 deletions
diff --git a/docs/reference/gi-sections.txt b/docs/reference/gi-sections.txt index 6d796f0d..7db8378d 100644 --- a/docs/reference/gi-sections.txt +++ b/docs/reference/gi-sections.txt @@ -191,6 +191,8 @@ GIEnumInfo GIValueInfo g_enum_info_get_n_values g_enum_info_get_value +g_enum_info_get_n_methods +g_enum_info_get_method g_enum_info_get_storage_type g_value_info_get_value </SECTION> diff --git a/girepository/gienuminfo.c b/girepository/gienuminfo.c index 338a46ee..90b19a96 100644 --- a/girepository/gienuminfo.c +++ b/girepository/gienuminfo.c @@ -112,6 +112,61 @@ g_enum_info_get_value (GIEnumInfo *info, } /** + * g_enum_info_get_n_methods: + * @info: a #GIEnumInfo + * + * Obtain the number of methods that this enum type has. + * + * Returns: number of methods + */ +gint +g_enum_info_get_n_methods (GIEnumInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), 0); + + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_methods; +} + +/** + * g_enum_info_get_method: + * @info: a #GIEnumInfo + * @n: index of method to get + * + * Obtain an enum type method at index @n. + * + * Returns: (transfer full): the #GIFunctionInfo. Free the struct by calling + * g_base_info_unref() when done. + */ +GIFunctionInfo * +g_enum_info_get_method (GIEnumInfo *info, + gint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->enum_blob_size + + blob->n_values * header->value_blob_size + + n * header->function_blob_size; + + return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** * g_enum_info_get_storage_type: * @info: a #GIEnumInfo * diff --git a/girepository/gienuminfo.h b/girepository/gienuminfo.h index fc0f3c84..def97f95 100644 --- a/girepository/gienuminfo.h +++ b/girepository/gienuminfo.h @@ -40,6 +40,9 @@ G_BEGIN_DECLS gint g_enum_info_get_n_values (GIEnumInfo *info); GIValueInfo * g_enum_info_get_value (GIEnumInfo *info, gint n); +gint g_enum_info_get_n_methods (GIEnumInfo *info); +GIFunctionInfo * g_enum_info_get_method (GIEnumInfo *info, + gint n); GITypeTag g_enum_info_get_storage_type (GIEnumInfo *info); const gchar * g_enum_info_get_error_domain (GIEnumInfo *info); diff --git a/girepository/girnode.c b/girepository/girnode.c index 166ca30a..fcc8ce5e 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -333,6 +333,10 @@ _g_ir_node_free (GIrNode *node) for (l = enum_->values; l; l = l->next) _g_ir_node_free ((GIrNode *)l->data); g_list_free (enum_->values); + + for (l = enum_->methods; l; l = l->next) + _g_ir_node_free ((GIrNode *)l->data); + g_list_free (enum_->methods); } break; @@ -467,6 +471,8 @@ _g_ir_node_get_size (GIrNode *node) size = sizeof (EnumBlob); for (l = enum_->values; l; l = l->next) size += _g_ir_node_get_size ((GIrNode *)l->data); + for (l = enum_->methods; l; l = l->next) + size += _g_ir_node_get_size ((GIrNode *)l->data); } break; @@ -718,6 +724,8 @@ _g_ir_node_get_full_size_internal (GIrNode *parent, for (l = enum_->values; l; l = l->next) size += _g_ir_node_get_full_size_internal (node, (GIrNode *)l->data); + for (l = enum_->methods; l; l = l->next) + size += _g_ir_node_get_full_size_internal (node, (GIrNode *)l->data); } break; @@ -2030,7 +2038,7 @@ _g_ir_node_build_typelib (GIrNode *node, blob->error_domain = 0; blob->n_values = 0; - blob->reserved2 = 0; + blob->n_methods = 0; for (l = enum_->values; l; l = l->next) { @@ -2039,6 +2047,14 @@ _g_ir_node_build_typelib (GIrNode *node, blob->n_values++; _g_ir_node_build_typelib (value, node, build, offset, offset2); } + + for (l = enum_->methods; l; l = l->next) + { + GIrNode *method = (GIrNode *)l->data; + + blob->n_methods++; + _g_ir_node_build_typelib (method, node, build, offset, offset2); + } } break; diff --git a/girepository/girnode.h b/girepository/girnode.h index 6e03821b..32863455 100644 --- a/girepository/girnode.h +++ b/girepository/girnode.h @@ -288,6 +288,7 @@ struct _GIrNodeEnum gchar *error_domain; GList *values; + GList *methods; }; struct _GIrNodeBoxed diff --git a/girepository/girparser.c b/girepository/girparser.c index c9b7d629..6984e826 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -805,6 +805,9 @@ start_function (GMarkupParseContext *context, strcmp (element_name, "method") == 0 || strcmp (element_name, "callback") == 0); break; + case STATE_ENUM: + found = strcmp (element_name, "function") == 0; + break; case STATE_STRUCT_FIELD: found = (found || strcmp (element_name, "callback") == 0); break; @@ -925,6 +928,15 @@ start_function (GMarkupParseContext *context, union_->members = g_list_append (union_->members, function); } break; + case G_IR_NODE_ENUM: + case G_IR_NODE_FLAGS: + { + GIrNodeEnum *enum_; + + enum_ = (GIrNodeEnum *)CURRENT_NODE (ctx); + enum_->methods = g_list_append (enum_->methods, function); + } + break; default: g_assert_not_reached (); } @@ -3186,6 +3198,9 @@ end_element_handler (GMarkupParseContext *context, state_switch (ctx, STATE_STRUCT); else if (CURRENT_NODE (ctx)->type == G_IR_NODE_UNION) state_switch (ctx, STATE_UNION); + else if (CURRENT_NODE (ctx)->type == G_IR_NODE_ENUM || + CURRENT_NODE (ctx)->type == G_IR_NODE_FLAGS) + state_switch (ctx, STATE_ENUM); else { int line_number, char_number; @@ -3256,6 +3271,8 @@ end_element_handler (GMarkupParseContext *context, case STATE_ENUM: if (strcmp ("member", element_name) == 0) break; + else if (strcmp ("function", element_name) == 0) + break; else if (require_one_of_end_elements (context, ctx, element_name, error, "enumeration", "bitfield", NULL)) diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index 1dde5163..f450a2fb 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -800,8 +800,10 @@ typedef struct { * @gtype_init: String naming the symbol which gets the runtime #GType * @error_domain: String naming the #GError domain this enum is * associated with - * @n_values: The lengths of the values arrays. + * @n_values: The length of the values array. + * @n_methods: The length of the methods array. * @values: Describes the enum values. + * @methods: Describes the enum methods. */ typedef struct { guint16 blob_type; @@ -817,11 +819,14 @@ typedef struct { guint32 gtype_init; guint16 n_values; - guint16 reserved2; + guint16 n_methods; guint32 error_domain; ValueBlob values[]; +#if 0 + FunctionBlob methods[]; +#endif } EnumBlob; /** diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c index f610d458..2e5b0e1b 100644 --- a/girepository/gitypelib.c +++ b/girepository/gitypelib.c @@ -1428,6 +1428,7 @@ validate_enum_blob (ValidateContext *ctx, GITypelib *typelib = ctx->typelib; EnumBlob *blob; gint i; + guint32 offset2; if (typelib->len < offset + sizeof (EnumBlob)) { @@ -1473,7 +1474,8 @@ validate_enum_blob (ValidateContext *ctx, return FALSE; if (typelib->len < offset + sizeof (EnumBlob) + - blob->n_values * sizeof (ValueBlob)) + blob->n_values * sizeof (ValueBlob) + + blob->n_methods * sizeof (FunctionBlob)) { g_set_error (error, G_TYPELIB_ERROR, @@ -1482,22 +1484,22 @@ validate_enum_blob (ValidateContext *ctx, return FALSE; } + offset2 = offset + sizeof (EnumBlob); + push_context (ctx, get_string_nofail (typelib, blob->name)); - for (i = 0; i < blob->n_values; i++) + for (i = 0; i < blob->n_values; i++, offset2 += sizeof (ValueBlob)) { if (!validate_value_blob (typelib, - offset + sizeof (EnumBlob) + - i * sizeof (ValueBlob), + offset2, error)) return FALSE; #if 0 - v1 = (ValueBlob *)&typelib->data[offset + sizeof (EnumBlob) + - i * sizeof (ValueBlob)]; + v1 = (ValueBlob *)&typelib->data[offset2]; for (j = 0; j < i; j++) { - v2 = (ValueBlob *)&typelib->data[offset + sizeof (EnumBlob) + + v2 = (ValueBlob *)&typelib->data[offset2 + j * sizeof (ValueBlob)]; if (v1->value == v2->value) @@ -1514,6 +1516,12 @@ validate_enum_blob (ValidateContext *ctx, #endif } + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (ctx, offset2, BLOB_TYPE_ENUM, error)) + return FALSE; + } + pop_context (ctx); return TRUE; diff --git a/giscanner/ast.py b/giscanner/ast.py index 1433422c..373daa9f 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -736,6 +736,11 @@ class Enum(Node, Registered): self.members = members # Associated error domain name self.error_domain = None + self.static_methods = [] + + def _walk(self, callback, chain): + for meth in self.static_methods: + meth.walk(callback, chain) class Bitfield(Node, Registered): @@ -750,6 +755,11 @@ class Bitfield(Node, Registered): self.ctype = ctype self.c_symbol_prefix = c_symbol_prefix self.members = members + self.static_methods = [] + + def _walk(self, callback, chain): + for meth in self.static_methods: + meth.walk(callback, chain) class Member(Annotated): diff --git a/giscanner/girparser.py b/giscanner/girparser.py index 51ef9340..8568fea3 100644 --- a/giscanner/girparser.py +++ b/giscanner/girparser.py @@ -572,3 +572,6 @@ class GIRParser(object): return for member in self._find_children(node, _corens('member')): members.append(self._parse_member(member)) + for func_node in self._find_children(node, _corens('function')): + func = self._parse_function_common(func_node, ast.Function) + obj.static_methods.append(func) diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index f9937291..f1e150df 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -337,6 +337,8 @@ and/or use gtk-doc annotations. ''') self._write_generic(enum) for member in enum.members: self._write_member(member) + for method in sorted(enum.static_methods): + self._write_static_method(method) def _write_bitfield(self, bitfield): attrs = [('name', bitfield.name)] @@ -348,6 +350,8 @@ and/or use gtk-doc annotations. ''') self._write_generic(bitfield) for member in bitfield.members: self._write_member(member) + for method in sorted(bitfield.static_methods): + self._write_static_method(method) def _write_member(self, member): attrs = [('name', member.name), diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py index 8c07fda5..79004199 100644 --- a/giscanner/maintransformer.py +++ b/giscanner/maintransformer.py @@ -1006,7 +1006,7 @@ method or constructor of some type.""" node.static_methods.append(func) return True elif isinstance(node, (ast.Interface, ast.Record, ast.Union, - ast.Boxed)): + ast.Boxed, ast.Enum, ast.Bitfield)): # prior to the introduction of this part of the code, only # ast.Class could have static methods. so for backwards # compatibility, instead of removing the func from the namespace, diff --git a/tests/repository/gitypelibtest.c b/tests/repository/gitypelibtest.c index 9e9b8d22..2896846a 100644 --- a/tests/repository/gitypelibtest.c +++ b/tests/repository/gitypelibtest.c @@ -23,10 +23,8 @@ test_enum_and_flags_cidentifier(GIRepository *repo) for (i = 0; i < n_infos; i++) { GIBaseInfo *info; - GIInfoType type; info = g_irepository_get_info (repo, "GIMarshallingTests", i); - type = g_base_info_get_type (info); /* both GI_INFO_TYPE_ENUM and GI_INFO_TYPE_FLAGS use GIEnumInfo */ if (GI_IS_ENUM_INFO (info)) { @@ -54,6 +52,60 @@ test_enum_and_flags_cidentifier(GIRepository *repo) } } +static void +_check_enum_methods (GIBaseInfo *info, const gchar *name, const gchar *prefix) +{ + gint n_methods, i; + + n_methods = g_enum_info_get_n_methods ((GIEnumInfo *) info); + if (n_methods <= 0) + g_error ("%s should have methods", name); + + for (i = 0; i < n_methods; i += n_methods-1) { + GIBaseInfo *function_info; + GIFunctionInfoFlags flags; + const gchar *symbol; + function_info = g_enum_info_get_method ((GIEnumInfo *) info, i); + if (!function_info) + g_error ("Could not find %s method nr. %d", name, i+1); + flags = g_function_info_get_flags ((GIFunctionInfo *) function_info); + if (flags != 0) + g_error ("%s methods should be static", name); + symbol = g_function_info_get_symbol ((GIFunctionInfo *) function_info); + if (!symbol || !g_str_has_prefix (symbol, prefix)) + g_error ("Could not find valid function symbol"); + g_base_info_unref (function_info); + } +} + +static void +test_enum_and_flags_static_methods(GIRepository *repo) +{ + GITypelib *ret; + GError *error = NULL; + GIBaseInfo *enum_info; + + ret = g_irepository_require (repo, "GIMarshallingTests", NULL, 0, &error); + if (!ret) + g_error ("%s", error->message); + + enum_info = g_irepository_find_by_name (repo, "GIMarshallingTests", "GEnum"); + if (!enum_info) + g_error ("Could not find GIMarshallingTests.GEnum"); + _check_enum_methods (enum_info, + "GIMarshallingTests.GEnum", + "gi_marshalling_tests_genum_"); + g_base_info_unref (enum_info); + + enum_info = g_irepository_find_by_name (repo, "GIMarshallingTests", "Flags"); + if (!enum_info) + g_error ("Could not find GIMarshallingTests.Flags"); + _check_enum_methods (enum_info, + "GIMarshallingTests.Flags", + "gi_marshalling_tests_flags_"); + g_base_info_unref (enum_info); +} + int main(int argc, char **argv) { @@ -65,6 +117,7 @@ main(int argc, char **argv) /* do tests */ test_enum_and_flags_cidentifier (repo); + test_enum_and_flags_static_methods (repo); exit(0); } diff --git a/tests/scanner/Foo-1.0-expected.gir b/tests/scanner/Foo-1.0-expected.gir index f18ed56d..ffcf2167 100644 --- a/tests/scanner/Foo-1.0-expected.gir +++ b/tests/scanner/Foo-1.0-expected.gir @@ -186,6 +186,26 @@ and/or use gtk-doc annotations. --> value="2" c:identifier="FOO_ENUM_DELTA" glib:nick="delta"/> + <function name="method" c:identifier="foo_enum_type_method"> + <return-value transfer-ownership="none"> + <type name="gint" c:type="int"/> + </return-value> + <parameters> + <parameter name="foo_enum" transfer-ownership="none"> + <type name="EnumType" c:type="FooEnumType"/> + </parameter> + </parameters> + </function> + <function name="returnv" c:identifier="foo_enum_type_returnv"> + <return-value transfer-ownership="none"> + <type name="EnumType" c:type="FooEnumType"/> + </return-value> + <parameters> + <parameter name="x" transfer-ownership="none"> + <type name="gint" c:type="int"/> + </parameter> + </parameters> + </function> </enumeration> <enumeration name="Error" glib:type-name="FooError" @@ -204,6 +224,11 @@ and/or use gtk-doc annotations. --> value="2" c:identifier="FOO_ERROR_UGLY" glib:nick="ugly"/> + <function name="quark" c:identifier="foo_error_quark"> + <return-value transfer-ownership="none"> + <type name="GLib.Quark" c:type="GQuark"/> + </return-value> + </function> </enumeration> <union name="Event" c:type="FooEvent"> <field name="type" writable="1"> @@ -954,7 +979,9 @@ exposed to language bindings.</doc> </parameter> </parameters> </function> - <function name="enum_type_method" c:identifier="foo_enum_type_method"> + <function name="enum_type_method" + c:identifier="foo_enum_type_method" + moved-to="EnumType.method"> <return-value transfer-ownership="none"> <type name="gint" c:type="int"/> </return-value> @@ -964,7 +991,9 @@ exposed to language bindings.</doc> </parameter> </parameters> </function> - <function name="enum_type_returnv" c:identifier="foo_enum_type_returnv"> + <function name="enum_type_returnv" + c:identifier="foo_enum_type_returnv" + moved-to="EnumType.returnv"> <return-value transfer-ownership="none"> <type name="EnumType" c:type="FooEnumType"/> </return-value> @@ -974,7 +1003,9 @@ exposed to language bindings.</doc> </parameter> </parameters> </function> - <function name="error_quark" c:identifier="foo_error_quark"> + <function name="error_quark" + c:identifier="foo_error_quark" + moved-to="Error.quark"> <return-value transfer-ownership="none"> <type name="GLib.Quark" c:type="GQuark"/> </return-value> diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir index 80b0c68e..ce5af5c0 100644 --- a/tests/scanner/Regress-1.0-expected.gir +++ b/tests/scanner/Regress-1.0-expected.gir @@ -188,6 +188,16 @@ use it should be.</doc> value="48" c:identifier="REGRESS_TEST_VALUE4" glib:nick="value4"/> + <function name="param" c:identifier="regress_test_enum_param"> + <return-value transfer-ownership="none"> + <type name="utf8" c:type="gchar*"/> + </return-value> + <parameters> + <parameter name="e" transfer-ownership="none"> + <type name="TestEnum" c:type="RegressTestEnum"/> + </parameter> + </parameters> + </function> </enumeration> <enumeration name="TestEnumNoGEnum" c:type="RegressTestEnumNoGEnum"> <member name="evalue1" value="0" c:identifier="REGRESS_TEST_EVALUE1"/> @@ -1887,7 +1897,9 @@ call and can be released on return.</doc> </parameter> </parameters> </function> - <function name="test_enum_param" c:identifier="regress_test_enum_param"> + <function name="test_enum_param" + c:identifier="regress_test_enum_param" + moved-to="TestEnum.param"> <return-value transfer-ownership="none"> <type name="utf8" c:type="gchar*"/> </return-value> |