[gobject-introspection] giscanner: Correctly consume field annotations on structs



commit 2a569cb68ca4e4ce08ff66fc20a79bc57222c2e2
Author: Stef Walter <stefw gnome org>
Date:   Sun Oct 20 20:47:13 2013 +0200

    giscanner: Correctly consume field annotations on structs
    
    A hidden exception was being thrown (which we now log), due to fields
    being treated as function parameters. Fixed to make field array
    annotations be transformed and written out to the gir correctly.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=710561

 giscanner/ast.py                                   |   12 +++++++
 giscanner/girwriter.py                             |   24 ++++++++------
 giscanner/maintransformer.py                       |   34 +++++++++++++++-----
 .../Regress.AnnotationFields.page                  |   25 ++++++++++++++
 tests/scanner/Regress-1.0-expected.gir             |   14 ++++++++
 tests/scanner/annotation.h                         |   15 +++++++++
 6 files changed, 106 insertions(+), 18 deletions(-)
---
diff --git a/giscanner/ast.py b/giscanner/ast.py
index a30a6a7..bd536c6 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -888,6 +888,18 @@ class Compound(Node, Registered):
             if field.anonymous_node is not None:
                 field.anonymous_node.walk(callback, chain)
 
+    def get_field(self, name):
+        for field in self.fields:
+            if field.name == name:
+                return field
+        raise ValueError("Unknown field %s" % (name, ))
+
+    def get_field_index(self, name):
+        for i, field in enumerate(self.fields):
+            if field.name == name:
+                return i
+        raise ValueError("Unknown field %s" % (name, ))
+
 
 class Field(Annotated):
 
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 78ad7e4..304cf32 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -217,7 +217,7 @@ class GIRWriter(XMLWriter):
             attrs.append(('skip', '1'))
         with self.tagcontext('return-value', attrs):
             self._write_generic(return_)
-            self._write_type(return_.type, function=parent)
+            self._write_type(return_.type, parent=parent)
 
     def _write_parameters(self, callable):
         if not callable.parameters and callable.instance_parameter is None:
@@ -253,7 +253,7 @@ class GIRWriter(XMLWriter):
             attrs.append(('skip', '1'))
         with self.tagcontext(nodename, attrs):
             self._write_generic(parameter)
-            self._write_type(parameter.type, function=parent)
+            self._write_type(parameter.type, parent=parent)
 
     def _type_to_name(self, typeval):
         if not typeval.resolved:
@@ -286,7 +286,7 @@ class GIRWriter(XMLWriter):
 
         self.write_tag('type', attrs)
 
-    def _write_type(self, ntype, relation=None, function=None):
+    def _write_type(self, ntype, relation=None, parent=None):
         assert isinstance(ntype, ast.Type), ntype
         attrs = []
         if ntype.complete_ctype:
@@ -309,8 +309,12 @@ class GIRWriter(XMLWriter):
             if ntype.size is not None:
                 attrs.append(('fixed-size', '%d' % (ntype.size, )))
             if ntype.length_param_name is not None:
-                assert function
-                length = function.get_parameter_index(ntype.length_param_name)
+                if isinstance(parent, ast.Callable):
+                    length = parent.get_parameter_index(ntype.length_param_name)
+                elif isinstance(parent, ast.Compound):
+                    length = parent.get_field_index(ntype.length_param_name)
+                else:
+                    assert False, "parent not a callable or compound: %r" % parent
                 attrs.insert(0, ('length', '%d' % (length, )))
 
             with self.tagcontext('array', attrs):
@@ -445,7 +449,7 @@ class GIRWriter(XMLWriter):
             for prop in sorted(node.properties):
                 self._write_property(prop)
             for field in node.fields:
-                self._write_field(field)
+                self._write_field(field, node)
             for signal in sorted(node.signals):
                 self._write_signal(signal)
 
@@ -518,7 +522,7 @@ class GIRWriter(XMLWriter):
             self._write_generic(record)
             if record.fields:
                 for field in record.fields:
-                    self._write_field(field, is_gtype_struct)
+                    self._write_field(field, record, is_gtype_struct)
             for method in sorted(record.constructors):
                 self._write_constructor(method)
             for method in sorted(record.methods):
@@ -541,7 +545,7 @@ class GIRWriter(XMLWriter):
             self._write_generic(union)
             if union.fields:
                 for field in union.fields:
-                    self._write_field(field)
+                    self._write_field(field, union)
             for method in sorted(union.constructors):
                 self._write_constructor(method)
             for method in sorted(union.methods):
@@ -549,7 +553,7 @@ class GIRWriter(XMLWriter):
             for method in sorted(union.static_methods):
                 self._write_static_method(method)
 
-    def _write_field(self, field, is_gtype_struct=False):
+    def _write_field(self, field, parent, is_gtype_struct=False):
         if field.anonymous_node:
             if isinstance(field.anonymous_node, ast.Callback):
                 attrs = [('name', field.name)]
