[gobject-introspection] Parse and expose ownership transfer for instance parameters



commit a4c9d09d7a89d3c80b4465a5c2ae0efa24158b24
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Tue May 6 18:53:21 2014 +0200

    Parse and expose ownership transfer for instance parameters
    
    Knowing the ownership transfer for instance parameters is
    necessary for correct memory management of functions which
    "eat" their instance argument, such as g_dbus_method_invocation_return_*.
    Parse this information from the gir file and store in the
    typelib, and then provide new API on GICallableInfo to
    retrieve this.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=729662

 girepository/gicallableinfo.c                      |   26 +++++++
 girepository/gicallableinfo.h                      |    2 +
 girepository/girepository.symbols                  |    1 +
 girepository/girnode.c                             |    3 +
 girepository/girnode.h                             |    3 +
 girepository/girparser.c                           |   74 ++++++++++++++++++--
 girepository/gitypelib-internal.h                  |    5 +-
 tests/repository/gitypelibtest.c                   |   29 ++++++++
 .../Regress.TestObj.instance_method_full.page      |   38 ++++++++++
 .../Regress.TestObj.instance_method_full.page      |   26 +++++++
 .../Regress.TestObj.instance_method_full.page      |   37 ++++++++++
 tests/scanner/Regress-1.0-expected.gir             |   11 +++
 tests/scanner/Regress-1.0-sections-expected.txt    |    1 +
 tests/scanner/regress.c                            |   11 +++
 tests/scanner/regress.h                            |    1 +
 15 files changed, 262 insertions(+), 6 deletions(-)
