[gobject-introspection] scanner: allow multiline annotations



commit 90f69635057171b45cccb785fc1c53ccc992e0c3
Author: Dieter Verfaillie <dieterv optionexplicit be>
Date:   Sun Mar 15 20:31:44 2015 +0100

    scanner: allow multiline annotations
    
    Allow `identifier`, `parameter` and `tag` part `annotations` fields
    to span multiple lines
    
    https://bugzilla.gnome.org/show_bug.cgi?id=676133

 giscanner/annotationparser.py                      |   99 ++--
 .../annotationparser/gi/identifier_symbol.xml      |   14 +-
 tests/scanner/annotationparser/gi/parameter.xml    |   21 +-
 .../gi/syntax_multiline_annotations.xml            |  619 +++++++++++++++++++-
 tests/scanner/annotationparser/gi/tag.xml          |   19 +-
 5 files changed, 678 insertions(+), 94 deletions(-)
---
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index e093f34..f69ff25 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -61,12 +61,12 @@ specific order:
    comment block which consists of:
 
    * a required `identifier_name` field
-   * an optional `annotations` field
+   * an optional `annotations` field, optionally spanning multiple lines
 
 #. Zero or more `parameter` parts, each consisting of:
 
    * a required `parameter_name` field
-   * an optional `annotations` field
+   * an optional `annotations` field, optionally spanning multiple lines
    * a required `description` field (can be the empty string)
 
 #. One optional `comment block description` part which must begin with at
@@ -75,7 +75,7 @@ specific order:
 #. Zero or more `tag` parts, each consisting of:
 
    * a required `tag_name` field
-   * an optional `annotations` field
+   * an optional `annotations` field, optionally spanning multiple lines
    * an optional `value` field
    * a required `description` field (can be the empty string)
 
@@ -95,6 +95,7 @@ Additionally, the following restrictions are in effect:
 
    * the `comment_block_description` part
    * `parameter description` and `tag description` fields
+   * `identifier`, `parameter` and `tag` part `annotations` fields
 
 #. Taking the above restrictions into account, spanning multiple paragraphs is
    limited to the `comment block description` part and `tag description` fields.
@@ -507,13 +508,16 @@ class GtkDocAnnotations(OrderedDict):
 
     __slots__ = ('position')
 
-    def __init__(self, position=None):
-        OrderedDict.__init__(self)
+    def __init__(self, position=None, sequence=None):
+        OrderedDict.__init__(self, sequence)
 
         #: A :class:`giscanner.message.Position` instance specifying the location of the
         #: annotations in the source file or :const:`None`.
         self.position = position
 
