[gobject-introspection/ebassi/property-annotation: 3/17] Add new annotations for property accessors
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gobject-introspection/ebassi/property-annotation: 3/17] Add new annotations for property accessors
- Date: Tue, 27 Jul 2021 10:45:31 +0000 (UTC)
commit baa676e8139d973107f1957cae7980e67175f09f
Author: Emmanuele Bassi <ebassi gnome org>
Date: Wed Jun 16 19:17:27 2021 +0100
Add new annotations for property accessors
We introduce two new annotations:
- (set-property PROPERTY_NAME)
- (get-property PROPERTY_NAME)
These annotations are valid inside function blocks for methods on
objects and interfaces, and define whether a function is a property
accessor, e.g.:
/**
* gtk_widget_set_name: (set-property name)
* @self: ...
* @name: ...
*
* ...
*/
/**
* gtk_widget_get_name: (get-property name)
* @self: ...
*
* ...
*
* Returns: ...
*/
The annotations are transformed into the GIR data as attributes:
- glib:set-property="PROPERTY_NAME"
- glib:get-property="PROPERTY_NAME"
The underlying typelib data has had flags for setter and getter
functions for a while, but they have never been plugged into the GIR
data or the introspection scanner. Now they are; you can retrieve the
GIPropertyInfo from a GIFunctionInfo that has the GI_FUNCTION_IS_SETTER
or GI_FUNCTION_IS_GETTER flags set.
Fixes: #13
girepository/girnode.c | 20 ++++++++++++++++++--
girepository/girnode.h | 1 +
girepository/girparser.c | 23 +++++++++++++++++++++++
girepository/girwriter.c | 20 ++++++++++++++++----
giscanner/annotationparser.py | 35 ++++++++++++++++++++++++++++++++---
giscanner/ast.py | 2 ++
giscanner/girparser.py | 2 ++
giscanner/girwriter.py | 4 ++++
giscanner/maintransformer.py | 17 +++++++++++++----
9 files changed, 111 insertions(+), 13 deletions(-)
---
diff --git a/girepository/girnode.c b/girepository/girnode.c
index fadfe56f..07e0d056 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -218,6 +218,7 @@ _g_ir_node_free (GIrNode *node)
g_free (node->name);
g_free (function->symbol);
+ g_free (function->property);
_g_ir_node_free ((GIrNode *)function->result);
for (l = function->parameters; l; l = l->next)
_g_ir_node_free ((GIrNode *)l->data);
@@ -1648,8 +1649,8 @@ _g_ir_node_build_typelib (GIrNode *node,
blob->blob_type = BLOB_TYPE_FUNCTION;
blob->deprecated = function->deprecated;
blob->is_static = !function->is_method;
- blob->setter = function->is_setter;
- blob->getter = function->is_getter;
+ blob->setter = FALSE;
+ blob->getter = FALSE;
blob->constructor = function->is_constructor;
blob->wraps_vfunc = function->wraps_vfunc;
blob->throws = function->throws; /* Deprecated. Also stored in SignatureBlob. */
@@ -1658,6 +1659,21 @@ _g_ir_node_build_typelib (GIrNode *node,
blob->symbol = _g_ir_write_string (function->symbol, strings, data, offset2);
blob->signature = signature;
+ if (function->is_setter || function->is_getter)
+ {
+ int index = get_index_of_member_type ((GIrNodeInterface*)parent,
+ G_IR_NODE_PROPERTY,
+ function->property);
+ if (index == -1)
+ {
+ g_error ("Unknown property %s for accessor %s", function->property, node->name);
+ }
+
+ blob->setter = function->is_setter;
+ blob->getter = function->is_getter;
+ blob->index = (guint) index;
+ }
+
/* function->result is special since it doesn't appear in the serialized format but
* we do want the attributes for it to appear
*/
diff --git a/girepository/girnode.h b/girepository/girnode.h
index e4ce85a4..2cb5a960 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -103,6 +103,7 @@ struct _GIrNodeFunction
gboolean instance_transfer_full;
gchar *symbol;
+ char *property;
GIrNodeParam *result;
GList *parameters;
diff --git a/girepository/girparser.c b/girepository/girparser.c
index f62b1de6..99ec91a9 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -807,6 +807,8 @@ start_function (GMarkupParseContext *context,
const gchar *symbol;
const gchar *deprecated;
const gchar *throws;
+ const gchar *set_property;
+ const gchar *get_property;
GIrNodeFunction *function;
gboolean found = FALSE;
ParseState in_embedded_state = STATE_NONE;
@@ -854,6 +856,8 @@ start_function (GMarkupParseContext *context,
symbol = find_attribute ("c:identifier", attribute_names, attribute_values);
deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
throws = find_attribute ("throws", attribute_names, attribute_values);
+ set_property = find_attribute ("glib:set-property", attribute_names, attribute_values);
+ get_property = find_attribute ("glib:get-property", attribute_names, attribute_values);
if (name == NULL)
{
@@ -889,6 +893,25 @@ start_function (GMarkupParseContext *context,
function->is_constructor = TRUE;
else
function->is_constructor = FALSE;
+
+ if (set_property != NULL)
+ {
+ function->is_setter = TRUE;
+ function->is_getter = FALSE;
+ function->property = g_strdup (set_property);
+ }
+ else if (get_property != NULL)
+ {
+ function->is_setter = FALSE;
+ function->is_getter = TRUE;
+ function->property = g_strdup (get_property);
+ }
+ else
+ {
+ function->is_setter = FALSE;
+ function->is_getter = FALSE;
+ function->property = NULL;
+ }
}
else
{
diff --git a/girepository/girwriter.c b/girepository/girwriter.c
index d092df10..b913da00 100644
--- a/girepository/girwriter.c
+++ b/girepository/girwriter.c
@@ -586,10 +586,22 @@ write_function_info (const gchar *namespace,
xml_printf (file, " name=\"%s\" c:identifier=\"%s\"",
name, symbol);
- if (flags & GI_FUNCTION_IS_SETTER)
- xml_printf (file, " type=\"setter\"");
- else if (flags & GI_FUNCTION_IS_GETTER)
- xml_printf (file, " type=\"getter\"");
+ if ((flags & GI_FUNCTION_IS_SETTER) || (flags & GI_FUNCTION_IS_GETTER))
+ {
+ GIPropertyInfo *property = g_function_info_get_property (info);
+
+ if (property != NULL)
+ {
+ const char *property_name = g_base_info_get_name ((GIBaseInfo *)property);
+
+ if (flags & GI_FUNCTION_IS_SETTER)
+ xml_printf (file, " glib:set-property=\"%s\"", property_name);
+ else if (flags & GI_FUNCTION_IS_GETTER)
+ xml_printf (file, " glib:get-property=\"%s\"", property_name);
+
+ g_base_info_unref (property);
+ }
+ }
if (deprecated)
xml_printf (file, " deprecated=\"1\"");
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index 267542f9..95ee1f97 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -196,6 +196,7 @@ ANN_CONSTRUCTOR = 'constructor'
ANN_DESTROY = 'destroy'
ANN_ELEMENT_TYPE = 'element-type'
ANN_FOREIGN = 'foreign'
+ANN_GET_PROPERTY = 'get-property'
ANN_GET_VALUE_FUNC = 'get-value-func'
ANN_IN = 'in'
ANN_INOUT = 'inout'
@@ -207,6 +208,7 @@ ANN_OUT = 'out'
ANN_REF_FUNC = 'ref-func'
ANN_RENAME_TO = 'rename-to'
ANN_SCOPE = 'scope'
+ANN_SET_PROPERTY = 'set-property'
ANN_SET_VALUE_FUNC = 'set-value-func'
ANN_SKIP = 'skip'
ANN_TRANSFER = 'transfer'
@@ -226,6 +228,7 @@ GI_ANNS = [ANN_ALLOW_NONE,
ANN_DESTROY,
ANN_ELEMENT_TYPE,
ANN_FOREIGN,
+ ANN_GET_PROPERTY,
ANN_GET_VALUE_FUNC,
ANN_IN,
ANN_INOUT,
@@ -234,6 +237,7 @@ GI_ANNS = [ANN_ALLOW_NONE,
ANN_REF_FUNC,
ANN_RENAME_TO,
ANN_SCOPE,
+ ANN_SET_PROPERTY,
ANN_SET_VALUE_FUNC,
ANN_SKIP,
ANN_TRANSFER,
@@ -812,6 +816,18 @@ class GtkDocAnnotatable(object):
self._validate_annotation(position, ann_name, options, exact_n_options=0)
+ def _do_validate_get_property(self, position, ann_name, options):
+ '''
+ Validate the ``(get-property)`` annotation.
+
+ :param position: :class:`giscanner.message.Position` of the line in the source file
+ containing the annotation to be validated
+ :param ann_name: name of the annotation holding the options to validate
+ :param options: annotation options to validate
+ '''
+
+ self._validate_annotation(position, ann_name, options, exact_n_options=1)
+
def _do_validate_get_value_func(self, position, ann_name, options):
'''
Validate the ``(value-func)`` annotation.
@@ -947,6 +963,18 @@ class GtkDocAnnotatable(object):
self._validate_annotation(position, ann_name, options, exact_n_options=1,
choices=SCOPE_OPTIONS)
+ def _do_validate_set_property(self, position, ann_name, options):
+ '''
+ Validate the ``(set-property)`` annotation.
+
+ :param position: :class:`giscanner.message.Position` of the line in the source file
+ containing the annotation to be validated
+ :param ann_name: name of the annotation holding the options to validate
+ :param options: annotation options to validate
+ '''
+
+ self._validate_annotation(position, ann_name, options, exact_n_options=1)
+
def _do_validate_set_value_func(self, position, ann_name, options):
'''
Validate the ``(value-func)`` annotation.
@@ -1092,9 +1120,10 @@ class GtkDocCommentBlock(GtkDocAnnotatable):
'name', 'params', 'description', 'tags')
#: Valid annotation names for the GTK-Doc comment block identifier part.
- valid_annotations = (ANN_ATTRIBUTES, ANN_CONSTRUCTOR, ANN_FOREIGN, ANN_GET_VALUE_FUNC,
- ANN_METHOD, ANN_REF_FUNC, ANN_RENAME_TO, ANN_SET_VALUE_FUNC,
- ANN_SKIP, ANN_TRANSFER, ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE, ANN_VFUNC)
+ valid_annotations = (ANN_ATTRIBUTES, ANN_CONSTRUCTOR, ANN_FOREIGN, ANN_GET_PROPERTY,
+ ANN_GET_VALUE_FUNC, ANN_METHOD, ANN_REF_FUNC, ANN_RENAME_TO,
+ ANN_SET_PROPERTY, ANN_SET_VALUE_FUNC, ANN_SKIP, ANN_TRANSFER,
+ ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE, ANN_VFUNC)
def __init__(self, name, position=None):
GtkDocAnnotatable.__init__(self, position)
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 9a0d95c7..7cb6f622 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -752,6 +752,8 @@ class Function(Callable):
self.shadows = None # C symbol string
self.moved_to = None # namespaced function name string
self.internal_skipped = False # if True, this func will not be written to GIR
+ self.set_property = None # Property name
+ self.get_property = None # Property name
def clone(self):
clone = copy.copy(self)
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index da200a65..0fe85ed4 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -379,6 +379,8 @@ class GIRParser(object):
else:
assert False
+ func.set_property = node.attrib.get(_glibns('set-property'), None)
+ func.get_property = node.attrib.get(_glibns('get-property'), None)
func.shadows = node.attrib.get('shadows', None)
func.shadowed_by = node.attrib.get('shadowed-by', None)
func.moved_to = node.attrib.get('moved-to', None)
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 54c957c0..f8e61985 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -224,6 +224,10 @@ class GIRWriter(XMLWriter):
attrs.append(('shadows', func.shadows))
if func.moved_to is not None:
attrs.append(('moved-to', func.moved_to))
+ if func.set_property is not None:
+ attrs.append(('glib:set-property', func.set_property))
+ if func.get_property is not None:
+ attrs.append(('glib:get-property', func.get_property))
self._write_callable(func, tag_name, attrs)
def _write_function_macro(self, macro):
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index 9077a1d0..23073b4e 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -24,10 +24,11 @@ from . import message
from .annotationparser import (TAG_DEPRECATED, TAG_SINCE, TAG_STABILITY, TAG_RETURNS)
from .annotationparser import (ANN_ALLOW_NONE, ANN_ARRAY, ANN_ATTRIBUTES, ANN_CLOSURE,
ANN_CONSTRUCTOR, ANN_DESTROY, ANN_ELEMENT_TYPE, ANN_FOREIGN,
- ANN_GET_VALUE_FUNC, ANN_IN, ANN_INOUT, ANN_METHOD, ANN_OUT,
- ANN_REF_FUNC, ANN_RENAME_TO, ANN_SCOPE, ANN_SET_VALUE_FUNC,
- ANN_SKIP, ANN_TRANSFER, ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE,
- ANN_VFUNC, ANN_NULLABLE, ANN_OPTIONAL, ANN_NOT)
+ ANN_GET_PROPERTY, ANN_GET_VALUE_FUNC, ANN_IN, ANN_INOUT,
+ ANN_METHOD, ANN_OUT, ANN_REF_FUNC, ANN_RENAME_TO, ANN_SCOPE,
+ ANN_SET_PROPERTY, ANN_SET_VALUE_FUNC, ANN_SKIP, ANN_TRANSFER,
+ ANN_TYPE, ANN_UNREF_FUNC, ANN_VALUE, ANN_VFUNC, ANN_NULLABLE,
+ ANN_OPTIONAL, ANN_NOT)
from .annotationparser import (OPT_ARRAY_FIXED_SIZE, OPT_ARRAY_LENGTH, OPT_ARRAY_ZERO_TERMINATED,
OPT_OUT_CALLEE_ALLOCATES, OPT_OUT_CALLER_ALLOCATES,
OPT_TRANSFER_CONTAINER, OPT_TRANSFER_FLOATING, OPT_TRANSFER_NONE)
@@ -773,6 +774,14 @@ class MainTransformer(object):
if ANN_METHOD in block.annotations:
node.is_method = True
+ set_property = block.annotations.get(ANN_SET_PROPERTY)
+ if set_property is not None and isinstance(node, ast.Function):
+ node.set_property = set_property[0]
+
+ get_property = block.annotations.get(ANN_GET_PROPERTY)
+ if get_property is not None and isinstance(node, ast.Function):
+ node.get_property = get_property[0]
+
def _apply_annotations_alias(self, node, chain):
block = self._get_block(node)
self._apply_annotations_annotated(node, block)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]