qapi: Recognize section tags and 'Features:' only after blank line

Putting a blank line before section tags and 'Features:' is good,
existing practice.  Enforce it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-ID: <20240216145841.2099240-12-armbru@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Markus Armbruster 2024-02-16 15:58:35 +01:00
parent d23055b8db
commit 66227e9047
9 changed files with 32 additions and 12 deletions

View File

@ -986,16 +986,17 @@ indented like this::
Extensions added after the definition was first released carry a Extensions added after the definition was first released carry a
"(since x.y.z)" comment. "(since x.y.z)" comment.
The feature descriptions must be preceded by a line "Features:", like The feature descriptions must be preceded by a blank line and then a
this:: line "Features:", like this::
#
# Features: # Features:
# #
# @feature: Description text # @feature: Description text
A tagged section starts with one of the following words: A tagged section begins with a paragraph that starts with one of the
"Note:"/"Notes:", "Since:", "Example:"/"Examples:", "Returns:", following words: "Note:"/"Notes:", "Since:", "Example:"/"Examples:",
"TODO:". The section ends with the start of a new section. "Returns:", "TODO:". It ends with the start of a new section.
The second and subsequent lines of tagged sections must be indented The second and subsequent lines of tagged sections must be indented
like this:: like this::
@ -1086,8 +1087,10 @@ need to line up with each other, like this::
# or cache associativity unknown) # or cache associativity unknown)
# (since 5.0) # (since 5.0)
Section tags are case-sensitive and end with a colon. Good example:: Section tags are case-sensitive and end with a colon. They are only
recognized after a blank line. Good example::
#
# Since: 7.1 # Since: 7.1
Bad examples (all ordinary paragraphs):: Bad examples (all ordinary paragraphs)::

View File

@ -538,6 +538,7 @@ class QAPIDoc:
# the current section # the current section
self._section = self.body self._section = self.body
self._append_line = self._append_body_line self._append_line = self._append_body_line
self._first_line_in_paragraph = False
def has_section(self, tag: str) -> bool: def has_section(self, tag: str) -> bool:
"""Return True if we have a section with this tag.""" """Return True if we have a section with this tag."""
@ -560,12 +561,14 @@ class QAPIDoc:
line = line[1:] line = line[1:]
if not line: if not line:
self._append_freeform(line) self._append_freeform(line)
self._first_line_in_paragraph = True
return return
if line[0] != ' ': if line[0] != ' ':
raise QAPIParseError(self._parser, "missing space after #") raise QAPIParseError(self._parser, "missing space after #")
line = line[1:] line = line[1:]
self._append_line(line) self._append_line(line)
self._first_line_in_paragraph = False
def end_comment(self) -> None: def end_comment(self) -> None:
self._switch_section(QAPIDoc.NullSection(self._parser)) self._switch_section(QAPIDoc.NullSection(self._parser))
@ -574,9 +577,11 @@ class QAPIDoc:
def _match_at_name_colon(string: str) -> Optional[Match[str]]: def _match_at_name_colon(string: str) -> Optional[Match[str]]:
return re.match(r'@([^:]*): *', string) return re.match(r'@([^:]*): *', string)
@staticmethod def _match_section_tag(self, string: str) -> Optional[Match[str]]:
def _match_section_tag(string: str) -> Optional[Match[str]]: if not self._first_line_in_paragraph:
return re.match(r'(Returns|Since|Notes?|Examples?|TODO): *', string) return None
return re.match(r'(Returns|Since|Notes?|Examples?|TODO): *',
string)
def _append_body_line(self, line: str) -> None: def _append_body_line(self, line: str) -> None:
""" """

View File

@ -1 +1 @@
doc-duplicated-return.json:7:1: duplicated 'Returns' section doc-duplicated-return.json:8:1: duplicated 'Returns' section

View File

@ -4,5 +4,6 @@
# @foo: # @foo:
# #
# Returns: 0 # Returns: 0
#
# Returns: 1 # Returns: 1
## ##

View File

@ -1 +1 @@
doc-duplicated-since.json:7:1: duplicated 'Since' section doc-duplicated-since.json:8:1: duplicated 'Since' section

View File

@ -4,5 +4,6 @@
# @foo: # @foo:
# #
# Since: 0 # Since: 0
#
# Since: 1 # Since: 1
## ##

View File

@ -154,22 +154,29 @@
# Features: # Features:
# @cmd-feat1: a feature # @cmd-feat1: a feature
# @cmd-feat2: another feature # @cmd-feat2: another feature
#
# Note: @arg3 is undocumented # Note: @arg3 is undocumented
#
# Returns: @Object # Returns: @Object
#
# TODO: frobnicate # TODO: frobnicate
#
# Notes: # Notes:
# #
# - Lorem ipsum dolor sit amet # - Lorem ipsum dolor sit amet
# - Ut enim ad minim veniam # - Ut enim ad minim veniam
# #
# Duis aute irure dolor # Duis aute irure dolor
#
# Example: # Example:
# #
# -> in # -> in
# <- out # <- out
#
# Examples: # Examples:
# - *verbatim* # - *verbatim*
# - {braces} # - {braces}
#
# Since: 2.10 # Since: 2.10
## ##
{ 'command': 'cmd', { 'command': 'cmd',
@ -180,9 +187,11 @@
## ##
# @cmd-boxed: # @cmd-boxed:
# If you're bored enough to read this, go see a video of boxed cats # If you're bored enough to read this, go see a video of boxed cats
#
# Features: # Features:
# @cmd-feat1: a feature # @cmd-feat1: a feature
# @cmd-feat2: another feature # @cmd-feat2: another feature
#
# Example: # Example:
# #
# -> in # -> in

View File

@ -1 +1 @@
doc-invalid-return.json:5: 'Returns:' is only valid for commands doc-invalid-return.json:6: 'Returns:' is only valid for commands

View File

@ -2,6 +2,7 @@
## ##
# @FOO: # @FOO:
#
# Returns: blah # Returns: blah
## ##
{ 'event': 'FOO' } { 'event': 'FOO' }