From b621a26040dd626cf9098c277e763f55fcfacf67 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Oct 2019 13:02:24 +0200 Subject: qapi: Implement boxed event argument documentation Generate a reference "Arguments: the members of ...", just like we do for commands since commit c2dd311cb7 "qapi2texi: Implement boxed argument documentation". No change to generated QMP documentation; we don't yet use boxed events outside tests/. Signed-off-by: Markus Armbruster Message-Id: <20191024110237.30963-7-armbru@redhat.com> --- scripts/qapi/doc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'scripts/qapi/doc.py') diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index 6d5726cf6e..f2462c9877 100644 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -266,9 +266,17 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor): def visit_event(self, name, info, ifcond, arg_type, boxed): doc = self.cur_doc + if boxed: + body = texi_body(doc) + body += ('\n@b{Arguments:} the members of @code{%s}\n' + % arg_type.name) + body += texi_features(doc) + body += texi_sections(doc, ifcond) + else: + body = texi_entity(doc, 'Arguments', ifcond) self._gen.add(MSG_FMT(type='Event', name=doc.symbol, - body=texi_entity(doc, 'Arguments', ifcond))) + body=body)) def symbol(self, doc, entity): if self._gen._body: -- cgit 1.4.1 From a4bd91d3f3d69414c9c76b856a0d69b12773503c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Oct 2019 13:02:25 +0200 Subject: qapi: De-duplicate entity documentation generation code QAPISchemaGenDocVisitor.visit_command() duplicates texi_entity() for its boxed arguments case. The previous commit added another copy in .visit_event(). Replace texi_entity() by texi_type() and texi_msg(). Use texi_msg() for the boxed arguments case as well. Signed-off-by: Markus Armbruster Message-Id: <20191024110237.30963-8-armbru@redhat.com> --- scripts/qapi/doc.py | 82 ++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 42 deletions(-) (limited to 'scripts/qapi/doc.py') diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index f2462c9877..c8c4bda153 100644 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -12,7 +12,7 @@ from qapi.gen import QAPIGenDoc, QAPISchemaVisitor MSG_FMT = """ @deftypefn {type} {{}} {name} -{body} +{body}{members}{features}{sections} @end deftypefn """.format @@ -20,7 +20,7 @@ MSG_FMT = """ TYPE_FMT = """ @deftp {{{type}}} {name} -{body} +{body}{members}{features}{sections} @end deftp """.format @@ -149,7 +149,8 @@ def texi_member(member, desc, suffix): suffix, desc, texi_if(member.ifcond, prefix='@*')) -def texi_members(doc, what, base, variants, member_func): +def texi_members(doc, what, base=None, variants=None, + member_func=texi_member): """Format the table of members""" items = '' for section in doc.args.values(): @@ -182,6 +183,13 @@ def texi_members(doc, what, base, variants, member_func): return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items) +def texi_arguments(doc, boxed_arg_type): + if boxed_arg_type: + return ('\n@b{Arguments:} the members of @code{%s}\n' + % boxed_arg_type.name) + return texi_members(doc, 'Arguments') + + def texi_features(doc): """Format the table of features""" items = '' @@ -208,12 +216,22 @@ def texi_sections(doc, ifcond): return body -def texi_entity(doc, what, ifcond, base=None, variants=None, - member_func=texi_member): - return (texi_body(doc) - + texi_members(doc, what, base, variants, member_func) - + texi_features(doc) - + texi_sections(doc, ifcond)) +def texi_type(typ, doc, ifcond, members): + return TYPE_FMT(type=typ, + name=doc.symbol, + body=texi_body(doc), + members=members, + features=texi_features(doc), + sections=texi_sections(doc, ifcond)) + + +def texi_msg(typ, doc, ifcond, members): + return MSG_FMT(type=typ, + name=doc.symbol, + body=texi_body(doc), + members=members, + features=texi_features(doc), + sections=texi_sections(doc, ifcond)) class QAPISchemaGenDocVisitor(QAPISchemaVisitor): @@ -227,56 +245,36 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor): def visit_enum_type(self, name, info, ifcond, members, prefix): doc = self.cur_doc - self._gen.add(TYPE_FMT(type='Enum', - name=doc.symbol, - body=texi_entity(doc, 'Values', ifcond, - member_func=texi_enum_value))) + self._gen.add(texi_type('Enum', doc, ifcond, + texi_members(doc, 'Values', + member_func=texi_enum_value))) def visit_object_type(self, name, info, ifcond, base, members, variants, features): doc = self.cur_doc if base and base.is_implicit(): base = None - self._gen.add(TYPE_FMT(type='Object', - name=doc.symbol, - body=texi_entity(doc, 'Members', ifcond, - base, variants))) + self._gen.add(texi_type('Object', doc, ifcond, + texi_members(doc, 'Members', base, variants))) def visit_alternate_type(self, name, info, ifcond, variants): doc = self.cur_doc - self._gen.add(TYPE_FMT(type='Alternate', - name=doc.symbol, - body=texi_entity(doc, 'Members', ifcond))) + self._gen.add(texi_type('Alternate', doc, ifcond, + texi_members(doc, 'Members'))) def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, features): doc = self.cur_doc - if boxed: - body = texi_body(doc) - body += ('\n@b{Arguments:} the members of @code{%s}\n' - % arg_type.name) - body += texi_features(doc) - body += texi_sections(doc, ifcond) - else: - body = texi_entity(doc, 'Arguments', ifcond) - self._gen.add(MSG_FMT(type='Command', - name=doc.symbol, - body=body)) + self._gen.add(texi_msg('Command', doc, ifcond, + texi_arguments(doc, + arg_type if boxed else None))) def visit_event(self, name, info, ifcond, arg_type, boxed): doc = self.cur_doc - if boxed: - body = texi_body(doc) - body += ('\n@b{Arguments:} the members of @code{%s}\n' - % arg_type.name) - body += texi_features(doc) - body += texi_sections(doc, ifcond) - else: - body = texi_entity(doc, 'Arguments', ifcond) - self._gen.add(MSG_FMT(type='Event', - name=doc.symbol, - body=body)) + self._gen.add(texi_msg('Event', doc, ifcond, + texi_arguments(doc, + arg_type if boxed else None))) def symbol(self, doc, entity): if self._gen._body: -- cgit 1.4.1 From bf83f04e13063bb723fb8b9df789a3613c6d0ceb Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 24 Oct 2019 13:02:29 +0200 Subject: qapi: Fix doc comment checking for commands and events When a command's 'data' is an object, its doc comment describes the arguments defined there. When 'data' names a type, the doc comment does not describe arguments. Instead, the doc generator inserts a pointer to the named type. An event's doc comment works the same. We don't actually check doc comments for commands and events. Instead, QAPISchema._def_command() forwards the doc comment to the implicit argument type, where it gets checked. Works because the check only cares for the implicit argument type's members. Not only is this needlessly hard to understand, it actually falls apart in two cases: * When 'data' is empty, there is nothing to forward to, and the doc comment remains unchecked. Demonstrated by test doc-bad-event-arg. * When 'data' names a type, we can't forward, as the type has its own doc comment. The command or event's doc comment remains unchecked. Demonstrated by test doc-bad-boxed-command-arg. The forwarding goes back to commit 069fb5b250 "qapi: Prepare for requiring more complete documentation", put to use in commit 816a57cd6e "qapi: Fix detection of bogus member documentation". That fix was incomplete. To fix this, make QAPISchemaCommand and QAPISchemaEvent check doc comments, and drop the forwarding of doc comments to implicit argument types. Signed-off-by: Markus Armbruster Message-Id: <20191024110237.30963-12-armbru@redhat.com> --- qapi/net.json | 2 -- scripts/qapi/doc.py | 1 + scripts/qapi/schema.py | 24 ++++++++++++++++++++-- tests/qapi-schema/doc-bad-boxed-command-arg.err | 1 + tests/qapi-schema/doc-bad-boxed-command-arg.json | 1 - tests/qapi-schema/doc-bad-boxed-command-arg.out | 26 ------------------------ tests/qapi-schema/doc-bad-event-arg.err | 1 + tests/qapi-schema/doc-bad-event-arg.json | 1 - tests/qapi-schema/doc-bad-event-arg.out | 19 ----------------- 9 files changed, 25 insertions(+), 51 deletions(-) (limited to 'scripts/qapi/doc.py') diff --git a/qapi/net.json b/qapi/net.json index 728990f4fb..4c96137811 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -723,8 +723,6 @@ # Trigger generation of broadcast RARP frames to update network switches. # This can be useful when network bonds fail-over the active slave. # -# @params: AnnounceParameters giving timing and repetition count of announce -# # Example: # # -> { "execute": "announce-self", diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py index c8c4bda153..6f1c17f71f 100644 --- a/scripts/qapi/doc.py +++ b/scripts/qapi/doc.py @@ -185,6 +185,7 @@ def texi_members(doc, what, base=None, variants=None, def texi_arguments(doc, boxed_arg_type): if boxed_arg_type: + assert not doc.args return ('\n@b{Arguments:} the members of @code{%s}\n' % boxed_arg_type.name) return texi_members(doc, 'Arguments') diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index c16dce1fe0..06e37c9c49 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -739,6 +739,16 @@ class QAPISchemaCommand(QAPISchemaEntity): for f in self.features: f.check_clash(self.info, seen) + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + if self.arg_type and self.arg_type.is_implicit(): + self.arg_type.connect_doc(doc) + + def check_doc(self): + if self.doc: + self.doc.check() + def visit(self, visitor): QAPISchemaEntity.visit(self, visitor) visitor.visit_command(self.name, self.info, self.ifcond, @@ -775,6 +785,16 @@ class QAPISchemaEvent(QAPISchemaEntity): "event's 'data' can take %s only with 'boxed': true" % self.arg_type.describe()) + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + if self.arg_type and self.arg_type.is_implicit(): + self.arg_type.connect_doc(doc) + + def check_doc(self): + if self.doc: + self.doc.check() + def visit(self, visitor): QAPISchemaEntity.visit(self, visitor) visitor.visit_event(self.name, self.info, self.ifcond, @@ -1026,7 +1046,7 @@ class QAPISchema(object): features = expr.get('features', []) if isinstance(data, OrderedDict): data = self._make_implicit_object_type( - name, info, doc, ifcond, 'arg', self._make_members(data, info)) + name, info, None, ifcond, 'arg', self._make_members(data, info)) if isinstance(rets, list): assert len(rets) == 1 rets = self._make_array_type(rets[0], info) @@ -1042,7 +1062,7 @@ class QAPISchema(object): ifcond = expr.get('if') if isinstance(data, OrderedDict): data = self._make_implicit_object_type( - name, info, doc, ifcond, 'arg', self._make_members(data, info)) + name, info, None, ifcond, 'arg', self._make_members(data, info)) self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed)) def _def_exprs(self, exprs): diff --git a/tests/qapi-schema/doc-bad-boxed-command-arg.err b/tests/qapi-schema/doc-bad-boxed-command-arg.err index e69de29bb2..e1101b1667 100644 --- a/tests/qapi-schema/doc-bad-boxed-command-arg.err +++ b/tests/qapi-schema/doc-bad-boxed-command-arg.err @@ -0,0 +1 @@ +doc-bad-boxed-command-arg.json:9: the following documented members are not in the declaration: a diff --git a/tests/qapi-schema/doc-bad-boxed-command-arg.json b/tests/qapi-schema/doc-bad-boxed-command-arg.json index 2c265d2ca3..bd143241ec 100644 --- a/tests/qapi-schema/doc-bad-boxed-command-arg.json +++ b/tests/qapi-schema/doc-bad-boxed-command-arg.json @@ -1,5 +1,4 @@ # Boxed arguments are not to be documented with the command -# BUG: not rejected ## # @Args: diff --git a/tests/qapi-schema/doc-bad-boxed-command-arg.out b/tests/qapi-schema/doc-bad-boxed-command-arg.out index 4ccd788253..e69de29bb2 100644 --- a/tests/qapi-schema/doc-bad-boxed-command-arg.out +++ b/tests/qapi-schema/doc-bad-boxed-command-arg.out @@ -1,26 +0,0 @@ -module None -object q_empty -enum QType - prefix QTYPE - member none - member qnull - member qnum - member qstring - member qdict - member qlist - member qbool -module doc-bad-boxed-command-arg.json -object Args - member a: int optional=False -command cmd-boxed Args -> None - gen=True success_response=True boxed=True oob=False preconfig=False -doc symbol=Args - body= - - arg=a -an argument -doc symbol=cmd-boxed - body= - - arg=a -bogus diff --git a/tests/qapi-schema/doc-bad-event-arg.err b/tests/qapi-schema/doc-bad-event-arg.err index e69de29bb2..114ff4a3c7 100644 --- a/tests/qapi-schema/doc-bad-event-arg.err +++ b/tests/qapi-schema/doc-bad-event-arg.err @@ -0,0 +1 @@ +doc-bad-event-arg.json:3: the following documented members are not in the declaration: a diff --git a/tests/qapi-schema/doc-bad-event-arg.json b/tests/qapi-schema/doc-bad-event-arg.json index 80d4e1240b..23c83cc81f 100644 --- a/tests/qapi-schema/doc-bad-event-arg.json +++ b/tests/qapi-schema/doc-bad-event-arg.json @@ -1,5 +1,4 @@ # Arguments listed in the doc comment must exist in the actual schema -# BUG: nonexistent @a is not rejected ## # @FOO: diff --git a/tests/qapi-schema/doc-bad-event-arg.out b/tests/qapi-schema/doc-bad-event-arg.out index ad0367cd45..e69de29bb2 100644 --- a/tests/qapi-schema/doc-bad-event-arg.out +++ b/tests/qapi-schema/doc-bad-event-arg.out @@ -1,19 +0,0 @@ -module None -object q_empty -enum QType - prefix QTYPE - member none - member qnull - member qnum - member qstring - member qdict - member qlist - member qbool -module doc-bad-event-arg.json -event FOO None - boxed=False -doc symbol=FOO - body= - - arg=a -a -- cgit 1.4.1