summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDieter Verfaillie <dieterv@optionexplicit.be>2015-03-15 20:31:44 +0100
committerDieter Verfaillie <dieterv@optionexplicit.be>2015-03-15 20:36:56 +0100
commit53ba6368eb56d5fa3be1f9d4bf1a4226035b82ac (patch)
tree2e8e9a00aae5bdaa108ffc52c07d372fea85d94b
parent323bdacee2a3cd5e4ac2c1857a4d4bd2b7a76146 (diff)
downloadgobject-introspection-wip/dieterv/multiline-annotations.tar.gz
scanner: allow multiline annotationswip/dieterv/multiline-annotations
Allow `identifier`, `parameter` and `tag` part `annotations` fields to span multiple lines https://bugzilla.gnome.org/show_bug.cgi?id=676133
-rw-r--r--giscanner/annotationparser.py99
-rw-r--r--tests/scanner/annotationparser/gi/identifier_symbol.xml14
-rw-r--r--tests/scanner/annotationparser/gi/parameter.xml21
-rw-r--r--tests/scanner/annotationparser/gi/syntax_multiline_annotations.xml619
-rw-r--r--tests/scanner/annotationparser/gi/tag.xml19
5 files changed, 678 insertions, 94 deletions
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index e093f340..f69ff250 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 522f1fa8..fd611cd9 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 43f97b3f..51ba6f5e 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 4aa92e42..c2897948 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 8480d4b4..7dd7bb19 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>