+    def __copy__(self):
+        return GtkDocAnnotations(self.position, self)
+
 
 class GtkDocAnnotatable(object):
     '''
@@ -1071,10 +1075,12 @@ class GtkDocCommentBlock(GtkDocAnnotatable):
 
 
 #: Result object returned by :class:`GtkDocCommentBlockParser`._parse_annotations()
-_ParseAnnotationsResult = namedtuple('Result', ['success', 'annotations', 'start_pos', 'end_pos'])
+_ParseAnnotationsResult = namedtuple('Result', ['success', 'annotations', 'annotations_changed',
+                                                'start_pos', 'end_pos'])
 
 #: Result object returned by :class:`GtkDocCommentBlockParser`._parse_fields()
-_ParseFieldsResult = namedtuple('Result', ['success', 'annotations', 'description'])
+_ParseFieldsResult = namedtuple('Result', ['success', 'annotations', 'annotations_changed',
+                                           'description'])
 
 
 class GtkDocCommentBlockParser(object):
@@ -1459,6 +1465,7 @@ class GtkDocCommentBlockParser(object):
                                                     result.start('tag_name') + column_offset,
                                                     line,
                                                     tag_fields.strip(),
+                                                    None,
                                                     False,
                                                     False)
 
@@ -1592,8 +1599,12 @@ class GtkDocCommentBlockParser(object):
             if in_part in [PART_IDENTIFIER, PART_DESCRIPTION]:
                 if not comment_block.description:
                     if in_part == PART_IDENTIFIER:
-                        self._validate_multiline_annotation_continuation(line, original_line,
-                                                                         column_offset, position)
+                        r = self._parse_annotations(position, column_offset, original_line, line,
+                                                    comment_block.annotations)
+
+                        if r.success and r.annotations_changed:
+                            comment_block.annotations = r.annotations
+                            continue
                 if comment_block.description is None:
                     comment_block.description = line
                 else:
@@ -1601,8 +1612,12 @@ class GtkDocCommentBlockParser(object):
                 continue
             elif in_part in [PART_PARAMETERS, PART_TAGS]:
                 if not current_part.description:
-                    self._validate_multiline_annotation_continuation(line, original_line,
-                                                                     column_offset, position)
+                    r = self._parse_fields(position, column_offset, original_line, line,
+                                           current_part.annotations)
+                    if r.success and r.annotations_changed:
+                        current_part.annotations = r.annotations
+                        current_part.description = r.description
+                        continue
                 if current_part.description is None:
                     current_part.description = line
                 else:
@@ -1646,34 +1661,6 @@ class GtkDocCommentBlockParser(object):
                 else:
                     part.description = part.description.strip()
 
-    def _validate_multiline_annotation_continuation(self, line, original_line,
-                                                    column_offset, position):
-        '''
-        Validate annotatable parts' source text ensuring annotations don't span multiple lines.
-        For example, the following comment block would result in a warning being emitted for
-        the forth line::
-
-            /**
-             * shiny_function:
-             * @array_: (out caller-allocates) (array)
-             *          (element-type utf8) (transfer full): A beautiful array
-             */
-
-        :param line: line to validate, stripped from  ("``*/``") at start of the line.
-        :param original_line: original line (including  ("``*/``"))  being validated
-        :param column_offset: number of characters stripped from `line` when   ("``*/``")
-                              was removed
-        :param position: :class:`giscanner.message.Position` of `line` in the source file
-        '''
-
-        result = self._parse_annotations(position, column_offset, original_line, line)
-
-        if result.success and result.annotations:
-            marker = ' ' * (result.start_pos + column_offset) + '^'
-            error('ignoring invalid multiline annotation continuation:\n%s\n%s' %
-                  (original_line, marker),
-                  position)
-
     def _parse_annotation_options_list(self, position, column, line, options):
         '''
         Parse annotation options into a list. For example::
@@ -1831,7 +1818,8 @@ class GtkDocCommentBlockParser(object):
 
         return ann_name, ann_options
 
-    def _parse_annotations(self, position, column, line, fields, parse_options=True):
+    def _parse_annotations(self, position, column, line, fields,
+                           annotations=None, parse_options=True):
         '''
         Parse annotations into a :class:`GtkDocAnnotations` object.
 
@@ -1839,6 +1827,7 @@ class GtkDocCommentBlockParser(object):
         :param column: start column of the `annotations` in the source file
         :param line: complete source line
         :param fields: string containing the fields to parse
+        :param annotations: a :class:`GtkDocAnnotations` object
         :param parse_options: whether options will be parsed into a :class:`GtkDocAnnotations`
                               object or into a :class:`list`
         :returns: if `parse_options` evaluates to True a :class:`GtkDocAnnotations` object,
@@ -1847,10 +1836,15 @@ class GtkDocCommentBlockParser(object):
         '''
 
         if parse_options:
-            parsed_annotations = GtkDocAnnotations(position)
+            if annotations is None:
+                parsed_annotations = GtkDocAnnotations(position)
+            else:
+                parsed_annotations = annotations.copy()
         else:
             parsed_annotations = []
 
+        parsed_annotations_changed = False
+
         i = 0
         parens_level = 0
         prev_char = ''
@@ -1872,7 +1866,7 @@ class GtkDocCommentBlockParser(object):
                     error('unexpected parentheses, annotations will be ignored:\n%s\n%s' %
                           (line, marker),
                           position)
-                    return _ParseAnnotationsResult(False, None, None, None)
+                    return _ParseAnnotationsResult(False, None, None, None, None)
                 elif parens_level > 1:
                     char_buffer.append(cur_char)
             elif cur_char == ANN_RPAR:
@@ -1883,13 +1877,13 @@ class GtkDocCommentBlockParser(object):
                     error('unexpected parentheses, annotations will be ignored:\n%s\n%s' %
                           (line, marker),
                           position)
-                    return _ParseAnnotationsResult(False, None, None, None)
+                    return _ParseAnnotationsResult(False, None, None, None, None)
                 elif parens_level < 0:
                     marker = ' ' * (column + i) + '^'
                     error('unbalanced parentheses, annotations will be ignored:\n%s\n%s' %
                           (line, marker),
                           position)
-                    return _ParseAnnotationsResult(False, None, None, None)
+                    return _ParseAnnotationsResult(False, None, None, None, None)
                 elif parens_level == 0:
                     end_pos = i + 1
 
