Commit 5589687a authored by Colin Walters's avatar Colin Walters

Support (out caller-allocates)

People have wanted support for marking (out) on functions of the
form:

/**
 * clutter_color_from_pixel:
 * @pixel: A pixel
 * @color: (out): Color to initialize with value of @pixel
 */
void
clutter_color_from_pixel (guint32 pixel, ClutterColor *color);

Where the caller is supposed to have allocated the argument; the
C function just initializes it.  This patch adds support for this
argument passing style to introspection.  In this case, we see the
(out), and notice that there's only a single indirection (*) on
the argument, and assume that this means (out caller-allocates).

https://bugzilla.gnome.org/show_bug.cgi?id=604749
parent 786da5cd
......@@ -270,16 +270,25 @@ and/or use gtk-doc annotations. -->
<parameter name="x" transfer-ownership="none">
<type name="int" c:type="int"/>
</parameter>
<parameter name="y" direction="out" transfer-ownership="full">
<parameter name="y"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="double*"/>
</parameter>
<parameter name="z" direction="out" transfer-ownership="full">
<parameter name="z"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="foo" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
<parameter name="q" direction="out" transfer-ownership="full">
<parameter name="q"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="m" transfer-ownership="none">
......@@ -298,16 +307,25 @@ and/or use gtk-doc annotations. -->
<parameter name="x" transfer-ownership="none">
<type name="int" c:type="int"/>
</parameter>
<parameter name="y" direction="out" transfer-ownership="full">
<parameter name="y"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="double*"/>
</parameter>
<parameter name="z" direction="out" transfer-ownership="full">
<parameter name="z"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="foo" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
<parameter name="q" direction="out" transfer-ownership="full">
<parameter name="q"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="m" transfer-ownership="none">
......@@ -475,7 +493,11 @@ case.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="a_out" transfer-ownership="none">
<parameter name="a_out"
direction="out"
caller-allocates="1"
transfer-ownership="none"
doc="the cloned structure">
<type name="TestStructA" c:type="TestStructA*"/>
</parameter>
</parameters>
......@@ -495,7 +517,11 @@ case.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="b_out" transfer-ownership="none">
<parameter name="b_out"
direction="out"
caller-allocates="1"
transfer-ownership="none"
doc="the cloned structure">
<type name="TestStructB" c:type="TestStructB*"/>
</parameter>
</parameters>
......@@ -629,6 +655,7 @@ case.">
<parameters>
<parameter name="ints"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc="a list of 5 integers ranging from 0 to 4">
<array c:type="int**" fixed-size="5">
......@@ -729,7 +756,10 @@ case.">
</array>
</return-value>
<parameters>
<parameter name="len" direction="out" transfer-ownership="full">
<parameter name="len"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
</parameters>
......@@ -772,12 +802,14 @@ case.">
<parameters>
<parameter name="n_ints"
direction="inout"
caller-allocates="0"
transfer-ownership="full"
doc="the length of @ints">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="ints"
direction="inout"
caller-allocates="0"
transfer-ownership="full"
doc="a list of integers whose items will be increased by 1, except the first that will be dropped">
<array length="0" c:type="int**">
......@@ -795,7 +827,10 @@ case.">
</array>
</return-value>
<parameters>
<parameter name="len" direction="out" transfer-ownership="full">
<parameter name="len"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
</parameters>
......@@ -824,6 +859,7 @@ case.">
<parameters>
<parameter name="arr"
direction="out"
caller-allocates="0"
transfer-ownership="full"
allow-none="1">
<array length="1" c:type="int**">
......@@ -832,6 +868,7 @@ case.">
</parameter>
<parameter name="len"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc=": length">
<type name="int" c:type="int*"/>
......@@ -845,12 +882,14 @@ case.">
<parameters>
<parameter name="n_ints"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc="the length of @ints">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="ints"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc="a list of 5 integers, from 0 to 4 in consecutive order">
<array length="0" c:type="int**">
......@@ -923,7 +962,10 @@ case.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="surface" direction="out" transfer-ownership="full">
<parameter name="surface"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="cairo.Surface" c:type="cairo_surface_t**"/>
</parameter>
</parameters>
......@@ -1248,6 +1290,7 @@ call and can be released on return.">
<parameters>
<parameter name="out"
direction="out"
caller-allocates="0"
transfer-ownership="full"
allow-none="1">
<type name="GLib.HashTable" c:type="GHashTable**">
......@@ -1381,6 +1424,7 @@ call and can be released on return.">
<parameters>
<parameter name="out_list"
direction="out"
caller-allocates="0"
transfer-ownership="full"
allow-none="1">
<type name="GLib.SList" c:type="GSList**">
......@@ -1504,6 +1548,7 @@ call and can be released on return.">
<parameters>
<parameter name="out_list"
direction="out"
caller-allocates="0"
transfer-ownership="full"
allow-none="1">
<type name="GLib.SList" c:type="GSList**">
......@@ -1577,7 +1622,10 @@ call and can be released on return.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="length" direction="out" transfer-ownership="full">
<parameter name="length"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="in" transfer-ownership="none">
......@@ -1627,10 +1675,16 @@ call and can be released on return.">
<parameter name="in" transfer-ownership="none">
<type name="double" c:type="gdouble"/>
</parameter>
<parameter name="one" direction="out" transfer-ownership="full">
<parameter name="one"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="gdouble*"/>
</parameter>
<parameter name="two" direction="out" transfer-ownership="full">
<parameter name="two"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="gdouble*"/>
</parameter>
</parameters>
......@@ -1655,6 +1709,7 @@ call and can be released on return.">
<parameters>
<parameter name="obj"
direction="out"
caller-allocates="0"
transfer-ownership="full"
allow-none="1"
doc="A #TestObj">
......@@ -1767,7 +1822,10 @@ call and can be released on return.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="retp" direction="out" transfer-ownership="container">
<parameter name="retp"
direction="out"
caller-allocates="0"
transfer-ownership="container">
<array c:type="char***">
<type name="utf8"/>
</array>
......@@ -1793,16 +1851,25 @@ call and can be released on return.">
<parameter name="x" transfer-ownership="none">
<type name="int" c:type="int"/>
</parameter>
<parameter name="y" direction="out" transfer-ownership="full">
<parameter name="y"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="double*"/>
</parameter>
<parameter name="z" direction="out" transfer-ownership="full">
<parameter name="z"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="foo" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
<parameter name="q" direction="out" transfer-ownership="full">
<parameter name="q"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="m" transfer-ownership="none">
......@@ -1821,16 +1888,25 @@ call and can be released on return.">
<parameter name="x" transfer-ownership="none">
<type name="int" c:type="int"/>
</parameter>
<parameter name="y" direction="out" transfer-ownership="full">
<parameter name="y"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="double*"/>
</parameter>
<parameter name="z" direction="out" transfer-ownership="full">
<parameter name="z"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="foo" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
<parameter name="q" direction="out" transfer-ownership="full">
<parameter name="q"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="m" transfer-ownership="none">
......@@ -1860,16 +1936,25 @@ call and can be released on return.">
<parameter name="notify" transfer-ownership="none" scope="call">
<type name="GLib.DestroyNotify" c:type="GDestroyNotify"/>
</parameter>
<parameter name="y" direction="out" transfer-ownership="full">
<parameter name="y"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="double" c:type="double*"/>
</parameter>
<parameter name="z" direction="out" transfer-ownership="full">
<parameter name="z"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="foo" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
<parameter name="q" direction="out" transfer-ownership="full">
<parameter name="q"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="int" c:type="int*"/>
</parameter>
<parameter name="m" transfer-ownership="none">
......@@ -1968,7 +2053,10 @@ call and can be released on return.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="inout" direction="inout" transfer-ownership="full">
<parameter name="inout"
direction="inout"
caller-allocates="0"
transfer-ownership="full">
<type name="utf8" c:type="char**"/>
</parameter>
</parameters>
......@@ -2007,6 +2095,7 @@ call and can be released on return.">
<parameters>
<parameter name="char_out"
direction="out"
caller-allocates="0"
transfer-ownership="full"
allow-none="1">
<type name="utf8" c:type="char**"/>
......@@ -2018,7 +2107,10 @@ call and can be released on return.">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="out" direction="out" transfer-ownership="full">
<parameter name="out"
direction="out"
caller-allocates="0"
transfer-ownership="full">
<type name="utf8" c:type="char**"/>
</parameter>
</parameters>
......@@ -2032,6 +2124,7 @@ call and can be released on return.">
<parameters>
<parameter name="out"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc="a copy of &quot;second&quot;">
<type name="utf8" c:type="char**"/>
......@@ -2045,12 +2138,14 @@ call and can be released on return.">
<parameters>
<parameter name="out0"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc="a copy of &quot;first&quot;">
<type name="utf8" c:type="char**"/>
</parameter>
<parameter name="out1"
direction="out"
caller-allocates="0"
transfer-ownership="full"
doc="a copy of &quot;second&quot;">
<type name="utf8" c:type="char**"/>
......
This diff is collapsed.
......@@ -1325,7 +1325,7 @@ test_enum_param(TestEnum e)
/**
* test_struct_a_clone:
* @a: the structure
* @a_out: the cloned structure
* @a_out: (out caller-allocates): the cloned structure
*
* Make a copy of a TestStructA
*/
......@@ -1339,7 +1339,7 @@ test_struct_a_clone (TestStructA *a,
/**
* test_struct_b_clone:
* @b: the structure
* @b_out: the cloned structure
* @b_out: (out): the cloned structure
*
* Make a copy of a TestStructB
*/
......
......@@ -1021,21 +1021,23 @@ g_arg_info_is_return_value (GIArgInfo *info)
}
/**
* g_arg_info_is_dipper:
* g_arg_info_is_caller_allocates:
* @info: a #GIArgInfo
*
* Obtain if the argument is a pointer to a struct or object that will
* receive an output of a function.
* receive an output of a function. The default assumption for
* %GI_DIRECTION_OUT arguments which have allocation is that the
* callee allocates; if this is %TRUE, then the caller must allocate.
*
* Returns: %TRUE if it is a dipper argument
* Returns: %TRUE if caller is required to have allocated the argument
*/
gboolean
g_arg_info_is_dipper (GIArgInfo *info)
g_arg_info_is_caller_allocates (GIArgInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
ArgBlob *blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset];
return blob->dipper;
return blob->caller_allocates;
}
/**
......
......@@ -551,6 +551,7 @@ GIDirection g_arg_info_get_direction (GIArgInfo *info);
gboolean g_arg_info_is_dipper (GIArgInfo *info);
gboolean g_arg_info_is_return_value (GIArgInfo *info);
gboolean g_arg_info_is_optional (GIArgInfo *info);
gboolean g_arg_info_is_caller_allocates (GIArgInfo *info);
gboolean g_arg_info_may_be_null (GIArgInfo *info);
GITransfer g_arg_info_get_ownership_transfer (GIArgInfo *info);
GIScopeType g_arg_info_get_scope (GIArgInfo *info);
......
......@@ -1864,7 +1864,7 @@ g_ir_node_build_typelib (GIrNode *node,
blob->name = write_string (node->name, strings, data, offset2);
blob->in = param->in;
blob->out = param->out;
blob->dipper = param->dipper;
blob->caller_allocates = param->caller_allocates;
blob->allow_none = param->allow_none;
blob->optional = param->optional;
blob->transfer_ownership = param->transfer;
......
......@@ -153,7 +153,7 @@ struct _GIrNodeParam
gboolean in;
gboolean out;
gboolean dipper;
gboolean caller_allocates;
gboolean optional;
gboolean retval;
gboolean allow_none;
......
......@@ -881,8 +881,8 @@ start_parameter (GMarkupParseContext *context,
const gchar *name;
const gchar *direction;
const gchar *retval;
const gchar *dipper;
const gchar *optional;
const gchar *caller_allocates;
const gchar *allow_none;
const gchar *transfer;
const gchar *scope;
......@@ -897,9 +897,9 @@ start_parameter (GMarkupParseContext *context,
name = find_attribute ("name", attribute_names, attribute_values);
direction = find_attribute ("direction", attribute_names, attribute_values);
retval = find_attribute ("retval", attribute_names, attribute_values);
dipper = find_attribute ("dipper", attribute_names, attribute_values);
optional = find_attribute ("optional", attribute_names, attribute_values);
allow_none = find_attribute ("allow-none", attribute_names, attribute_values);
caller_allocates = find_attribute ("caller-allocates", attribute_names, attribute_values);
transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
scope = find_attribute ("scope", attribute_names, attribute_values);
closure = find_attribute ("closure", attribute_names, attribute_values);
......@@ -919,16 +919,27 @@ start_parameter (GMarkupParseContext *context,
{
param->in = FALSE;
param->out = TRUE;
if (caller_allocates == NULL)
{
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT,
"caller-allocates attribute required on out parameters");
return FALSE;
}
param->caller_allocates = strcmp (caller_allocates, "1") == 0;
}
else if (direction && strcmp (direction, "inout") == 0)
{
param->in = TRUE;
param->out = TRUE;
param->caller_allocates = FALSE;
}
else
{
param->in = TRUE;
param->out = FALSE;
param->caller_allocates = FALSE;
}
if (retval && strcmp (retval, "1") == 0)
......@@ -936,11 +947,6 @@ start_parameter (GMarkupParseContext *context,
else
param->retval = FALSE;
if (dipper && strcmp (dipper, "1") == 0)
param->dipper = TRUE;
else
param->dipper = FALSE;
if (optional && strcmp (optional, "1") == 0)
param->optional = TRUE;
else
......
......@@ -349,7 +349,7 @@ typedef union
* add another level of indirection to the parameter type. Ie if
* the type is uint32 in an out parameter, the function actually
* takes an uint32*.
* @dipper: The parameter is a pointer to a struct or object that will
* @caller_allocates: The parameter is a pointer to a struct or object that will
* receive an output of the function.
* @allow_none: Only meaningful for types which are passed as pointers.
* For an in parameter, indicates if it is ok to pass NULL in, for
......@@ -388,7 +388,7 @@ typedef struct {
guint in : 1;
guint out : 1;
guint dipper : 1;
guint caller_allocates : 1;
guint allow_none : 1;
guint optional : 1;
guint transfer_ownership : 1;
......@@ -397,7 +397,7 @@ typedef struct {
guint scope : 3;
/* <private> */
guint reserved :21;
/* <public> */
gint8 closure;
gint8 destroy;
......
......@@ -587,13 +587,15 @@ class AnnotationApplier(object):
def _parse_param_ret_common(self, parent, node, tag):
options = getattr(tag, 'options', {})
node.direction = self._extract_direction(node, options)
(node.direction, node.caller_allocates) = \
self._extract_direction(node, options)
container_type = self._extract_container_type(
parent, node, options)
if container_type is not None:
node.type = container_type
if node.direction is None:
node.direction = self._guess_direction(node)
node.caller_allocates = False
node.transfer = self._extract_transfer(parent, node, options)
param_type = options.get(OPT_TYPE)
if param_type:
......@@ -608,16 +610,32 @@ class AnnotationApplier(object):
node.doc = tag.comment
def _extract_direction(self, node, options):
caller_allocates = False
if (OPT_INOUT in options or
OPT_INOUT_ALT in options):
direction = PARAM_DIRECTION_INOUT
elif OPT_OUT in options:
subtype = options[OPT_OUT]
if subtype is not None:
subtype = subtype.one()
direction = PARAM_DIRECTION_OUT
if subtype in (None, ''):
if (node.type.name not in BASIC_GIR_TYPES) and node.type.ctype:
caller_allocates = '**' not in node.type.ctype
else:
caller_allocates = False
elif subtype == 'caller-allocates':
caller_allocates = True
elif subtype == 'callee-allocates':
caller_allocates = False
else:
raise InvalidAnnotationError(
"out direction for %s is invalid (%r)" % (node, subtype))
elif OPT_IN in options:
direction = PARAM_DIRECTION_IN
else:
direction = node.direction
return direction
return (direction, caller_allocates)
def _guess_array(self, node):
ctype = node.type.ctype
......@@ -885,6 +903,8 @@ class AnnotationApplier(object):
elif isinstance(node, Parameter):
if node.direction in [PARAM_DIRECTION_INOUT,
PARAM_DIRECTION_OUT]:
if node.caller_allocates:
return PARAM_TRANSFER_NONE
return PARAM_TRANSFER_FULL
# This one is a hack for compatibility; the transfer
# for string parameters really has no defined meaning.
......
......@@ -367,6 +367,7 @@ class Parameter(TypeContainer):
else:
self.direction = PARAM_DIRECTION_IN
self.caller_allocates = False
self.allow_none = allow_none
self.scope = scope
self.closure_index = -1
......
......@@ -207,6 +207,8 @@ and/or use gtk-doc annotations. ''')
attrs.append(('name', parameter.name))
if parameter.direction != 'in':
attrs.append(('direction', parameter.direction))
attrs.append(('caller-allocates',
'1' if parameter.caller_allocates else '0'))
attrs.append(('transfer-ownership',
parameter.transfer))
if parameter.allow_none:
......
......@@ -23,7 +23,7 @@
<parameter name="in" c:type="gint" direction="in" transfer-ownership="none">
<type name="int" c:type="gint"/>
</parameter>
<parameter name="out" c:type="gint" direction="out" transfer-ownership="none">
<parameter name="out" c:type="gint" direction="out" transfer-ownership="none" caller-allocates="0">
<type name="int" c:type="gint"/>
</parameter>
</parameters>
......@@ -56,10 +56,10 @@
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="blurb" direction="out" transfer-ownership="full">
<parameter name="blurb" direction="out" transfer-ownership="full" caller-allocates="0">
<type name="utf8" c:type="gchar*"/>
</parameter>
<parameter name="len" direction="out" transfer-ownership="none">
<parameter name="len" direction="out" transfer-ownership="none" caller-allocates="0">
<type name="int" c:type="gint"/>
</parameter>
</parameters>
......@@ -104,7 +104,7 @@
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="out" direction="out" transfer-ownership="full">