[gobject-introspection] girepository: Support GError exceptions on callbacks



commit 0aef39a20bd229170871edda862ade7d24ff7edd
Author: Garrett Regier <garrett regier riftio com>
Date:   Wed Jun 3 05:24:21 2015 -0700

    girepository: Support GError exceptions on callbacks
    
    Generalize "throws" attribute to SignatureBlob which can be used by all
    callable blob types. Keep FunctionBlob and VFuncBlob throw attributes
    around and functional for compatibility. Refactor girwriter.c to write
    out throws attribute for all callable types.
    
    Based on a patch by Simon Feltman.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=729543

 girepository/gicallableinfo.c     |   11 +++++
 girepository/girnode.c            |    7 ++-
 girepository/girwriter.c          |   11 +----
 girepository/gitypelib-internal.h |    9 +++-
 tests/repository/gitestthrows.c   |   81 +++++++++++++++++++++++++++++++++++++
 5 files changed, 106 insertions(+), 13 deletions(-)
---
diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c
index 7e0ec77..8360bbf 100644
--- a/girepository/gicallableinfo.c
+++ b/girepository/gicallableinfo.c
@@ -96,6 +96,17 @@ gboolean
 g_callable_info_can_throw_gerror (GICallableInfo *info)
 {
   GIRealInfo *rinfo = (GIRealInfo*)info;
+  SignatureBlob *signature;
+
+  signature = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)];
+  if (signature->throws)
+    return TRUE;
+
+  /* Functions and VFuncs store "throws" in their own blobs.
+   * This info was additionally added to the SignatureBlob
+   * to support the other callables. For Functions and VFuncs,
+   * also check their legacy flag for compatibility.
+   */
   switch (rinfo->type) {
   case GI_INFO_TYPE_FUNCTION:
     {
diff --git a/girepository/girnode.c b/girepository/girnode.c
index a7a77e3..d0a18a3 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -1641,7 +1641,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob->getter = function->is_getter;
        blob->constructor = function->is_constructor;
        blob->wraps_vfunc = function->wraps_vfunc;
-       blob->throws = function->throws;
+       blob->throws = function->throws; /* Deprecated. Also stored in SignatureBlob. */
        blob->index = 0;
        blob->name = _g_ir_write_string (node->name, strings, data, offset2);
        blob->symbol = _g_ir_write_string (function->symbol, strings, data, offset2);
@@ -1667,6 +1667,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
         blob2->instance_transfer_ownership = function->instance_transfer_full;
        blob2->reserved = 0;
        blob2->n_arguments = n;
+       blob2->throws = function->throws;
 
        signature += 4;
 
@@ -1708,6 +1709,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob2->caller_owns_return_container = function->result->shallow_transfer;
        blob2->reserved = 0;
        blob2->n_arguments = n;
+       blob2->throws = function->throws;
 
        signature += 4;
 
@@ -1797,7 +1799,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
        blob->must_be_implemented = 0; /* FIXME */
        blob->must_not_be_implemented = 0; /* FIXME */
        blob->class_closure = 0; /* FIXME */
-        blob->throws = vfunc->throws;
+       blob->throws = vfunc->throws; /* Deprecated. Also stored in SignatureBlob. */
        blob->reserved = 0;
 
        if (vfunc->invoker)
@@ -1825,6 +1827,7 @@ _g_ir_node_build_typelib (GIrNode         *node,
         blob2->instance_transfer_ownership = vfunc->instance_transfer_full;
        blob2->reserved = 0;
        blob2->n_arguments = n;
+       blob2->throws = vfunc->throws;
 
        signature += 4;
 
diff --git a/girepository/girwriter.c b/girepository/girwriter.c
index 01f5f50..4bc7fc9 100644
--- a/girepository/girwriter.c
+++ b/girepository/girwriter.c
@@ -454,6 +454,9 @@ write_callable_info (const gchar    *namespace,
   GITypeInfo *type;
   gint i;
 
+  if (g_callable_info_can_throw_gerror (info))
+    xml_printf (file, " throws=\"1\"");
+
   write_attributes (file, (GIBaseInfo*) info);
 
   type = g_callable_info_get_return_type (info);
@@ -558,13 +561,11 @@ write_function_info (const gchar    *namespace,
   const gchar *name;
   const gchar *symbol;
   gboolean deprecated;
-  gboolean throws;
 
   flags = g_function_info_get_flags (info);
   name = g_base_info_get_name ((GIBaseInfo *)info);
   symbol = g_function_info_get_symbol (info);
   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
-  throws = flags & GI_FUNCTION_THROWS;
 
   if (flags & GI_FUNCTION_IS_CONSTRUCTOR)
     tag = "constructor";
@@ -585,9 +586,6 @@ write_function_info (const gchar    *namespace,
   if (deprecated)
     xml_printf (file, " deprecated=\"1\"");
 
-  if (throws)
-    xml_printf (file, " throws=\"1\"");
-
   write_callable_info (namespace, (GICallableInfo*)info, file);
   xml_end_element (file, tag);
 }
@@ -914,9 +912,6 @@ write_vfunc_info (const gchar *namespace,
   else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE)
     xml_printf (file, " override=\"never\"");
 
-  if (flags & GI_VFUNC_THROWS)
-    xml_printf (file, " throws=\"1\"");
-
   xml_printf (file, " offset=\"%d\"", offset);
 
   if (invoker)
diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h
index e50ccac..5ccff71 100644
--- a/girepository/gitypelib-internal.h
+++ b/girepository/gitypelib-internal.h
@@ -467,6 +467,8 @@ typedef struct {
  *   be skipped.
  * @instance_transfer_ownership: When calling, the function assumes ownership of
  *   the instance parameter.
+ * @throws: Denotes the signature takes an additional #GError argument beyond
+ *   the annotated arguments.
  * @reserved: Reserved for future use.
  * @n_arguments: The number of arguments that this function expects, also the
  *   length of the array of ArgBlobs.
@@ -482,7 +484,8 @@ typedef struct {
   guint16        caller_owns_return_container : 1;
   guint16        skip_return                  : 1;
   guint16        instance_transfer_ownership  : 1;
-  guint16        reserved                     :11;
+  guint16        throws                       : 1;
+  guint16        reserved                     :10;
 
   guint16        n_arguments;
 
@@ -522,7 +525,7 @@ typedef struct {
  * @constructor: The function acts as a constructor for the object it is
  *   contained in.
  * @wraps_vfunc: The function is a simple wrapper for a virtual function.
- * @throws: TODO
+ * @throws: (deprecated): This is now additionally stored in the #SignatureBlob.
  * @index: Index of the property that this function is a setter or getter of
  *   in the array of properties of the containing interface, or index
  *   of the virtual function that this function wraps.
@@ -990,7 +993,7 @@ typedef struct {
  *   virtual function.
  * @class_closure: Set if this virtual function is the class closure of a
  *   signal.
- * @throws: TODO
+ * @throws: (deprecated): This is now additionally stored in the #SignatureBlob.
  * @reserved: Reserved for future use.
  * @signal: The index of the signal in the list of signals of the object or
  *   interface to which this virtual function belongs.
diff --git a/tests/repository/gitestthrows.c b/tests/repository/gitestthrows.c
index 17694bf..826ed41 100644
--- a/tests/repository/gitestthrows.c
+++ b/tests/repository/gitestthrows.c
@@ -42,12 +42,93 @@ test_invoke_gerror (void)
   g_assert (error->code == G_FILE_ERROR_NOENT);
 }
 
+static void
+test_vfunc_can_throw_gerror (void)
+{
+  GIRepository *repo;
+  GITypelib *ret;
+  GIBaseInfo *object_info;
+  GIFunctionInfo *invoker_info;
+  GIVFuncInfo *vfunc_info;
+  GError *error = NULL;
+
+  repo = g_irepository_get_default ();
+
+  ret = g_irepository_require (repo, "GIMarshallingTests", NULL, 0, &error);
+  g_assert_nonnull (ret);
+  g_assert_no_error (error);
+
+  object_info = g_irepository_find_by_name (repo, "GIMarshallingTests", "Object");
+  g_assert_nonnull (object_info);
+  g_assert (g_base_info_get_type (object_info) == GI_INFO_TYPE_OBJECT);
+
+  invoker_info = g_object_info_find_method ((GIObjectInfo *)object_info,
+                                            "vfunc_meth_with_error");
+  g_assert_nonnull (invoker_info);
+  g_assert (g_function_info_get_flags (invoker_info) & GI_FUNCTION_THROWS);
+  g_assert (g_callable_info_can_throw_gerror ((GICallableInfo *)invoker_info));
+
+  vfunc_info = g_object_info_find_vfunc ((GIObjectInfo *)object_info,
+                                         "vfunc_meth_with_err");
+  g_assert_nonnull (vfunc_info);
+  g_assert (g_vfunc_info_get_flags (vfunc_info) & GI_VFUNC_THROWS);
+  g_assert (g_callable_info_can_throw_gerror ((GICallableInfo *)vfunc_info));
+
+  g_base_info_unref (vfunc_info);
+  g_base_info_unref (invoker_info);
+  g_base_info_unref (object_info);
+}
+
+static void
+test_callback_can_throw_gerror (void)
+{
+  GIRepository *repo;
+  GITypelib *ret;
+  GIStructInfo *class_info;
+  GIFieldInfo *field_info;
+  GITypeInfo *field_type;
+  GICallbackInfo *callback_info;
+  GError *error = NULL;
+
+  repo = g_irepository_get_default ();
+
+  ret = g_irepository_require (repo, "GIMarshallingTests", NULL, 0, &error);
+  g_assert_nonnull (ret);
+  g_assert_no_error (error);
+
+  class_info = g_irepository_find_by_name (repo, "GIMarshallingTests", "ObjectClass");
+  g_assert_nonnull (class_info);
+  g_assert (g_base_info_get_type (class_info) == GI_INFO_TYPE_STRUCT);
+
+  field_info = g_struct_info_find_field (class_info, "vfunc_meth_with_err");
+  g_assert_nonnull (field_info);
+  g_assert (g_base_info_get_type (field_info) == GI_INFO_TYPE_FIELD);
+
+  field_type = g_field_info_get_type (field_info);
+  g_assert_nonnull (field_type);
+  g_assert (g_base_info_get_type (field_type) == GI_INFO_TYPE_TYPE);
+  g_assert (g_type_info_get_tag (field_type) == GI_TYPE_TAG_INTERFACE);
+
+  callback_info = g_type_info_get_interface (field_type);
+  g_assert_nonnull (callback_info);
+  g_assert (g_callable_info_can_throw_gerror ((GICallableInfo *)callback_info));
+
+  g_base_info_unref (callback_info);
+  g_base_info_unref (field_type);
+  g_base_info_unref (field_info);
+  g_base_info_unref (class_info);
+}
+
 int
 main(int argc, char **argv)
 {
   g_test_init (&argc, &argv, NULL);
 
   g_test_add_func ("/girepository/throws/invoke-gerror", test_invoke_gerror);
+  g_test_add_func ("/girepository/throws/vfunc-can-throw-gerror",
+                   test_vfunc_can_throw_gerror);
+  g_test_add_func ("/girepository/throws/callback-can-throw-gerror",
+                   test_callback_can_throw_gerror);
 
   return g_test_run ();
 }


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