@@ -1904,8 +1898,10 @@ class GtkDocCommentBlockParser(object):
                                 error('multiple "%s" annotations:\n%s\n%s' %
                                       (name, line, marker), position)
                             parsed_annotations[name] = options
+                            parsed_annotations_changed = True
                     else:
                         parsed_annotations.append(''.join(char_buffer).strip())
+                        parsed_annotations_changed = True
 
                     char_buffer = []
                 else:
@@ -1926,12 +1922,13 @@ class GtkDocCommentBlockParser(object):
             error('unbalanced parentheses, annotations will be ignored:\n%s\n%s' %
                   (line, marker),
                   position)
-            return _ParseAnnotationsResult(False, None, None, None)
+            return _ParseAnnotationsResult(False, None, None, None, None)
         else:
-            return _ParseAnnotationsResult(True, parsed_annotations, start_pos, end_pos)
+            return _ParseAnnotationsResult(True, parsed_annotations, parsed_annotations_changed,
+                                           start_pos, end_pos)
 
-    def _parse_fields(self, position, column, line, fields, parse_options=True,
-                      validate_description_field=True):
+    def _parse_fields(self, position, column, line, fields, annotations=None,
+                      parse_options=True, validate_description_field=True):
         '''
         Parse annotations out of field data. For example::
 
@@ -1953,7 +1950,8 @@ class GtkDocCommentBlockParser(object):
                   :const:`None` and a string holding the remaining fields
         '''
         description_field = ''
-        result = self._parse_annotations(position, column, line, fields, parse_options)
+        result = self._parse_annotations(position, column, line, fields,
+                                         annotations, parse_options)
         if result.success:
             description_field = fields[result.end_pos:].strip()
 
@@ -1968,7 +1966,8 @@ class GtkDocCommentBlockParser(object):
                              (marker_position + 1, line, marker),
                              position)
 
-        return _ParseFieldsResult(result.success, result.annotations, description_field)
+        return _ParseFieldsResult(result.success, result.annotations, result.annotations_changed,
+                                  description_field)
 
 
 class GtkDocCommentBlockWriter(object):
diff --git a/tests/scanner/annotationparser/gi/identifier_symbol.xml 
b/tests/scanner/annotationparser/gi/identifier_symbol.xml
index 522f1fa..fd611cd 100644
--- a/tests/scanner/annotationparser/gi/identifier_symbol.xml
+++ b/tests/scanner/annotationparser/gi/identifier_symbol.xml
@@ -393,6 +393,9 @@
           <annotation>
             <name>skip</name>
           </annotation>
+          <annotation>
+            <name>foreign</name>
+          </annotation>
         </annotations>
       </identifier>
       <parameters>
@@ -414,20 +417,13 @@
           <description>first parameter</description>
         </parameter>
       </parameters>
-      <description>(foreign)
-Annotations spanning multiple lines are not valid</description>
+      <description>Annotations spanning multiple lines are not valid</description>
     </docblock>
-    <messages>
-      <message>3: Error: Test: ignoring invalid multiline annotation continuation:
- * (foreign)
-   ^</message>
-    </messages>
   </parser>
   <output>/**
- * test_multiline_annotations_on_identifier: (skip)
+ * test_multiline_annotations_on_identifier: (skip) (foreign)
  * @param1: (allow-none) (transfer full): first parameter
  *
- * (foreign)
  * Annotations spanning multiple lines are not valid
  */</output>
 </test>
diff --git a/tests/scanner/annotationparser/gi/parameter.xml b/tests/scanner/annotationparser/gi/parameter.xml
index 43f97b3..51ba6f5 100644
--- a/tests/scanner/annotationparser/gi/parameter.xml
+++ b/tests/scanner/annotationparser/gi/parameter.xml
@@ -138,23 +138,24 @@
             <annotation>
               <name>allow-none</name>
             </annotation>
+            <annotation>
+              <name>transfer</name>
+              <options>
+                <option>
+                  <name>full</name>
+                </option>
+              </options>
+            </annotation>
           </annotations>
-          <description>
-(transfer full): first parameter</description>
+          <description>first parameter</description>
         </parameter>
       </parameters>
       <description>Annotations spanning multiple lines are not valid</description>
     </docblock>