@@ -577,7 +581,7 @@ class GIRWriter(XMLWriter):
                 attrs.append(('private', '1'))
             with self.tagcontext('field', attrs):
                 self._write_generic(field)
-                self._write_type(field.type)
+                self._write_type(field.type, parent=parent)
 
     def _write_signal(self, signal):
         attrs = [('name', signal.name)]
diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
index d0eae90..0878313 100644
--- a/giscanner/maintransformer.py
+++ b/giscanner/maintransformer.py
@@ -130,6 +130,20 @@ class MainTransformer(object):
 
         return param.argname
 
+    def _get_validate_field_name(self, parent, field_name, origin):
+        try:
+            field = parent.get_field(field_name)
+        except ValueError:
+            field = None
+        if field is None:
+            origin_name = 'field %s' % (origin.name, )
+            message.log_node(
+                message.FATAL, parent,
+                "can't find field %s referenced by %s of %r"
+                % (field_name, origin_name, parent.name))
+
+        return field.name
+
     def _apply_annotation_rename_to(self, node, chain, block):
         if not block:
             return
@@ -375,13 +389,17 @@ class MainTransformer(object):
 
         length = array_options.get(OPT_ARRAY_LENGTH)
         if length:
-            paramname = self._get_validate_parameter_name(parent, length, node)
+            if isinstance(parent, ast.Compound):
+                paramname = self._get_validate_field_name(parent, length, node)
+            else:
+                paramname = self._get_validate_parameter_name(parent, length, node)
+                if paramname:
+                    param = parent.get_parameter(paramname)
+                    param.direction = node.direction
+                    if param.direction == ast.PARAM_DIRECTION_OUT:
+                        param.transfer = ast.PARAM_TRANSFER_FULL
             if paramname:
-                param = parent.get_parameter(paramname)
-                param.direction = node.direction
-                if param.direction == ast.PARAM_DIRECTION_OUT:
-                    param.transfer = ast.PARAM_TRANSFER_FULL
-                container_type.length_param_name = param.argname
+                container_type.length_param_name = paramname
         fixed = array_options.get(OPT_ARRAY_FIXED_SIZE)
         if fixed:
             try:
@@ -728,8 +746,8 @@ class MainTransformer(object):
 
         try:
             self._adjust_container_type(parent, field, tag.annotations)
-        except AttributeError:
-            pass
+        except AttributeError, ex:
+            print ex
 
     def _apply_annotations_property(self, parent, prop):
         prefix = self._get_annotation_name(parent)
diff --git a/tests/scanner/Regress-1.0-C-expected/Regress.AnnotationFields.page 
b/tests/scanner/Regress-1.0-C-expected/Regress.AnnotationFields.page
new file mode 100644
index 0000000..74c6eab
--- /dev/null
+++ b/tests/scanner/Regress-1.0-C-expected/Regress.AnnotationFields.page
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<page id="Regress.AnnotationFields"
+      type="topic"
+      style="record"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    
+      <link xref="index" group="record" type="guide"/>
+    
+  </info>
+  <title>Regress.AnnotationFields</title>
+  
+  
+  
+    <p>This is a struct for testing field documentation and annotations</p>
+  
+  
+  
+  
+  
+  
+  
+</page>
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index bb83e22..925fe53 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -87,6 +87,20 @@ and/or use gtk-doc annotations.  -->
         </parameter>
       </parameters>
     </callback>
+    <record name="AnnotationFields" c:type="RegressAnnotationFields">
+      <doc xml:space="preserve">This is a struct for testing field documentation and annotations</doc>
+      <field name="field1" writable="1">
+        <type name="gint" c:type="int"/>
+      </field>
+      <field name="arr" writable="1">
+        <array length="2" zero-terminated="0" c:type="guchar*">
+          <type name="guint8" c:type="guchar"/>
+        </array>
+      </field>
+      <field name="len" writable="1">
+        <type name="gulong" c:type="gulong"/>
+      </field>
+    </record>
     <callback name="AnnotationForeachFunc"
               c:type="RegressAnnotationForeachFunc">
       <return-value transfer-ownership="none">
diff --git a/tests/scanner/annotation.h b/tests/scanner/annotation.h
index 2084da2..b0cbe42 100644
--- a/tests/scanner/annotation.h
+++ b/tests/scanner/annotation.h
@@ -159,6 +159,21 @@ struct RegressAnnotationStruct
   RegressAnnotationObject *objects[10];
 };
 
+/**
+ * RegressAnnotationFields:
+ * @field1: Some documentation
+ * @arr: (array length=len): an array of length @len
+ * @len: the length of array
+ *
+ * This is a struct for testing field documentation and annotations
+ */
+struct RegressAnnotationFields
+{
+  int field1;
+  guchar *arr;
+  gulong len;
+};
+
 void    regress_annotation_ptr_array (GPtrArray *array);
 
 GObject  * regress_annotation_test_parsing_bug630862 (void);


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