[gobject-introspection] Bug 574284 - Add support for a 'closure' and 'destroy' annotations



commit cf7621f31c6b3eaf29e1da82631a9404f8b1c036
Author: Andreas Rottmann <a rottmann gmx at>
Date:   Mon Mar 23 23:19:24 2009 +0100

    Bug 574284 - Add support for a 'closure' and 'destroy' annotations
    
    This allows to annotate cases where the heuristics don't work.
    
    TODO: According to Juerbi, there are cases where two callbacks refer
          to the same user_data, which is prohibited by the current
          implementation.
    
    Signed-off-by: Andreas Rottmann <a rottmann gmx at>
---
 giscanner/annotationparser.py              |   27 ++++++++++++++++++-
 giscanner/ast.py                           |   10 +++++++
 tests/scanner/annotation-1.0-expected.gir  |   39 ++++++++++++++++++++++++++++
 tests/scanner/annotation-1.0-expected.tgir |   26 ++++++++++++++++++
 tests/scanner/annotation.c                 |   15 ++++++++++
 tests/scanner/annotation.h                 |   12 ++++++++
 6 files changed, 128 insertions(+), 1 deletions(-)

diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index fae839f..30b0eed 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -60,6 +60,8 @@ OPT_OUT = 'out'
 OPT_SCOPE = 'scope'
 OPT_TRANSFER = 'transfer'
 OPT_TYPE = 'type'
+OPT_CLOSURE = 'closure'
+OPT_DESTROY = 'destroy'
 
 # Specific option values
 OPT_VAL_BITFIELD = 'bitfield'
@@ -476,14 +478,37 @@ class AnnotationApplier(object):
         self._parse_param_ret_common(parent, return_, tag)
 
     def _parse_param(self, parent, param, tag):
+        options = getattr(tag, 'options', {})
         if isinstance(parent, Function):
-            options = getattr(tag, 'options', {})
             scope = options.get(OPT_SCOPE)
             if scope:
                 param.scope = scope.one()
                 param.transfer = PARAM_TRANSFER_NONE
+            destroy = options.get(OPT_DESTROY)
+            if destroy:
+                param.destroy_index = parent.get_parameter_index(destroy.one())
+                self._fixup_param_destroy(parent, param)
+            closure = options.get(OPT_CLOSURE)
+            if closure:
+                param.closure_index = parent.get_parameter_index(closure.one())
+                self._fixup_param_closure(parent, param)
+        if isinstance(parent, Callback):
+            if OPT_CLOSURE in options:
+                param.closure_index = parent.get_parameter_index(param.name)
+                self._fixup_param_closure(parent, param)
+
         self._parse_param_ret_common(parent, param, tag)
 
+    def _fixup_param_destroy(self, parent, param):
+        for p in parent.parameters:
+            if p is not param and p.destroy_index == param.destroy_index:
+                p.destroy_index = None
+
+    def _fixup_param_closure(self, parent, param):
+        for p in parent.parameters:
+            if p is not param and p.closure_index == param.closure_index:
+                p.closure_index = None
+
     def _parse_param_ret_common(self, parent, node, tag):
         options = getattr(tag, 'options', {})
         node.direction = self._extract_direction(node, options)
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 0d3f0bb..b0db6e2 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -521,6 +521,16 @@ class Callback(Node):
         self.throws = False
         self.doc = None
 
+    def get_parameter_index(self, name):
+        for i, parameter in enumerate(self.parameters):
+            if parameter.name == name:
+                return i
+
+    def get_parameter(self, name):
+        for parameter in self.parameters:
+            if parameter.name == name:
+                return parameter
+
     def __repr__(self):
         return 'Callback(%r, %r, %r)' % (
             self.name, self.retval, self.parameters)
diff --git a/tests/scanner/annotation-1.0-expected.gir b/tests/scanner/annotation-1.0-expected.gir
index e82201e..c4e0fa0 100644
--- a/tests/scanner/annotation-1.0-expected.gir
+++ b/tests/scanner/annotation-1.0-expected.gir
@@ -58,6 +58,22 @@ and/or use gtk-doc annotations.  -->
         </parameter>
       </parameters>
     </callback>
+    <callback name="NotifyFunc"
+              c:type="AnnotationNotifyFunc"
+              doc="This is a callback with a &apos;closure&apos; argument that is not named
+&apos;user_data&apos; and hence has to be annotated.">
+      <return-value transfer-ownership="none">
+        <type name="none" c:type="void"/>
+      </return-value>
+      <parameters>
+        <parameter name="data"
+                   transfer-ownership="none"
+                   closure="0"
+                   doc="The user data">
+          <type name="any" c:type="gpointer"/>
+        </parameter>
+      </parameters>
+    </callback>
     <class name="Object"
            c:type="AnnotationObject"
            doc="This is an object used to test annotations."