-    <messages>
-      <message>4: Error: Test: ignoring invalid multiline annotation continuation:
- * (transfer full): first parameter
-   ^</message>
-    </messages>
   </parser>
   <output>/**
  * test_multiline_annotations_on_parameter:
- * @param1: (allow-none):
- * (transfer full): first parameter
+ * @param1: (allow-none) (transfer full): first parameter
  *
  * Annotations spanning multiple lines are not valid
  */</output>
@@ -202,7 +203,7 @@
  * anjuta_async_notify_get_error:
  *
  * @self: An #AnjutaAsyncNotify object
- * @error: Return location for the error set by the called interface to which 
+ * @error: Return location for the error set by the called interface to which
  *                 this object was passed. If no error is set, @error is set to NULL.
  *
  * Gets the error set on @self.
diff --git a/tests/scanner/annotationparser/gi/syntax_multiline_annotations.xml 
b/tests/scanner/annotationparser/gi/syntax_multiline_annotations.xml
index 4aa92e4..c289794 100644
--- a/tests/scanner/annotationparser/gi/syntax_multiline_annotations.xml
+++ b/tests/scanner/annotationparser/gi/syntax_multiline_annotations.xml
@@ -4,6 +4,40 @@
 
 <test>
   <input>/**
+ * regress_forced_method:
+ *   (skip)
+ *   (method)
+ * @obj: A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+        <annotations>
+          <annotation>
+            <name>skip</name>
+          </annotation>
+          <annotation>
+            <name>method</name>
+          </annotation>
+        </annotations>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <description>A #RegressTestObj</description>
+        </parameter>
+      </parameters>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method: (skip) (method)
+ * @obj: A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
  * regress_forced_method: (skip)
  * (method)
  * @obj: A #RegressTestObj
@@ -16,6 +50,9 @@
           <annotation>
             <name>skip</name>
           </annotation>
+          <annotation>
+            <name>method</name>
+          </annotation>
         </annotations>
       </identifier>
       <parameters>
@@ -24,19 +61,11 @@
           <description>A #RegressTestObj</description>
         </parameter>
       </parameters>
-      <description>(method)</description>
     </docblock>
-    <messages>
-      <message>3: Error: Test: ignoring invalid multiline annotation continuation:
- * (method)
-   ^</message>
-    </messages>
   </parser>
   <output>/**
- * regress_forced_method: (skip)
+ * regress_forced_method: (skip) (method)
  * @obj: A #RegressTestObj
- *
- * (method)
  */</output>
 </test>
 
@@ -54,6 +83,9 @@
           <annotation>
             <name>skip</name>
           </annotation>
+          <annotation>
+            <name>method</name>
+          </annotation>
         </annotations>
       </identifier>
       <parameters>
@@ -62,19 +94,574 @@
           <description>A #RegressTestObj</description>
         </parameter>
       </parameters>
-      <description>(method)</description>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method: (skip) (method)
+ * @obj: A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ *   (skip) (method)
+ * @obj: A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+        <annotations>
+          <annotation>
+            <name>skip</name>
+          </annotation>
+          <annotation>
+            <name>method</name>
+          </annotation>
+        </annotations>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <description>A #RegressTestObj</description>
+        </parameter>
+      </parameters>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method: (skip) (method)
+ * @obj: A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ * @obj:
+ *   (skip)
+ *   (nullable): A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </parameter>
+      </parameters>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ * @obj: (skip) (nullable): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ * @obj:
+ *   (skip)
+ *   (nullable):
+ *   A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>
+  A #RegressTestObj</description>
+        </parameter>
+      </parameters>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ * @obj: (skip) (nullable):
+ *   A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ * @obj: (skip)
+ * (nullable): A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </parameter>
+      </parameters>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ * @obj: (skip) (nullable): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ * @obj: (skip)
+ *     (nullable) A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </parameter>
+      </parameters>
     </docblock>
     <messages>
