summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Schönfeld <kaffeetisch@gmx.de>2011-08-13 17:28:30 +0200
committerTorsten Schönfeld <kaffeetisch@gmx.de>2011-08-16 18:43:23 +0200
commit169b206cbb4b347e4b17854e8f0c62a40404f803 (patch)
tree929ddaefcedf7c9d4778ea355e58f0b1cc2f2f96
parent64848acb817369436d629d153c5750789c0addc3 (diff)
downloadgobject-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.txt2
-rw-r--r--girepository/gienuminfo.c55
-rw-r--r--girepository/gienuminfo.h3
-rw-r--r--girepository/girnode.c18
-rw-r--r--girepository/girnode.h1
-rw-r--r--girepository/girparser.c17
-rw-r--r--girepository/gitypelib-internal.h9
-rw-r--r--girepository/gitypelib.c22
-rw-r--r--giscanner/ast.py10
-rw-r--r--giscanner/girparser.py3
-rw-r--r--giscanner/girwriter.py4
-rw-r--r--giscanner/maintransformer.py2
-rw-r--r--tests/repository/gitypelibtest.c57
-rw-r--r--tests/scanner/Foo-1.0-expected.gir37
-rw-r--r--tests/scanner/Regress-1.0-expected.gir14
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>