@@ -517,6 +533,29 @@ known by GObject as it&apos;s only marked as G_TYPE_POINTER">
         </array>
       </field>
     </record>
+    <function name="custom_destroy"
+              c:identifier="annotation_custom_destroy"
+              doc="Test messing up the heuristic of closure/destroy-notification
+detection, and fixing it via annotations.">
+      <return-value transfer-ownership="none">
+        <type name="none" c:type="void"/>
+      </return-value>
+      <parameters>
+        <parameter name="callback"
+                   transfer-ownership="none"
+                   closure="2"
+                   destroy="1"
+                   doc="Destroy notification">
+          <type name="Callback" c:type="AnnotationCallback"/>
+        </parameter>
+        <parameter name="destroy" transfer-ownership="none">
+          <type name="NotifyFunc" c:type="AnnotationNotifyFunc"/>
+        </parameter>
+        <parameter name="data" transfer-ownership="none">
+          <type name="any" c:type="gpointer"/>
+        </parameter>
+      </parameters>
+    </function>
     <function name="get_source_file" c:identifier="annotation_get_source_file">
       <return-value transfer-ownership="full" doc="Source file">
         <type name="filename" c:type="char*"/>
diff --git a/tests/scanner/annotation-1.0-expected.tgir b/tests/scanner/annotation-1.0-expected.tgir
index 0d88c47..46af2ec 100644
--- a/tests/scanner/annotation-1.0-expected.tgir
+++ b/tests/scanner/annotation-1.0-expected.tgir
@@ -47,6 +47,16 @@
         </parameter>
       </parameters>
     </callback>
+    <callback name="NotifyFunc">
+      <return-value transfer-ownership="none">
+        <type name="none"/>
+      </return-value>
+      <parameters>
+        <parameter name="data" transfer-ownership="none" closure="0">
+          <type name="any"/>
+        </parameter>
+      </parameters>
+    </callback>
     <class name="Object" parent="GObject.Object" glib:type-struct="ObjectClass" glib:type-name="AnnotationObject" glib:get-type="annotation_object_get_type">
       <attribute name="org.example.Test" value="cows"/>
       <field name="parent_instance">
@@ -384,6 +394,22 @@
         </array>
       </field>
     </record>
+    <function name="custom_destroy" c:identifier="annotation_custom_destroy">
+      <return-value transfer-ownership="none">
+        <type name="none"/>
+      </return-value>
+      <parameters>
+        <parameter name="callback" transfer-ownership="none" closure="2" destroy="1">
+          <type name="Callback"/>
+        </parameter>
+        <parameter name="destroy" transfer-ownership="none">
+          <type name="NotifyFunc"/>
+        </parameter>
+        <parameter name="data" transfer-ownership="none">
+          <type name="any"/>
+        </parameter>
+      </parameters>
+    </function>
     <function name="get_source_file" c:identifier="annotation_get_source_file">
       <return-value transfer-ownership="full">
         <type name="filename"/>
diff --git a/tests/scanner/annotation.c b/tests/scanner/annotation.c
index cbc9244..5c5d46d 100644
--- a/tests/scanner/annotation.c
+++ b/tests/scanner/annotation.c
@@ -611,6 +611,21 @@ annotation_object_extra_annos (AnnotationObject *object)
 }
 
 /**
+ * annotation_custom_destroy:
+ *
+ * @callback: (destroy destroy) (closure data): Destroy notification
+ *
+ * Test messing up the heuristic of closure/destroy-notification
+ * detection, and fixing it via annotations.
+ */
+void
+annotation_custom_destroy (AnnotationCallback callback,
+                           AnnotationNotifyFunc destroy,
+                           gpointer data)
+{
+}
+
+/**
  * annotation_get_source_file:
  *
  * Return value: (type filename): Source file
diff --git a/tests/scanner/annotation.h b/tests/scanner/annotation.h
index e43e7ba..745a94b 100644
--- a/tests/scanner/annotation.h
+++ b/tests/scanner/annotation.h
@@ -22,6 +22,15 @@ typedef const gint* (*AnnotationCallback) (const gint *in);
 typedef GList* (*AnnotationListCallback) (GList *in);
 
 /**
+ * AnnotationNotifyFunc:
+ * @data: (closure): The user data
+ *
+ * This is a callback with a 'closure' argument that is not named
+ * 'user_data' and hence has to be annotated.
+ */
+typedef void (*AnnotationNotifyFunc) (gpointer data);
+
+/**
  * AnnotationObject:
  *
  * This is an object used to test annotations.
@@ -122,6 +131,9 @@ void     annotation_string_zero_terminated_out (char ***out);
 
 void     annotation_object_extra_annos (AnnotationObject *object);
 
+void     annotation_custom_destroy (AnnotationCallback callback,
+                                    AnnotationNotifyFunc destroy,
+                                    gpointer data);
 char *   annotation_get_source_file (void);
 void     annotation_set_source_file (const char *fname);
 



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