-      <message>3: Error: Test: ignoring invalid multiline annotation continuation:
- *     (method)
-       ^</message>
+      <message>4: Warning: Test: missing ":" at column 18:
+ *     (nullable) A #RegressTestObj
+                 ^</message>
     </messages>
   </parser>
   <output>/**
- * regress_forced_method: (skip)
- * @obj: A #RegressTestObj
+ * regress_forced_method:
+ * @obj: (skip) (nullable): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ * @obj: (skip)
+ *     (skip): A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>obj</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </parameter>
+      </parameters>
+    </docblock>
+    <messages>
+      <message>4: Error: Test: multiple "skip" annotations:
+ *     (skip): A #RegressTestObj
+            ^
+      </message>
+    </messages>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ * @obj: (skip): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
  *
- * (method)
+ * Returns:
+ *   (skip)
+ *   (nullable): A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <tags>
+        <tag>
+          <name>returns</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </tag>
+      </tags>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip) (nullable): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ *
+ * Returns:
+ *   (skip)
+ *   (nullable):
+ *   A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <tags>
+        <tag>
+          <name>returns</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>
+  A #RegressTestObj</description>
+        </tag>
+      </tags>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip) (nullable):
+ *   A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip)
+ * (nullable): A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <tags>
+        <tag>
+          <name>returns</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </tag>
+      </tags>
+    </docblock>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip) (nullable): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip)
+ *     (nullable) A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <tags>
+        <tag>
+          <name>returns</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+            <annotation>
+              <name>nullable</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </tag>
+      </tags>
+    </docblock>
+    <messages>
+      <message>5: Warning: Test: missing ":" at column 18:
+ *     (nullable) A #RegressTestObj
+                 ^</message>
+    </messages>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip) (nullable): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip)
+ *     (skip): A #RegressTestObj
+ */</input>
+  <parser>
+    <docblock>
+      <identifier>
+        <name>regress_forced_method</name>
+      </identifier>
+      <tags>
+        <tag>
+          <name>returns</name>
+          <annotations>
+            <annotation>
+              <name>skip</name>
+            </annotation>
+          </annotations>
+          <description>A #RegressTestObj</description>
+        </tag>
+      </tags>
+    </docblock>
+    <messages>
+      <message>5: Error: Test: multiple "skip" annotations:
+ *     (skip): A #RegressTestObj
+            ^
+      </message>
+    </messages>
+  </parser>
+  <output>/**
+ * regress_forced_method:
+ *
+ * Returns: (skip): A #RegressTestObj
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * gtk_window_set_has_frame:
+ * @window: a #GtkWindow
+ * @setting: a boolean
+ *
+ * (Note: this is a special-purpose function for the framebuffer port,
+ *  that causes GTK+ to draw its own window border. For most applications,
+ *  you want gtk_window_set_decorated() instead, which tells the window
+ *  manager whether to draw the window border.)
+ *
+ * If this function is called on a window with setting of %TRUE, before
+ * it is realized or showed, it will have a "frame" window around
+ * @window->window, accessible in @window->frame. Using the signal
+ * frame_event you can receive all events targeted at the frame.
+ *
+ * This function is used by the linux-fb port to implement managed
+ * windows, but it could conceivably be used by X-programs that
+ * want to do their own window decorations.
+ *
+ * Deprecated: 2.24: This function will be removed in GTK+ 3
+ **/</input>
+  <parser>
+<docblock>
+      <identifier>
+        <name>gtk_window_set_has_frame</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>window</name>
+          <description>a #GtkWindow</description>
+        </parameter>
+        <parameter>
+          <name>setting</name>
+          <description>a boolean</description>
+        </parameter>
+      </parameters>
+      <description>(Note: this is a special-purpose function for the framebuffer port,
+ that causes GTK+ to draw its own window border. For most applications,
+ you want gtk_window_set_decorated() instead, which tells the window
+ manager whether to draw the window border.)
+
+If this function is called on a window with setting of %TRUE, before
+it is realized or showed, it will have a "frame" window around
+ window->window, accessible in @window->frame. Using the signal
+frame_event you can receive all events targeted at the frame.
+
+This function is used by the linux-fb port to implement managed
+windows, but it could conceivably be used by X-programs that
+want to do their own window decorations.</description>
+      <tags>
+        <tag>
+          <name>deprecated</name>
+          <value>2.24</value>
+          <description>This function will be removed in GTK+ 3</description>
+        </tag>
+      </tags>
+    </docblock>
+  </parser>
+  <output>/**
+ * gtk_window_set_has_frame:
+ * @window: a #GtkWindow
+ * @setting: a boolean
+ *
+ * (Note: this is a special-purpose function for the framebuffer port,
+ *  that causes GTK+ to draw its own window border. For most applications,
+ *  you want gtk_window_set_decorated() instead, which tells the window
+ *  manager whether to draw the window border.)
+ *
+ * If this function is called on a window with setting of %TRUE, before
+ * it is realized or showed, it will have a "frame" window around
+ * @window->window, accessible in @window->frame. Using the signal
+ * frame_event you can receive all events targeted at the frame.
+ *
+ * This function is used by the linux-fb port to implement managed
+ * windows, but it could conceivably be used by X-programs that
+ * want to do their own window decorations.
+ *
+ * Deprecated: 2.24: This function will be removed in GTK+ 3
+ */</output>
+</test>
+
+<test>
+  <input>/**
+ * gtk_window_set_has_frame:
+ * @window: a #GtkWindow
+ * @setting:
+ * (Note: this is a special-purpose function for the framebuffer port,
+ *  that causes GTK+ to draw its own window border. For most applications,
+ *  you want gtk_window_set_decorated() instead, which tells the window
+ *  manager whether to draw the window border.)
+ *
+ * If this function is called on a window with setting of %TRUE, before
+ * it is realized or showed, it will have a "frame" window around
+ * @window->window, accessible in @window->frame. Using the signal
+ * frame_event you can receive all events targeted at the frame.
+ *
+ * This function is used by the linux-fb port to implement managed
+ * windows, but it could conceivably be used by X-programs that
+ * want to do their own window decorations.
+ *
+ * Deprecated: 2.24: This function will be removed in GTK+ 3
+ **/</input>
+  <parser>
+<docblock>
+      <identifier>
+        <name>gtk_window_set_has_frame</name>
+      </identifier>
+      <parameters>
+        <parameter>
+          <name>window</name>
+          <description>a #GtkWindow</description>
+        </parameter>
+        <parameter>
+          <name>setting</name>
+          <description>(Note: this is a special-purpose function for the framebuffer port,
+ that causes GTK+ to draw its own window border. For most applications,
+ you want gtk_window_set_decorated() instead, which tells the window
+ manager whether to draw the window border.)</description>
+        </parameter>
+      </parameters>
+      <description>If this function is called on a window with setting of %TRUE, before
+it is realized or showed, it will have a "frame" window around
+ window->window, accessible in @window->frame. Using the signal
+frame_event you can receive all events targeted at the frame.
+
+This function is used by the linux-fb port to implement managed
+windows, but it could conceivably be used by X-programs that
+want to do their own window decorations.</description>
+      <tags>
+        <tag>
+          <name>deprecated</name>
+          <value>2.24</value>
+          <description>This function will be removed in GTK+ 3</description>
+        </tag>
+      </tags>
+    </docblock>
+    <messages>
+      <message>5: Error: Test: unbalanced parentheses, annotations will be ignored:
+ * (Note: this is a special-purpose function for the framebuffer port,
+                                                                     ^</message>
+    </messages>
+  </parser>
+  <output>/**
+ * gtk_window_set_has_frame:
+ * @window: a #GtkWindow
+ * @setting: (Note: this is a special-purpose function for the framebuffer port,
+ *  that causes GTK+ to draw its own window border. For most applications,
+ *  you want gtk_window_set_decorated() instead, which tells the window
+ *  manager whether to draw the window border.)
+ *
+ * If this function is called on a window with setting of %TRUE, before
+ * it is realized or showed, it will have a "frame" window around
+ * @window->window, accessible in @window->frame. Using the signal
+ * frame_event you can receive all events targeted at the frame.
+ *
+ * This function is used by the linux-fb port to implement managed
+ * windows, but it could conceivably be used by X-programs that
+ * want to do their own window decorations.
+ *
+ * Deprecated: 2.24: This function will be removed in GTK+ 3
  */</output>
 </test>
 
diff --git a/tests/scanner/annotationparser/gi/tag.xml b/tests/scanner/annotationparser/gi/tag.xml
index 8480d4b..7dd7bb1 100644
--- a/tests/scanner/annotationparser/gi/tag.xml
+++ b/tests/scanner/annotationparser/gi/tag.xml
@@ -187,25 +187,26 @@ Moo: anything</description>
             <annotation>
               <name>allow-none</name>
             </annotation>
+            <annotation>
+              <name>transfer</name>
+              <options>
+                <option>
+                  <name>full</name>
+                </option>
+              </options>
+            </annotation>
           </annotations>
-          <description>
-(transfer full): something</description>
+          <description>something</description>
         </tag>
       </tags>
     </docblock>
-    <messages>
-      <message>7: Error: Test: ignoring invalid multiline annotation continuation:
- * (transfer full): something
-   ^</message>
-    </messages>
   </parser>
   <output>/**
  * test_multiline_annotations_on_tag:
  *
  * Annotations spanning multiple lines are not valid
  *
- * Returns: (allow-none):
- * (transfer full): something
+ * Returns: (allow-none) (transfer full): something
  */</output>
 </test>
 


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