From 8107ba47fd78bcf8c3206de42dbfb5ba8184d706 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Fri, 31 Oct 2025 21:31:29 +0300 Subject: [PATCH] qapi: Add documentation format validation Add explicit validation for QAPI documentation formatting rules: 1. Lines must not exceed 70 columns in width (including '# ' prefix) 2. Sentences must be separated by two spaces Example sections and literal :: blocks (seldom case) are excluded, we don't require them to be <= 70, that would be too restrictive. Anyway, they share common 80-columns recommendations (not requirements). Add two simple tests, illustrating the change. Signed-off-by: Vladimir Sementsov-Ogievskiy Message-ID: <20251031183129.246814-1-vsementsov@yandex-team.ru> The detection of example and literal blocks isn't quite correct, but it works well enough, and we can improve on top. Reviewed-by: Markus Armbruster [Comments, error messages, and test file names tweaked] Signed-off-by: Markus Armbruster --- scripts/qapi/parser.py | 50 ++++++++++++++++++- .../doc-bad-space-between-sentences.err | 2 + .../doc-bad-space-between-sentences.json | 6 +++ .../doc-bad-space-between-sentences.out | 0 tests/qapi-schema/doc-long-line.err | 1 + tests/qapi-schema/doc-long-line.json | 6 +++ tests/qapi-schema/doc-long-line.out | 0 tests/qapi-schema/meson.build | 2 + 8 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/qapi-schema/doc-bad-space-between-sentences.err create mode 100644 tests/qapi-schema/doc-bad-space-between-sentences.json create mode 100644 tests/qapi-schema/doc-bad-space-between-sentences.out create mode 100644 tests/qapi-schema/doc-long-line.err create mode 100644 tests/qapi-schema/doc-long-line.json create mode 100644 tests/qapi-schema/doc-long-line.out diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index 9fbf80a5410..1bb1af7051f 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -108,6 +108,11 @@ class QAPISchemaParser: self.exprs: List[QAPIExpression] = [] self.docs: List[QAPIDoc] = [] + # State for tracking qmp-example blocks and simple + # :: literal blocks. + self._literal_mode = False + self._literal_mode_indent = 0 + # Showtime! self._parse() @@ -423,12 +428,55 @@ class QAPISchemaParser: if self.val != '##': raise QAPIParseError( self, "junk after '##' at end of documentation comment") + self._literal_mode = False return None if self.val == '#': return '' if self.val[1] != ' ': raise QAPIParseError(self, "missing space after #") - return self.val[2:].rstrip() + + line = self.val[2:].rstrip() + + if re.match(r'(\.\. +qmp-example)? *::$', line): + self._literal_mode = True + self._literal_mode_indent = 0 + elif self._literal_mode and line: + indent = re.match(r'^ *', line).end() + if self._literal_mode_indent == 0: + self._literal_mode_indent = indent + elif indent < self._literal_mode_indent: + # ReST directives stop at decreasing indentation + self._literal_mode = False + + if not self._literal_mode: + self._validate_doc_line_format(line) + + return line + + def _validate_doc_line_format(self, line: str) -> None: + """ + Validate documentation format rules for a single line: + 1. Lines should not exceed 70 characters + 2. Sentences should be separated by two spaces + """ + full_line_length = len(line) + 2 # "# " = 2 characters + if full_line_length > 70: + # Skip URL lines - they can't be broken + if re.match(r' *(https?|ftp)://[^ ]*$', line): + pass + else: + raise QAPIParseError( + self, "documentation line longer than 70 characters") + + single_space_pattern = r'(\be\.g\.|^ *\d\.|([.!?])) [A-Z0-9(]' + for m in list(re.finditer(single_space_pattern, line)): + if not m.group(2): + continue + # HACK so the error message points to the offending spot + self.pos = self.line_pos + 2 + m.start(2) + 1 + raise QAPIParseError( + self, "Use two spaces between sentences\n" + "If this not the end of a sentence, please report a bug.") @staticmethod def _match_at_name_colon(string: str) -> Optional[Match[str]]: diff --git a/tests/qapi-schema/doc-bad-space-between-sentences.err b/tests/qapi-schema/doc-bad-space-between-sentences.err new file mode 100644 index 00000000000..479982ce229 --- /dev/null +++ b/tests/qapi-schema/doc-bad-space-between-sentences.err @@ -0,0 +1,2 @@ +doc-bad-space-between-sentences.json:4:47: Use two spaces between sentences +If this not the end of a sentence, please report a bug. diff --git a/tests/qapi-schema/doc-bad-space-between-sentences.json b/tests/qapi-schema/doc-bad-space-between-sentences.json new file mode 100644 index 00000000000..87b6f6eb4e9 --- /dev/null +++ b/tests/qapi-schema/doc-bad-space-between-sentences.json @@ -0,0 +1,6 @@ +## +# @foo: +# +# Sentences should be separated by two spaces. But here is only one. +## +{ 'command': 'foo' } diff --git a/tests/qapi-schema/doc-bad-space-between-sentences.out b/tests/qapi-schema/doc-bad-space-between-sentences.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/qapi-schema/doc-long-line.err b/tests/qapi-schema/doc-long-line.err new file mode 100644 index 00000000000..7baa5297cfa --- /dev/null +++ b/tests/qapi-schema/doc-long-line.err @@ -0,0 +1 @@ +doc-long-line.json:4:1: documentation line longer than 70 characters diff --git a/tests/qapi-schema/doc-long-line.json b/tests/qapi-schema/doc-long-line.json new file mode 100644 index 00000000000..c10153b0d5d --- /dev/null +++ b/tests/qapi-schema/doc-long-line.json @@ -0,0 +1,6 @@ +## +# @foo: +# +# This line has exactly 71 chars, including the leading hash and space. +## +{ 'command': 'foo' } diff --git a/tests/qapi-schema/doc-long-line.out b/tests/qapi-schema/doc-long-line.out new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/qapi-schema/meson.build b/tests/qapi-schema/meson.build index c47025d16d8..debff633ac1 100644 --- a/tests/qapi-schema/meson.build +++ b/tests/qapi-schema/meson.build @@ -61,6 +61,7 @@ schemas = [ 'doc-bad-event-arg.json', 'doc-bad-feature.json', 'doc-bad-indent.json', + 'doc-bad-space-between-sentences.json', 'doc-bad-symbol.json', 'doc-bad-union-member.json', 'doc-before-include.json', @@ -81,6 +82,7 @@ schemas = [ 'doc-invalid-return2.json', 'doc-invalid-section.json', 'doc-invalid-start.json', + 'doc-long-line.json', 'doc-missing-colon.json', 'doc-missing-expr.json', 'doc-missing-space.json', -- 2.47.3