---
diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c
index e69e3e9..702e16c 100644
--- a/girepository/gicallableinfo.c
+++ b/girepository/gicallableinfo.c
@@ -276,6 +276,32 @@ g_callable_info_get_caller_owns (GICallableInfo *info)
 }
 
 /**
+ * g_callable_info_get_instance_ownership_transfer:
+ * @info: a #GICallableInfo
+ *
+ * Obtains the ownership transfer for the instance argument.
+ * #GITransfer contains a list of possible transfer values.
+ *
+ * Returns: the transfer
+ */
+GITransfer
+g_callable_info_get_instance_ownership_transfer (GICallableInfo *info)
+{
+  GIRealInfo *rinfo = (GIRealInfo*) info;
+  SignatureBlob *blob;
+
+  g_return_val_if_fail (info != NULL, -1);
+  g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1);
+
+  blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
+
+  if (blob->instance_transfer_ownership)
+    return GI_TRANSFER_EVERYTHING;
+  else
+    return GI_TRANSFER_NOTHING;
+}
+
+/**
  * g_callable_info_get_n_args:
  * @info: a #GICallableInfo
  *
diff --git a/girepository/gicallableinfo.h b/girepository/gicallableinfo.h
index 71f9d0c..f273d29 100644
--- a/girepository/gicallableinfo.h
+++ b/girepository/gicallableinfo.h
@@ -73,6 +73,8 @@ gboolean               g_callable_info_invoke          (GICallableInfo   *info,
                                                         gboolean          is_method,
                                                         gboolean          throws,
                                                         GError          **error);
+GITransfer             g_callable_info_get_instance_ownership_transfer (GICallableInfo *info);
+
 G_END_DECLS
 
 
diff --git a/girepository/girepository.symbols b/girepository/girepository.symbols
index 5f01adf..48fb0d9 100644
--- a/girepository/girepository.symbols
+++ b/girepository/girepository.symbols
@@ -26,6 +26,7 @@ g_info_new
 g_callable_info_can_throw_gerror
 g_callable_info_get_arg
 g_callable_info_get_caller_owns
+g_callable_info_get_instance_ownership_transfer
 g_callable_info_get_n_args
 g_callable_info_get_return_attribute
 g_callable_info_get_return_type
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 53385c2..a7a77e3 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -1664,6 +1664,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob2->caller_owns_return_value = function->result->transfer;
        blob2->caller_owns_return_container = function->result->shallow_transfer;
        blob2->skip_return = function->result->skip;
+        blob2->instance_transfer_ownership = function->instance_transfer_full;
        blob2->reserved = 0;
        blob2->n_arguments = n;
 
@@ -1762,6 +1763,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob2->may_return_null = signal->result->nullable;
        blob2->caller_owns_return_value = signal->result->transfer;
        blob2->caller_owns_return_container = signal->result->shallow_transfer;
+        blob2->instance_transfer_ownership = signal->instance_transfer_full;
        blob2->reserved = 0;
        blob2->n_arguments = n;
 
@@ -1820,6 +1822,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob2->may_return_null = vfunc->result->nullable;
        blob2->caller_owns_return_value = vfunc->result->transfer;
        blob2->caller_owns_return_container = vfunc->result->shallow_transfer;
+        blob2->instance_transfer_ownership = vfunc->instance_transfer_full;
        blob2->reserved = 0;
        blob2->n_arguments = n;
 
diff --git a/girepository/girnode.h b/girepository/girnode.h
index 4beef7f..02196e7 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -100,6 +100,7 @@ struct _GIrNodeFunction
   gboolean is_constructor;
   gboolean wraps_vfunc;
   gboolean throws;
+  gboolean instance_transfer_full;
 
   gchar *symbol;
 
@@ -188,6 +189,7 @@ struct _GIrNodeSignal
   gboolean detailed;
   gboolean action;
   gboolean no_hooks;
+  gboolean instance_transfer_full;
 
   gboolean has_class_closure;
   gboolean true_stops_emit;
@@ -208,6 +210,7 @@ struct _GIrNodeVFunc
   gboolean must_not_be_implemented;
   gboolean is_class_closure;
   gboolean throws;
+  gboolean instance_transfer_full;
 
   char *invoker;
 
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 6c76866..f928c2e 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -1047,6 +1047,71 @@ parse_param_transfer (GIrNodeParam *param, const gchar *transfer, const gchar *n
 }
 
 static gboolean
+start_instance_parameter (GMarkupParseContext *context,
+                          const gchar         *element_name,
+                          const gchar        **attribute_names,
+                          const gchar        **attribute_values,
+                          ParseContext        *ctx,
+                          GError             **error)
+{
+  const gchar *transfer;
+  gboolean transfer_full;
+
+  if (!(strcmp (element_name, "instance-parameter") == 0 &&
+       ctx->state == STATE_FUNCTION_PARAMETERS))
+    return FALSE;
+
+  transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values);
+
+  state_switch (ctx, STATE_PASSTHROUGH);
+
+  if (strcmp (transfer, "full") == 0)
+    transfer_full = TRUE;
+  else if (strcmp (transfer, "none") == 0)
+    transfer_full = FALSE;
+  else
+    {
+      g_set_error (error, G_MARKUP_ERROR,
+                  G_MARKUP_ERROR_INVALID_CONTENT,
+                  "invalid value for 'transfer-ownership' for instance parameter: %s", transfer);
+      return FALSE;
+    }
+
+  switch (CURRENT_NODE (ctx)->type)
+    {
+    case G_IR_NODE_FUNCTION:
+    case G_IR_NODE_CALLBACK:
+      {
+       GIrNodeFunction *func;
+
+       func = (GIrNodeFunction *)CURRENT_NODE (ctx);
+        func->instance_transfer_full = transfer_full;
+      }
+      break;
+    case G_IR_NODE_SIGNAL:
+      {
+       GIrNodeSignal *signal;
+
+       signal = (GIrNodeSignal *)CURRENT_NODE (ctx);
+        signal->instance_transfer_full = transfer_full;
+      }
+      break;
+    case G_IR_NODE_VFUNC:
+      {
+       GIrNodeVFunc *vfunc;
+
+       vfunc = (GIrNodeVFunc *)CURRENT_NODE (ctx);
+        vfunc->instance_transfer_full = transfer_full;
+      }
+      break;
+    default:
+      g_assert_not_reached ();
+    }
+
+  return TRUE;
+}
+
+static gboolean
 start_parameter (GMarkupParseContext *context,
                 const gchar         *element_name,
                 const gchar        **attribute_names,
@@ -2848,11 +2913,10 @@ start_element_handler (GMarkupParseContext *context,
                                 attribute_names, attribute_values,
                                 ctx, error))
        goto out;
-      else if (strcmp (element_name, "instance-parameter") == 0)
-        {
-          state_switch (ctx, STATE_PASSTHROUGH);
-          goto out;
-        }
+      else if (start_instance_parameter (context, element_name,
+                               attribute_names, attribute_values,
+                               ctx, error))
+       goto out;
       else if (strcmp (element_name, "c:include") == 0)
        {
          state_switch (ctx, STATE_C_INCLUDE);
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index 93d621b..5ccb617 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -465,6 +465,8 @@ typedef struct {
  *   freeing the container, but not its contents.
  * @skip_return: Indicates that the return value is only useful in C and should
  *   be skipped.
+ * @instance_transfer_ownership: When calling, the function assumes ownership of
+ *   the instance parameter.
  * @reserved: Reserved for future use.
  * @n_arguments: The number of arguments that this function expects, also the
  *   length of the array of ArgBlobs.
@@ -479,7 +481,8 @@ typedef struct {
   guint16        caller_owns_return_value     : 1;
   guint16        caller_owns_return_container : 1;
   guint16        skip_return                  : 1;
-  guint16        reserved                     :12;
+  guint16        instance_transfer_ownership  : 1;
+  guint16        reserved                     :11;
 
   guint16        n_arguments;
 
diff --git a/tests/repository/gitypelibtest.c b/tests/repository/gitypelibtest.c
index 565c95c..7b9cb35 100644
--- a/tests/repository/gitypelibtest.c
+++ b/tests/repository/gitypelibtest.c
@@ -276,6 +276,34 @@ test_signal_array_len (GIRepository * repo)
   g_base_info_unref (testobj_info);
 }
 
+static void
+test_instance_transfer_ownership (GIRepository * repo)
+{
+  GIObjectInfo *testobj_info;
+  GIFunctionInfo *func_info;
+  GITransfer transfer;
+
+  g_assert (g_irepository_require (repo, "Regress", NULL, 0, NULL));
+  testobj_info = g_irepository_find_by_name (repo, "Regress", "TestObj");
+  g_assert (testobj_info != NULL);
+
+  func_info = g_object_info_find_method (testobj_info, "instance_method");
+  g_assert (func_info != NULL);
+  transfer = g_callable_info_get_instance_ownership_transfer ((GICallableInfo*) func_info);
+  g_assert_cmpint (GI_TRANSFER_NOTHING, ==, transfer);
+
+  g_base_info_unref (func_info);
+
+  func_info = g_object_info_find_method (testobj_info, "instance_method_full");
+  g_assert (func_info != NULL);
+  transfer = g_callable_info_get_instance_ownership_transfer ((GICallableInfo*) func_info);
+  g_assert_cmpint (GI_TRANSFER_EVERYTHING, ==, transfer);
+
+  g_base_info_unref (func_info);
+
+  g_base_info_unref (testobj_info);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -292,6 +320,7 @@ main (int argc, char **argv)
   test_hash_with_cairo_typelib (repo);
   test_char_types (repo);
   test_signal_array_len (repo);
+  test_instance_transfer_ownership (repo);
 
   exit (0);
 }
diff --git a/tests/scanner/Regress-1.0-C-expected/Regress.TestObj.instance_method_full.page 
b/tests/scanner/Regress-1.0-C-expected/Regress.TestObj.instance_method_full.page
new file mode 100644
index 0000000..2222bec
--- /dev/null
+++ b/tests/scanner/Regress-1.0-C-expected/Regress.TestObj.instance_method_full.page
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj.instance_method_full"
+      type="topic"
+      style="method"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="Regress.TestObj" group="method" type="guide"/>
+    <api:function>
+      <api:returns>
+        <api:type>void</api:type>
+      </api:returns>
+      <api:name>regress_test_obj_instance_method_full</api:name>
+      <api:arg>
+        <api:type>RegressTestObj*</api:type>
+        <api:name>obj</api:name>
+      </api:arg>
+    </api:function>
+  </info>
+  <title>regress_test_obj_instance_method_full</title>
+  <synopsis><code mime="text/x-csrc">
+void regress_test_obj_instance_method_full (RegressTestObj* obj);
+  </code></synopsis>
+
+
+<terms>
+<item>
+<title><code>obj</code></title>
+
+</item>
+<item>
+<title><code>Returns</code></title>
+
+</item>
+</terms>
+
+</page>
diff --git a/tests/scanner/Regress-1.0-Gjs-expected/Regress.TestObj.instance_method_full.page 
b/tests/scanner/Regress-1.0-Gjs-expected/Regress.TestObj.instance_method_full.page
new file mode 100644
index 0000000..5b7e1c9
--- /dev/null
+++ b/tests/scanner/Regress-1.0-Gjs-expected/Regress.TestObj.instance_method_full.page
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj.instance_method_full"
+      type="topic"
+      style="method"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="Regress.TestObj" group="method" type="guide"/>
+    <api:function>
+      <api:returns>
+        <api:type>void</api:type>
+      </api:returns>
+      <api:name>regress_test_obj_instance_method_full</api:name>
+    </api:function>
+  </info>
+  <title>Regress.TestObj.prototype.instance_method_full</title>
+  <synopsis><code mime="text/x-gjs">
+function instance_method_full(): void {
+    // Gjs wrapper for regress_test_obj_instance_method_full()
+}
+  </code></synopsis>
+
+
+
+</page>
diff --git a/tests/scanner/Regress-1.0-Python-expected/Regress.TestObj.instance_method_full.page 
b/tests/scanner/Regress-1.0-Python-expected/Regress.TestObj.instance_method_full.page
new file mode 100644
index 0000000..2b5c1dc
--- /dev/null
+++ b/tests/scanner/Regress-1.0-Python-expected/Regress.TestObj.instance_method_full.page
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj.instance_method_full"
+      type="topic"
+      style="method"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="Regress.TestObj" group="method" type="guide"/>
+    <api:function>
+      <api:returns>
+        <api:type>none</api:type>
+      </api:returns>
+      <api:name>regress_test_obj_instance_method_full</api:name>
+      <api:arg>
+        <api:type>Regress.TestObj</api:type>
+        <api:name>self</api:name>
+      </api:arg>
+    </api:function>
+  </info>
+  <title>Regress.TestObj.instance_method_full</title>
+  <synopsis><code mime="text/x-python">
+ accepts(Regress.TestObj)
+ returns(none)
+def instance_method_full(self):
+    # Python wrapper for regress_test_obj_instance_method_full()
+  </code></synopsis>
+
+
+<terms>
+<item>
+<title><code>self</code></title>
+
+</item>
+</terms>
+
+</page>
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index 1c9c300..89ecaa4 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -3057,6 +3057,17 @@ case.</doc>
           </parameter>
         </parameters>
       </method>
+      <method name="instance_method_full"
+              c:identifier="regress_test_obj_instance_method_full">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="obj" transfer-ownership="full">
+            <type name="TestObj" c:type="RegressTestObj*"/>
+          </instance-parameter>
+        </parameters>
+      </method>
       <method name="set_bare" c:identifier="regress_test_obj_set_bare">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
diff --git a/tests/scanner/Regress-1.0-sections-expected.txt b/tests/scanner/Regress-1.0-sections-expected.txt
index c9ff60a..187aa16 100644
--- a/tests/scanner/Regress-1.0-sections-expected.txt
+++ b/tests/scanner/Regress-1.0-sections-expected.txt
@@ -334,6 +334,7 @@ regress_test_obj_emit_sig_with_uint64
 regress_forced_method
 regress_test_obj_instance_method
 regress_test_obj_instance_method_callback
+regress_test_obj_instance_method_full
 regress_test_obj_set_bare
 regress_test_obj_skip_inout_param
 regress_test_obj_skip_out_param
diff --git a/tests/scanner/regress.c b/tests/scanner/regress.c
index 1bad36e..b42e0cd 100644
--- a/tests/scanner/regress.c
+++ b/tests/scanner/regress.c
@@ -2679,6 +2679,17 @@ regress_test_obj_instance_method (RegressTestObj *obj)
     return -1;
 }
 
+/**
+ * regress_test_obj_instance_method_full:
+ * @obj: (transfer full):
+ *
+ */
+void
+regress_test_obj_instance_method_full (RegressTestObj *obj)
+{
+  g_object_unref (obj);
+}
+
 double
 regress_test_obj_static_method (int x)
 {
diff --git a/tests/scanner/regress.h b/tests/scanner/regress.h
index e2e645b..667f129 100644
--- a/tests/scanner/regress.h
+++ b/tests/scanner/regress.h
@@ -527,6 +527,7 @@ void       regress_test_obj_emit_sig_with_foreign_struct (RegressTestObj *obj);
 void       regress_test_obj_emit_sig_with_int64 (RegressTestObj *obj);
 void       regress_test_obj_emit_sig_with_uint64 (RegressTestObj *obj);
 int        regress_test_obj_instance_method (RegressTestObj *obj);
+void       regress_test_obj_instance_method_full (RegressTestObj *obj);
 double     regress_test_obj_static_method (int x);
 void       regress_forced_method (RegressTestObj *obj);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]