diff options
author | David Zeuthen <davidz@redhat.com> | 2010-06-15 11:01:37 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-06-24 11:53:18 -0400 |
commit | 11cfe386c37ced44a8e3efb5556bde3a43a11171 (patch) | |
tree | a01903a4e4596ca80c79abbc8d35c33dc665e526 | |
parent | 751ffa016e410a031028282e63f98a94cc444b7b (diff) | |
download | gobject-introspection-11cfe386c37ced44a8e3efb5556bde3a43a11171.tar.gz |
Allow attributes on parameters and return values
Any annotation where the key has a dot in the name will go into the
attribute list. For example
* @arg: (foo.bar baz): some arg
the parameter @arg will get the attribute with key foo.bar and value
baz. This also works for.
* Returns: (foo.bar2 baz2): the return value
Also add tests for this new feature.
See https://bugzilla.gnome.org/show_bug.cgi?id=571548
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | docs/reference/gi-sections.txt | 2 | ||||
-rw-r--r-- | girepository/gibaseinfo.c | 24 | ||||
-rw-r--r-- | girepository/gicallableinfo.c | 76 | ||||
-rw-r--r-- | girepository/gicallableinfo.h | 6 | ||||
-rw-r--r-- | girepository/girnode.c | 16 | ||||
-rw-r--r-- | girepository/girparser.c | 9 | ||||
-rw-r--r-- | girepository/girwriter.c | 21 | ||||
-rw-r--r-- | girepository/gitypelib-internal.h | 4 | ||||
-rw-r--r-- | giscanner/annotationparser.py | 6 | ||||
-rw-r--r-- | giscanner/girwriter.py | 2 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.gir | 34 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.tgir | 33 | ||||
-rw-r--r-- | tests/scanner/annotation.c | 37 | ||||
-rw-r--r-- | tests/scanner/annotation.h | 3 |
14 files changed, 265 insertions, 8 deletions
diff --git a/docs/reference/gi-sections.txt b/docs/reference/gi-sections.txt index 6b1cd074..261afd81 100644 --- a/docs/reference/gi-sections.txt +++ b/docs/reference/gi-sections.txt @@ -74,6 +74,8 @@ GICallableInfo g_callable_info_get_return_type g_callable_info_get_caller_owns g_callable_info_may_return_null +g_callable_info_get_return_attribute +g_callable_info_iterate_return_attributes g_callable_info_get_n_args g_callable_info_get_arg g_callable_info_load_arg diff --git a/girepository/gibaseinfo.c b/girepository/gibaseinfo.c index c8444a5e..81b936d8 100644 --- a/girepository/gibaseinfo.c +++ b/girepository/gibaseinfo.c @@ -475,7 +475,7 @@ g_base_info_get_attribute (GIBaseInfo *info, static int cmp_attribute (const void *av, - const void *bv) + const void *bv) { const AttributeBlob *a = av; const AttributeBlob *b = bv; @@ -488,13 +488,25 @@ cmp_attribute (const void *av, return 1; } -static AttributeBlob * -find_first_attribute (GIRealInfo *rinfo) +/* + * _attribute_blob_find_first: + * @GIBaseInfo: A #GIBaseInfo. + * @blob_offset: The offset for the blob to find the first attribute for. + * + * Searches for the first #AttributeBlob for @blob_offset and returns + * it if found. + * + * Returns: A pointer to #AttributeBlob or %NULL if not found. + */ +AttributeBlob * +_attribute_blob_find_first (GIBaseInfo *info, + guint32 blob_offset) { + GIRealInfo *rinfo = (GIRealInfo *) info; Header *header = (Header *)rinfo->typelib->data; AttributeBlob blob, *first, *res, *previous; - blob.offset = rinfo->offset; + blob.offset = blob_offset; first = (AttributeBlob *) &rinfo->typelib->data[header->attributes]; @@ -505,7 +517,7 @@ find_first_attribute (GIRealInfo *rinfo) return NULL; previous = res - 1; - while (previous >= first && previous->offset == rinfo->offset) + while (previous >= first && previous->offset == blob_offset) { res = previous; previous = res - 1; @@ -563,7 +575,7 @@ g_base_info_iterate_attributes (GIBaseInfo *info, if (iterator->data != NULL) next = (AttributeBlob *) iterator->data; else - next = find_first_attribute (rinfo); + next = _attribute_blob_find_first (info, rinfo->offset); if (next == NULL || next->offset != rinfo->offset || next >= after) return FALSE; diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c index 6097cb48..6b79e62c 100644 --- a/girepository/gicallableinfo.c +++ b/girepository/gicallableinfo.c @@ -19,6 +19,8 @@ * Boston, MA 02111-1307, USA. */ +#include <stdlib.h> + #include <glib.h> #include <girepository.h> @@ -259,3 +261,77 @@ g_callable_info_load_arg (GICallableInfo *info, _g_info_init ((GIRealInfo*)arg, GI_INFO_TYPE_ARG, rinfo->repository, (GIBaseInfo*)info, rinfo->typelib, offset + header->signature_blob_size + n * header->arg_blob_size); } + +/** + * g_callable_info_get_return_attribute: + * @info: a #GICallableInfo + * @name: a freeform string naming an attribute + * + * Retrieve an arbitrary attribute associated with the return value. + * + * Returns: The value of the attribute, or %NULL if no such attribute exists + */ +const gchar * +g_callable_info_get_return_attribute (GICallableInfo *info, + const gchar *name) +{ + GIAttributeIter iter = { 0, }; + gchar *curname, *curvalue; + while (g_callable_info_iterate_return_attributes (info, &iter, &curname, &curvalue)) + { + if (g_strcmp0 (name, curname) == 0) + return (const gchar*) curvalue; + } + + return NULL; +} + +/** + * g_callable_info_iterate_return_attributes: + * @info: a #GICallableInfo + * @iterator: a #GIAttributeIter structure, must be initialized; see below + * @name: (out) (transfer none): Returned name, must not be freed + * @value: (out) (transfer none): Returned name, must not be freed + * + * Iterate over all attributes associated with the return value. The + * iterator structure is typically stack allocated, and must have its + * first member initialized to %NULL. + * + * Both the @name and @value should be treated as constants + * and must not be freed. + * + * See g_base_info_iterate_attributes() for an example of how to use a + * similar API. + * + * Returns: %TRUE if there are more attributes + */ +gboolean +g_callable_info_iterate_return_attributes (GICallableInfo *info, + GIAttributeIter *iterator, + char **name, + char **value) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + AttributeBlob *next, *after; + guint32 blob_offset; + + after = (AttributeBlob *) &rinfo->typelib->data[header->attributes + + header->n_attributes * header->attribute_blob_size]; + + blob_offset = signature_offset (info); + + if (iterator->data != NULL) + next = (AttributeBlob *) iterator->data; + else + next = _attribute_blob_find_first (info, blob_offset); + + if (next == NULL || next->offset != blob_offset || next >= after) + return FALSE; + + *name = (gchar*) g_typelib_get_string (rinfo->typelib, next->name); + *value = (gchar*) g_typelib_get_string (rinfo->typelib, next->value); + iterator->data = next + 1; + + return TRUE; +} diff --git a/girepository/gicallableinfo.h b/girepository/gicallableinfo.h index 479baa2a..54d2cacb 100644 --- a/girepository/gicallableinfo.h +++ b/girepository/gicallableinfo.h @@ -39,6 +39,12 @@ G_BEGIN_DECLS GITypeInfo * g_callable_info_get_return_type (GICallableInfo *info); void g_callable_info_load_return_type (GICallableInfo *info, GITypeInfo *type); +const gchar * g_callable_info_get_return_attribute (GICallableInfo *info, + const gchar *name); +gboolean g_callable_info_iterate_return_attributes (GICallableInfo *info, + GIAttributeIter *iterator, + char **name, + char **value); GITransfer g_callable_info_get_caller_owns (GICallableInfo *info); gboolean g_callable_info_may_return_null (GICallableInfo *info); gint g_callable_info_get_n_args (GICallableInfo *info); diff --git a/girepository/girnode.c b/girepository/girnode.c index fbdcdf96..576ac100 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -1678,6 +1678,14 @@ g_ir_node_build_typelib (GIrNode *node, blob->symbol = write_string (function->symbol, strings, data, offset2); blob->signature = signature; + /* function->result is special since it doesn't appear in the serialized format but + * we do want the attributes for it to appear + */ + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, function->result); + build->n_attributes += g_hash_table_size (((GIrNode *) function->result)->attributes); + g_assert (((GIrNode *) function->result)->offset == 0); + ((GIrNode *) function->result)->offset = signature; + g_debug ("building function '%s'", function->symbol); g_ir_node_build_typelib ((GIrNode *)function->result->type, @@ -1770,6 +1778,14 @@ g_ir_node_build_typelib (GIrNode *node, blob->name = write_string (node->name, strings, data, offset2); blob->signature = signature; + /* signal->result is special since it doesn't appear in the serialized format but + * we do want the attributes for it to appear + */ + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, signal->result); + build->n_attributes += g_hash_table_size (((GIrNode *) signal->result)->attributes); + g_assert (((GIrNode *) signal->result)->offset == 0); + ((GIrNode *) signal->result)->offset = signature; + g_ir_node_build_typelib ((GIrNode *)signal->result->type, node, build, &signature, offset2); diff --git a/girepository/girparser.c b/girepository/girparser.c index 2713bb46..5efe7fde 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -1990,7 +1990,14 @@ start_attribute (GMarkupParseContext *context, curnode = CURRENT_NODE (ctx); - g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value)); + if (ctx->current_typed && ctx->current_typed->type == G_IR_NODE_PARAM) + { + g_hash_table_insert (ctx->current_typed->attributes, g_strdup (name), g_strdup (value)); + } + else + { + g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value)); + } return TRUE; } diff --git a/girepository/girwriter.c b/girepository/girwriter.c index b123a134..19862b0d 100644 --- a/girepository/girwriter.c +++ b/girepository/girwriter.c @@ -358,7 +358,7 @@ write_type_info (const gchar *namespace, static void write_attributes (Xml *file, - GIBaseInfo *info) + GIBaseInfo *info) { GIAttributeIter iter = { 0, }; char *name, *value; @@ -372,6 +372,21 @@ write_attributes (Xml *file, } static void +write_return_value_attributes (Xml *file, + GICallableInfo *info) +{ + GIAttributeIter iter = { 0, }; + char *name, *value; + + while (g_callable_info_iterate_return_attributes (info, &iter, &name, &value)) + { + xml_start_element (file, "attribute"); + xml_printf (file, " name=\"%s\" value=\"%s\"", name, value); + xml_end_element (file, "attribute"); + } +} + +static void write_constant_value (const gchar *namespace, GITypeInfo *info, GArgument *argument, @@ -467,6 +482,8 @@ write_callable_info (const gchar *namespace, if (g_callable_info_may_return_null (info)) xml_printf (file, " allow-none=\"1\""); + write_return_value_attributes (file, info); + write_type_info (namespace, type, file); xml_end_element (file, "return-value"); @@ -528,6 +545,8 @@ write_callable_info (const gchar *namespace, if (g_arg_info_get_destroy (arg) >= 0) xml_printf (file, " destroy=\"%d\"", g_arg_info_get_destroy (arg)); + write_attributes (file, (GIBaseInfo*) arg); + type = g_arg_info_get_type (arg); write_type_info (namespace, type, file); diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index 90113ac2..d4577acc 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -1110,6 +1110,10 @@ gboolean g_typelib_validate (GTypelib *typelib, GError **error); +/* defined in gibaseinfo.c */ +AttributeBlob *_attribute_blob_find_first (GIBaseInfo *info, + guint32 blob_offset); + G_END_DECLS #endif /* __G_TYPELIB_H__ */ diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py index 43ca03c4..01cbb1ac 100644 --- a/giscanner/annotationparser.py +++ b/giscanner/annotationparser.py @@ -635,6 +635,12 @@ class AnnotationApplier(object): if tag is not None and tag.comment is not None: node.doc = tag.comment + for key in options: + if '.' in key: + value = options.get(key) + if value: + node.attributes.append((key, value.one())) + def _extract_direction(self, node, options): caller_allocates = False if (OPT_INOUT in options or diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index 9b48d4ef..59b4b495 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -192,6 +192,7 @@ and/or use gtk-doc annotations. ''') if return_.doc: attrs.append(('doc', return_.doc)) with self.tagcontext('return-value', attrs): + self._write_attributes(return_) self._write_type(return_.type) def _write_parameters(self, parameters): @@ -224,6 +225,7 @@ and/or use gtk-doc annotations. ''') if parameter.doc: attrs.append(('doc', parameter.doc)) with self.tagcontext('parameter', attrs): + self._write_attributes(parameter) self._write_type(parameter.type) def _type_to_string(self, ntype): diff --git a/tests/scanner/annotation-1.0-expected.gir b/tests/scanner/annotation-1.0-expected.gir index 2599cf31..12025ed8 100644 --- a/tests/scanner/annotation-1.0-expected.gir +++ b/tests/scanner/annotation-1.0-expected.gir @@ -503,6 +503,23 @@ type."> <field name="parent_instance"> <type name="GObject.Object" c:type="GObject"/> </field> + <glib:signal name="attribute-signal" + doc="This signal tests a signal with attributes."> + <return-value transfer-ownership="full" doc="the return value"> + <attribute name="some.annotation.foo3" value="val3"/> + <type name="utf8" c:type="gchararray"/> + </return-value> + <parameters> + <parameter name="arg1" transfer-ownership="none" doc="a value"> + <attribute name="some.annotation.foo1" value="val1"/> + <type name="utf8" c:type="gchararray"/> + </parameter> + <parameter name="arg2" transfer-ownership="none" doc="another value"> + <attribute name="some.annotation.foo2" value="val2"/> + <type name="utf8" c:type="gchararray"/> + </parameter> + </parameters> + </glib:signal> <glib:signal name="doc-empty-arg-parsing" doc="This signal tests an empty document argument (@arg1)"> <return-value transfer-ownership="full"> @@ -562,6 +579,23 @@ it says it's pointer but it's actually a string." </array> </field> </record> + <function name="attribute_func" c:identifier="annotation_attribute_func"> + <return-value transfer-ownership="none" doc="The return value."> + <attribute name="yet.another.annotation" value="another_value"/> + <attribute name="some.other.annotation" value="value2"/> + <type name="int" c:type="gint"/> + </return-value> + <parameters> + <parameter name="object" transfer-ownership="none"> + <type name="Object" c:type="AnnotationObject*"/> + </parameter> + <parameter name="data" transfer-ownership="none" doc="Some data."> + <attribute name="another.annotation" value="blahvalue"/> + <attribute name="some.annotation" value="value"/> + <type name="utf8" c:type="gchar*"/> + </parameter> + </parameters> + </function> <function name="custom_destroy" c:identifier="annotation_custom_destroy" doc="Test messing up the heuristic of closure/destroy-notification diff --git a/tests/scanner/annotation-1.0-expected.tgir b/tests/scanner/annotation-1.0-expected.tgir index ba56be6e..0f8a5fe7 100644 --- a/tests/scanner/annotation-1.0-expected.tgir +++ b/tests/scanner/annotation-1.0-expected.tgir @@ -362,6 +362,22 @@ <property name="string-property" writable="1" construct="1" transfer-ownership="none"> <type name="utf8"/> </property> + <glib:signal name="attribute-signal" when="LAST"> + <return-value transfer-ownership="full"> + <attribute name="some.annotation.foo3" value="val3"/> + <type name="utf8"/> + </return-value> + <parameters> + <parameter name="arg1" transfer-ownership="none"> + <attribute name="some.annotation.foo1" value="val1"/> + <type name="utf8"/> + </parameter> + <parameter name="arg2" transfer-ownership="none"> + <attribute name="some.annotation.foo2" value="val2"/> + <type name="utf8"/> + </parameter> + </parameters> + </glib:signal> <glib:signal name="doc-empty-arg-parsing" when="LAST"> <return-value transfer-ownership="full"> <type name="none"/> @@ -407,6 +423,23 @@ </array> </field> </record> + <function name="attribute_func" c:identifier="annotation_attribute_func"> + <return-value transfer-ownership="none"> + <attribute name="yet.another.annotation" value="another_value"/> + <attribute name="some.other.annotation" value="value2"/> + <type name="int"/> + </return-value> + <parameters> + <parameter name="object" transfer-ownership="none"> + <type name="Object"/> + </parameter> + <parameter name="data" transfer-ownership="none"> + <attribute name="another.annotation" value="blahvalue"/> + <attribute name="some.annotation" value="value"/> + <type name="utf8"/> + </parameter> + </parameters> + </function> <function name="custom_destroy" c:identifier="annotation_custom_destroy"> <return-value transfer-ownership="none"> <type name="none"/> diff --git a/tests/scanner/annotation.c b/tests/scanner/annotation.c index 9795263d..64f9cc32 100644 --- a/tests/scanner/annotation.c +++ b/tests/scanner/annotation.c @@ -14,6 +14,7 @@ enum { STRING_SIGNAL, LIST_SIGNAL, DOC_EMPTY_ARG_PARSING, + ATTRIBUTE_SIGNAL, LAST_SIGNAL }; @@ -119,6 +120,28 @@ annotation_object_class_init (AnnotationObjectClass *klass) G_TYPE_NONE, 1, G_TYPE_POINTER); /** + * AnnotationObject::attribute-signal: + * @annotation: the annotation object + * @arg1: (some.annotation.foo1 val1): a value + * @arg2: (some.annotation.foo2 val2): another value + * + * This signal tests a signal with attributes. + * + * Returns: (some.annotation.foo3 val3): the return value + */ + annotation_object_signals[ATTRIBUTE_SIGNAL] = + g_signal_new ("attribute-signal", + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + NULL, /* marshaller */ + G_TYPE_STRING, + 2, + G_TYPE_STRING, + G_TYPE_STRING); + + /** * AnnotationObject:string-property: * * This is a property which is a string @@ -700,4 +723,18 @@ annotation_ptr_array (GPtrArray *array) { } +/** + * annotation_attribute_func: + * @object: A #AnnotationObject. + * @data: (some.annotation value) (another.annotation blahvalue): Some data. + * + * Returns: (some.other.annotation value2) (yet.another.annotation another_value): The return value. + */ +gint +annotation_attribute_func (AnnotationObject *object, + const gchar *data) +{ + return 42; +} + char backslash_parsing_tester_2 = '\\'; diff --git a/tests/scanner/annotation.h b/tests/scanner/annotation.h index 0f47d22e..ace36515 100644 --- a/tests/scanner/annotation.h +++ b/tests/scanner/annotation.h @@ -139,6 +139,9 @@ void annotation_custom_destroy (AnnotationCallback callback, char * annotation_get_source_file (void); void annotation_set_source_file (const char *fname); +gint annotation_attribute_func (AnnotationObject *object, + const gchar *data); + /** * AnnotationStruct: * |