All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
@ 2017-03-13  6:18 Markus Armbruster
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__() Markus Armbruster
                   ` (49 more replies)
  0 siblings, 50 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

I'm proposing this is 2.9 because it fixes a documentation regression.
It affects only documentation; generated C code is unchanged except
for the removal of trailing space in PATCH 46.

Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.

Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
the QAPI schema and generate their replacements from the schema
(commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
also was a step back: the documentation lost information on JSON
types, because I didn't like Marc-André's patch to add it.  He
reposted it for further review afterwards:

    Subject: [PATCH 0/2] qapi2texi: add type information
    Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
    https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html

His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
descriptions in a new formal language to the generated documentation.
Quoting the commit message:

    Array types have the following syntax: type[]. Ex: str[].

    - Struct, commands and events use the following members syntax:

      { 'member': type, ('foo': str), ... }

    Optional members are under parentheses.

    A structure with a base type will have 'BaseStruct +' prepended.

    - Alternates use the following syntax:

      [ 'foo': type, 'bar': type, ... ]

    - Simple unions use the following syntax:

      { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }

    - Flat unions use the following syntax:

      BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]

End quote.  Looks like this in generated documentation:

 -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
          VncBasicInfo}

     Emitted when a VNC client establishes a connection
     ''server''
          server information
     ''client''
          client information

     Note: This event is emitted before any authentication takes place,
     thus the authentication ID is not provided
[...]

 -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}

     The network connection information for server
     ''auth'' (optional)
          authentication method used for the plain (non-websocket) VNC
          server

     Since: 2.1

 -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
          InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
          VsockSocketAddress, 'fd': String] }

     Captures the address of a socket, which could also be a named file
     descriptor

     Since: 1.3

Here's my counter-proposal: instead of inventing a formal language,
fix the natural language documentation to actually mention *all*
members, and add type information in a plain, easy-to-understand way.
Looks like this:

 -- Event: VNC_CONNECTED

     Emitted when a VNC client establishes a connection

     Arguments:
     'server: VncServerInfo'
          server information
     'client: VncBasicInfo'
          client information

     Note: This event is emitted before any authentication takes place,
     thus the authentication ID is not provided
[...]

 -- Object: VncServerInfo

     The network connection information for server

     Members:
     'auth: string' (optional)
          authentication method used for the plain (non-websocket) VNC
          server
     The members of 'VncBasicInfo'

     Since: 2.1

 -- Object: SocketAddress

     Captures the address of a socket, which could also be a named file
     descriptor

     Members:
     'type'
          One of "inet", "unix", "vsock", "fd"
     'data: InetSocketAddress' when 'type' is "inet"
     'data: UnixSocketAddress' when 'type' is "unix"
     'data: VsockSocketAddress' when 'type' is "vsock"
     'data: String' when 'type' is "fd"

     Since: 1.3

Additionally, my series fixes a number of bugs and cleans up along the
way.  In particular, it converts qapi2texi.py from parse trees to the
visitor interface the other generators use.

Future generated documentation work includes eliding types that aren't
visible in QMP (like introspection does), and making uses of type
names links in HTML.

Markus Armbruster (47):
  qapi: Factor QAPISchemaParser._include() out of .__init__()
  qapi: Make doc comments optional where we don't need them
  qapi: Back out doc comments added just to please qapi.py
  docs/qapi-code-gen.txt: Drop confusing reference to 'gen'
  qapi: Have each QAPI schema declare its returns white-list
  qapi: Have each QAPI schema declare its name rule violations
  qapi: Clean up build of generated documentation
  tests/qapi-schema: Cover empty union base
  qapi: Fix to reject empty union base gracefully
  qapi2texi: Fix up output around #optional
  qapi: Avoid unwanted blank lines in QAPIDoc
  qapi/rocker: Fix up doc comment notes on optional members
  qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType'
  qapi: Prepare for requiring more complete documentation
  qapi: Conjure up QAPIDoc.ArgSection for undocumented members
  qapi2texi: Convert to QAPISchemaVisitor
  qapi: The #optional tag is redundant, drop
  qapi: Use raw strings for regular expressions consistently
  qapi: Prefer single-quoted strings more consistently
  qapi2texi: Plainer enum value and member name formatting
  qapi2texi: Present the table of members more clearly
  qapi2texi: Explain enum value undocumentedness more clearly
  qapi2texi: Don't hide undocumented members and arguments
  qapi2texi: Implement boxed argument documentation
  qapi2texi: Include member type in generated documentation
  qapi2texi: Generate reference to base type members
  qapi2texi: Generate documentation for variant members
  qapi2texi: Generate descriptions for simple union tags
  qapi2texi: Use category "Object" for all object types
  tests/qapi-schema: Improve doc / expression mismatch coverage
  qapi: Fix detection of doc / expression mismatch
  qapi: Move detection of doc / expression name mismatch
  qapi: Improve error message on @NAME: in free-form doc
  qapi: Move empty doc section checking to doc parser
  tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg
  tests/qapi-schema: Improve coverage of bogus member docs
  qapi: Fix detection of bogus member documentation
  qapi: Eliminate check_docs() and drop QAPIDoc.expr
  qapi: Drop unused variable events
  qapi: Simplify what gets stored in enum_types
  qapi: Factor add_name() calls out of the meta conditional
  qapi: enum_types is a list used like a dict, make it one
  qapi: struct_types is a list used like a dict, make it one
  qapi: union_types is a list used like a dict, make it one
  qapi: Drop unused .check_clash() parameter schema
  qapi: Make pylint a bit happier
  qapi: Fix a misleading parser error message

 .gitignore                                         |  10 +-
 Makefile                                           |  27 +-
 docs/qapi-code-gen.txt                             |  81 +--
 docs/qemu-qmp-ref.texi                             |   2 +-
 docs/writing-qmp-commands.txt                      |   4 +-
 qapi-schema.json                                   | 403 ++++++-------
 qapi/block-core.json                               | 428 +++++++-------
 qapi/block.json                                    |   8 +-
 qapi/crypto.json                                   |  22 +-
 qapi/event.json                                    |  10 +-
 qapi/introspect.json                               |   6 +-
 qapi/rocker.json                                   |  88 +--
 qapi/trace.json                                    |   6 +-
 qga/qapi-schema.json                               |  55 +-
 rules.mak                                          |   2 +-
 scripts/qapi-commands.py                           |   6 +-
 scripts/qapi-event.py                              |   2 +-
 scripts/qapi-introspect.py                         |   4 +-
 scripts/qapi-types.py                              |   4 +-
 scripts/qapi-visit.py                              |   5 +-
 scripts/qapi.py                                    | 632 ++++++++++-----------
 scripts/qapi2texi.py                               | 298 +++++-----
 tests/Makefile.include                             |   9 +-
 tests/qapi-schema/alternate-any.err                |   2 +-
 tests/qapi-schema/alternate-any.json               |   4 -
 tests/qapi-schema/alternate-array.err              |   2 +-
 tests/qapi-schema/alternate-array.json             |   7 -
 tests/qapi-schema/alternate-base.err               |   2 +-
 tests/qapi-schema/alternate-base.json              |   7 -
 tests/qapi-schema/alternate-clash.err              |   2 +-
 tests/qapi-schema/alternate-clash.json             |   4 -
 tests/qapi-schema/alternate-conflict-dict.err      |   2 +-
 tests/qapi-schema/alternate-conflict-dict.json     |  10 -
 tests/qapi-schema/alternate-conflict-string.err    |   2 +-
 tests/qapi-schema/alternate-conflict-string.json   |   7 -
 tests/qapi-schema/alternate-empty.err              |   2 +-
 tests/qapi-schema/alternate-empty.json             |   4 -
 tests/qapi-schema/alternate-nested.err             |   2 +-
 tests/qapi-schema/alternate-nested.json            |   7 -
 tests/qapi-schema/alternate-unknown.err            |   2 +-
 tests/qapi-schema/alternate-unknown.json           |   4 -
 tests/qapi-schema/args-alternate.err               |   2 +-
 tests/qapi-schema/args-alternate.json              |   8 -
 tests/qapi-schema/args-any.err                     |   2 +-
 tests/qapi-schema/args-any.json                    |   4 -
 tests/qapi-schema/args-array-empty.err             |   2 +-
 tests/qapi-schema/args-array-empty.json            |   4 -
 tests/qapi-schema/args-array-unknown.err           |   2 +-
 tests/qapi-schema/args-array-unknown.json          |   4 -
 tests/qapi-schema/args-bad-boxed.err               |   2 +-
 tests/qapi-schema/args-bad-boxed.json              |   4 -
 tests/qapi-schema/args-boxed-anon.err              |   2 +-
 tests/qapi-schema/args-boxed-anon.json             |   4 -
 tests/qapi-schema/args-boxed-empty.err             |   2 +-
 tests/qapi-schema/args-boxed-empty.json            |   8 -
 tests/qapi-schema/args-boxed-string.err            |   2 +-
 tests/qapi-schema/args-boxed-string.json           |   4 -
 tests/qapi-schema/args-int.err                     |   2 +-
 tests/qapi-schema/args-int.json                    |   4 -
 tests/qapi-schema/args-invalid.err                 |   2 +-
 tests/qapi-schema/args-invalid.json                |   3 -
 tests/qapi-schema/args-member-array-bad.err        |   2 +-
 tests/qapi-schema/args-member-array-bad.json       |   4 -
 tests/qapi-schema/args-member-case.err             |   2 +-
 tests/qapi-schema/args-member-case.json            |   4 -
 tests/qapi-schema/args-member-unknown.err          |   2 +-
 tests/qapi-schema/args-member-unknown.json         |   4 -
 tests/qapi-schema/args-name-clash.err              |   2 +-
 tests/qapi-schema/args-name-clash.json             |   4 -
 tests/qapi-schema/args-union.err                   |   2 +-
 tests/qapi-schema/args-union.json                  |   7 -
 tests/qapi-schema/args-unknown.err                 |   2 +-
 tests/qapi-schema/args-unknown.json                |   4 -
 tests/qapi-schema/bad-base.err                     |   2 +-
 tests/qapi-schema/bad-base.json                    |   7 -
 tests/qapi-schema/bad-data.err                     |   2 +-
 tests/qapi-schema/bad-data.json                    |   4 -
 tests/qapi-schema/bad-ident.err                    |   2 +-
 tests/qapi-schema/bad-ident.json                   |   4 -
 tests/qapi-schema/bad-type-bool.err                |   2 +-
 tests/qapi-schema/bad-type-bool.json               |   4 -
 tests/qapi-schema/bad-type-dict.err                |   2 +-
 tests/qapi-schema/bad-type-dict.json               |   4 -
 tests/qapi-schema/base-cycle-direct.err            |   2 +-
 tests/qapi-schema/base-cycle-direct.json           |   4 -
 tests/qapi-schema/base-cycle-indirect.err          |   2 +-
 tests/qapi-schema/base-cycle-indirect.json         |   7 -
 tests/qapi-schema/command-int.err                  |   2 +-
 tests/qapi-schema/command-int.json                 |   4 -
 tests/qapi-schema/comments.json                    |   4 -
 tests/qapi-schema/comments.out                     |   1 -
 tests/qapi-schema/doc-bad-alternate-member.err     |   1 +
 ...optional.exit => doc-bad-alternate-member.exit} |   0
 tests/qapi-schema/doc-bad-alternate-member.json    |   9 +
 ...c-optional.out => doc-bad-alternate-member.out} |   0
 tests/qapi-schema/doc-bad-args.err                 |   1 -
 tests/qapi-schema/doc-bad-command-arg.err          |   1 +
 ...{doc-bad-args.exit => doc-bad-command-arg.exit} |   0
 ...{doc-bad-args.json => doc-bad-command-arg.json} |   0
 .../{doc-bad-args.out => doc-bad-command-arg.out}  |   0
 tests/qapi-schema/doc-bad-expr.err                 |   1 +
 tests/qapi-schema/doc-bad-expr.exit                |   1 +
 tests/qapi-schema/doc-bad-expr.json                |   7 +
 tests/qapi-schema/doc-bad-expr.out                 |   0
 tests/qapi-schema/doc-bad-symbol.err               |   2 +-
 tests/qapi-schema/doc-bad-union-member.err         |   1 +
 tests/qapi-schema/doc-bad-union-member.exit        |   1 +
 tests/qapi-schema/doc-bad-union-member.json        |  19 +
 tests/qapi-schema/doc-bad-union-member.out         |   0
 tests/qapi-schema/doc-empty-section.err            |   2 +-
 tests/qapi-schema/doc-invalid-section.err          |   2 +-
 tests/qapi-schema/doc-missing-expr.err             |   2 +-
 tests/qapi-schema/doc-missing.err                  |   1 +
 tests/qapi-schema/doc-missing.exit                 |   1 +
 tests/qapi-schema/doc-missing.json                 |   5 +
 tests/qapi-schema/doc-missing.out                  |   0
 tests/qapi-schema/doc-no-symbol.err                |   1 +
 tests/qapi-schema/doc-no-symbol.exit               |   1 +
 tests/qapi-schema/doc-no-symbol.json               |   6 +
 tests/qapi-schema/doc-no-symbol.out                |   0
 tests/qapi-schema/doc-optional.err                 |   1 -
 tests/qapi-schema/doc-optional.json                |   7 -
 tests/qapi-schema/double-type.err                  |   2 +-
 tests/qapi-schema/double-type.json                 |   4 -
 tests/qapi-schema/enum-bad-name.err                |   2 +-
 tests/qapi-schema/enum-bad-name.json               |   4 -
 tests/qapi-schema/enum-bad-prefix.err              |   2 +-
 tests/qapi-schema/enum-bad-prefix.json             |   4 -
 tests/qapi-schema/enum-clash-member.err            |   2 +-
 tests/qapi-schema/enum-clash-member.json           |   4 -
 tests/qapi-schema/enum-dict-member.err             |   2 +-
 tests/qapi-schema/enum-dict-member.json            |   4 -
 tests/qapi-schema/enum-member-case.err             |   2 +-
 tests/qapi-schema/enum-member-case.json            |   8 +-
 tests/qapi-schema/enum-missing-data.err            |   2 +-
 tests/qapi-schema/enum-missing-data.json           |   4 -
 tests/qapi-schema/enum-wrong-data.err              |   2 +-
 tests/qapi-schema/enum-wrong-data.json             |   4 -
 tests/qapi-schema/event-boxed-empty.err            |   2 +-
 tests/qapi-schema/event-boxed-empty.json           |   4 -
 tests/qapi-schema/event-case.json                  |   4 -
 tests/qapi-schema/event-case.out                   |   1 -
 tests/qapi-schema/event-nest-struct.err            |   2 +-
 tests/qapi-schema/event-nest-struct.json           |   4 -
 tests/qapi-schema/flat-union-array-branch.err      |   2 +-
 tests/qapi-schema/flat-union-array-branch.json     |  12 -
 tests/qapi-schema/flat-union-bad-base.err          |   2 +-
 tests/qapi-schema/flat-union-bad-base.json         |  13 -
 tests/qapi-schema/flat-union-bad-discriminator.err |   2 +-
 .../qapi-schema/flat-union-bad-discriminator.json  |  16 -
 tests/qapi-schema/flat-union-base-any.err          |   2 +-
 tests/qapi-schema/flat-union-base-any.json         |  13 -
 tests/qapi-schema/flat-union-base-union.err        |   2 +-
 tests/qapi-schema/flat-union-base-union.json       |  16 -
 tests/qapi-schema/flat-union-clash-member.err      |   2 +-
 tests/qapi-schema/flat-union-clash-member.json     |  16 -
 tests/qapi-schema/flat-union-empty.err             |   2 +-
 tests/qapi-schema/flat-union-empty.json            |  10 -
 tests/qapi-schema/flat-union-incomplete-branch.err |   2 +-
 .../qapi-schema/flat-union-incomplete-branch.json  |  10 -
 tests/qapi-schema/flat-union-inline.err            |   2 +-
 tests/qapi-schema/flat-union-inline.json           |  10 -
 tests/qapi-schema/flat-union-int-branch.err        |   2 +-
 tests/qapi-schema/flat-union-int-branch.json       |  13 -
 .../qapi-schema/flat-union-invalid-branch-key.err  |   2 +-
 .../qapi-schema/flat-union-invalid-branch-key.json |  15 -
 .../flat-union-invalid-discriminator.err           |   2 +-
 .../flat-union-invalid-discriminator.json          |  15 -
 tests/qapi-schema/flat-union-no-base.err           |   2 +-
 tests/qapi-schema/flat-union-no-base.json          |  13 -
 .../flat-union-optional-discriminator.err          |   2 +-
 .../flat-union-optional-discriminator.json         |  13 -
 .../flat-union-string-discriminator.err            |   2 +-
 .../flat-union-string-discriminator.json           |  15 -
 tests/qapi-schema/ident-with-escape.json           |   4 -
 tests/qapi-schema/ident-with-escape.out            |   1 -
 tests/qapi-schema/include-relpath-sub.json         |   3 -
 tests/qapi-schema/include-relpath.out              |   1 -
 tests/qapi-schema/include-repetition.out           |   1 -
 tests/qapi-schema/include-simple-sub.json          |   3 -
 tests/qapi-schema/include-simple.out               |   1 -
 tests/qapi-schema/indented-expr.json               |   6 -
 tests/qapi-schema/indented-expr.out                |   2 -
 tests/qapi-schema/missing-type.err                 |   2 +-
 tests/qapi-schema/missing-type.json                |   4 -
 tests/qapi-schema/nested-struct-data.err           |   2 +-
 tests/qapi-schema/nested-struct-data.json          |   4 -
 tests/qapi-schema/qapi-schema-test.json            | 218 +------
 tests/qapi-schema/qapi-schema-test.out             | 130 -----
 tests/qapi-schema/redefined-builtin.err            |   2 +-
 tests/qapi-schema/redefined-builtin.json           |   4 -
 tests/qapi-schema/redefined-command.err            |   2 +-
 tests/qapi-schema/redefined-command.json           |   7 -
 tests/qapi-schema/redefined-event.err              |   2 +-
 tests/qapi-schema/redefined-event.json             |   7 -
 tests/qapi-schema/redefined-type.err               |   2 +-
 tests/qapi-schema/redefined-type.json              |   7 -
 tests/qapi-schema/reserved-command-q.err           |   2 +-
 tests/qapi-schema/reserved-command-q.json          |   7 -
 tests/qapi-schema/reserved-enum-q.err              |   2 +-
 tests/qapi-schema/reserved-enum-q.json             |   4 -
 tests/qapi-schema/reserved-member-has.err          |   2 +-
 tests/qapi-schema/reserved-member-has.json         |   4 -
 tests/qapi-schema/reserved-member-q.err            |   2 +-
 tests/qapi-schema/reserved-member-q.json           |   4 -
 tests/qapi-schema/reserved-member-u.err            |   2 +-
 tests/qapi-schema/reserved-member-u.json           |   4 -
 tests/qapi-schema/reserved-member-underscore.err   |   2 +-
 tests/qapi-schema/reserved-member-underscore.json  |   4 -
 tests/qapi-schema/reserved-type-kind.err           |   2 +-
 tests/qapi-schema/reserved-type-kind.json          |   4 -
 tests/qapi-schema/reserved-type-list.err           |   2 +-
 tests/qapi-schema/reserved-type-list.json          |   4 -
 tests/qapi-schema/returns-alternate.err            |   2 +-
 tests/qapi-schema/returns-alternate.json           |   7 -
 tests/qapi-schema/returns-array-bad.err            |   2 +-
 tests/qapi-schema/returns-array-bad.json           |   4 -
 tests/qapi-schema/returns-dict.err                 |   2 +-
 tests/qapi-schema/returns-dict.json                |   4 -
 tests/qapi-schema/returns-unknown.err              |   2 +-
 tests/qapi-schema/returns-unknown.json             |   4 -
 tests/qapi-schema/returns-whitelist.err            |   2 +-
 tests/qapi-schema/returns-whitelist.json           |  18 +-
 tests/qapi-schema/struct-base-clash-deep.err       |   2 +-
 tests/qapi-schema/struct-base-clash-deep.json      |  10 -
 tests/qapi-schema/struct-base-clash.err            |   2 +-
 tests/qapi-schema/struct-base-clash.json           |   7 -
 tests/qapi-schema/struct-data-invalid.err          |   2 +-
 tests/qapi-schema/struct-data-invalid.json         |   3 -
 tests/qapi-schema/struct-member-invalid.err        |   2 +-
 tests/qapi-schema/struct-member-invalid.json       |   3 -
 tests/qapi-schema/test-qapi.py                     |  14 -
 tests/qapi-schema/trailing-comma-list.err          |   2 +-
 tests/qapi-schema/type-bypass-bad-gen.err          |   2 +-
 tests/qapi-schema/type-bypass-bad-gen.json         |   4 -
 tests/qapi-schema/unicode-str.err                  |   2 +-
 tests/qapi-schema/unicode-str.json                 |   4 -
 tests/qapi-schema/union-base-empty.err             |   1 +
 tests/qapi-schema/union-base-empty.exit            |   1 +
 tests/qapi-schema/union-base-empty.json            |   9 +
 tests/qapi-schema/union-base-empty.out             |   0
 tests/qapi-schema/union-base-no-discriminator.err  |   2 +-
 tests/qapi-schema/union-base-no-discriminator.json |  12 -
 tests/qapi-schema/union-branch-case.err            |   2 +-
 tests/qapi-schema/union-branch-case.json           |   4 -
 tests/qapi-schema/union-clash-branches.err         |   2 +-
 tests/qapi-schema/union-clash-branches.json        |   4 -
 tests/qapi-schema/union-empty.err                  |   2 +-
 tests/qapi-schema/union-empty.json                 |   4 -
 tests/qapi-schema/union-invalid-base.err           |   2 +-
 tests/qapi-schema/union-invalid-base.json          |  10 -
 tests/qapi-schema/union-optional-branch.err        |   2 +-
 tests/qapi-schema/union-optional-branch.json       |   4 -
 tests/qapi-schema/union-unknown.err                |   2 +-
 tests/qapi-schema/union-unknown.json               |   4 -
 tests/qapi-schema/unknown-escape.err               |   2 +-
 tests/qapi-schema/unknown-escape.json              |   4 -
 tests/qapi-schema/unknown-expr-key.err             |   2 +-
 tests/qapi-schema/unknown-expr-key.json            |   4 -
 259 files changed, 1263 insertions(+), 2109 deletions(-)
 create mode 100644 tests/qapi-schema/doc-bad-alternate-member.err
 rename tests/qapi-schema/{doc-optional.exit => doc-bad-alternate-member.exit} (100%)
 create mode 100644 tests/qapi-schema/doc-bad-alternate-member.json
 rename tests/qapi-schema/{doc-optional.out => doc-bad-alternate-member.out} (100%)
 delete mode 100644 tests/qapi-schema/doc-bad-args.err
 create mode 100644 tests/qapi-schema/doc-bad-command-arg.err
 rename tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit} (100%)
 rename tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json} (100%)
 rename tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out} (100%)
 create mode 100644 tests/qapi-schema/doc-bad-expr.err
 create mode 100644 tests/qapi-schema/doc-bad-expr.exit
 create mode 100644 tests/qapi-schema/doc-bad-expr.json
 create mode 100644 tests/qapi-schema/doc-bad-expr.out
 create mode 100644 tests/qapi-schema/doc-bad-union-member.err
 create mode 100644 tests/qapi-schema/doc-bad-union-member.exit
 create mode 100644 tests/qapi-schema/doc-bad-union-member.json
 create mode 100644 tests/qapi-schema/doc-bad-union-member.out
 create mode 100644 tests/qapi-schema/doc-missing.err
 create mode 100644 tests/qapi-schema/doc-missing.exit
 create mode 100644 tests/qapi-schema/doc-missing.json
 create mode 100644 tests/qapi-schema/doc-missing.out
 create mode 100644 tests/qapi-schema/doc-no-symbol.err
 create mode 100644 tests/qapi-schema/doc-no-symbol.exit
 create mode 100644 tests/qapi-schema/doc-no-symbol.json
 create mode 100644 tests/qapi-schema/doc-no-symbol.out
 delete mode 100644 tests/qapi-schema/doc-optional.err
 delete mode 100644 tests/qapi-schema/doc-optional.json
 create mode 100644 tests/qapi-schema/union-base-empty.err
 create mode 100644 tests/qapi-schema/union-base-empty.exit
 create mode 100644 tests/qapi-schema/union-base-empty.json
 create mode 100644 tests/qapi-schema/union-base-empty.out

-- 
2.7.4

^ permalink raw reply	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__()
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13 19:34   ` Eric Blake
  2017-03-14  8:28   ` Marc-André Lureau
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them Markus Armbruster
                   ` (48 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 45 +++++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 53a4477..345cde1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -268,34 +268,15 @@ class QAPISchemaParser(object):
                 continue
 
             expr = self.get_expr(False)
-            if isinstance(expr, dict) and "include" in expr:
+            if 'include' in expr:
                 if len(expr) != 1:
                     raise QAPISemError(info, "Invalid 'include' directive")
                 include = expr["include"]
                 if not isinstance(include, str):
                     raise QAPISemError(info,
                                        "Value of 'include' must be a string")
-                incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
-                                              include)
-                # catch inclusion cycle
-                inf = info
-                while inf:
-                    if incl_abs_fname == os.path.abspath(inf['file']):
-                        raise QAPISemError(info, "Inclusion loop for %s"
-                                           % include)
-                    inf = inf['parent']
-
-                # skip multiple include of the same file
-                if incl_abs_fname in previously_included:
-                    continue
-                try:
-                    fobj = open(incl_abs_fname, 'r')
-                except IOError as e:
-                    raise QAPISemError(info, '%s: %s' % (e.strerror, include))
-                exprs_include = QAPISchemaParser(fobj, previously_included,
-                                                 info)
-                self.exprs.extend(exprs_include.exprs)
-                self.docs.extend(exprs_include.docs)
+                self._include(include, info, os.path.dirname(abs_fname),
+                              previously_included)
             else:
                 expr_elem = {'expr': expr,
                              'info': info}
@@ -307,6 +288,26 @@ class QAPISchemaParser(object):
 
                 self.exprs.append(expr_elem)
 
+    def _include(self, include, info, base_dir, previously_included):
+        incl_abs_fname = os.path.join(base_dir, include)
+        # catch inclusion cycle
+        inf = info
+        while inf:
+            if incl_abs_fname == os.path.abspath(inf['file']):
+                raise QAPISemError(info, "Inclusion loop for %s" % include)
+            inf = inf['parent']
+
+        # skip multiple include of the same file
+        if incl_abs_fname in previously_included:
+            return
+        try:
+            fobj = open(incl_abs_fname, 'r')
+        except IOError as e:
+            raise QAPISemError(info, '%s: %s' % (e.strerror, include))
+        exprs_include = QAPISchemaParser(fobj, previously_included, info)
+        self.exprs.extend(exprs_include.exprs)
+        self.docs.extend(exprs_include.docs)
+
     def accept(self, skip_comment=True):
         while True:
             self.tok = self.src[self.cursor]
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__() Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13 21:00   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py Markus Armbruster
                   ` (47 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Since we added the documentation generator in commit 3313b61, doc
comments are mandatory.  That's a very good idea for a schema that
needs to be documented, but has proven to be annoying for testing.

Make doc comments optional again, but add a new directive

    { 'pragma': { 'doc-required': true } }

to let a QAPI schema require them.

Require documentation in the schemas we actually want documented:
qapi-schema.json and qga/qapi-schema.json.

We could probably make qapi2texi.py cope with incomplete
documentation, but for now, simply make it refuse to run unless the
schema has 'doc-required': true.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 docs/qapi-code-gen.txt             | 40 +++++++++++++++++++++++++-------------
 qapi-schema.json                   |  2 ++
 qga/qapi-schema.json               |  2 ++
 scripts/qapi.py                    | 20 ++++++++++++++++++-
 scripts/qapi2texi.py               |  3 +++
 tests/Makefile.include             |  1 +
 tests/qapi-schema/doc-missing.err  |  1 +
 tests/qapi-schema/doc-missing.exit |  1 +
 tests/qapi-schema/doc-missing.json |  5 +++++
 tests/qapi-schema/doc-missing.out  |  0
 10 files changed, 61 insertions(+), 14 deletions(-)
 create mode 100644 tests/qapi-schema/doc-missing.err
 create mode 100644 tests/qapi-schema/doc-missing.exit
 create mode 100644 tests/qapi-schema/doc-missing.json
 create mode 100644 tests/qapi-schema/doc-missing.out

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 9514d93..88de5c7 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -117,10 +117,13 @@ Example:
 
 ==== Expression documentation ====
 
-Each expression that isn't an include directive must be preceded by a
+Each expression that isn't an include directive may be preceded by a
 documentation block.  Such blocks are called expression documentation
 blocks.
 
+When documentation is required (see pragma 'doc-required'), expression
+documentation blocks are mandatory.
+
 The documentation block consists of a first line naming the
 expression, an optional overview, a description of each argument (for
 commands and events) or member (for structs, unions and alternates),
@@ -204,17 +207,17 @@ once.  It is permissible for the schema to contain additional types
 not used by any commands or events in the Client JSON Protocol, for
 the side effect of generated C code used internally.
 
-There are seven top-level expressions recognized by the parser:
-'include', 'command', 'struct', 'enum', 'union', 'alternate', and
-'event'.  There are several groups of types: simple types (a number of
-built-in types, such as 'int' and 'str'; as well as enumerations),
-complex types (structs and two flavors of unions), and alternate types
-(a choice between other types).  The 'command' and 'event' expressions
-can refer to existing types by name, or list an anonymous type as a
-dictionary. Listing a type name inside an array refers to a
-single-dimension array of that type; multi-dimension arrays are not
-directly supported (although an array of a complex struct that
-contains an array member is possible).
+There are eight top-level expressions recognized by the parser:
+'include', 'pragma', 'command', 'struct', 'enum', 'union',
+'alternate', and 'event'.  There are several groups of types: simple
+types (a number of built-in types, such as 'int' and 'str'; as well as
+enumerations), complex types (structs and two flavors of unions), and
+alternate types (a choice between other types).  The 'command' and
+'event' expressions can refer to existing types by name, or list an
+anonymous type as a dictionary. Listing a type name inside an array
+refers to a single-dimension array of that type; multi-dimension
+arrays are not directly supported (although an array of a complex
+struct that contains an array member is possible).
 
 All names must begin with a letter, and contain only ASCII letters,
 digits, hyphen, and underscore.  There are two exceptions: enum values
@@ -282,7 +285,7 @@ The following types are predefined, and map to C as follows:
   QType     QType      JSON string matching enum QType values
 
 
-=== Includes ===
+=== Include directives ===
 
 Usage: { 'include': STRING }
 
@@ -302,6 +305,17 @@ an outer file.  The parser may be made stricter in the future to
 prevent incomplete include files.
 
 
+=== Pragma directives ===
+
+Usage: { 'pragma': DICT }
+
+The pragma directive lets you control optional generator behavior.
+The dictionary's entries are pragma names and values.
+
+Pragma 'doc-required' takes a boolean value.  If true, documentation
+is required.  Default is false.
+
+
 === Struct types ===
 
 Usage: { 'struct': STRING, 'data': DICT, '*base': STRUCT-NAME }
diff --git a/qapi-schema.json b/qapi-schema.json
index 32b4a4b..d5438ee 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -49,6 +49,8 @@
 #
 ##
 
+{ 'pragma': { 'doc-required': true } }
+
 # QAPI common definitions
 { 'include': 'qapi/common.json' }
 
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index d421609..3f3d428 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -11,6 +11,8 @@
 #
 ##
 
+{ 'pragma': { 'doc-required': true } }
+
 ##
 # @guest-sync-delimited:
 #
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 345cde1..29a8b77 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -37,6 +37,9 @@ builtin_types = {
     'QType':    'QTYPE_QSTRING',
 }
 
+# Are documentation comments required?
+doc_required = False
+
 # Whitelist of commands allowed to return a non-dictionary
 returns_whitelist = [
     # From QMP:
@@ -277,6 +280,11 @@ class QAPISchemaParser(object):
                                        "Value of 'include' must be a string")
                 self._include(include, info, os.path.dirname(abs_fname),
                               previously_included)
+            elif "pragma" in expr:
+                if len(expr) != 1:
+                    raise QAPISemError(info, "Invalid 'pragma' directive")
+                for name, value in expr['pragma'].iteritems():
+                    self._pragma(name, value, info)
             else:
                 expr_elem = {'expr': expr,
                              'info': info}
@@ -308,6 +316,16 @@ class QAPISchemaParser(object):
         self.exprs.extend(exprs_include.exprs)
         self.docs.extend(exprs_include.docs)
 
+    def _pragma(self, name, value, info):
+        global doc_required
+        if name == 'doc-required':
+            if not isinstance(value, bool):
+                raise QAPISemError(info,
+                                   "Pragma 'doc-required' must be boolean")
+            doc_required = value
+        else:
+            raise QAPISemError(info, "Unknown pragma '%s'" % name)
+
     def accept(self, skip_comment=True):
         while True:
             self.tok = self.src[self.cursor]
@@ -863,7 +881,7 @@ def check_exprs(exprs):
         expr = expr_elem['expr']
         info = expr_elem['info']
 
-        if 'doc' not in expr_elem:
+        if 'doc' not in expr_elem and doc_required:
             raise QAPISemError(info,
                                "Expression missing documentation comment")
 
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 69f5edc..06d6abf 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -254,6 +254,9 @@ def main(argv):
         sys.exit(1)
 
     schema = qapi.QAPISchema(argv[1])
+    if not qapi.doc_required:
+        print >>sys.stderr, ("%s: need pragma 'doc-required' "
+                             "to generate documentation" % argv[0])
     print texi(schema.docs)
 
 
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 346345e..736dd15 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -381,6 +381,7 @@ qapi-schema += doc-invalid-end2.json
 qapi-schema += doc-invalid-return.json
 qapi-schema += doc-invalid-section.json
 qapi-schema += doc-invalid-start.json
+qapi-schema += doc-missing.json
 qapi-schema += doc-missing-colon.json
 qapi-schema += doc-missing-expr.json
 qapi-schema += doc-missing-space.json
diff --git a/tests/qapi-schema/doc-missing.err b/tests/qapi-schema/doc-missing.err
new file mode 100644
index 0000000..7f2f326
--- /dev/null
+++ b/tests/qapi-schema/doc-missing.err
@@ -0,0 +1 @@
+tests/qapi-schema/doc-missing.json:5: Expression missing documentation comment
diff --git a/tests/qapi-schema/doc-missing.exit b/tests/qapi-schema/doc-missing.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/doc-missing.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/doc-missing.json b/tests/qapi-schema/doc-missing.json
new file mode 100644
index 0000000..5956709
--- /dev/null
+++ b/tests/qapi-schema/doc-missing.json
@@ -0,0 +1,5 @@
+# Expression documentation required
+
+{ 'pragma': { 'doc-required': true } }
+
+{ 'command': 'undocumented' }
diff --git a/tests/qapi-schema/doc-missing.out b/tests/qapi-schema/doc-missing.out
new file mode 100644
index 0000000..e69de29
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__() Markus Armbruster
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13 21:13   ` Eric Blake
  2017-03-14  8:28   ` Marc-André Lureau
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen' Markus Armbruster
                   ` (46 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

This reverts commit 3313b61's changes to tests/qapi-schema/, except
for tests/qapi-schema/doc-*.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/qapi-schema/alternate-any.err                |   2 +-
 tests/qapi-schema/alternate-any.json               |   4 -
 tests/qapi-schema/alternate-array.err              |   2 +-
 tests/qapi-schema/alternate-array.json             |   7 -
 tests/qapi-schema/alternate-base.err               |   2 +-
 tests/qapi-schema/alternate-base.json              |   7 -
 tests/qapi-schema/alternate-clash.err              |   2 +-
 tests/qapi-schema/alternate-clash.json             |   4 -
 tests/qapi-schema/alternate-conflict-dict.err      |   2 +-
 tests/qapi-schema/alternate-conflict-dict.json     |  10 -
 tests/qapi-schema/alternate-conflict-string.err    |   2 +-
 tests/qapi-schema/alternate-conflict-string.json   |   7 -
 tests/qapi-schema/alternate-empty.err              |   2 +-
 tests/qapi-schema/alternate-empty.json             |   4 -
 tests/qapi-schema/alternate-nested.err             |   2 +-
 tests/qapi-schema/alternate-nested.json            |   7 -
 tests/qapi-schema/alternate-unknown.err            |   2 +-
 tests/qapi-schema/alternate-unknown.json           |   4 -
 tests/qapi-schema/args-alternate.err               |   2 +-
 tests/qapi-schema/args-alternate.json              |   8 -
 tests/qapi-schema/args-any.err                     |   2 +-
 tests/qapi-schema/args-any.json                    |   4 -
 tests/qapi-schema/args-array-empty.err             |   2 +-
 tests/qapi-schema/args-array-empty.json            |   4 -
 tests/qapi-schema/args-array-unknown.err           |   2 +-
 tests/qapi-schema/args-array-unknown.json          |   4 -
 tests/qapi-schema/args-bad-boxed.err               |   2 +-
 tests/qapi-schema/args-bad-boxed.json              |   4 -
 tests/qapi-schema/args-boxed-anon.err              |   2 +-
 tests/qapi-schema/args-boxed-anon.json             |   4 -
 tests/qapi-schema/args-boxed-empty.err             |   2 +-
 tests/qapi-schema/args-boxed-empty.json            |   8 -
 tests/qapi-schema/args-boxed-string.err            |   2 +-
 tests/qapi-schema/args-boxed-string.json           |   4 -
 tests/qapi-schema/args-int.err                     |   2 +-
 tests/qapi-schema/args-int.json                    |   4 -
 tests/qapi-schema/args-invalid.err                 |   2 +-
 tests/qapi-schema/args-invalid.json                |   3 -
 tests/qapi-schema/args-member-array-bad.err        |   2 +-
 tests/qapi-schema/args-member-array-bad.json       |   4 -
 tests/qapi-schema/args-member-case.err             |   2 +-
 tests/qapi-schema/args-member-case.json            |   4 -
 tests/qapi-schema/args-member-unknown.err          |   2 +-
 tests/qapi-schema/args-member-unknown.json         |   4 -
 tests/qapi-schema/args-name-clash.err              |   2 +-
 tests/qapi-schema/args-name-clash.json             |   4 -
 tests/qapi-schema/args-union.err                   |   2 +-
 tests/qapi-schema/args-union.json                  |   7 -
 tests/qapi-schema/args-unknown.err                 |   2 +-
 tests/qapi-schema/args-unknown.json                |   4 -
 tests/qapi-schema/bad-base.err                     |   2 +-
 tests/qapi-schema/bad-base.json                    |   7 -
 tests/qapi-schema/bad-data.err                     |   2 +-
 tests/qapi-schema/bad-data.json                    |   4 -
 tests/qapi-schema/bad-ident.err                    |   2 +-
 tests/qapi-schema/bad-ident.json                   |   4 -
 tests/qapi-schema/bad-type-bool.err                |   2 +-
 tests/qapi-schema/bad-type-bool.json               |   4 -
 tests/qapi-schema/bad-type-dict.err                |   2 +-
 tests/qapi-schema/bad-type-dict.json               |   4 -
 tests/qapi-schema/base-cycle-direct.err            |   2 +-
 tests/qapi-schema/base-cycle-direct.json           |   4 -
 tests/qapi-schema/base-cycle-indirect.err          |   2 +-
 tests/qapi-schema/base-cycle-indirect.json         |   7 -
 tests/qapi-schema/command-int.err                  |   2 +-
 tests/qapi-schema/command-int.json                 |   4 -
 tests/qapi-schema/comments.json                    |   4 -
 tests/qapi-schema/comments.out                     |   1 -
 tests/qapi-schema/double-type.err                  |   2 +-
 tests/qapi-schema/double-type.json                 |   4 -
 tests/qapi-schema/enum-bad-name.err                |   2 +-
 tests/qapi-schema/enum-bad-name.json               |   4 -
 tests/qapi-schema/enum-bad-prefix.err              |   2 +-
 tests/qapi-schema/enum-bad-prefix.json             |   4 -
 tests/qapi-schema/enum-clash-member.err            |   2 +-
 tests/qapi-schema/enum-clash-member.json           |   4 -
 tests/qapi-schema/enum-dict-member.err             |   2 +-
 tests/qapi-schema/enum-dict-member.json            |   4 -
 tests/qapi-schema/enum-member-case.err             |   2 +-
 tests/qapi-schema/enum-member-case.json            |   7 -
 tests/qapi-schema/enum-missing-data.err            |   2 +-
 tests/qapi-schema/enum-missing-data.json           |   4 -
 tests/qapi-schema/enum-wrong-data.err              |   2 +-
 tests/qapi-schema/enum-wrong-data.json             |   4 -
 tests/qapi-schema/event-boxed-empty.err            |   2 +-
 tests/qapi-schema/event-boxed-empty.json           |   4 -
 tests/qapi-schema/event-case.json                  |   4 -
 tests/qapi-schema/event-case.out                   |   1 -
 tests/qapi-schema/event-nest-struct.err            |   2 +-
 tests/qapi-schema/event-nest-struct.json           |   4 -
 tests/qapi-schema/flat-union-array-branch.err      |   2 +-
 tests/qapi-schema/flat-union-array-branch.json     |  12 --
 tests/qapi-schema/flat-union-bad-base.err          |   2 +-
 tests/qapi-schema/flat-union-bad-base.json         |  13 --
 tests/qapi-schema/flat-union-bad-discriminator.err |   2 +-
 .../qapi-schema/flat-union-bad-discriminator.json  |  16 --
 tests/qapi-schema/flat-union-base-any.err          |   2 +-
 tests/qapi-schema/flat-union-base-any.json         |  13 --
 tests/qapi-schema/flat-union-base-union.err        |   2 +-
 tests/qapi-schema/flat-union-base-union.json       |  16 --
 tests/qapi-schema/flat-union-clash-member.err      |   2 +-
 tests/qapi-schema/flat-union-clash-member.json     |  16 --
 tests/qapi-schema/flat-union-empty.err             |   2 +-
 tests/qapi-schema/flat-union-empty.json            |  10 -
 tests/qapi-schema/flat-union-incomplete-branch.err |   2 +-
 .../qapi-schema/flat-union-incomplete-branch.json  |  10 -
 tests/qapi-schema/flat-union-inline.err            |   2 +-
 tests/qapi-schema/flat-union-inline.json           |  10 -
 tests/qapi-schema/flat-union-int-branch.err        |   2 +-
 tests/qapi-schema/flat-union-int-branch.json       |  13 --
 .../qapi-schema/flat-union-invalid-branch-key.err  |   2 +-
 .../qapi-schema/flat-union-invalid-branch-key.json |  15 --
 .../flat-union-invalid-discriminator.err           |   2 +-
 .../flat-union-invalid-discriminator.json          |  15 --
 tests/qapi-schema/flat-union-no-base.err           |   2 +-
 tests/qapi-schema/flat-union-no-base.json          |  13 --
 .../flat-union-optional-discriminator.err          |   2 +-
 .../flat-union-optional-discriminator.json         |  13 --
 .../flat-union-string-discriminator.err            |   2 +-
 .../flat-union-string-discriminator.json           |  15 --
 tests/qapi-schema/ident-with-escape.json           |   4 -
 tests/qapi-schema/ident-with-escape.out            |   1 -
 tests/qapi-schema/include-relpath-sub.json         |   3 -
 tests/qapi-schema/include-relpath.out              |   1 -
 tests/qapi-schema/include-repetition.out           |   1 -
 tests/qapi-schema/include-simple-sub.json          |   3 -
 tests/qapi-schema/include-simple.out               |   1 -
 tests/qapi-schema/indented-expr.json               |   6 -
 tests/qapi-schema/indented-expr.out                |   2 -
 tests/qapi-schema/missing-type.err                 |   2 +-
 tests/qapi-schema/missing-type.json                |   4 -
 tests/qapi-schema/nested-struct-data.err           |   2 +-
 tests/qapi-schema/nested-struct-data.json          |   4 -
 tests/qapi-schema/qapi-schema-test.json            | 213 ---------------------
 tests/qapi-schema/qapi-schema-test.out             | 130 -------------
 tests/qapi-schema/redefined-builtin.err            |   2 +-
 tests/qapi-schema/redefined-builtin.json           |   4 -
 tests/qapi-schema/redefined-command.err            |   2 +-
 tests/qapi-schema/redefined-command.json           |   7 -
 tests/qapi-schema/redefined-event.err              |   2 +-
 tests/qapi-schema/redefined-event.json             |   7 -
 tests/qapi-schema/redefined-type.err               |   2 +-
 tests/qapi-schema/redefined-type.json              |   7 -
 tests/qapi-schema/reserved-command-q.err           |   2 +-
 tests/qapi-schema/reserved-command-q.json          |   7 -
 tests/qapi-schema/reserved-enum-q.err              |   2 +-
 tests/qapi-schema/reserved-enum-q.json             |   4 -
 tests/qapi-schema/reserved-member-has.err          |   2 +-
 tests/qapi-schema/reserved-member-has.json         |   4 -
 tests/qapi-schema/reserved-member-q.err            |   2 +-
 tests/qapi-schema/reserved-member-q.json           |   4 -
 tests/qapi-schema/reserved-member-u.err            |   2 +-
 tests/qapi-schema/reserved-member-u.json           |   4 -
 tests/qapi-schema/reserved-member-underscore.err   |   2 +-
 tests/qapi-schema/reserved-member-underscore.json  |   4 -
 tests/qapi-schema/reserved-type-kind.err           |   2 +-
 tests/qapi-schema/reserved-type-kind.json          |   4 -
 tests/qapi-schema/reserved-type-list.err           |   2 +-
 tests/qapi-schema/reserved-type-list.json          |   4 -
 tests/qapi-schema/returns-alternate.err            |   2 +-
 tests/qapi-schema/returns-alternate.json           |   7 -
 tests/qapi-schema/returns-array-bad.err            |   2 +-
 tests/qapi-schema/returns-array-bad.json           |   4 -
 tests/qapi-schema/returns-dict.err                 |   2 +-
 tests/qapi-schema/returns-dict.json                |   4 -
 tests/qapi-schema/returns-unknown.err              |   2 +-
 tests/qapi-schema/returns-unknown.json             |   4 -
 tests/qapi-schema/returns-whitelist.err            |   2 +-
 tests/qapi-schema/returns-whitelist.json           |  16 --
 tests/qapi-schema/struct-base-clash-deep.err       |   2 +-
 tests/qapi-schema/struct-base-clash-deep.json      |  10 -
 tests/qapi-schema/struct-base-clash.err            |   2 +-
 tests/qapi-schema/struct-base-clash.json           |   7 -
 tests/qapi-schema/struct-data-invalid.err          |   2 +-
 tests/qapi-schema/struct-data-invalid.json         |   3 -
 tests/qapi-schema/struct-member-invalid.err        |   2 +-
 tests/qapi-schema/struct-member-invalid.json       |   3 -
 tests/qapi-schema/test-qapi.py                     |  14 --
 tests/qapi-schema/type-bypass-bad-gen.err          |   2 +-
 tests/qapi-schema/type-bypass-bad-gen.json         |   4 -
 tests/qapi-schema/unicode-str.err                  |   2 +-
 tests/qapi-schema/unicode-str.json                 |   4 -
 tests/qapi-schema/union-base-no-discriminator.err  |   2 +-
 tests/qapi-schema/union-base-no-discriminator.json |  12 --
 tests/qapi-schema/union-branch-case.err            |   2 +-
 tests/qapi-schema/union-branch-case.json           |   4 -
 tests/qapi-schema/union-clash-branches.err         |   2 +-
 tests/qapi-schema/union-clash-branches.json        |   4 -
 tests/qapi-schema/union-empty.err                  |   2 +-
 tests/qapi-schema/union-empty.json                 |   4 -
 tests/qapi-schema/union-invalid-base.err           |   2 +-
 tests/qapi-schema/union-invalid-base.json          |  10 -
 tests/qapi-schema/union-optional-branch.err        |   2 +-
 tests/qapi-schema/union-optional-branch.json       |   4 -
 tests/qapi-schema/union-unknown.err                |   2 +-
 tests/qapi-schema/union-unknown.json               |   4 -
 tests/qapi-schema/unknown-escape.err               |   2 +-
 tests/qapi-schema/unknown-escape.json              |   4 -
 tests/qapi-schema/unknown-expr-key.err             |   2 +-
 tests/qapi-schema/unknown-expr-key.json            |   4 -
 200 files changed, 92 insertions(+), 1074 deletions(-)

diff --git a/tests/qapi-schema/alternate-any.err b/tests/qapi-schema/alternate-any.err
index 395c8ab..aaa0154 100644
--- a/tests/qapi-schema/alternate-any.err
+++ b/tests/qapi-schema/alternate-any.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-any.json:6: Alternate 'Alt' member 'one' cannot use type 'any'
+tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any'
diff --git a/tests/qapi-schema/alternate-any.json b/tests/qapi-schema/alternate-any.json
index c958776..e47a73a 100644
--- a/tests/qapi-schema/alternate-any.json
+++ b/tests/qapi-schema/alternate-any.json
@@ -1,8 +1,4 @@
 # we do not allow the 'any' type as an alternate branch
-
-##
-# @Alt:
-##
 { 'alternate': 'Alt',
   'data': { 'one': 'any',
             'two': 'int' } }
diff --git a/tests/qapi-schema/alternate-array.err b/tests/qapi-schema/alternate-array.err
index 09628e9..7b930c6 100644
--- a/tests/qapi-schema/alternate-array.err
+++ b/tests/qapi-schema/alternate-array.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-array.json:12: Member 'two' of alternate 'Alt' cannot be an array
+tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array
diff --git a/tests/qapi-schema/alternate-array.json b/tests/qapi-schema/alternate-array.json
index c2f98ad..f241aac 100644
--- a/tests/qapi-schema/alternate-array.json
+++ b/tests/qapi-schema/alternate-array.json
@@ -1,14 +1,7 @@
 # we do not allow array branches in alternates
-
-##
-# @One:
-##
 # TODO: should we support this?
 { 'struct': 'One',
   'data': { 'name': 'str' } }
-##
-# @Alt:
-##
 { 'alternate': 'Alt',
   'data': { 'one': 'One',
             'two': [ 'int' ] } }
diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err
index 3b67914..30d8a34 100644
--- a/tests/qapi-schema/alternate-base.err
+++ b/tests/qapi-schema/alternate-base.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-base.json:11: Unknown key 'base' in alternate 'Alt'
+tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'
diff --git a/tests/qapi-schema/alternate-base.json b/tests/qapi-schema/alternate-base.json
index 9612b79..529430ec 100644
--- a/tests/qapi-schema/alternate-base.json
+++ b/tests/qapi-schema/alternate-base.json
@@ -1,13 +1,6 @@
 # we reject alternate with base type
-
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'string': 'str' } }
-##
-# @Alt:
-##
 { 'alternate': 'Alt',
   'base': 'Base',
   'data': { 'number': 'int' } }
diff --git a/tests/qapi-schema/alternate-clash.err b/tests/qapi-schema/alternate-clash.err
index f07c3e8..604d849 100644
--- a/tests/qapi-schema/alternate-clash.err
+++ b/tests/qapi-schema/alternate-clash.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-clash.json:11: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1)
+tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1)
diff --git a/tests/qapi-schema/alternate-clash.json b/tests/qapi-schema/alternate-clash.json
index 97ca7c8..6d73bc5 100644
--- a/tests/qapi-schema/alternate-clash.json
+++ b/tests/qapi-schema/alternate-clash.json
@@ -4,9 +4,5 @@
 # TODO: In the future, if alternates are simplified to not generate
 # the implicit Alt1Kind enum, we would still have a collision with the
 # resulting C union trying to have two members named 'a_b'.
-
-##
-# @Alt1:
-##
 { 'alternate': 'Alt1',
   'data': { 'a-b': 'str', 'a_b': 'int' } }
diff --git a/tests/qapi-schema/alternate-conflict-dict.err b/tests/qapi-schema/alternate-conflict-dict.err
index 7cb023f..0f411f4 100644
--- a/tests/qapi-schema/alternate-conflict-dict.err
+++ b/tests/qapi-schema/alternate-conflict-dict.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-conflict-dict.json:16: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-dict.json b/tests/qapi-schema/alternate-conflict-dict.json
index 9f9d97f..d566cca 100644
--- a/tests/qapi-schema/alternate-conflict-dict.json
+++ b/tests/qapi-schema/alternate-conflict-dict.json
@@ -1,18 +1,8 @@
 # we reject alternates with multiple object branches
-
-##
-# @One:
-##
 { 'struct': 'One',
   'data': { 'name': 'str' } }
-##
-# @Two:
-##
 { 'struct': 'Two',
   'data': { 'value': 'int' } }
-##
-# @Alt:
-##
 { 'alternate': 'Alt',
   'data': { 'one': 'One',
             'two': 'Two' } }
diff --git a/tests/qapi-schema/alternate-conflict-string.err b/tests/qapi-schema/alternate-conflict-string.err
index 6dbbacd..fc523b0 100644
--- a/tests/qapi-schema/alternate-conflict-string.err
+++ b/tests/qapi-schema/alternate-conflict-string.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-conflict-string.json:11: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
diff --git a/tests/qapi-schema/alternate-conflict-string.json b/tests/qapi-schema/alternate-conflict-string.json
index 12aafab..72f04a8 100644
--- a/tests/qapi-schema/alternate-conflict-string.json
+++ b/tests/qapi-schema/alternate-conflict-string.json
@@ -1,13 +1,6 @@
 # we reject alternates with multiple string-like branches
-
-##
-# @Enum:
-##
 { 'enum': 'Enum',
   'data': [ 'hello', 'world' ] }
-##
-# @Alt:
-##
 { 'alternate': 'Alt',
   'data': { 'one': 'str',
             'two': 'Enum' } }
diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err
index 8245ce3..bb06c5b 100644
--- a/tests/qapi-schema/alternate-empty.err
+++ b/tests/qapi-schema/alternate-empty.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-empty.json:6: Alternate 'Alt' should have at least two branches in 'data'
+tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data'
diff --git a/tests/qapi-schema/alternate-empty.json b/tests/qapi-schema/alternate-empty.json
index db54405..fff15ba 100644
--- a/tests/qapi-schema/alternate-empty.json
+++ b/tests/qapi-schema/alternate-empty.json
@@ -1,6 +1,2 @@
 # alternates must list at least two types to be useful
-
-##
-# @Alt:
-##
 { 'alternate': 'Alt', 'data': { 'i': 'int' } }
diff --git a/tests/qapi-schema/alternate-nested.err b/tests/qapi-schema/alternate-nested.err
index 1804ffb..4d1187e 100644
--- a/tests/qapi-schema/alternate-nested.err
+++ b/tests/qapi-schema/alternate-nested.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-nested.json:11: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1'
+tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1'
diff --git a/tests/qapi-schema/alternate-nested.json b/tests/qapi-schema/alternate-nested.json
index 9f83ebe..8e22186 100644
--- a/tests/qapi-schema/alternate-nested.json
+++ b/tests/qapi-schema/alternate-nested.json
@@ -1,12 +1,5 @@
 # we reject a nested alternate branch
-
-##
-# @Alt1:
-##
 { 'alternate': 'Alt1',
   'data': { 'name': 'str', 'value': 'int' } }
-##
-# @Alt2:
-##
 { 'alternate': 'Alt2',
   'data': { 'nested': 'Alt1', 'b': 'bool' } }
diff --git a/tests/qapi-schema/alternate-unknown.err b/tests/qapi-schema/alternate-unknown.err
index cf5b9b6..dea45dc 100644
--- a/tests/qapi-schema/alternate-unknown.err
+++ b/tests/qapi-schema/alternate-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/alternate-unknown.json:6: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType'
+tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType'
diff --git a/tests/qapi-schema/alternate-unknown.json b/tests/qapi-schema/alternate-unknown.json
index 941ba1f..08c80dc 100644
--- a/tests/qapi-schema/alternate-unknown.json
+++ b/tests/qapi-schema/alternate-unknown.json
@@ -1,7 +1,3 @@
 # we reject an alternate with unknown type in branch
-
-##
-# @Alt:
-##
 { 'alternate': 'Alt',
   'data': { 'unknown': 'MissingType', 'i': 'int' } }
diff --git a/tests/qapi-schema/args-alternate.err b/tests/qapi-schema/args-alternate.err
index 2e6bf54..3086eae 100644
--- a/tests/qapi-schema/args-alternate.err
+++ b/tests/qapi-schema/args-alternate.err
@@ -1 +1 @@
-tests/qapi-schema/args-alternate.json:11: 'data' for command 'oops' cannot use alternate type 'Alt'
+tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt'
diff --git a/tests/qapi-schema/args-alternate.json b/tests/qapi-schema/args-alternate.json
index 49d0211..69e94d4 100644
--- a/tests/qapi-schema/args-alternate.json
+++ b/tests/qapi-schema/args-alternate.json
@@ -1,11 +1,3 @@
 # we do not allow alternate arguments
-
-##
-# @Alt:
-##
 { 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } }
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': 'Alt' }
diff --git a/tests/qapi-schema/args-any.err b/tests/qapi-schema/args-any.err
index 955504b..bf9b5e0 100644
--- a/tests/qapi-schema/args-any.err
+++ b/tests/qapi-schema/args-any.err
@@ -1 +1 @@
-tests/qapi-schema/args-any.json:6: 'data' for command 'oops' cannot use built-in type 'any'
+tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any'
diff --git a/tests/qapi-schema/args-any.json b/tests/qapi-schema/args-any.json
index f494479..58fe5e4 100644
--- a/tests/qapi-schema/args-any.json
+++ b/tests/qapi-schema/args-any.json
@@ -1,6 +1,2 @@
 # we do not allow an 'any' argument
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': 'any' }
diff --git a/tests/qapi-schema/args-array-empty.err b/tests/qapi-schema/args-array-empty.err
index e85f791..cb7ed33 100644
--- a/tests/qapi-schema/args-array-empty.err
+++ b/tests/qapi-schema/args-array-empty.err
@@ -1 +1 @@
-tests/qapi-schema/args-array-empty.json:6: Member 'empty' of 'data' for command 'oops': array type must contain single type name
+tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name
diff --git a/tests/qapi-schema/args-array-empty.json b/tests/qapi-schema/args-array-empty.json
index 78a0b88..652dcfb 100644
--- a/tests/qapi-schema/args-array-empty.json
+++ b/tests/qapi-schema/args-array-empty.json
@@ -1,6 +1,2 @@
 # we reject an array for data if it does not contain a known type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': { 'empty': [ ] } }
diff --git a/tests/qapi-schema/args-array-unknown.err b/tests/qapi-schema/args-array-unknown.err
index 77788de..cd7a0f9 100644
--- a/tests/qapi-schema/args-array-unknown.err
+++ b/tests/qapi-schema/args-array-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/args-array-unknown.json:6: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/args-array-unknown.json b/tests/qapi-schema/args-array-unknown.json
index f680fc1..6f3e883 100644
--- a/tests/qapi-schema/args-array-unknown.json
+++ b/tests/qapi-schema/args-array-unknown.json
@@ -1,6 +1,2 @@
 # we reject an array for data if it does not contain a known type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } }
diff --git a/tests/qapi-schema/args-bad-boxed.err b/tests/qapi-schema/args-bad-boxed.err
index 87a9061..ad0d417 100644
--- a/tests/qapi-schema/args-bad-boxed.err
+++ b/tests/qapi-schema/args-bad-boxed.err
@@ -1 +1 @@
-tests/qapi-schema/args-bad-boxed.json:6: 'boxed' of command 'foo' should only use true value
+tests/qapi-schema/args-bad-boxed.json:2: 'boxed' of command 'foo' should only use true value
diff --git a/tests/qapi-schema/args-bad-boxed.json b/tests/qapi-schema/args-bad-boxed.json
index 4c0b28f..dea0cd0 100644
--- a/tests/qapi-schema/args-bad-boxed.json
+++ b/tests/qapi-schema/args-bad-boxed.json
@@ -1,6 +1,2 @@
 # 'boxed' should only appear with value true
-
-##
-# @foo:
-##
 { 'command': 'foo', 'boxed': false }
diff --git a/tests/qapi-schema/args-boxed-anon.err b/tests/qapi-schema/args-boxed-anon.err
index 3cfac0b..f24f345 100644
--- a/tests/qapi-schema/args-boxed-anon.err
+++ b/tests/qapi-schema/args-boxed-anon.err
@@ -1 +1 @@
-tests/qapi-schema/args-boxed-anon.json:6: 'data' for command 'foo' should be a type name
+tests/qapi-schema/args-boxed-anon.json:2: 'data' for command 'foo' should be a type name
diff --git a/tests/qapi-schema/args-boxed-anon.json b/tests/qapi-schema/args-boxed-anon.json
index 2358e6a..95f60da 100644
--- a/tests/qapi-schema/args-boxed-anon.json
+++ b/tests/qapi-schema/args-boxed-anon.json
@@ -1,6 +1,2 @@
 # 'boxed' can only be used with named types
-
-##
-# @foo:
-##
 { 'command': 'foo', 'boxed': true, 'data': { 'string': 'str' } }
diff --git a/tests/qapi-schema/args-boxed-empty.err b/tests/qapi-schema/args-boxed-empty.err
index 963f495..039603e 100644
--- a/tests/qapi-schema/args-boxed-empty.err
+++ b/tests/qapi-schema/args-boxed-empty.err
@@ -1 +1 @@
-tests/qapi-schema/args-boxed-empty.json:11: Cannot use 'boxed' with empty type
+tests/qapi-schema/args-boxed-empty.json:3: Cannot use 'boxed' with empty type
diff --git a/tests/qapi-schema/args-boxed-empty.json b/tests/qapi-schema/args-boxed-empty.json
index 8e8cc26..52717e0 100644
--- a/tests/qapi-schema/args-boxed-empty.json
+++ b/tests/qapi-schema/args-boxed-empty.json
@@ -1,11 +1,3 @@
 # 'boxed' requires a non-empty type
-
-##
-# @Empty:
-##
 { 'struct': 'Empty', 'data': {} }
-
-##
-# @foo:
-##
 { 'command': 'foo', 'boxed': true, 'data': 'Empty' }
diff --git a/tests/qapi-schema/args-boxed-string.err b/tests/qapi-schema/args-boxed-string.err
index 7623755..d326b48 100644
--- a/tests/qapi-schema/args-boxed-string.err
+++ b/tests/qapi-schema/args-boxed-string.err
@@ -1 +1 @@
-tests/qapi-schema/args-boxed-string.json:6: 'data' for command 'foo' cannot use built-in type 'str'
+tests/qapi-schema/args-boxed-string.json:2: 'data' for command 'foo' cannot use built-in type 'str'
diff --git a/tests/qapi-schema/args-boxed-string.json b/tests/qapi-schema/args-boxed-string.json
index aecdf97..f91a150 100644
--- a/tests/qapi-schema/args-boxed-string.json
+++ b/tests/qapi-schema/args-boxed-string.json
@@ -1,6 +1,2 @@
 # 'boxed' requires a complex (not built-in) type
-
-##
-# @foo:
-##
 { 'command': 'foo', 'boxed': true, 'data': 'str' }
diff --git a/tests/qapi-schema/args-int.err b/tests/qapi-schema/args-int.err
index 38b3202..dc1d250 100644
--- a/tests/qapi-schema/args-int.err
+++ b/tests/qapi-schema/args-int.err
@@ -1 +1 @@
-tests/qapi-schema/args-int.json:6: 'data' for command 'oops' cannot use built-in type 'int'
+tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'
diff --git a/tests/qapi-schema/args-int.json b/tests/qapi-schema/args-int.json
index 7f4e1b7..a334d92 100644
--- a/tests/qapi-schema/args-int.json
+++ b/tests/qapi-schema/args-int.json
@@ -1,6 +1,2 @@
 # we reject commands where data is not an array or complex type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': 'int' }
diff --git a/tests/qapi-schema/args-invalid.err b/tests/qapi-schema/args-invalid.err
index 5d3568d..fe1e949 100644
--- a/tests/qapi-schema/args-invalid.err
+++ b/tests/qapi-schema/args-invalid.err
@@ -1 +1 @@
-tests/qapi-schema/args-invalid.json:4: 'data' for command 'foo' should be a dictionary or type name
+tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name
diff --git a/tests/qapi-schema/args-invalid.json b/tests/qapi-schema/args-invalid.json
index 1a7e63b..db09813 100644
--- a/tests/qapi-schema/args-invalid.json
+++ b/tests/qapi-schema/args-invalid.json
@@ -1,5 +1,2 @@
-##
-# @foo:
-##
 { 'command': 'foo',
   'data': false }
diff --git a/tests/qapi-schema/args-member-array-bad.err b/tests/qapi-schema/args-member-array-bad.err
index 825ffca..881b4d9 100644
--- a/tests/qapi-schema/args-member-array-bad.err
+++ b/tests/qapi-schema/args-member-array-bad.err
@@ -1 +1 @@
-tests/qapi-schema/args-member-array-bad.json:6: Member 'member' of 'data' for command 'oops': array type must contain single type name
+tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name
diff --git a/tests/qapi-schema/args-member-array-bad.json b/tests/qapi-schema/args-member-array-bad.json
index e934f5c..b2ff144 100644
--- a/tests/qapi-schema/args-member-array-bad.json
+++ b/tests/qapi-schema/args-member-array-bad.json
@@ -1,6 +1,2 @@
 # we reject data if it does not contain a valid array type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } }
diff --git a/tests/qapi-schema/args-member-case.err b/tests/qapi-schema/args-member-case.err
index a3fb2bd..19c4426 100644
--- a/tests/qapi-schema/args-member-case.err
+++ b/tests/qapi-schema/args-member-case.err
@@ -1 +1 @@
-tests/qapi-schema/args-member-case.json:6: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase
+tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase
diff --git a/tests/qapi-schema/args-member-case.json b/tests/qapi-schema/args-member-case.json
index 811e658..93439be 100644
--- a/tests/qapi-schema/args-member-case.json
+++ b/tests/qapi-schema/args-member-case.json
@@ -1,6 +1,2 @@
 # Member names should be 'lower-case' unless the struct/command is whitelisted
-
-##
-# @no-way-this-will-get-whitelisted:
-##
 { 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } }
diff --git a/tests/qapi-schema/args-member-unknown.err b/tests/qapi-schema/args-member-unknown.err
index 3db452b..f6f8282 100644
--- a/tests/qapi-schema/args-member-unknown.err
+++ b/tests/qapi-schema/args-member-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/args-member-unknown.json:6: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/args-member-unknown.json b/tests/qapi-schema/args-member-unknown.json
index e2fef9c..342a41e 100644
--- a/tests/qapi-schema/args-member-unknown.json
+++ b/tests/qapi-schema/args-member-unknown.json
@@ -1,6 +1,2 @@
 # we reject data if it does not contain a known type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': { 'member': 'NoSuchType' } }
diff --git a/tests/qapi-schema/args-name-clash.err b/tests/qapi-schema/args-name-clash.err
index 23988cb..d953e8d 100644
--- a/tests/qapi-schema/args-name-clash.err
+++ b/tests/qapi-schema/args-name-clash.err
@@ -1 +1 @@
-tests/qapi-schema/args-name-clash.json:8: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops)
+tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops)
diff --git a/tests/qapi-schema/args-name-clash.json b/tests/qapi-schema/args-name-clash.json
index 991323b..61423cb 100644
--- a/tests/qapi-schema/args-name-clash.json
+++ b/tests/qapi-schema/args-name-clash.json
@@ -1,8 +1,4 @@
 # C member name collision
 # Reject members that clash when mapped to C names (we would have two 'a_b'
 # members).
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }
diff --git a/tests/qapi-schema/args-union.err b/tests/qapi-schema/args-union.err
index ce0a34e..f8ad223 100644
--- a/tests/qapi-schema/args-union.err
+++ b/tests/qapi-schema/args-union.err
@@ -1 +1 @@
-tests/qapi-schema/args-union.json:10: 'data' for command 'oops' cannot use union type 'Uni'
+tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use union type 'Uni'
diff --git a/tests/qapi-schema/args-union.json b/tests/qapi-schema/args-union.json
index 57284b4..2fcaeaa 100644
--- a/tests/qapi-schema/args-union.json
+++ b/tests/qapi-schema/args-union.json
@@ -1,10 +1,3 @@
 # use of union arguments requires 'boxed':true
-
-##
-# @Uni:
-##
 { 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } }
-##
-# oops:
-##
 { 'command': 'oops', 'data': 'Uni' }
diff --git a/tests/qapi-schema/args-unknown.err b/tests/qapi-schema/args-unknown.err
index ba6c6cf..4d91ec8 100644
--- a/tests/qapi-schema/args-unknown.err
+++ b/tests/qapi-schema/args-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/args-unknown.json:6: 'data' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/args-unknown.json b/tests/qapi-schema/args-unknown.json
index 12666dc..32aba43 100644
--- a/tests/qapi-schema/args-unknown.json
+++ b/tests/qapi-schema/args-unknown.json
@@ -1,6 +1,2 @@
 # we reject data if it does not contain a known type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': 'NoSuchType' }
diff --git a/tests/qapi-schema/bad-base.err b/tests/qapi-schema/bad-base.err
index e668761..154274b 100644
--- a/tests/qapi-schema/bad-base.err
+++ b/tests/qapi-schema/bad-base.err
@@ -1 +1 @@
-tests/qapi-schema/bad-base.json:10: 'base' for struct 'MyType' cannot use union type 'Union'
+tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union'
diff --git a/tests/qapi-schema/bad-base.json b/tests/qapi-schema/bad-base.json
index c3faa82..a634331 100644
--- a/tests/qapi-schema/bad-base.json
+++ b/tests/qapi-schema/bad-base.json
@@ -1,10 +1,3 @@
 # we reject a base that is not a struct
-
-##
-# @Union:
-##
 { 'union': 'Union', 'data': { 'a': 'int', 'b': 'str' } }
-##
-# @MyType:
-##
 { 'struct': 'MyType', 'base': 'Union', 'data': { 'c': 'int' } }
diff --git a/tests/qapi-schema/bad-data.err b/tests/qapi-schema/bad-data.err
index c1b9e35..8523ac4 100644
--- a/tests/qapi-schema/bad-data.err
+++ b/tests/qapi-schema/bad-data.err
@@ -1 +1 @@
-tests/qapi-schema/bad-data.json:6: 'data' for command 'oops' cannot be an array
+tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array
diff --git a/tests/qapi-schema/bad-data.json b/tests/qapi-schema/bad-data.json
index 51c444f..832eeb7 100644
--- a/tests/qapi-schema/bad-data.json
+++ b/tests/qapi-schema/bad-data.json
@@ -1,6 +1,2 @@
 # we ensure 'data' is a dictionary for all but enums
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': [ ] }
diff --git a/tests/qapi-schema/bad-ident.err b/tests/qapi-schema/bad-ident.err
index b757aa2..c419060 100644
--- a/tests/qapi-schema/bad-ident.err
+++ b/tests/qapi-schema/bad-ident.err
@@ -1 +1 @@
-tests/qapi-schema/bad-ident.json:6: 'struct' does not allow optional name '*oops'
+tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops'
diff --git a/tests/qapi-schema/bad-ident.json b/tests/qapi-schema/bad-ident.json
index b43df7a..763627a 100644
--- a/tests/qapi-schema/bad-ident.json
+++ b/tests/qapi-schema/bad-ident.json
@@ -1,6 +1,2 @@
 # we reject creating a type name with bad name
-
-##
-# @*oops:
-##
 { 'struct': '*oops', 'data': { 'i': 'int' } }
diff --git a/tests/qapi-schema/bad-type-bool.err b/tests/qapi-schema/bad-type-bool.err
index 72e026b..62fd70b 100644
--- a/tests/qapi-schema/bad-type-bool.err
+++ b/tests/qapi-schema/bad-type-bool.err
@@ -1 +1 @@
-tests/qapi-schema/bad-type-bool.json:6: 'struct' key must have a string value
+tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string value
diff --git a/tests/qapi-schema/bad-type-bool.json b/tests/qapi-schema/bad-type-bool.json
index 1f9eddf..bde17b5 100644
--- a/tests/qapi-schema/bad-type-bool.json
+++ b/tests/qapi-schema/bad-type-bool.json
@@ -1,6 +1,2 @@
 # we reject an expression with a metatype that is not a string
-
-##
-# @true:
-##
 { 'struct': true, 'data': { } }
diff --git a/tests/qapi-schema/bad-type-dict.err b/tests/qapi-schema/bad-type-dict.err
index d0d1f60..0b2a2ae 100644
--- a/tests/qapi-schema/bad-type-dict.err
+++ b/tests/qapi-schema/bad-type-dict.err
@@ -1 +1 @@
-tests/qapi-schema/bad-type-dict.json:6: 'command' key must have a string value
+tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value
diff --git a/tests/qapi-schema/bad-type-dict.json b/tests/qapi-schema/bad-type-dict.json
index 5952caa..2a91b24 100644
--- a/tests/qapi-schema/bad-type-dict.json
+++ b/tests/qapi-schema/bad-type-dict.json
@@ -1,6 +1,2 @@
 # we reject an expression with a metatype that is not a string
-
-##
-# @foo:
-##
 { 'command': { } }
diff --git a/tests/qapi-schema/base-cycle-direct.err b/tests/qapi-schema/base-cycle-direct.err
index dd7f5aa..9c68f65 100644
--- a/tests/qapi-schema/base-cycle-direct.err
+++ b/tests/qapi-schema/base-cycle-direct.err
@@ -1 +1 @@
-tests/qapi-schema/base-cycle-direct.json:6: Object Loopy contains itself
+tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself
diff --git a/tests/qapi-schema/base-cycle-direct.json b/tests/qapi-schema/base-cycle-direct.json
index 9780f7e..4fc66d0 100644
--- a/tests/qapi-schema/base-cycle-direct.json
+++ b/tests/qapi-schema/base-cycle-direct.json
@@ -1,6 +1,2 @@
 # we reject a loop in base classes
-
-##
-# @Loopy:
-##
 { 'struct': 'Loopy', 'base': 'Loopy', 'data': {} }
diff --git a/tests/qapi-schema/base-cycle-indirect.err b/tests/qapi-schema/base-cycle-indirect.err
index f4198e4..fc92fe4 100644
--- a/tests/qapi-schema/base-cycle-indirect.err
+++ b/tests/qapi-schema/base-cycle-indirect.err
@@ -1 +1 @@
-tests/qapi-schema/base-cycle-indirect.json:6: Object Base1 contains itself
+tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself
diff --git a/tests/qapi-schema/base-cycle-indirect.json b/tests/qapi-schema/base-cycle-indirect.json
index 99926c4..2866772 100644
--- a/tests/qapi-schema/base-cycle-indirect.json
+++ b/tests/qapi-schema/base-cycle-indirect.json
@@ -1,10 +1,3 @@
 # we reject a loop in base classes
-
-##
-# @Base1:
-##
 { 'struct': 'Base1', 'base': 'Base2', 'data': {} }
-##
-# @Base2:
-##
 { 'struct': 'Base2', 'base': 'Base1', 'data': {} }
diff --git a/tests/qapi-schema/command-int.err b/tests/qapi-schema/command-int.err
index 3c834a9..0f93006 100644
--- a/tests/qapi-schema/command-int.err
+++ b/tests/qapi-schema/command-int.err
@@ -1 +1 @@
-tests/qapi-schema/command-int.json:6: built-in 'int' is already defined
+tests/qapi-schema/command-int.json:2: built-in 'int' is already defined
diff --git a/tests/qapi-schema/command-int.json b/tests/qapi-schema/command-int.json
index 5b51bf1..9a62554 100644
--- a/tests/qapi-schema/command-int.json
+++ b/tests/qapi-schema/command-int.json
@@ -1,6 +1,2 @@
 # we reject collisions between commands and types
-
-##
-# @int:
-##
 { 'command': 'int', 'data': { 'character': 'str' } }
diff --git a/tests/qapi-schema/comments.json b/tests/qapi-schema/comments.json
index d31ef0d..e643f3a 100644
--- a/tests/qapi-schema/comments.json
+++ b/tests/qapi-schema/comments.json
@@ -1,8 +1,4 @@
 # Unindented comment
-
-##
-# @Status:
-##
 { 'enum': 'Status',             # Comment to the right of code
   # Indented comment
   'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index a962fb2..5d7c13c 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -2,4 +2,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
 object q_empty
-doc symbol=Status expr=('enum', 'Status')
diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err
index 424df9b..f9613c6 100644
--- a/tests/qapi-schema/double-type.err
+++ b/tests/qapi-schema/double-type.err
@@ -1 +1 @@
-tests/qapi-schema/double-type.json:6: Unknown key 'command' in struct 'bar'
+tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar'
diff --git a/tests/qapi-schema/double-type.json b/tests/qapi-schema/double-type.json
index ab59523..911fa7a 100644
--- a/tests/qapi-schema/double-type.json
+++ b/tests/qapi-schema/double-type.json
@@ -1,6 +1,2 @@
 # we reject an expression with ambiguous metatype
-
-##
-# @foo:
-##
 { 'command': 'foo', 'struct': 'bar', 'data': { } }
diff --git a/tests/qapi-schema/enum-bad-name.err b/tests/qapi-schema/enum-bad-name.err
index 157d1b0..9c3c100 100644
--- a/tests/qapi-schema/enum-bad-name.err
+++ b/tests/qapi-schema/enum-bad-name.err
@@ -1 +1 @@
-tests/qapi-schema/enum-bad-name.json:6: Member of enum 'MyEnum' uses invalid name 'not^possible'
+tests/qapi-schema/enum-bad-name.json:2: Member of enum 'MyEnum' uses invalid name 'not^possible'
diff --git a/tests/qapi-schema/enum-bad-name.json b/tests/qapi-schema/enum-bad-name.json
index 978cb88..8506562 100644
--- a/tests/qapi-schema/enum-bad-name.json
+++ b/tests/qapi-schema/enum-bad-name.json
@@ -1,6 +1,2 @@
 # we ensure all enum names can map to C
-
-##
-# @MyEnum:
-##
 { 'enum': 'MyEnum', 'data': [ 'not^possible' ] }
diff --git a/tests/qapi-schema/enum-bad-prefix.err b/tests/qapi-schema/enum-bad-prefix.err
index 918915f..399f5f7 100644
--- a/tests/qapi-schema/enum-bad-prefix.err
+++ b/tests/qapi-schema/enum-bad-prefix.err
@@ -1 +1 @@
-tests/qapi-schema/enum-bad-prefix.json:6: Enum 'MyEnum' requires a string for 'prefix'
+tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix'
diff --git a/tests/qapi-schema/enum-bad-prefix.json b/tests/qapi-schema/enum-bad-prefix.json
index 25f17a7..996f628 100644
--- a/tests/qapi-schema/enum-bad-prefix.json
+++ b/tests/qapi-schema/enum-bad-prefix.json
@@ -1,6 +1,2 @@
 # The prefix must be a string type
-
-##
-# @MyEnum:
-##
 { 'enum': 'MyEnum', 'data': [ 'one' ], 'prefix': [ 'fish' ] }
diff --git a/tests/qapi-schema/enum-clash-member.err b/tests/qapi-schema/enum-clash-member.err
index 25249b6..5403c78 100644
--- a/tests/qapi-schema/enum-clash-member.err
+++ b/tests/qapi-schema/enum-clash-member.err
@@ -1 +1 @@
-tests/qapi-schema/enum-clash-member.json:6: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum)
+tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum)
diff --git a/tests/qapi-schema/enum-clash-member.json b/tests/qapi-schema/enum-clash-member.json
index fd52751..b6928b8 100644
--- a/tests/qapi-schema/enum-clash-member.json
+++ b/tests/qapi-schema/enum-clash-member.json
@@ -1,6 +1,2 @@
 # we reject enums where members will clash when mapped to C enum
-
-##
-# @MyEnum:
-##
 { 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] }
diff --git a/tests/qapi-schema/enum-dict-member.err b/tests/qapi-schema/enum-dict-member.err
index 9b7d2f1..8ca146e 100644
--- a/tests/qapi-schema/enum-dict-member.err
+++ b/tests/qapi-schema/enum-dict-member.err
@@ -1 +1 @@
-tests/qapi-schema/enum-dict-member.json:6: Member of enum 'MyEnum' requires a string name
+tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum' requires a string name
diff --git a/tests/qapi-schema/enum-dict-member.json b/tests/qapi-schema/enum-dict-member.json
index 69d30f0..79672e0 100644
--- a/tests/qapi-schema/enum-dict-member.json
+++ b/tests/qapi-schema/enum-dict-member.json
@@ -1,6 +1,2 @@
 # we reject any enum member that is not a string
-
-##
-# @MyEnum:
-##
 { 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
diff --git a/tests/qapi-schema/enum-member-case.err b/tests/qapi-schema/enum-member-case.err
index df96e22..b652e9a 100644
--- a/tests/qapi-schema/enum-member-case.err
+++ b/tests/qapi-schema/enum-member-case.err
@@ -1 +1 @@
-tests/qapi-schema/enum-member-case.json:10: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase
+tests/qapi-schema/enum-member-case.json:3: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase
diff --git a/tests/qapi-schema/enum-member-case.json b/tests/qapi-schema/enum-member-case.json
index d2e4aba..2096b35 100644
--- a/tests/qapi-schema/enum-member-case.json
+++ b/tests/qapi-schema/enum-member-case.json
@@ -1,10 +1,3 @@
 # Member names should be 'lower-case' unless the enum is whitelisted
-
-##
-# @UuidInfo:
-##
 { 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted
-##
-# @NoWayThisWillGetWhitelisted:
-##
 { 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] }
diff --git a/tests/qapi-schema/enum-missing-data.err b/tests/qapi-schema/enum-missing-data.err
index de4b9e8..ba4873a 100644
--- a/tests/qapi-schema/enum-missing-data.err
+++ b/tests/qapi-schema/enum-missing-data.err
@@ -1 +1 @@
-tests/qapi-schema/enum-missing-data.json:6: Key 'data' is missing from enum 'MyEnum'
+tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum'
diff --git a/tests/qapi-schema/enum-missing-data.json b/tests/qapi-schema/enum-missing-data.json
index d7601f9..558fd35 100644
--- a/tests/qapi-schema/enum-missing-data.json
+++ b/tests/qapi-schema/enum-missing-data.json
@@ -1,6 +1,2 @@
 # we require that all QAPI enums have a data array
-
-##
-# @MyEnum:
-##
 { 'enum': 'MyEnum' }
diff --git a/tests/qapi-schema/enum-wrong-data.err b/tests/qapi-schema/enum-wrong-data.err
index c44e9b5..11b4347 100644
--- a/tests/qapi-schema/enum-wrong-data.err
+++ b/tests/qapi-schema/enum-wrong-data.err
@@ -1 +1 @@
-tests/qapi-schema/enum-wrong-data.json:6: Enum 'MyEnum' requires an array for 'data'
+tests/qapi-schema/enum-wrong-data.json:2: Enum 'MyEnum' requires an array for 'data'
diff --git a/tests/qapi-schema/enum-wrong-data.json b/tests/qapi-schema/enum-wrong-data.json
index 4b9e978..7b3e255 100644
--- a/tests/qapi-schema/enum-wrong-data.json
+++ b/tests/qapi-schema/enum-wrong-data.json
@@ -1,6 +1,2 @@
 # we require that all qapi enums have an array for data
-
-##
-# @MyEnum:
-##
 { 'enum': 'MyEnum', 'data': { 'value': 'str' } }
diff --git a/tests/qapi-schema/event-boxed-empty.err b/tests/qapi-schema/event-boxed-empty.err
index defe656..68ec6f2 100644
--- a/tests/qapi-schema/event-boxed-empty.err
+++ b/tests/qapi-schema/event-boxed-empty.err
@@ -1 +1 @@
-tests/qapi-schema/event-boxed-empty.json:6: Use of 'boxed' requires 'data'
+tests/qapi-schema/event-boxed-empty.json:2: Use of 'boxed' requires 'data'
diff --git a/tests/qapi-schema/event-boxed-empty.json b/tests/qapi-schema/event-boxed-empty.json
index 63b870b..cb145f1 100644
--- a/tests/qapi-schema/event-boxed-empty.json
+++ b/tests/qapi-schema/event-boxed-empty.json
@@ -1,6 +1,2 @@
 # 'boxed' requires a non-empty type
-
-##
-# @FOO:
-##
 { 'event': 'FOO', 'boxed': true }
diff --git a/tests/qapi-schema/event-case.json b/tests/qapi-schema/event-case.json
index 6b05c5d..3a92d8b 100644
--- a/tests/qapi-schema/event-case.json
+++ b/tests/qapi-schema/event-case.json
@@ -1,7 +1,3 @@
 # TODO: might be nice to enforce naming conventions; but until then this works
 # even though events should usually be ALL_CAPS
-
-##
-# @oops:
-##
 { 'event': 'oops' }
diff --git a/tests/qapi-schema/event-case.out b/tests/qapi-schema/event-case.out
index 2865714..5a0f2bf 100644
--- a/tests/qapi-schema/event-case.out
+++ b/tests/qapi-schema/event-case.out
@@ -3,4 +3,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo
 event oops None
    boxed=False
 object q_empty
-doc symbol=oops expr=('event', 'oops')
diff --git a/tests/qapi-schema/event-nest-struct.err b/tests/qapi-schema/event-nest-struct.err
index 17a6c3c..5a42701 100644
--- a/tests/qapi-schema/event-nest-struct.err
+++ b/tests/qapi-schema/event-nest-struct.err
@@ -1 +1 @@
-tests/qapi-schema/event-nest-struct.json:5: Member 'a' of 'data' for event 'EVENT_A' should be a type name
+tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' should be a type name
diff --git a/tests/qapi-schema/event-nest-struct.json b/tests/qapi-schema/event-nest-struct.json
index 328e0a6..ee6f3ec 100644
--- a/tests/qapi-schema/event-nest-struct.json
+++ b/tests/qapi-schema/event-nest-struct.json
@@ -1,6 +1,2 @@
-##
-# @EVENT_A:
-# event-nest-struct
-##
 { 'event': 'EVENT_A',
   'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
diff --git a/tests/qapi-schema/flat-union-array-branch.err b/tests/qapi-schema/flat-union-array-branch.err
index e456094..8ea91ea 100644
--- a/tests/qapi-schema/flat-union-array-branch.err
+++ b/tests/qapi-schema/flat-union-array-branch.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-array-branch.json:20: Member 'value1' of union 'TestUnion' cannot be an array
+tests/qapi-schema/flat-union-array-branch.json:8: Member 'value1' of union 'TestUnion' cannot be an array
diff --git a/tests/qapi-schema/flat-union-array-branch.json b/tests/qapi-schema/flat-union-array-branch.json
index 51dde10..0b98820 100644
--- a/tests/qapi-schema/flat-union-array-branch.json
+++ b/tests/qapi-schema/flat-union-array-branch.json
@@ -1,22 +1,10 @@
-##
-# @TestEnum:
-##
 # we require flat union branches to be a struct
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'enum1': 'TestEnum' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'Base',
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-bad-base.err b/tests/qapi-schema/flat-union-bad-base.err
index 072ffba..bee24a2 100644
--- a/tests/qapi-schema/flat-union-bad-base.err
+++ b/tests/qapi-schema/flat-union-bad-base.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-bad-base.json:21: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion)
+tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion)
diff --git a/tests/qapi-schema/flat-union-bad-base.json b/tests/qapi-schema/flat-union-bad-base.json
index 7713e7f..74dd421 100644
--- a/tests/qapi-schema/flat-union-bad-base.json
+++ b/tests/qapi-schema/flat-union-bad-base.json
@@ -1,23 +1,10 @@
 # we allow anonymous base, but enforce no duplicate keys
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': { 'enum1': 'TestEnum', 'string': 'str' },
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-bad-discriminator.err b/tests/qapi-schema/flat-union-bad-discriminator.err
index 1be4e7b..c38cc8e 100644
--- a/tests/qapi-schema/flat-union-bad-discriminator.err
+++ b/tests/qapi-schema/flat-union-bad-discriminator.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-bad-discriminator.json:27: Discriminator of flat union 'TestUnion' requires a string name
+tests/qapi-schema/flat-union-bad-discriminator.json:11: Discriminator of flat union 'TestUnion' requires a string name
diff --git a/tests/qapi-schema/flat-union-bad-discriminator.json b/tests/qapi-schema/flat-union-bad-discriminator.json
index ef92f9b..cd10b9d 100644
--- a/tests/qapi-schema/flat-union-bad-discriminator.json
+++ b/tests/qapi-schema/flat-union-bad-discriminator.json
@@ -1,29 +1,13 @@
 # we require the discriminator to be a string naming a base-type member
 # this tests the old syntax for anonymous unions before we added alternates
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @TestBase:
-##
 { 'struct': 'TestBase',
   'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'TestBase',
   'discriminator': {},
diff --git a/tests/qapi-schema/flat-union-base-any.err b/tests/qapi-schema/flat-union-base-any.err
index c1ea2d7..646f1c9 100644
--- a/tests/qapi-schema/flat-union-base-any.err
+++ b/tests/qapi-schema/flat-union-base-any.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-base-any.json:21: 'base' for union 'TestUnion' cannot use built-in type 'any'
+tests/qapi-schema/flat-union-base-any.json:8: 'base' for union 'TestUnion' cannot use built-in type 'any'
diff --git a/tests/qapi-schema/flat-union-base-any.json b/tests/qapi-schema/flat-union-base-any.json
index 3dfb02f..fe66b71 100644
--- a/tests/qapi-schema/flat-union-base-any.json
+++ b/tests/qapi-schema/flat-union-base-any.json
@@ -1,23 +1,10 @@
 # we require the base to be an existing struct
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'any',
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-base-union.err b/tests/qapi-schema/flat-union-base-union.err
index ccc5e85..f138395 100644
--- a/tests/qapi-schema/flat-union-base-union.err
+++ b/tests/qapi-schema/flat-union-base-union.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-base-union.json:30: 'base' for union 'TestUnion' cannot use union type 'UnionBase'
+tests/qapi-schema/flat-union-base-union.json:14: 'base' for union 'TestUnion' cannot use union type 'UnionBase'
diff --git a/tests/qapi-schema/flat-union-base-union.json b/tests/qapi-schema/flat-union-base-union.json
index c63c613..98b4eba 100644
--- a/tests/qapi-schema/flat-union-base-union.json
+++ b/tests/qapi-schema/flat-union-base-union.json
@@ -2,31 +2,15 @@
 # TODO: It would be possible to allow a union as a base, as long as all
 # permutations of QMP names exposed by base do not clash with any QMP
 # member names added by local variants.
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @UnionBase:
-##
 { 'union': 'UnionBase',
   'data': { 'kind1': 'TestTypeA',
             'kind2': 'TestTypeB' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'UnionBase',
   'discriminator': 'type',
diff --git a/tests/qapi-schema/flat-union-clash-member.err b/tests/qapi-schema/flat-union-clash-member.err
index fe12a07..2adf697 100644
--- a/tests/qapi-schema/flat-union-clash-member.err
+++ b/tests/qapi-schema/flat-union-clash-member.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-clash-member.json:27: 'name' (member of Branch1) collides with 'name' (member of Base)
+tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base)
diff --git a/tests/qapi-schema/flat-union-clash-member.json b/tests/qapi-schema/flat-union-clash-member.json
index 9000b94..9efc771 100644
--- a/tests/qapi-schema/flat-union-clash-member.json
+++ b/tests/qapi-schema/flat-union-clash-member.json
@@ -1,29 +1,13 @@
 # We check for no duplicate keys between branch members and base
 # base's member 'name' clashes with Branch1's
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'enum1': 'TestEnum', '*name': 'str' } }
-##
-# @Branch1:
-##
 { 'struct': 'Branch1',
   'data': { 'name': 'str' } }
-##
-# @Branch2:
-##
 { 'struct': 'Branch2',
   'data': { 'value': 'int' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'Base',
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err
index ead7bd4..15754f5 100644
--- a/tests/qapi-schema/flat-union-empty.err
+++ b/tests/qapi-schema/flat-union-empty.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-empty.json:14: Union 'Union' cannot have empty 'data'
+tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data'
diff --git a/tests/qapi-schema/flat-union-empty.json b/tests/qapi-schema/flat-union-empty.json
index afa8988..77f1d9a 100644
--- a/tests/qapi-schema/flat-union-empty.json
+++ b/tests/qapi-schema/flat-union-empty.json
@@ -1,14 +1,4 @@
 # flat unions cannot be empty
-
-##
-# @Empty:
-##
 { 'enum': 'Empty', 'data': [ ] }
-##
-# @Base:
-##
 { 'struct': 'Base', 'data': { 'type': 'Empty' } }
-##
-# @Union:
-##
 { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
diff --git a/tests/qapi-schema/flat-union-incomplete-branch.err b/tests/qapi-schema/flat-union-incomplete-branch.err
index c655bbf..e826bf0 100644
--- a/tests/qapi-schema/flat-union-incomplete-branch.err
+++ b/tests/qapi-schema/flat-union-incomplete-branch.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-incomplete-branch.json:16: Union 'TestUnion' data missing 'value2' branch
+tests/qapi-schema/flat-union-incomplete-branch.json:6: Union 'TestUnion' data missing 'value2' branch
diff --git a/tests/qapi-schema/flat-union-incomplete-branch.json b/tests/qapi-schema/flat-union-incomplete-branch.json
index dea0377..25a411b 100644
--- a/tests/qapi-schema/flat-union-incomplete-branch.json
+++ b/tests/qapi-schema/flat-union-incomplete-branch.json
@@ -1,18 +1,8 @@
 # we require all branches of the union to be covered
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': { 'type': 'TestEnum' },
   'discriminator': 'type',
diff --git a/tests/qapi-schema/flat-union-inline.err b/tests/qapi-schema/flat-union-inline.err
index c2c3f76..2333358 100644
--- a/tests/qapi-schema/flat-union-inline.err
+++ b/tests/qapi-schema/flat-union-inline.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-inline.json:17: Member 'value1' of union 'TestUnion' should be a type name
+tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name
diff --git a/tests/qapi-schema/flat-union-inline.json b/tests/qapi-schema/flat-union-inline.json
index 400f081..62c7cda 100644
--- a/tests/qapi-schema/flat-union-inline.json
+++ b/tests/qapi-schema/flat-union-inline.json
@@ -1,19 +1,9 @@
 # we require branches to be a struct name
 # TODO: should we allow anonymous inline branch types?
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'Base',
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-int-branch.err b/tests/qapi-schema/flat-union-int-branch.err
index 299cbb2..faf0157 100644
--- a/tests/qapi-schema/flat-union-int-branch.err
+++ b/tests/qapi-schema/flat-union-int-branch.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-int-branch.json:21: Member 'value1' of union 'TestUnion' cannot use built-in type 'int'
+tests/qapi-schema/flat-union-int-branch.json:8: Member 'value1' of union 'TestUnion' cannot use built-in type 'int'
diff --git a/tests/qapi-schema/flat-union-int-branch.json b/tests/qapi-schema/flat-union-int-branch.json
index 9603e17..9370c34 100644
--- a/tests/qapi-schema/flat-union-int-branch.json
+++ b/tests/qapi-schema/flat-union-int-branch.json
@@ -1,23 +1,10 @@
 # we require flat union branches to be a struct
-
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'enum1': 'TestEnum' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'Base',
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err
index 455f2dc..ccf72d2 100644
--- a/tests/qapi-schema/flat-union-invalid-branch-key.err
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-invalid-branch-key.json:28: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
+tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.json b/tests/qapi-schema/flat-union-invalid-branch-key.json
index 00f2896..95ff774 100644
--- a/tests/qapi-schema/flat-union-invalid-branch-key.json
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.json
@@ -1,30 +1,15 @@
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
 
-##
-# @TestBase:
-##
 { 'struct': 'TestBase',
   'data': { 'enum1': 'TestEnum' } }
 
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
 
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
 
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'TestBase',
   'discriminator': 'enum1',
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err
index f0e427b..5f40556 100644
--- a/tests/qapi-schema/flat-union-invalid-discriminator.err
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-invalid-discriminator.json:28: Discriminator 'enum_wrong' is not a member of base struct 'TestBase'
+tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator 'enum_wrong' is not a member of base struct 'TestBase'
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json b/tests/qapi-schema/flat-union-invalid-discriminator.json
index c8700c7..48b94c3 100644
--- a/tests/qapi-schema/flat-union-invalid-discriminator.json
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.json
@@ -1,30 +1,15 @@
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
 
-##
-# @TestBase:
-##
 { 'struct': 'TestBase',
   'data': { 'enum1': 'TestEnum' } }
 
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
 
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
 
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'TestBase',
   'discriminator': 'enum_wrong',
diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err
index a2d0a81..841c93b 100644
--- a/tests/qapi-schema/flat-union-no-base.err
+++ b/tests/qapi-schema/flat-union-no-base.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-no-base.json:22: Flat union 'TestUnion' must have a base
+tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a base
diff --git a/tests/qapi-schema/flat-union-no-base.json b/tests/qapi-schema/flat-union-no-base.json
index 641f68a..ffc4c6f 100644
--- a/tests/qapi-schema/flat-union-no-base.json
+++ b/tests/qapi-schema/flat-union-no-base.json
@@ -1,24 +1,11 @@
 # flat unions require a base
 # TODO: simple unions should be able to use an enum discriminator
-
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
-##
-# @Enum:
-##
 { 'enum': 'Enum',
   'data': [ 'value1', 'value2' ] }
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'discriminator': 'Enum',
   'data': { 'value1': 'TestTypeA',
diff --git a/tests/qapi-schema/flat-union-optional-discriminator.err b/tests/qapi-schema/flat-union-optional-discriminator.err
index e15f856..aaabedb 100644
--- a/tests/qapi-schema/flat-union-optional-discriminator.err
+++ b/tests/qapi-schema/flat-union-optional-discriminator.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-optional-discriminator.json:19: Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
+tests/qapi-schema/flat-union-optional-discriminator.json:6: Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
diff --git a/tests/qapi-schema/flat-union-optional-discriminator.json b/tests/qapi-schema/flat-union-optional-discriminator.json
index 9f19af5..08a8f7e 100644
--- a/tests/qapi-schema/flat-union-optional-discriminator.json
+++ b/tests/qapi-schema/flat-union-optional-discriminator.json
@@ -1,21 +1,8 @@
 # we require the discriminator to be non-optional
-
-##
-# @Enum:
-##
 { 'enum': 'Enum', 'data': [ 'one', 'two' ] }
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { '*switch': 'Enum' } }
-##
-# @Branch:
-##
 { 'struct': 'Branch', 'data': { 'name': 'str' } }
-##
-# @MyUnion:
-##
 { 'union': 'MyUnion',
   'base': 'Base',
   'discriminator': '*switch',
diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err
index bc0c133..200016b 100644
--- a/tests/qapi-schema/flat-union-string-discriminator.err
+++ b/tests/qapi-schema/flat-union-string-discriminator.err
@@ -1 +1 @@
-tests/qapi-schema/flat-union-string-discriminator.json:28: Discriminator 'kind' must be of enumeration type
+tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type
diff --git a/tests/qapi-schema/flat-union-string-discriminator.json b/tests/qapi-schema/flat-union-string-discriminator.json
index 47a17d2..8af6033 100644
--- a/tests/qapi-schema/flat-union-string-discriminator.json
+++ b/tests/qapi-schema/flat-union-string-discriminator.json
@@ -1,30 +1,15 @@
-##
-# @TestEnum:
-##
 { 'enum': 'TestEnum',
   'data': [ 'value1', 'value2' ] }
 
-##
-# @TestBase:
-##
 { 'struct': 'TestBase',
   'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
 
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
 
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
 
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'TestBase',
   'discriminator': 'kind',
diff --git a/tests/qapi-schema/ident-with-escape.json b/tests/qapi-schema/ident-with-escape.json
index c03404b..5661750 100644
--- a/tests/qapi-schema/ident-with-escape.json
+++ b/tests/qapi-schema/ident-with-escape.json
@@ -1,8 +1,4 @@
 # we allow escape sequences in strings, if they map back to ASCII
 # { 'command': 'fooA', 'data': { 'bar1': 'str' } }
-
-##
-# @fooA:
-##
 { 'c\u006fmmand': '\u0066\u006f\u006FA',
   'd\u0061ta': { '\u0062\u0061\u00721': '\u0073\u0074\u0072' } }
diff --git a/tests/qapi-schema/ident-with-escape.out b/tests/qapi-schema/ident-with-escape.out
index 69fc908..1d2722c 100644
--- a/tests/qapi-schema/ident-with-escape.out
+++ b/tests/qapi-schema/ident-with-escape.out
@@ -5,4 +5,3 @@ command fooA q_obj_fooA-arg -> None
 object q_empty
 object q_obj_fooA-arg
     member bar1: str optional=False
-doc symbol=fooA expr=('command', 'fooA')
diff --git a/tests/qapi-schema/include-relpath-sub.json b/tests/qapi-schema/include-relpath-sub.json
index b4bd8a2..4bd4af4 100644
--- a/tests/qapi-schema/include-relpath-sub.json
+++ b/tests/qapi-schema/include-relpath-sub.json
@@ -1,5 +1,2 @@
-##
-# @Status:
-##
 { 'enum': 'Status',
   'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/include-relpath.out b/tests/qapi-schema/include-relpath.out
index a962fb2..5d7c13c 100644
--- a/tests/qapi-schema/include-relpath.out
+++ b/tests/qapi-schema/include-relpath.out
@@ -2,4 +2,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
 object q_empty
-doc symbol=Status expr=('enum', 'Status')
diff --git a/tests/qapi-schema/include-repetition.out b/tests/qapi-schema/include-repetition.out
index a962fb2..5d7c13c 100644
--- a/tests/qapi-schema/include-repetition.out
+++ b/tests/qapi-schema/include-repetition.out
@@ -2,4 +2,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
 object q_empty
-doc symbol=Status expr=('enum', 'Status')
diff --git a/tests/qapi-schema/include-simple-sub.json b/tests/qapi-schema/include-simple-sub.json
index b4bd8a2..4bd4af4 100644
--- a/tests/qapi-schema/include-simple-sub.json
+++ b/tests/qapi-schema/include-simple-sub.json
@@ -1,5 +1,2 @@
-##
-# @Status:
-##
 { 'enum': 'Status',
   'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/include-simple.out b/tests/qapi-schema/include-simple.out
index a962fb2..5d7c13c 100644
--- a/tests/qapi-schema/include-simple.out
+++ b/tests/qapi-schema/include-simple.out
@@ -2,4 +2,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbo
     prefix QTYPE
 enum Status ['good', 'bad', 'ugly']
 object q_empty
-doc symbol=Status expr=('enum', 'Status')
diff --git a/tests/qapi-schema/indented-expr.json b/tests/qapi-schema/indented-expr.json
index d759be1..7115d31 100644
--- a/tests/qapi-schema/indented-expr.json
+++ b/tests/qapi-schema/indented-expr.json
@@ -1,8 +1,2 @@
-##
-# @eins:
-##
 { 'command' : 'eins' }
-##
-# @zwei:
-##
  { 'command' : 'zwei' }
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
index 285d052..e8171c9 100644
--- a/tests/qapi-schema/indented-expr.out
+++ b/tests/qapi-schema/indented-expr.out
@@ -5,5 +5,3 @@ command eins None -> None
 object q_empty
 command zwei None -> None
    gen=True success_response=True boxed=False
-doc symbol=eins expr=('command', 'eins')
-doc symbol=zwei expr=('command', 'zwei')
diff --git a/tests/qapi-schema/missing-type.err b/tests/qapi-schema/missing-type.err
index 74c4ef7..b3e7b14 100644
--- a/tests/qapi-schema/missing-type.err
+++ b/tests/qapi-schema/missing-type.err
@@ -1 +1 @@
-tests/qapi-schema/missing-type.json:6: Expression is missing metatype
+tests/qapi-schema/missing-type.json:2: Expression is missing metatype
diff --git a/tests/qapi-schema/missing-type.json b/tests/qapi-schema/missing-type.json
index c2fc62d..ff5349d 100644
--- a/tests/qapi-schema/missing-type.json
+++ b/tests/qapi-schema/missing-type.json
@@ -1,6 +1,2 @@
 # we reject an expression with missing metatype
-
-##
-# @foo:
-##
 { 'data': { } }
diff --git a/tests/qapi-schema/nested-struct-data.err b/tests/qapi-schema/nested-struct-data.err
index 379bd1d..da767ba 100644
--- a/tests/qapi-schema/nested-struct-data.err
+++ b/tests/qapi-schema/nested-struct-data.err
@@ -1 +1 @@
-tests/qapi-schema/nested-struct-data.json:6: Member 'a' of 'data' for command 'foo' should be a type name
+tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' should be a type name
diff --git a/tests/qapi-schema/nested-struct-data.json b/tests/qapi-schema/nested-struct-data.json
index 6106e15..efbe773 100644
--- a/tests/qapi-schema/nested-struct-data.json
+++ b/tests/qapi-schema/nested-struct-data.json
@@ -1,7 +1,3 @@
 # inline subtypes collide with our desired future use of defaults
-
-##
-# @foo:
-##
 { 'command': 'foo',
   'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index f4d8cc4..1719463 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -3,153 +3,67 @@
 # This file is a stress test of supported qapi constructs that must
 # parse and compile correctly.
 
-##
-# = Section
-# == subsection
-#
-# Some text foo with *strong* and _emphasis_
-# 1. with a list
-# 2. like that @foo
-#
-# And some code:
-# | $ echo foo
-# | -> do this
-# | <- get that
-#
-# Note: is not a meta
-##
-
-##
-# @TestStruct:
-#
-# body with @var
-#
-# @integer: foo
-#           blah
-#
-#           bao
-#
-# @boolean: bar
-# @string: baz
-#
-# Example:
-#
-# -> { "execute": ... }
-# <- { "return": ... }
-#
-# Since: 2.3
-# Note: a note
-#
-##
 { 'struct': 'TestStruct',
   'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } }
 
-##
-# @NestedEnumsOne:
 # for testing enums
-##
 { 'struct': 'NestedEnumsOne',
   'data': { 'enum1': 'EnumOne',   # Intentional forward reference
             '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
 
-##
-# @MyEnum:
 # An empty enum, although unusual, is currently acceptable
-##
 { 'enum': 'MyEnum', 'data': [ ] }
 
-##
-# @Empty1:
 # Likewise for an empty struct, including an empty base
-##
 { 'struct': 'Empty1', 'data': { } }
-##
-# @Empty2:
-##
 { 'struct': 'Empty2', 'base': 'Empty1', 'data': { } }
 
-##
-# @user_def_cmd0:
-##
 { 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
 
-##
-# @QEnumTwo:
 # for testing override of default naming heuristic
-##
 { 'enum': 'QEnumTwo',
   'prefix': 'QENUM_TWO',
   'data': [ 'value1', 'value2' ] }
 
-##
-# @UserDefOne:
 # for testing nested structs
-##
 { 'struct': 'UserDefOne',
   'base': 'UserDefZero',        # intentional forward reference
   'data': { 'string': 'str',
             '*enum1': 'EnumOne' } }   # intentional forward reference
 
-##
-# @EnumOne:
-##
 { 'enum': 'EnumOne',
   'data': [ 'value1', 'value2', 'value3' ] }
 
-##
-# @UserDefZero:
-##
 { 'struct': 'UserDefZero',
   'data': { 'integer': 'int' } }
 
-##
-# @UserDefTwoDictDict:
-##
 { 'struct': 'UserDefTwoDictDict',
   'data': { 'userdef': 'UserDefOne', 'string': 'str' } }
 
-##
-# @UserDefTwoDict:
-##
 { 'struct': 'UserDefTwoDict',
   'data': { 'string1': 'str',
             'dict2': 'UserDefTwoDictDict',
             '*dict3': 'UserDefTwoDictDict' } }
 
-##
-# @UserDefTwo:
-##
 { 'struct': 'UserDefTwo',
   'data': { 'string0': 'str',
             'dict1': 'UserDefTwoDict' } }
 
-##
-# @ForceArrays:
 # dummy struct to force generation of array types not otherwise mentioned
-##
 { 'struct': 'ForceArrays',
   'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'],
             'unused3':['TestStruct'] } }
 
-##
-# @UserDefA:
 # for testing unions
 # Among other things, test that a name collision between branches does
 # not cause any problems (since only one branch can be in use at a time),
 # by intentionally using two branches that both have a C member 'a_b'
-##
 { 'struct': 'UserDefA',
   'data': { 'boolean': 'bool', '*a_b': 'int' } }
 
-##
-# @UserDefB:
-##
 { 'struct': 'UserDefB',
   'data': { 'intb': 'int', '*a-b': 'bool' } }
 
-##
-# @UserDefFlatUnion:
-##
 { 'union': 'UserDefFlatUnion',
   'base': 'UserDefUnionBase',   # intentional forward reference
   'discriminator': 'enum1',
@@ -157,71 +71,35 @@
             'value2' : 'UserDefB',
             'value3' : 'UserDefB' } }
 
-##
-# @UserDefUnionBase:
-##
 { 'struct': 'UserDefUnionBase',
   'base': 'UserDefZero',
   'data': { 'string': 'str', 'enum1': 'EnumOne' } }
 
-##
-# @UserDefFlatUnion2:
 # this variant of UserDefFlatUnion defaults to a union that uses members with
 # allocated types to test corner cases in the cleanup/dealloc visitor
-##
 { 'union': 'UserDefFlatUnion2',
   'base': { '*integer': 'int', 'string': 'str', 'enum1': 'QEnumTwo' },
   'discriminator': 'enum1',
   'data': { 'value1' : 'UserDefC', # intentional forward reference
             'value2' : 'UserDefB' } }
 
-##
-# @WrapAlternate:
-##
 { 'struct': 'WrapAlternate',
   'data': { 'alt': 'UserDefAlternate' } }
-##
-# @UserDefAlternate:
-##
 { 'alternate': 'UserDefAlternate',
   'data': { 'udfu': 'UserDefFlatUnion', 's': 'str', 'i': 'int' } }
 
-##
-# @UserDefC:
-##
 { 'struct': 'UserDefC',
   'data': { 'string1': 'str', 'string2': 'str' } }
 
 # for testing use of 'number' within alternates
-##
-# @AltStrBool:
-##
 { 'alternate': 'AltStrBool', 'data': { 's': 'str', 'b': 'bool' } }
-##
-# @AltStrNum:
-##
 { 'alternate': 'AltStrNum', 'data': { 's': 'str', 'n': 'number' } }
-##
-# @AltNumStr:
-##
 { 'alternate': 'AltNumStr', 'data': { 'n': 'number', 's': 'str' } }
-##
-# @AltStrInt:
-##
 { 'alternate': 'AltStrInt', 'data': { 's': 'str', 'i': 'int' } }
-##
-# @AltIntNum:
-##
 { 'alternate': 'AltIntNum', 'data': { 'i': 'int', 'n': 'number' } }
-##
-# @AltNumInt:
-##
 { 'alternate': 'AltNumInt', 'data': { 'n': 'number', 'i': 'int' } }
 
-##
-# @UserDefNativeListUnion:
 # for testing native lists
-##
 { 'union': 'UserDefNativeListUnion',
   'data': { 'integer': ['int'],
             's8': ['int8'],
@@ -239,61 +117,19 @@
             'any': ['any'] } }
 
 # testing commands
-##
-# @user_def_cmd:
-##
 { 'command': 'user_def_cmd', 'data': {} }
-##
-# @user_def_cmd1:
-##
 { 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
-##
-# @user_def_cmd2:
-##
 { 'command': 'user_def_cmd2',
   'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'},
   'returns': 'UserDefTwo' }
 
-##
-# Another comment
-##
-
-##
-# @guest-get-time:
-#
-# @guest-get-time body
-#
-# @a: an integer
-# @b: #optional integer
-#
-# Returns: returns something
-#
-# Example:
-#
-# -> { "execute": "guest-get-time", ... }
-# <- { "return": "42" }
-#
-##
-
 # Returning a non-dictionary requires a name from the whitelist
 { 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' },
   'returns': 'int' }
-##
-# @guest-sync:
-##
 { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
-##
-# @boxed-struct:
-##
 { 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' }
-##
-# @boxed-union:
-##
 { 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true }
 
-##
-# @UserDefOptions:
-#
 # For testing integer range flattening in opts-visitor. The following schema
 # corresponds to the option format:
 #
@@ -301,7 +137,6 @@
 #
 # For simplicity, this example doesn't use [type=]discriminator nor optargs
 # specific to discriminator values.
-##
 { 'struct': 'UserDefOptions',
   'data': {
     '*i64' : [ 'int'    ],
@@ -311,83 +146,35 @@
     '*u64x':   'uint64'  } }
 
 # testing event
-##
-# @EventStructOne:
-##
 { 'struct': 'EventStructOne',
   'data': { 'struct1': 'UserDefOne', 'string': 'str', '*enum2': 'EnumOne' } }
 
-##
-# @EVENT_A:
-##
 { 'event': 'EVENT_A' }
-##
-# @EVENT_B:
-##
 { 'event': 'EVENT_B',
   'data': { } }
-##
-# @EVENT_C:
-##
 { 'event': 'EVENT_C',
   'data': { '*a': 'int', '*b': 'UserDefOne', 'c': 'str' } }
-##
-# @EVENT_D:
-##
 { 'event': 'EVENT_D',
   'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } }
-##
-# @EVENT_E:
-##
 { 'event': 'EVENT_E', 'boxed': true, 'data': 'UserDefZero' }
-##
-# @EVENT_F:
-##
 { 'event': 'EVENT_F', 'boxed': true, 'data': 'UserDefAlternate' }
 
 # test that we correctly compile downstream extensions, as well as munge
 # ticklish names
-##
-# @__org.qemu_x-Enum:
-##
 { 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] }
-##
-# @__org.qemu_x-Base:
-##
 { 'struct': '__org.qemu_x-Base',
   'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } }
-##
-# @__org.qemu_x-Struct:
-##
 { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base',
   'data': { '__org.qemu_x-member2': 'str', '*wchar-t': 'int' } }
-##
-# @__org.qemu_x-Union1:
-##
 { 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } }
-##
-# @__org.qemu_x-Struct2:
-##
 { 'struct': '__org.qemu_x-Struct2',
   'data': { 'array': ['__org.qemu_x-Union1'] } }
-##
-# @__org.qemu_x-Union2:
-##
 { 'union': '__org.qemu_x-Union2', 'base': '__org.qemu_x-Base',
   'discriminator': '__org.qemu_x-member1',
   'data': { '__org.qemu_x-value': '__org.qemu_x-Struct2' } }
-##
-# @__org.qemu_x-Alt:
-##
 { 'alternate': '__org.qemu_x-Alt',
   'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
-##
-# @__ORG.QEMU_X-EVENT:
-##
 { 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
-##
-# @__org.qemu_x-command:
-##
 { 'command': '__org.qemu_x-command',
   'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
             'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index bc8d496..9d99c4e 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -232,133 +232,3 @@ command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
    gen=True success_response=True boxed=False
 command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
    gen=True success_response=True boxed=False
-doc freeform
-    body=
-= Section
-== subsection
-
-Some text foo with *strong* and _emphasis_
-1. with a list
-2. like that @foo
-
-And some code:
-| $ echo foo
-| -> do this
-| <- get that
-
-Note: is not a meta
-doc symbol=TestStruct expr=('struct', 'TestStruct')
-    arg=integer
-foo
-blah
-
-bao
-    arg=boolean
-bar
-    arg=string
-baz
-    section=Example
--> { "execute": ... }
-<- { "return": ... }
-    section=Since
-2.3
-    section=Note
-a note
-    body=
-body with @var
-doc symbol=NestedEnumsOne expr=('struct', 'NestedEnumsOne')
-    body=
-for testing enums
-doc symbol=MyEnum expr=('enum', 'MyEnum')
-    body=
-An empty enum, although unusual, is currently acceptable
-doc symbol=Empty1 expr=('struct', 'Empty1')
-    body=
-Likewise for an empty struct, including an empty base
-doc symbol=Empty2 expr=('struct', 'Empty2')
-doc symbol=user_def_cmd0 expr=('command', 'user_def_cmd0')
-doc symbol=QEnumTwo expr=('enum', 'QEnumTwo')
-    body=
-for testing override of default naming heuristic
-doc symbol=UserDefOne expr=('struct', 'UserDefOne')
-    body=
-for testing nested structs
-doc symbol=EnumOne expr=('enum', 'EnumOne')
-doc symbol=UserDefZero expr=('struct', 'UserDefZero')
-doc symbol=UserDefTwoDictDict expr=('struct', 'UserDefTwoDictDict')
-doc symbol=UserDefTwoDict expr=('struct', 'UserDefTwoDict')
-doc symbol=UserDefTwo expr=('struct', 'UserDefTwo')
-doc symbol=ForceArrays expr=('struct', 'ForceArrays')
-    body=
-dummy struct to force generation of array types not otherwise mentioned
-doc symbol=UserDefA expr=('struct', 'UserDefA')
-    body=
-for testing unions
-Among other things, test that a name collision between branches does
-not cause any problems (since only one branch can be in use at a time),
-by intentionally using two branches that both have a C member 'a_b'
-doc symbol=UserDefB expr=('struct', 'UserDefB')
-doc symbol=UserDefFlatUnion expr=('union', 'UserDefFlatUnion')
-doc symbol=UserDefUnionBase expr=('struct', 'UserDefUnionBase')
-doc symbol=UserDefFlatUnion2 expr=('union', 'UserDefFlatUnion2')
-    body=
-this variant of UserDefFlatUnion defaults to a union that uses members with
-allocated types to test corner cases in the cleanup/dealloc visitor
-doc symbol=WrapAlternate expr=('struct', 'WrapAlternate')
-doc symbol=UserDefAlternate expr=('alternate', 'UserDefAlternate')
-doc symbol=UserDefC expr=('struct', 'UserDefC')
-doc symbol=AltStrBool expr=('alternate', 'AltStrBool')
-doc symbol=AltStrNum expr=('alternate', 'AltStrNum')
-doc symbol=AltNumStr expr=('alternate', 'AltNumStr')
-doc symbol=AltStrInt expr=('alternate', 'AltStrInt')
-doc symbol=AltIntNum expr=('alternate', 'AltIntNum')
-doc symbol=AltNumInt expr=('alternate', 'AltNumInt')
-doc symbol=UserDefNativeListUnion expr=('union', 'UserDefNativeListUnion')
-    body=
-for testing native lists
-doc symbol=user_def_cmd expr=('command', 'user_def_cmd')
-doc symbol=user_def_cmd1 expr=('command', 'user_def_cmd1')
-doc symbol=user_def_cmd2 expr=('command', 'user_def_cmd2')
-doc freeform
-    body=
-Another comment
-doc symbol=guest-get-time expr=('command', 'guest-get-time')
-    arg=a
-an integer
-    arg=b
-#optional integer
-    section=Returns
-returns something
-    section=Example
--> { "execute": "guest-get-time", ... }
-<- { "return": "42" }
-    body=
-@guest-get-time body
-doc symbol=guest-sync expr=('command', 'guest-sync')
-doc symbol=boxed-struct expr=('command', 'boxed-struct')
-doc symbol=boxed-union expr=('command', 'boxed-union')
-doc symbol=UserDefOptions expr=('struct', 'UserDefOptions')
-    body=
-For testing integer range flattening in opts-visitor. The following schema
-corresponds to the option format:
-
--userdef i64=3-6,i64=-5--1,u64=2,u16=1,u16=7-12
-
-For simplicity, this example doesn't use [type=]discriminator nor optargs
-specific to discriminator values.
-doc symbol=EventStructOne expr=('struct', 'EventStructOne')
-doc symbol=EVENT_A expr=('event', 'EVENT_A')
-doc symbol=EVENT_B expr=('event', 'EVENT_B')
-doc symbol=EVENT_C expr=('event', 'EVENT_C')
-doc symbol=EVENT_D expr=('event', 'EVENT_D')
-doc symbol=EVENT_E expr=('event', 'EVENT_E')
-doc symbol=EVENT_F expr=('event', 'EVENT_F')
-doc symbol=__org.qemu_x-Enum expr=('enum', '__org.qemu_x-Enum')
-doc symbol=__org.qemu_x-Base expr=('struct', '__org.qemu_x-Base')
-doc symbol=__org.qemu_x-Struct expr=('struct', '__org.qemu_x-Struct')
-doc symbol=__org.qemu_x-Union1 expr=('union', '__org.qemu_x-Union1')
-doc symbol=__org.qemu_x-Struct2 expr=('struct', '__org.qemu_x-Struct2')
-doc symbol=__org.qemu_x-Union2 expr=('union', '__org.qemu_x-Union2')
-doc symbol=__org.qemu_x-Alt expr=('alternate', '__org.qemu_x-Alt')
-doc symbol=__ORG.QEMU_X-EVENT expr=('event', '__ORG.QEMU_X-EVENT')
-doc symbol=__org.qemu_x-command expr=('command', '__org.qemu_x-command')
diff --git a/tests/qapi-schema/redefined-builtin.err b/tests/qapi-schema/redefined-builtin.err
index ee0a2ad..b275722 100644
--- a/tests/qapi-schema/redefined-builtin.err
+++ b/tests/qapi-schema/redefined-builtin.err
@@ -1 +1 @@
-tests/qapi-schema/redefined-builtin.json:6: built-in 'size' is already defined
+tests/qapi-schema/redefined-builtin.json:2: built-in 'size' is already defined
diff --git a/tests/qapi-schema/redefined-builtin.json b/tests/qapi-schema/redefined-builtin.json
index 6d3a940..45b8a55 100644
--- a/tests/qapi-schema/redefined-builtin.json
+++ b/tests/qapi-schema/redefined-builtin.json
@@ -1,6 +1,2 @@
 # we reject types that duplicate builtin names
-
-##
-# @size:
-##
 { 'struct': 'size', 'data': { 'myint': 'size' } }
diff --git a/tests/qapi-schema/redefined-command.err b/tests/qapi-schema/redefined-command.err
index 1e297c4..82ae256 100644
--- a/tests/qapi-schema/redefined-command.err
+++ b/tests/qapi-schema/redefined-command.err
@@ -1 +1 @@
-tests/qapi-schema/redefined-command.json:10: command 'foo' is already defined
+tests/qapi-schema/redefined-command.json:3: command 'foo' is already defined
diff --git a/tests/qapi-schema/redefined-command.json b/tests/qapi-schema/redefined-command.json
index 3a8cb90..247e401 100644
--- a/tests/qapi-schema/redefined-command.json
+++ b/tests/qapi-schema/redefined-command.json
@@ -1,10 +1,3 @@
 # we reject commands defined more than once
-
-##
-# @foo:
-##
 { 'command': 'foo', 'data': { 'one': 'str' } }
-##
-# @foo:
-##
 { 'command': 'foo', 'data': { '*two': 'str' } }
diff --git a/tests/qapi-schema/redefined-event.err b/tests/qapi-schema/redefined-event.err
index 912c785..35429cb 100644
--- a/tests/qapi-schema/redefined-event.err
+++ b/tests/qapi-schema/redefined-event.err
@@ -1 +1 @@
-tests/qapi-schema/redefined-event.json:10: event 'EVENT_A' is already defined
+tests/qapi-schema/redefined-event.json:3: event 'EVENT_A' is already defined
diff --git a/tests/qapi-schema/redefined-event.json b/tests/qapi-schema/redefined-event.json
index ec7aeea..7717e91 100644
--- a/tests/qapi-schema/redefined-event.json
+++ b/tests/qapi-schema/redefined-event.json
@@ -1,10 +1,3 @@
 # we reject duplicate events
-
-##
-# @EVENT_A:
-##
 { 'event': 'EVENT_A', 'data': { 'myint': 'int' } }
-##
-# @EVENT_A:
-##
 { 'event': 'EVENT_A', 'data': { 'myint': 'int' } }
diff --git a/tests/qapi-schema/redefined-type.err b/tests/qapi-schema/redefined-type.err
index 28d87c0..06ea78c 100644
--- a/tests/qapi-schema/redefined-type.err
+++ b/tests/qapi-schema/redefined-type.err
@@ -1 +1 @@
-tests/qapi-schema/redefined-type.json:10: struct 'foo' is already defined
+tests/qapi-schema/redefined-type.json:3: struct 'foo' is already defined
diff --git a/tests/qapi-schema/redefined-type.json b/tests/qapi-schema/redefined-type.json
index 7a8f3e1..a09e768 100644
--- a/tests/qapi-schema/redefined-type.json
+++ b/tests/qapi-schema/redefined-type.json
@@ -1,10 +1,3 @@
 # we reject types defined more than once
-
-##
-# @foo:
-##
 { 'struct': 'foo', 'data': { 'one': 'str' } }
-##
-# @foo:
-##
 { 'enum': 'foo', 'data': [ 'two' ] }
diff --git a/tests/qapi-schema/reserved-command-q.err b/tests/qapi-schema/reserved-command-q.err
index 5e17f31..f939e04 100644
--- a/tests/qapi-schema/reserved-command-q.err
+++ b/tests/qapi-schema/reserved-command-q.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-command-q.json:12: 'command' uses invalid name 'q-unix'
+tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix'
diff --git a/tests/qapi-schema/reserved-command-q.json b/tests/qapi-schema/reserved-command-q.json
index bba0860..99f8aae 100644
--- a/tests/qapi-schema/reserved-command-q.json
+++ b/tests/qapi-schema/reserved-command-q.json
@@ -1,12 +1,5 @@
 # C entity name collision
 # We reject names like 'q-unix', because they can collide with the mangled
 # name for 'unix' in generated C.
-
-##
-# @unix:
-##
 { 'command': 'unix' }
-##
-# @q-unix:
-##
 { 'command': 'q-unix' }
diff --git a/tests/qapi-schema/reserved-enum-q.err b/tests/qapi-schema/reserved-enum-q.err
index acb2df8..e1c3480 100644
--- a/tests/qapi-schema/reserved-enum-q.err
+++ b/tests/qapi-schema/reserved-enum-q.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-enum-q.json:8: Member of enum 'Foo' uses invalid name 'q-Unix'
+tests/qapi-schema/reserved-enum-q.json:4: Member of enum 'Foo' uses invalid name 'q-Unix'
diff --git a/tests/qapi-schema/reserved-enum-q.json b/tests/qapi-schema/reserved-enum-q.json
index 6c7e717..3593a76 100644
--- a/tests/qapi-schema/reserved-enum-q.json
+++ b/tests/qapi-schema/reserved-enum-q.json
@@ -1,8 +1,4 @@
 # C entity name collision
 # We reject names like 'q-unix', because they can collide with the mangled
 # name for 'unix' in generated C.
-
-##
-# @Foo:
-##
 { 'enum': 'Foo', 'data': [ 'unix', 'q-Unix' ] }
diff --git a/tests/qapi-schema/reserved-member-has.err b/tests/qapi-schema/reserved-member-has.err
index 9ace796..e755771 100644
--- a/tests/qapi-schema/reserved-member-has.err
+++ b/tests/qapi-schema/reserved-member-has.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-member-has.json:9: Member of 'data' for command 'oops' uses reserved name 'has-a'
+tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a'
diff --git a/tests/qapi-schema/reserved-member-has.json b/tests/qapi-schema/reserved-member-has.json
index f0d8905..45b9109 100644
--- a/tests/qapi-schema/reserved-member-has.json
+++ b/tests/qapi-schema/reserved-member-has.json
@@ -2,8 +2,4 @@
 # We reject names like 'has-a', because they can collide with the flag
 # for an optional 'a' in generated C.
 # TODO we could munge the optional flag name to avoid the collision.
-
-##
-# @oops:
-##
 { 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
diff --git a/tests/qapi-schema/reserved-member-q.err b/tests/qapi-schema/reserved-member-q.err
index 1709a88..f3d5dd7 100644
--- a/tests/qapi-schema/reserved-member-q.err
+++ b/tests/qapi-schema/reserved-member-q.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-member-q.json:8: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
+tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
diff --git a/tests/qapi-schema/reserved-member-q.json b/tests/qapi-schema/reserved-member-q.json
index f51e312..62fed8f 100644
--- a/tests/qapi-schema/reserved-member-q.json
+++ b/tests/qapi-schema/reserved-member-q.json
@@ -1,8 +1,4 @@
 # C member name collision
 # We reject names like 'q-unix', because they can collide with the mangled
 # name for 'unix' in generated C.
-
-##
-# @Foo:
-##
 { 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }
diff --git a/tests/qapi-schema/reserved-member-u.err b/tests/qapi-schema/reserved-member-u.err
index 6ec69a7..87d4229 100644
--- a/tests/qapi-schema/reserved-member-u.err
+++ b/tests/qapi-schema/reserved-member-u.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-member-u.json:11: Member of 'data' for struct 'Oops' uses reserved name 'u'
+tests/qapi-schema/reserved-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u'
diff --git a/tests/qapi-schema/reserved-member-u.json b/tests/qapi-schema/reserved-member-u.json
index 3a578e5..1eaf0f3 100644
--- a/tests/qapi-schema/reserved-member-u.json
+++ b/tests/qapi-schema/reserved-member-u.json
@@ -4,8 +4,4 @@
 # This is true even for non-unions, because it is possible to convert a
 # struct to flat union while remaining backwards compatible in QMP.
 # TODO - we could munge the member name to 'q_u' to avoid the collision
-
-##
-# @Oops:
-##
 { 'struct': 'Oops', 'data': { 'u': 'str' } }
diff --git a/tests/qapi-schema/reserved-member-underscore.err b/tests/qapi-schema/reserved-member-underscore.err
index c9aefee..65ff0da 100644
--- a/tests/qapi-schema/reserved-member-underscore.err
+++ b/tests/qapi-schema/reserved-member-underscore.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-member-underscore.json:8: Member of 'data' for struct 'Oops' uses invalid name '_oops'
+tests/qapi-schema/reserved-member-underscore.json:4: Member of 'data' for struct 'Oops' uses invalid name '_oops'
diff --git a/tests/qapi-schema/reserved-member-underscore.json b/tests/qapi-schema/reserved-member-underscore.json
index cc34b54..4a3a017 100644
--- a/tests/qapi-schema/reserved-member-underscore.json
+++ b/tests/qapi-schema/reserved-member-underscore.json
@@ -1,8 +1,4 @@
 # C member name collision
 # We reject use of a single leading underscore in all names (names must
 # begin with a letter or a downstream extension double-underscore prefix).
-
-##
-# @Oops:
-##
 { 'struct': 'Oops', 'data': { '_oops': 'str' } }
diff --git a/tests/qapi-schema/reserved-type-kind.err b/tests/qapi-schema/reserved-type-kind.err
index 8698073..0a38efa 100644
--- a/tests/qapi-schema/reserved-type-kind.err
+++ b/tests/qapi-schema/reserved-type-kind.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-type-kind.json:6: enum 'UnionKind' should not end in 'Kind'
+tests/qapi-schema/reserved-type-kind.json:2: enum 'UnionKind' should not end in 'Kind'
diff --git a/tests/qapi-schema/reserved-type-kind.json b/tests/qapi-schema/reserved-type-kind.json
index a094941..9ecaba1 100644
--- a/tests/qapi-schema/reserved-type-kind.json
+++ b/tests/qapi-schema/reserved-type-kind.json
@@ -1,6 +1,2 @@
 # we reject types that would conflict with implicit union enum
-
-##
-# @UnionKind:
-##
 { 'enum': 'UnionKind', 'data': [ 'oops' ] }
diff --git a/tests/qapi-schema/reserved-type-list.err b/tests/qapi-schema/reserved-type-list.err
index ec0531c..4510fa6 100644
--- a/tests/qapi-schema/reserved-type-list.err
+++ b/tests/qapi-schema/reserved-type-list.err
@@ -1 +1 @@
-tests/qapi-schema/reserved-type-list.json:9: struct 'FooList' should not end in 'List'
+tests/qapi-schema/reserved-type-list.json:5: struct 'FooList' should not end in 'List'
diff --git a/tests/qapi-schema/reserved-type-list.json b/tests/qapi-schema/reserved-type-list.json
index 6effb78..98d53bf 100644
--- a/tests/qapi-schema/reserved-type-list.json
+++ b/tests/qapi-schema/reserved-type-list.json
@@ -2,8 +2,4 @@
 # We reserve names ending in 'List' for use by array types.
 # TODO - we could choose array names to avoid collision with user types,
 # in order to let this compile
-
-##
-# @FooList:
-##
 { 'struct': 'FooList', 'data': { 's': 'str' } }
diff --git a/tests/qapi-schema/returns-alternate.err b/tests/qapi-schema/returns-alternate.err
index 2b81623..dfbb419 100644
--- a/tests/qapi-schema/returns-alternate.err
+++ b/tests/qapi-schema/returns-alternate.err
@@ -1 +1 @@
-tests/qapi-schema/returns-alternate.json:10: 'returns' for command 'oops' cannot use alternate type 'Alt'
+tests/qapi-schema/returns-alternate.json:3: 'returns' for command 'oops' cannot use alternate type 'Alt'
diff --git a/tests/qapi-schema/returns-alternate.json b/tests/qapi-schema/returns-alternate.json
index 005bf2d..972390c 100644
--- a/tests/qapi-schema/returns-alternate.json
+++ b/tests/qapi-schema/returns-alternate.json
@@ -1,10 +1,3 @@
 # we reject returns if it is an alternate type
-
-##
-# @Alt:
-##
 { 'alternate': 'Alt', 'data': { 'a': 'int', 'b': 'str' } }
-##
-# @oops:
-##
 { 'command': 'oops', 'returns': 'Alt' }
diff --git a/tests/qapi-schema/returns-array-bad.err b/tests/qapi-schema/returns-array-bad.err
index b53bdb0..138095c 100644
--- a/tests/qapi-schema/returns-array-bad.err
+++ b/tests/qapi-schema/returns-array-bad.err
@@ -1 +1 @@
-tests/qapi-schema/returns-array-bad.json:6: 'returns' for command 'oops': array type must contain single type name
+tests/qapi-schema/returns-array-bad.json:2: 'returns' for command 'oops': array type must contain single type name
diff --git a/tests/qapi-schema/returns-array-bad.json b/tests/qapi-schema/returns-array-bad.json
index 30528fe..09b0b1f 100644
--- a/tests/qapi-schema/returns-array-bad.json
+++ b/tests/qapi-schema/returns-array-bad.json
@@ -1,6 +1,2 @@
 # we reject an array return that is not a single type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'returns': [ 'str', 'str' ] }
diff --git a/tests/qapi-schema/returns-dict.err b/tests/qapi-schema/returns-dict.err
index 1570a35..eb2d0c4 100644
--- a/tests/qapi-schema/returns-dict.err
+++ b/tests/qapi-schema/returns-dict.err
@@ -1 +1 @@
-tests/qapi-schema/returns-dict.json:6: 'returns' for command 'oops' should be a type name
+tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name
diff --git a/tests/qapi-schema/returns-dict.json b/tests/qapi-schema/returns-dict.json
index 6a3ed0f..1cfef3e 100644
--- a/tests/qapi-schema/returns-dict.json
+++ b/tests/qapi-schema/returns-dict.json
@@ -1,6 +1,2 @@
 # we reject inline struct return type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'returns': { 'a': 'str' } }
diff --git a/tests/qapi-schema/returns-unknown.err b/tests/qapi-schema/returns-unknown.err
index d76bcfe..1f43e3a 100644
--- a/tests/qapi-schema/returns-unknown.err
+++ b/tests/qapi-schema/returns-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/returns-unknown.json:6: 'returns' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/returns-unknown.json:2: 'returns' for command 'oops' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/returns-unknown.json b/tests/qapi-schema/returns-unknown.json
index 3837f0e..25bd498 100644
--- a/tests/qapi-schema/returns-unknown.json
+++ b/tests/qapi-schema/returns-unknown.json
@@ -1,6 +1,2 @@
 # we reject returns if it does not contain a known type
-
-##
-# @oops:
-##
 { 'command': 'oops', 'returns': 'NoSuchType' }
diff --git a/tests/qapi-schema/returns-whitelist.err b/tests/qapi-schema/returns-whitelist.err
index e77ea2d..f47c1ee 100644
--- a/tests/qapi-schema/returns-whitelist.err
+++ b/tests/qapi-schema/returns-whitelist.err
@@ -1 +1 @@
-tests/qapi-schema/returns-whitelist.json:26: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
+tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
diff --git a/tests/qapi-schema/returns-whitelist.json b/tests/qapi-schema/returns-whitelist.json
index 0bc952d..e8b3cea 100644
--- a/tests/qapi-schema/returns-whitelist.json
+++ b/tests/qapi-schema/returns-whitelist.json
@@ -1,27 +1,11 @@
 # we enforce that 'returns' be a dict or array of dict unless whitelisted
-
-##
-# @human-monitor-command:
-##
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
   'returns': 'str' }
-##
-# @TpmModel:
-##
 { 'enum': 'TpmModel', 'data': [ 'tpm-tis' ] }
-##
-# @query-tpm-models:
-##
 { 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
-##
-# @guest-get-time:
-##
 { 'command': 'guest-get-time',
   'returns': 'int' }
 
-##
-# @no-way-this-will-get-whitelisted:
-##
 { 'command': 'no-way-this-will-get-whitelisted',
   'returns': [ 'int' ] }
diff --git a/tests/qapi-schema/struct-base-clash-deep.err b/tests/qapi-schema/struct-base-clash-deep.err
index 1b7c0e9..e2d7943 100644
--- a/tests/qapi-schema/struct-base-clash-deep.err
+++ b/tests/qapi-schema/struct-base-clash-deep.err
@@ -1 +1 @@
-tests/qapi-schema/struct-base-clash-deep.json:20: 'name' (member of Sub) collides with 'name' (member of Base)
+tests/qapi-schema/struct-base-clash-deep.json:10: 'name' (member of Sub) collides with 'name' (member of Base)
diff --git a/tests/qapi-schema/struct-base-clash-deep.json b/tests/qapi-schema/struct-base-clash-deep.json
index 646d680..fa873ab 100644
--- a/tests/qapi-schema/struct-base-clash-deep.json
+++ b/tests/qapi-schema/struct-base-clash-deep.json
@@ -2,21 +2,11 @@
 # Here, 'name' would have to appear twice on the wire, locally and
 # indirectly for the grandparent base; the collision doesn't care that
 # one instance is optional.
-
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'name': 'str' } }
-##
-# @Mid:
-##
 { 'struct': 'Mid',
   'base': 'Base',
   'data': { 'value': 'int' } }
-##
-# @Sub:
-##
 { 'struct': 'Sub',
   'base': 'Mid',
   'data': { '*name': 'str' } }
diff --git a/tests/qapi-schema/struct-base-clash.err b/tests/qapi-schema/struct-base-clash.err
index 5fe6393..c52f33d 100644
--- a/tests/qapi-schema/struct-base-clash.err
+++ b/tests/qapi-schema/struct-base-clash.err
@@ -1 +1 @@
-tests/qapi-schema/struct-base-clash.json:12: 'name' (member of Sub) collides with 'name' (member of Base)
+tests/qapi-schema/struct-base-clash.json:5: 'name' (member of Sub) collides with 'name' (member of Base)
diff --git a/tests/qapi-schema/struct-base-clash.json b/tests/qapi-schema/struct-base-clash.json
index a853995..11aec80 100644
--- a/tests/qapi-schema/struct-base-clash.json
+++ b/tests/qapi-schema/struct-base-clash.json
@@ -1,14 +1,7 @@
 # Reject attempts to duplicate QMP members
 # Here, 'name' would have to appear twice on the wire, locally and for base.
-
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'name': 'str' } }
-##
-# @Sub:
-##
 { 'struct': 'Sub',
   'base': 'Base',
   'data': { 'name': 'str' } }
diff --git a/tests/qapi-schema/struct-data-invalid.err b/tests/qapi-schema/struct-data-invalid.err
index 2716335..6644f4c 100644
--- a/tests/qapi-schema/struct-data-invalid.err
+++ b/tests/qapi-schema/struct-data-invalid.err
@@ -1 +1 @@
-tests/qapi-schema/struct-data-invalid.json:4: 'data' for struct 'foo' should be a dictionary or type name
+tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name
diff --git a/tests/qapi-schema/struct-data-invalid.json b/tests/qapi-schema/struct-data-invalid.json
index aa817bd..9adbc3b 100644
--- a/tests/qapi-schema/struct-data-invalid.json
+++ b/tests/qapi-schema/struct-data-invalid.json
@@ -1,5 +1,2 @@
-##
-# @foo:
-##
 { 'struct': 'foo',
   'data': false }
diff --git a/tests/qapi-schema/struct-member-invalid.err b/tests/qapi-schema/struct-member-invalid.err
index f2b105b..69a326d 100644
--- a/tests/qapi-schema/struct-member-invalid.err
+++ b/tests/qapi-schema/struct-member-invalid.err
@@ -1 +1 @@
-tests/qapi-schema/struct-member-invalid.json:4: Member 'a' of 'data' for struct 'foo' should be a type name
+tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name
diff --git a/tests/qapi-schema/struct-member-invalid.json b/tests/qapi-schema/struct-member-invalid.json
index 10c7426..8f172f7 100644
--- a/tests/qapi-schema/struct-member-invalid.json
+++ b/tests/qapi-schema/struct-member-invalid.json
@@ -1,5 +1,2 @@
-##
-# @foo:
-##
 { 'struct': 'foo',
   'data': { 'a': false } }
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index b4cde4f..ef74e2c 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -55,17 +55,3 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
 
 schema = QAPISchema(sys.argv[1])
 schema.visit(QAPISchemaTestVisitor())
-
-for doc in schema.docs:
-    if doc.symbol:
-        print 'doc symbol=%s expr=%s' % \
-            (doc.symbol, doc.expr.items()[0])
-    else:
-        print 'doc freeform'
-    for arg, section in doc.args.iteritems():
-        print '    arg=%s\n%s' % (arg, section)
-    for section in doc.sections:
-        print '    section=%s\n%s' % (section.name, section)
-    body = str(doc.body)
-    if body:
-        print '    body=\n%s' % body
diff --git a/tests/qapi-schema/type-bypass-bad-gen.err b/tests/qapi-schema/type-bypass-bad-gen.err
index bd5431f..a83c3c6 100644
--- a/tests/qapi-schema/type-bypass-bad-gen.err
+++ b/tests/qapi-schema/type-bypass-bad-gen.err
@@ -1 +1 @@
-tests/qapi-schema/type-bypass-bad-gen.json:6: 'gen' of command 'foo' should only use false value
+tests/qapi-schema/type-bypass-bad-gen.json:2: 'gen' of command 'foo' should only use false value
diff --git a/tests/qapi-schema/type-bypass-bad-gen.json b/tests/qapi-schema/type-bypass-bad-gen.json
index 7162c1a..e8dec34 100644
--- a/tests/qapi-schema/type-bypass-bad-gen.json
+++ b/tests/qapi-schema/type-bypass-bad-gen.json
@@ -1,6 +1,2 @@
 # 'gen' should only appear with value false
-
-##
-# @foo:
-##
 { 'command': 'foo', 'gen': 'whatever' }
diff --git a/tests/qapi-schema/unicode-str.err b/tests/qapi-schema/unicode-str.err
index 92ee277..f621cd6 100644
--- a/tests/qapi-schema/unicode-str.err
+++ b/tests/qapi-schema/unicode-str.err
@@ -1 +1 @@
-tests/qapi-schema/unicode-str.json:6: 'command' uses invalid name 'é'
+tests/qapi-schema/unicode-str.json:2: 'command' uses invalid name 'é'
diff --git a/tests/qapi-schema/unicode-str.json b/tests/qapi-schema/unicode-str.json
index 75a08b3..5253a1b 100644
--- a/tests/qapi-schema/unicode-str.json
+++ b/tests/qapi-schema/unicode-str.json
@@ -1,6 +1,2 @@
 # we don't support full Unicode strings, yet
-
-##
-# @e:
-##
 { 'command': 'é' }
diff --git a/tests/qapi-schema/union-base-no-discriminator.err b/tests/qapi-schema/union-base-no-discriminator.err
index ca6ee92..8b7a242 100644
--- a/tests/qapi-schema/union-base-no-discriminator.err
+++ b/tests/qapi-schema/union-base-no-discriminator.err
@@ -1 +1 @@
-tests/qapi-schema/union-base-no-discriminator.json:23: Simple union 'TestUnion' must not have a base
+tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base
diff --git a/tests/qapi-schema/union-base-no-discriminator.json b/tests/qapi-schema/union-base-no-discriminator.json
index cc6bac1..1409cf5 100644
--- a/tests/qapi-schema/union-base-no-discriminator.json
+++ b/tests/qapi-schema/union-base-no-discriminator.json
@@ -1,25 +1,13 @@
-##
-# @TestTypeA:
-##
 # we reject simple unions with a base (or flat unions without discriminator)
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
 
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
 
-##
-# @Base:
-##
 { 'struct': 'Base',
   'data': { 'string': 'str' } }
 
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'Base',
   'data': { 'value1': 'TestTypeA',
diff --git a/tests/qapi-schema/union-branch-case.err b/tests/qapi-schema/union-branch-case.err
index 9095bae..1152190 100644
--- a/tests/qapi-schema/union-branch-case.err
+++ b/tests/qapi-schema/union-branch-case.err
@@ -1 +1 @@
-tests/qapi-schema/union-branch-case.json:6: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase
+tests/qapi-schema/union-branch-case.json:2: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase
diff --git a/tests/qapi-schema/union-branch-case.json b/tests/qapi-schema/union-branch-case.json
index 6de1315..e6565dc 100644
--- a/tests/qapi-schema/union-branch-case.json
+++ b/tests/qapi-schema/union-branch-case.json
@@ -1,6 +1,2 @@
 # Branch names should be 'lower-case' unless the union is whitelisted
-
-##
-# @NoWayThisWillGetWhitelisted:
-##
 { 'union': 'NoWayThisWillGetWhitelisted', 'data': { 'Branch': 'int' } }
diff --git a/tests/qapi-schema/union-clash-branches.err b/tests/qapi-schema/union-clash-branches.err
index 640caea..e5b2113 100644
--- a/tests/qapi-schema/union-clash-branches.err
+++ b/tests/qapi-schema/union-clash-branches.err
@@ -1 +1 @@
-tests/qapi-schema/union-clash-branches.json:8: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion)
+tests/qapi-schema/union-clash-branches.json:4: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion)
diff --git a/tests/qapi-schema/union-clash-branches.json b/tests/qapi-schema/union-clash-branches.json
index 6615665..3bece8c 100644
--- a/tests/qapi-schema/union-clash-branches.json
+++ b/tests/qapi-schema/union-clash-branches.json
@@ -1,9 +1,5 @@
 # Union branch name collision
 # Reject a union that would result in a collision in generated C names (this
 # would try to generate two members 'a_b').
-
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'data': { 'a-b': 'int', 'a_b': 'str' } }
diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err
index 749bc76..12c2022 100644
--- a/tests/qapi-schema/union-empty.err
+++ b/tests/qapi-schema/union-empty.err
@@ -1 +1 @@
-tests/qapi-schema/union-empty.json:6: Union 'Union' cannot have empty 'data'
+tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data'
diff --git a/tests/qapi-schema/union-empty.json b/tests/qapi-schema/union-empty.json
index c9b0a1e..1f0b13c 100644
--- a/tests/qapi-schema/union-empty.json
+++ b/tests/qapi-schema/union-empty.json
@@ -1,6 +1,2 @@
 # unions cannot be empty
-
-##
-# @Union:
-##
 { 'union': 'Union', 'data': { } }
diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err
index 41e238f..03d7b97 100644
--- a/tests/qapi-schema/union-invalid-base.err
+++ b/tests/qapi-schema/union-invalid-base.err
@@ -1 +1 @@
-tests/qapi-schema/union-invalid-base.json:18: 'base' for union 'TestUnion' cannot use built-in type 'int'
+tests/qapi-schema/union-invalid-base.json:8: 'base' for union 'TestUnion' cannot use built-in type 'int'
diff --git a/tests/qapi-schema/union-invalid-base.json b/tests/qapi-schema/union-invalid-base.json
index fd837cb..92be39d 100644
--- a/tests/qapi-schema/union-invalid-base.json
+++ b/tests/qapi-schema/union-invalid-base.json
@@ -1,20 +1,10 @@
 # a union base type must be a struct
-
-##
-# @TestTypeA:
-##
 { 'struct': 'TestTypeA',
   'data': { 'string': 'str' } }
 
-##
-# @TestTypeB:
-##
 { 'struct': 'TestTypeB',
   'data': { 'integer': 'int' } }
 
-##
-# @TestUnion:
-##
 { 'union': 'TestUnion',
   'base': 'int',
   'discriminator': 'int',
diff --git a/tests/qapi-schema/union-optional-branch.err b/tests/qapi-schema/union-optional-branch.err
index 60523c0..3ada133 100644
--- a/tests/qapi-schema/union-optional-branch.err
+++ b/tests/qapi-schema/union-optional-branch.err
@@ -1 +1 @@
-tests/qapi-schema/union-optional-branch.json:6: Member of union 'Union' does not allow optional name '*a'
+tests/qapi-schema/union-optional-branch.json:2: Member of union 'Union' does not allow optional name '*a'
diff --git a/tests/qapi-schema/union-optional-branch.json b/tests/qapi-schema/union-optional-branch.json
index 7d2ee4c..591615f 100644
--- a/tests/qapi-schema/union-optional-branch.json
+++ b/tests/qapi-schema/union-optional-branch.json
@@ -1,6 +1,2 @@
 # union branches cannot be optional
-
-##
-# @Union:
-##
 { 'union': 'Union', 'data': { '*a': 'int', 'b': 'str' } }
diff --git a/tests/qapi-schema/union-unknown.err b/tests/qapi-schema/union-unknown.err
index 5568302..54fe456 100644
--- a/tests/qapi-schema/union-unknown.err
+++ b/tests/qapi-schema/union-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/union-unknown.json:6: Member 'unknown' of union 'Union' uses unknown type 'MissingType'
+tests/qapi-schema/union-unknown.json:2: Member 'unknown' of union 'Union' uses unknown type 'MissingType'
diff --git a/tests/qapi-schema/union-unknown.json b/tests/qapi-schema/union-unknown.json
index 5042b23..aa7e814 100644
--- a/tests/qapi-schema/union-unknown.json
+++ b/tests/qapi-schema/union-unknown.json
@@ -1,7 +1,3 @@
 # we reject a union with unknown type in branch
-
-##
-# @Union:
-##
 { 'union': 'Union',
   'data': { 'unknown': 'MissingType' } }
diff --git a/tests/qapi-schema/unknown-escape.err b/tests/qapi-schema/unknown-escape.err
index 1a4ead6..000e30d 100644
--- a/tests/qapi-schema/unknown-escape.err
+++ b/tests/qapi-schema/unknown-escape.err
@@ -1 +1 @@
-tests/qapi-schema/unknown-escape.json:7:21: Unknown escape \x
+tests/qapi-schema/unknown-escape.json:3:21: Unknown escape \x
diff --git a/tests/qapi-schema/unknown-escape.json b/tests/qapi-schema/unknown-escape.json
index e3ae679..8e6891e 100644
--- a/tests/qapi-schema/unknown-escape.json
+++ b/tests/qapi-schema/unknown-escape.json
@@ -1,7 +1,3 @@
 # we only recognize JSON escape sequences, plus our \' extension (no \x)
-
-##
-# @foo:
-##
 # { 'command': 'foo', 'data': {} }
 { 'command': 'foo', 'dat\x61':{} }
diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err
index b19a668..12f5ed5 100644
--- a/tests/qapi-schema/unknown-expr-key.err
+++ b/tests/qapi-schema/unknown-expr-key.err
@@ -1 +1 @@
-tests/qapi-schema/unknown-expr-key.json:6: Unknown key 'bogus' in struct 'bar'
+tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in struct 'bar'
diff --git a/tests/qapi-schema/unknown-expr-key.json b/tests/qapi-schema/unknown-expr-key.json
index 1b764c7..3b2be00 100644
--- a/tests/qapi-schema/unknown-expr-key.json
+++ b/tests/qapi-schema/unknown-expr-key.json
@@ -1,6 +1,2 @@
 # we reject an expression with unknown top-level keys
-
-##
-# @bar:
-##
 { 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { } }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen'
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (2 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13 22:17   ` Eric Blake
  2017-03-14  8:30   ` Marc-André Lureau
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list Markus Armbruster
                   ` (45 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Section "Commands" qualifies its rules on permitted argument and
return types "with one exception noted below when 'gen' is used".  The
note went away in commit 2d21291.  Clean up the dangling references.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 docs/qapi-code-gen.txt | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 88de5c7..d9c1f91 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -555,22 +555,20 @@ The 'data' argument maps to the "arguments" dictionary passed in as
 part of a Client JSON Protocol command.  The 'data' member is optional
 and defaults to {} (an empty dictionary).  If present, it must be the
 string name of a complex type, or a dictionary that declares an
-anonymous type with the same semantics as a 'struct' expression, with
-one exception noted below when 'gen' is used.
+anonymous type with the same semantics as a 'struct' expression.
 
 The 'returns' member describes what will appear in the "return" member
 of a Client JSON Protocol reply on successful completion of a command.
 The member is optional from the command declaration; if absent, the
 "return" member will be an empty dictionary.  If 'returns' is present,
 it must be the string name of a complex or built-in type, a
-one-element array containing the name of a complex or built-in type,
-with one exception noted below when 'gen' is used.  Although it is
-permitted to have the 'returns' member name a built-in type or an
-array of built-in types, any command that does this cannot be extended
-to return additional information in the future; thus, new commands
-should strongly consider returning a dictionary-based type or an array
-of dictionaries, even if the dictionary only contains one member at the
-present.
+one-element array containing the name of a complex or built-in type.
+Although it is permitted to have the 'returns' member name a built-in
+type or an array of built-in types, any command that does this cannot
+be extended to return additional information in the future; thus, new
+commands should strongly consider returning a dictionary-based type or
+an array of dictionaries, even if the dictionary only contains one
+member at the present.
 
 All commands in Client JSON Protocol use a dictionary to report
 failure, with no way to specify that in QAPI.  Where the error return
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (3 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen' Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13 22:41   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations Markus Armbruster
                   ` (44 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

qapi.py has a hardcoded white-list of command names that may violate
the rules on permitted return types.  Add a new pragma directive
'returns-whitelist', and use it to replace the hard-coded white-list.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 docs/qapi-code-gen.txt                   | 13 +++++++------
 qapi-schema.json                         | 12 ++++++++++++
 qga/qapi-schema.json                     | 15 +++++++++++++++
 scripts/qapi.py                          | 30 +++++++++---------------------
 tests/qapi-schema/qapi-schema-test.json  |  7 +++++++
 tests/qapi-schema/returns-whitelist.err  |  2 +-
 tests/qapi-schema/returns-whitelist.json |  4 ++++
 7 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index d9c1f91..e907e57 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -315,6 +315,9 @@ The dictionary's entries are pragma names and values.
 Pragma 'doc-required' takes a boolean value.  If true, documentation
 is required.  Default is false.
 
+Pragma 'returns-whitelist' takes a list of command names that may
+violate the rules on permitted return types.  Default is none.
+
 
 === Struct types ===
 
@@ -563,12 +566,10 @@ The member is optional from the command declaration; if absent, the
 "return" member will be an empty dictionary.  If 'returns' is present,
 it must be the string name of a complex or built-in type, a
 one-element array containing the name of a complex or built-in type.
-Although it is permitted to have the 'returns' member name a built-in
-type or an array of built-in types, any command that does this cannot
-be extended to return additional information in the future; thus, new
-commands should strongly consider returning a dictionary-based type or
-an array of dictionaries, even if the dictionary only contains one
-member at the present.
+To return anything else, you have to list the command in pragma
+'returns-whitelist'.  If you do this, the command cannot be extended
+to return additional information in the future.  Use of
+'returns-whitelist' for new commands is strongly discouraged.
 
 All commands in Client JSON Protocol use a dictionary to report
 failure, with no way to specify that in QAPI.  Where the error return
diff --git a/qapi-schema.json b/qapi-schema.json
index d5438ee..93e9e98 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -51,6 +51,18 @@
 
 { 'pragma': { 'doc-required': true } }
 
+# Whitelists to permit QAPI rule violations; think twice before you
+# add to them!
+{ 'pragma': {
+    # Commands allowed to return a non-dictionary:
+    'returns-whitelist': [
+        'human-monitor-command',
+        'qom-get',
+        'query-migrate-cache-size',
+        'query-tpm-models',
+        'query-tpm-types',
+        'ringbuf-read' ] } }
+
 # QAPI common definitions
 { 'include': 'qapi/common.json' }
 
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 3f3d428..a8e4bda 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -13,6 +13,21 @@
 
 { 'pragma': { 'doc-required': true } }
 
+# Whitelists to permit QAPI rule violations; think twice before you
+# add to them!
+{ 'pragma': {
+    # Commands allowed to return a non-dictionary:
+    'returns-whitelist': [
+        'guest-file-open',
+        'guest-fsfreeze-freeze',
+        'guest-fsfreeze-freeze-list',
+        'guest-fsfreeze-status',
+        'guest-fsfreeze-thaw',
+        'guest-get-time',
+        'guest-set-vcpus',
+        'guest-sync',
+        'guest-sync-delimited' ] } }
+
 ##
 # @guest-sync-delimited:
 #
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 29a8b77..a90b682 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -41,26 +41,7 @@ builtin_types = {
 doc_required = False
 
 # Whitelist of commands allowed to return a non-dictionary
-returns_whitelist = [
-    # From QMP:
-    'human-monitor-command',
-    'qom-get',
-    'query-migrate-cache-size',
-    'query-tpm-models',
-    'query-tpm-types',
-    'ringbuf-read',
-
-    # From QGA:
-    'guest-file-open',
-    'guest-fsfreeze-freeze',
-    'guest-fsfreeze-freeze-list',
-    'guest-fsfreeze-status',
-    'guest-fsfreeze-thaw',
-    'guest-get-time',
-    'guest-set-vcpus',
-    'guest-sync',
-    'guest-sync-delimited',
-]
+returns_whitelist = []
 
 # Whitelist of entities allowed to violate case conventions
 case_whitelist = [
@@ -317,12 +298,19 @@ class QAPISchemaParser(object):
         self.docs.extend(exprs_include.docs)
 
     def _pragma(self, name, value, info):
-        global doc_required
+        global doc_required, returns_whitelist
         if name == 'doc-required':
             if not isinstance(value, bool):
                 raise QAPISemError(info,
                                    "Pragma 'doc-required' must be boolean")
             doc_required = value
+        elif name == 'returns-whitelist':
+            if (not isinstance(value, list)
+                    or any([not isinstance(elt, str) for elt in value])):
+                raise QAPISemError(info,
+                                   "Pragma returns-whitelist must be"
+                                   " a list of strings")
+            returns_whitelist = value
         else:
             raise QAPISemError(info, "Unknown pragma '%s'" % name)
 
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 1719463..842ea3c 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -3,6 +3,13 @@
 # This file is a stress test of supported qapi constructs that must
 # parse and compile correctly.
 
+# Whitelists to permit QAPI rule violations
+{ 'pragma': {
+    # Commands allowed to return a non-dictionary:
+    'returns-whitelist': [
+        'guest-get-time',
+        'guest-sync' ] } }
+
 { 'struct': 'TestStruct',
   'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } }
 
diff --git a/tests/qapi-schema/returns-whitelist.err b/tests/qapi-schema/returns-whitelist.err
index f47c1ee..b2ba7a9 100644
--- a/tests/qapi-schema/returns-whitelist.err
+++ b/tests/qapi-schema/returns-whitelist.err
@@ -1 +1 @@
-tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
+tests/qapi-schema/returns-whitelist.json:14: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
diff --git a/tests/qapi-schema/returns-whitelist.json b/tests/qapi-schema/returns-whitelist.json
index e8b3cea..da20932 100644
--- a/tests/qapi-schema/returns-whitelist.json
+++ b/tests/qapi-schema/returns-whitelist.json
@@ -1,4 +1,8 @@
 # we enforce that 'returns' be a dict or array of dict unless whitelisted
+
+{ 'pragma': { 'returns-whitelist': [
+    'human-monitor-command', 'query-tpm-models', 'guest-get-time' ] } }
+
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
   'returns': 'str' }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (4 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13 22:46   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation Markus Armbruster
                   ` (43 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

qapi.py has a hardcoded white-list of type names that may violate the
rule on use of upper and lower case.  Add a new pragma directive
'name-case-whitelist', and use it to replace the hard-coded
white-list.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 docs/qapi-code-gen.txt                  |  6 ++++++
 qapi-schema.json                        | 11 ++++++++++-
 scripts/qapi.py                         | 22 ++++++++++------------
 tests/qapi-schema/enum-member-case.err  |  2 +-
 tests/qapi-schema/enum-member-case.json |  1 +
 5 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index e907e57..349dc02 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -252,6 +252,9 @@ Any name (command, event, type, member, or enum value) beginning with
 "x-" is marked experimental, and may be withdrawn or changed
 incompatibly in a future release.
 
+Pragma 'name-case-whitelist' lets you violate the rules on use of
+upper and lower case.  Use for new code is strongly discouraged.
+
 In the rest of this document, usage lines are given for each
 expression type, with literal strings written in lower case and
 placeholders written in capitals.  If a literal string includes a
@@ -318,6 +321,9 @@ is required.  Default is false.
 Pragma 'returns-whitelist' takes a list of command names that may
 violate the rules on permitted return types.  Default is none.
 
+Pragma 'name-case-whitelist' takes a list of names that may violate
+rules on use of upper- vs. lower-case letters.  Default is none.
+
 
 === Struct types ===
 
diff --git a/qapi-schema.json b/qapi-schema.json
index 93e9e98..17c766e 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -61,7 +61,16 @@
         'query-migrate-cache-size',
         'query-tpm-models',
         'query-tpm-types',
-        'ringbuf-read' ] } }
+        'ringbuf-read' ],
+    'name-case-whitelist': [
+        'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
+        'CpuInfoMIPS',          # PC, visible through query-cpu
+        'CpuInfoTricore',       # PC, visible through query-cpu
+        'QapiErrorClass',       # all members, visible through errors
+        'UuidInfo',             # UUID, visible through query-uuid
+        'X86CPURegister32',     # all members, visible indirectly through qom-get
+        'q_obj_CpuInfo-base'    # CPU, visible through query-cpu
+    ] } }
 
 # QAPI common definitions
 { 'include': 'qapi/common.json' }
diff --git a/scripts/qapi.py b/scripts/qapi.py
index a90b682..e98fd0c 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -44,16 +44,7 @@ doc_required = False
 returns_whitelist = []
 
 # Whitelist of entities allowed to violate case conventions
-case_whitelist = [
-    # From QMP:
-    'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
-    'CpuInfoMIPS',          # PC, visible through query-cpu
-    'CpuInfoTricore',       # PC, visible through query-cpu
-    'QapiErrorClass',       # all members, visible through errors
-    'UuidInfo',             # UUID, visible through query-uuid
-    'X86CPURegister32',     # all members, visible indirectly through qom-get
-    'q_obj_CpuInfo-base',   # CPU, visible through query-cpu
-]
+name_case_whitelist = []
 
 enum_types = []
 struct_types = []
@@ -298,7 +289,7 @@ class QAPISchemaParser(object):
         self.docs.extend(exprs_include.docs)
 
     def _pragma(self, name, value, info):
-        global doc_required, returns_whitelist
+        global doc_required, returns_whitelist, name_case_whitelist
         if name == 'doc-required':
             if not isinstance(value, bool):
                 raise QAPISemError(info,
@@ -311,6 +302,13 @@ class QAPISchemaParser(object):
                                    "Pragma returns-whitelist must be"
                                    " a list of strings")
             returns_whitelist = value
+        elif name == 'name-case-whitelist':
+            if (not isinstance(value, list)
+                    or any([not isinstance(elt, str) for elt in value])):
+                raise QAPISemError(info,
+                                   "Pragma name-case-whitelist must be"
+                                   " a list of strings")
+            name_case_whitelist = value
         else:
             raise QAPISemError(info, "Unknown pragma '%s'" % name)
 
@@ -1283,7 +1281,7 @@ class QAPISchemaMember(object):
 
     def check_clash(self, info, seen):
         cname = c_name(self.name)
-        if cname.lower() != cname and self.owner not in case_whitelist:
+        if cname.lower() != cname and self.owner not in name_case_whitelist:
             raise QAPISemError(info,
                                "%s should not use uppercase" % self.describe())
         if cname in seen:
diff --git a/tests/qapi-schema/enum-member-case.err b/tests/qapi-schema/enum-member-case.err
index b652e9a..3c67a3a 100644
--- a/tests/qapi-schema/enum-member-case.err
+++ b/tests/qapi-schema/enum-member-case.err
@@ -1 +1 @@
-tests/qapi-schema/enum-member-case.json:3: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase
+tests/qapi-schema/enum-member-case.json:4: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase
diff --git a/tests/qapi-schema/enum-member-case.json b/tests/qapi-schema/enum-member-case.json
index 2096b35..f8af3e4 100644
--- a/tests/qapi-schema/enum-member-case.json
+++ b/tests/qapi-schema/enum-member-case.json
@@ -1,3 +1,4 @@
 # Member names should be 'lower-case' unless the enum is whitelisted
+{ 'pragma': { 'name-case-whitelist': [ 'UuidInfo' ] } }
 { 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted
 { 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] }
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (5 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 15:55   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base Markus Armbruster
                   ` (42 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Rename intermediate qemu-qapi.texi to qemu-qmp-qapi.texi to match its
user qemu-qmp-ref.texi, just like qemu-ga-qapi.texi matches
qemu-ga-ref.texi.

Build the intermediate .texi next to the sources and the final output
in docs/ instead of dumping them into the build root.

Fix version.texi dependencies so that only the targets that actually
need it depend on it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 .gitignore             | 10 +++++-----
 Makefile               | 27 +++++++++++++++------------
 docs/qemu-qmp-ref.texi |  2 +-
 rules.mak              |  2 +-
 4 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/.gitignore b/.gitignore
index 2849d75..0e99e6a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,11 +103,11 @@
 /docs/qemu-ga-ref.txt
 /docs/qemu-qmp-ref.html
 /docs/qemu-qmp-ref.txt
-docs/qemu-ga-ref.info*
-docs/qemu-qmp-ref.info*
-/qemu-ga-qapi.texi
-/qemu-qapi.texi
-/version.texi
+/docs/qemu-ga-ref.info*
+/docs/qemu-qmp-ref.info*
+/docs/qemu-ga-qapi.texi
+/docs/qemu-qmp-qapi.texi
+/docs/version.texi
 *.tps
 .stgit-*
 cscope.*
diff --git a/Makefile b/Makefile
index 1c4c04f..35d32ee 100644
--- a/Makefile
+++ b/Makefile
@@ -516,7 +516,7 @@ distclean: clean
 	rm -f qemu-doc.vr qemu-doc.txt
 	rm -f config.log
 	rm -f linux-headers/asm
-	rm -f qemu-ga-qapi.texi qemu-qapi.texi version.texi
+	rm -f docs/qemu-ga-qapi.texi docs/qemu-qmp-qapi.texi docs/version.texi
 	rm -f docs/qemu-qmp-ref.7 docs/qemu-ga-ref.7
 	rm -f docs/qemu-qmp-ref.txt docs/qemu-ga-ref.txt
 	rm -f docs/qemu-qmp-ref.pdf docs/qemu-ga-ref.pdf
@@ -663,25 +663,28 @@ ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
 
 # documentation
 MAKEINFO=makeinfo
-MAKEINFOFLAGS=--no-split --number-sections
+MAKEINFOFLAGS=--no-split --number-sections -I docs
 TEXIFLAG=$(if $(V),,--quiet)
 
-version.texi: $(SRC_PATH)/VERSION
+docs/version.texi: $(SRC_PATH)/VERSION
 	$(call quiet-command,echo "@set VERSION $(VERSION)" > $@,"GEN","$@")
 
-%.html: %.texi version.texi
+%.html: %.texi
 	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \
 	--html $< -o $@,"GEN","$@")
 
-%.info: %.texi version.texi
+%.info: %.texi
 	$(call quiet-command,$(MAKEINFO) $(MAKEINFOFLAGS) $< -o $@,"GEN","$@")
 
-%.txt: %.texi version.texi
+%.txt: %.texi
 	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --no-headers \
 	--plaintext $< -o $@,"GEN","$@")
 
-%.pdf: %.texi version.texi
-	$(call quiet-command,texi2pdf $(TEXIFLAG) -I $(SRC_PATH) -I . $< -o $@,"GEN","$@")
+%.pdf: %.texi
+	$(call quiet-command,texi2pdf $(TEXIFLAG) -I $(SRC_PATH) -I docs $< -o $@,"GEN","$@")
+
+docs/qemu-ga-ref.html docs/qemu-ga-ref.info docs/qemu-ga-ref.txt docs/qemu-ga-ref.pdf docs/qemu-ga-ref.7.pod: docs/version.texi
+docs/qemu-qmp-ref.html docs/qemu-qmp-ref.info docs/qemu-qmp-ref.txt docs/qemu-qmp-ref.pdf docs/qemu-qmp-ref.pod: docs/version.texi
 
 qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
@@ -695,10 +698,10 @@ qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxt
 qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
 
-qemu-qapi.texi: $(qapi-modules) $(qapi-py)
+docs/qemu-qmp-qapi.texi: $(qapi-modules) $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
 
-qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
+docs/qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
 	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
 
 qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
@@ -719,10 +722,10 @@ qemu-doc.html qemu-doc.info qemu-doc.pdf qemu-doc.txt: \
 	qemu-monitor-info.texi
 
 docs/qemu-ga-ref.dvi docs/qemu-ga-ref.html docs/qemu-ga-ref.info docs/qemu-ga-ref.pdf docs/qemu-ga-ref.txt docs/qemu-ga-ref.7: \
-docs/qemu-ga-ref.texi qemu-ga-qapi.texi
+docs/qemu-ga-ref.texi docs/qemu-ga-qapi.texi
 
 docs/qemu-qmp-ref.dvi docs/qemu-qmp-ref.html docs/qemu-qmp-ref.info docs/qemu-qmp-ref.pdf docs/qemu-qmp-ref.txt docs/qemu-qmp-ref.7: \
-docs/qemu-qmp-ref.texi qemu-qapi.texi
+docs/qemu-qmp-ref.texi docs/qemu-qmp-qapi.texi
 
 
 ifdef CONFIG_WIN32
diff --git a/docs/qemu-qmp-ref.texi b/docs/qemu-qmp-ref.texi
index 0a00569..bb25758 100644
--- a/docs/qemu-qmp-ref.texi
+++ b/docs/qemu-qmp-ref.texi
@@ -65,7 +65,7 @@ along with this manual.  If not, see http://www.gnu.org/licenses/.
 @c for texi2pod:
 @c man begin DESCRIPTION
 
-@include qemu-qapi.texi
+@include qemu-qmp-qapi.texi
 
 @c man end
 
diff --git a/rules.mak b/rules.mak
index 83d6dd1..1c0eabb 100644
--- a/rules.mak
+++ b/rules.mak
@@ -380,7 +380,7 @@ define unnest-vars
 endef
 
 TEXI2MAN = $(call quiet-command, \
-	perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< $@.pod && \
+	perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl -I docs $< $@.pod && \
 	$(POD2MAN) --section=$(subst .,,$(suffix $@)) --center=" " --release=" " $@.pod > $@, \
 	"GEN","$@")
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (6 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14  8:41   ` Marc-André Lureau
  2017-03-14 15:56   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully Markus Armbruster
                   ` (41 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

The new test case shows off qapi.py choking on an empty union base.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/Makefile.include                  |  1 +
 tests/qapi-schema/union-base-empty.err  | 10 ++++++++++
 tests/qapi-schema/union-base-empty.exit |  1 +
 tests/qapi-schema/union-base-empty.json |  9 +++++++++
 tests/qapi-schema/union-base-empty.out  |  0
 5 files changed, 21 insertions(+)
 create mode 100644 tests/qapi-schema/union-base-empty.err
 create mode 100644 tests/qapi-schema/union-base-empty.exit
 create mode 100644 tests/qapi-schema/union-base-empty.json
 create mode 100644 tests/qapi-schema/union-base-empty.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 736dd15..9f4e890 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -470,6 +470,7 @@ qapi-schema += unclosed-list.json
 qapi-schema += unclosed-object.json
 qapi-schema += unclosed-string.json
 qapi-schema += unicode-str.json
+qapi-schema += union-base-empty.json
 qapi-schema += union-base-no-discriminator.json
 qapi-schema += union-branch-case.json
 qapi-schema += union-clash-branches.json
diff --git a/tests/qapi-schema/union-base-empty.err b/tests/qapi-schema/union-base-empty.err
new file mode 100644
index 0000000..61e6ec6
--- /dev/null
+++ b/tests/qapi-schema/union-base-empty.err
@@ -0,0 +1,10 @@
+Traceback (most recent call last):
+  File "tests/qapi-schema/test-qapi.py", line 56, in <module>
+    schema = QAPISchema(sys.argv[1])
+  File "scripts/qapi.py", line 1483, in __init__
+    self.exprs = check_exprs(parser.exprs)
+  File "scripts/qapi.py", line 917, in check_exprs
+    check_union(expr, info)
+  File "scripts/qapi.py", line 734, in check_union
+    assert base_members
+AssertionError
diff --git a/tests/qapi-schema/union-base-empty.exit b/tests/qapi-schema/union-base-empty.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/union-base-empty.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-base-empty.json b/tests/qapi-schema/union-base-empty.json
new file mode 100644
index 0000000..d1843d3
--- /dev/null
+++ b/tests/qapi-schema/union-base-empty.json
@@ -0,0 +1,9 @@
+# Flat union with empty base and therefore without discriminator
+
+{ 'struct': 'Empty', 'data': { } }
+
+{ 'union': 'TestUnion',
+  'base': 'Empty',
+  'discriminator': 'type',
+  'data': { 'value1': 'int',
+            'value2': 'str' } }
diff --git a/tests/qapi-schema/union-base-empty.out b/tests/qapi-schema/union-base-empty.out
new file mode 100644
index 0000000..e69de29
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (7 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14  8:40   ` Marc-André Lureau
  2017-03-14 15:58   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 10/47] qapi2texi: Fix up output around #optional Markus Armbruster
                   ` (40 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Common Python pitfall: 'assert base_members' fires on [] in addition
to None.  Correct to 'assert base_members is not None'.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                        |  2 +-
 tests/qapi-schema/union-base-empty.err | 11 +----------
 2 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index e98fd0c..eec7bfb 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -731,7 +731,7 @@ def check_union(expr, info):
             raise QAPISemError(info, "Flat union '%s' must have a base"
                                % name)
         base_members = find_base_members(base)
-        assert base_members
+        assert base_members is not None
 
         # The value of member 'discriminator' must name a non-optional
         # member of the base struct.
diff --git a/tests/qapi-schema/union-base-empty.err b/tests/qapi-schema/union-base-empty.err
index 61e6ec6..7695806 100644
--- a/tests/qapi-schema/union-base-empty.err
+++ b/tests/qapi-schema/union-base-empty.err
@@ -1,10 +1 @@
-Traceback (most recent call last):
-  File "tests/qapi-schema/test-qapi.py", line 56, in <module>
-    schema = QAPISchema(sys.argv[1])
-  File "scripts/qapi.py", line 1483, in __init__
-    self.exprs = check_exprs(parser.exprs)
-  File "scripts/qapi.py", line 917, in check_exprs
-    check_union(expr, info)
-  File "scripts/qapi.py", line 734, in check_union
-    assert base_members
-AssertionError
+tests/qapi-schema/union-base-empty.json:5: Discriminator 'type' is not a member of base struct 'Empty'
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 10/47] qapi2texi: Fix up output around #optional
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (8 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14  8:37   ` Marc-André Lureau
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 11/47] qapi: Avoid unwanted blank lines in QAPIDoc Markus Armbruster
                   ` (39 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

We use tag #optional to mark optional members, like this:

    # @name: #optional The name of the guest

texi_body() strips #optional, but not whitespace around it.  For the
above, we get in qemu-qmp-qapi.texi

    @item @code{'name'} (optional)
     The name of the guest
    @end table

The extra space can lead to artifacts in output, e.g in
qemu-qmp-ref.7.pod

    =item C<'name'> (optional)

     The name of the guest

and then in qemu-qmp-ref.7

    .IX Item "name (optional)"
    .Vb 1
    \& The name of the guest
    .Ve

instead of intended plain

    .IX Item "name (optional)"
    The name of the guest

Get rid of these artifacts by removing whitespace around #optional
along with it.

This turns three minus signs in qapi-schema.json into markup, because
they're now at the beginning of the line.  Drop them, they're unwanted
there.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 qapi-schema.json     | 6 +++---
 scripts/qapi2texi.py | 3 ++-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 17c766e..52141cd 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3779,11 +3779,11 @@
 #
 # @dstport: #optional destination port - mandatory for udp, optional for ip
 #
-# @ipv6: #optional - force the use of ipv6
+# @ipv6: #optional force the use of ipv6
 #
-# @udp: #optional - use the udp version of l2tpv3 encapsulation
+# @udp: #optional use the udp version of l2tpv3 encapsulation
 #
-# @cookie64: #optional - use 64 bit coookies
+# @cookie64: #optional use 64 bit coookies
 #
 # @counter: #optional have sequence counter
 #
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 06d6abf..0f3e573 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -137,7 +137,8 @@ def texi_body(doc):
             desc = str(section)
             opt = ''
             if "#optional" in desc:
-                desc = desc.replace("#optional", "")
+                desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
+                              '', desc)
                 opt = ' (optional)'
             body += "@item @code{'%s'}%s\n%s\n" % (arg, opt,
                                                    texi_format(desc))
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 11/47] qapi: Avoid unwanted blank lines in QAPIDoc
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (9 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 10/47] qapi2texi: Fix up output around #optional Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14  8:46   ` Marc-André Lureau
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 12/47] qapi/rocker: Fix up doc comment notes on optional members Markus Armbruster
                   ` (38 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

We silently fix missing #optional tags for QAPIDoc by appending a line
"#optional" to the section's .content.  However, this interferes with
.__repr__ stripping trailing blank lines from .content.

Use new ArgSection instance variable .optional instead, and leave
.content alone.

To permit testing .optional in texi_body(), clean up texi_enum()'s
hack to add empty documentation for undocumented enum values: add an
ArgSection instead of ''.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py      | 5 +++--
 scripts/qapi2texi.py | 4 ++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index eec7bfb..e6d023f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -107,6 +107,7 @@ class QAPIDoc(object):
             self.name = name
             # the list of lines for this section
             self.content = []
+            self.optional = False
 
         def append(self, line):
             self.content.append(line)
@@ -978,15 +979,15 @@ def check_definition_doc(doc, expr, info):
             desc = doc.args.get(arg)
         if not desc:
             continue
+        desc.optional = opt
         desc_opt = "#optional" in str(desc)
         if desc_opt and not opt:
             raise QAPISemError(info, "Description has #optional, "
                                "but the declaration doesn't")
         if not desc_opt and opt:
-            # silently fix the doc
             # TODO either fix the schema and make this an error,
             # or drop #optional entirely
-            desc.append("#optional")
+            pass
 
     doc_args = set(doc.args.keys())
     args = set([name.strip('*') for name in args])
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 0f3e573..0aaf45c 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -136,7 +136,7 @@ def texi_body(doc):
         for arg, section in doc.args.iteritems():
             desc = str(section)
             opt = ''
-            if "#optional" in desc:
+            if section.optional:
                 desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
                               '', desc)
                 opt = ' (optional)'
@@ -185,7 +185,7 @@ def texi_enum(expr, doc):
     """Format an enum to texi"""
     for i in expr['data']:
         if i not in doc.args:
-            doc.args[i] = ''
+            doc.args[i] = qapi.QAPIDoc.ArgSection(i)
     body = texi_body(doc)
     return TYPE_FMT(type="Enum",
                     name=doc.symbol,
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 12/47] qapi/rocker: Fix up doc comment notes on optional members
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (10 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 11/47] qapi: Avoid unwanted blank lines in QAPIDoc Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14  8:49   ` Marc-André Lureau
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 13/47] qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType' Markus Armbruster
                   ` (37 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Talking about #optional like this

    # Note: fields are marked #optional to indicate that they may or may
    # not appear ...

doesn't work so well in generated documentation, because the #optional
tag is not visible there.  Replace by

    # Note: optional members may or may not appear ...

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 qapi/rocker.json | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/qapi/rocker.json b/qapi/rocker.json
index 97e2b83..f374038 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -1,3 +1,5 @@
+# -*- Mode: Python -*-
+
 ##
 # = Rocker switch device
 ##
@@ -137,8 +139,8 @@
 #
 # @ip-dst: #optional IP header destination address
 #
-# Note: fields are marked #optional to indicate that they may or may not
-# appear in the flow key depending if they're relevant to the flow key.
+# Note: optional members may or may not appear in the flow key
+# depending if they're relevant to the flow key.
 #
 # Since: 2.4
 ##
@@ -167,8 +169,8 @@
 #
 # @ip-tos: #optional IP header TOS field
 #
-# Note: fields are marked #optional to indicate that they may or may not
-# appear in the flow mask depending if they're relevant to the flow mask.
+# Note: optional members may or may not appear in the flow mask
+# depending if they're relevant to the flow mask.
 #
 # Since: 2.4
 ##
@@ -194,8 +196,8 @@
 #
 # @out-pport: #optional physical output port
 #
-# Note: fields are marked #optional to indicate that they may or may not
-# appear in the flow action depending if they're relevant to the flow action.
+# Note: optional members may or may not appear in the flow action
+# depending if they're relevant to the flow action.
 #
 # Since: 2.4
 ##
@@ -288,8 +290,8 @@
 #
 # @ttl-check: #optional perform TTL check
 #
-# Note: fields are marked #optional to indicate that they may or may not
-# appear in the group depending if they're relevant to the group type.
+# Note: optional members may or may not appear in the group depending
+# if they're relevant to the group type.
 #
 # Since: 2.4
 ##
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 13/47] qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType'
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (11 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 12/47] qapi/rocker: Fix up doc comment notes on optional members Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 16:03   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 14/47] qapi: Prepare for requiring more complete documentation Markus Armbruster
                   ` (36 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Missed in commit 7264f5c.  Harmless, because nothing checks whether an
enumeration type is implicit so far.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index e6d023f..7a2b6ab 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1148,8 +1148,8 @@ class QAPISchemaEnumType(QAPISchemaType):
             v.check_clash(self.info, seen)
 
     def is_implicit(self):
-        # See QAPISchema._make_implicit_enum_type()
-        return self.name.endswith('Kind')
+        # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
+        return self.name.endswith('Kind') or self.name == 'QType'
 
     def c_type(self):
         return c_name(self.name)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 14/47] qapi: Prepare for requiring more complete documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (12 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 13/47] qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType' Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 16:08   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members Markus Armbruster
                   ` (35 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

We currently neglect to check all enumeration values, common members
of object types and members of alternate types are documented.
Unsurprisingly, many aren't.

Add the necessary plumbing to find undocumented ones, except for
variant members of object types.  Don't enforce anything just yet, but
connect each QAPIDoc.ArgSection to its QAPISchemaMember.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 110 +++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 65 insertions(+), 45 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 7a2b6ab..4886417 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -116,7 +116,12 @@ class QAPIDoc(object):
             return "\n".join(self.content).strip()
 
     class ArgSection(Section):
-        pass
+        def __init__(self, name):
+            QAPIDoc.Section.__init__(self, name)
+            self.member = None
+
+        def connect(self, member):
+            self.member = member
 
     def __init__(self, parser, info):
         # self.parser is used to report errors with QAPIParseError.  The
@@ -216,6 +221,13 @@ class QAPIDoc(object):
             line = line.strip()
         self.section.append(line)
 
+    def connect_member(self, member):
+        if not member.name in self.args:
+            # Undocumented TODO outlaw
+            pass
+        else:
+            self.args[member.name].connect(member)
+
 
 class QAPISchemaParser(object):
 
@@ -1017,7 +1029,7 @@ def check_docs(docs):
 #
 
 class QAPISchemaEntity(object):
-    def __init__(self, name, info):
+    def __init__(self, name, info, doc):
         assert isinstance(name, str)
         self.name = name
         # For explicitly defined entities, info points to the (explicit)
@@ -1026,6 +1038,7 @@ class QAPISchemaEntity(object):
         # triggered the implicit definition (there may be more than one
         # such place).
         self.info = info
+        self.doc = doc
 
     def c_name(self):
         return c_name(self.name)
@@ -1107,7 +1120,7 @@ class QAPISchemaType(QAPISchemaEntity):
 
 class QAPISchemaBuiltinType(QAPISchemaType):
     def __init__(self, name, json_type, c_type):
-        QAPISchemaType.__init__(self, name, None)
+        QAPISchemaType.__init__(self, name, None, None)
         assert not c_type or isinstance(c_type, str)
         assert json_type in ('string', 'number', 'int', 'boolean', 'null',
                              'value')
@@ -1133,8 +1146,8 @@ class QAPISchemaBuiltinType(QAPISchemaType):
 
 
 class QAPISchemaEnumType(QAPISchemaType):
-    def __init__(self, name, info, values, prefix):
-        QAPISchemaType.__init__(self, name, info)
+    def __init__(self, name, info, doc, values, prefix):
+        QAPISchemaType.__init__(self, name, info, doc)
         for v in values:
             assert isinstance(v, QAPISchemaMember)
             v.set_owner(name)
@@ -1146,6 +1159,8 @@ class QAPISchemaEnumType(QAPISchemaType):
         seen = {}
         for v in self.values:
             v.check_clash(self.info, seen)
+            if self.doc:
+                self.doc.connect_member(v)
 
     def is_implicit(self):
         # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
@@ -1167,7 +1182,7 @@ class QAPISchemaEnumType(QAPISchemaType):
 
 class QAPISchemaArrayType(QAPISchemaType):
     def __init__(self, name, info, element_type):
-        QAPISchemaType.__init__(self, name, info)
+        QAPISchemaType.__init__(self, name, info, None)
         assert isinstance(element_type, str)
         self._element_type_name = element_type
         self.element_type = None
@@ -1190,11 +1205,11 @@ class QAPISchemaArrayType(QAPISchemaType):
 
 
 class QAPISchemaObjectType(QAPISchemaType):
-    def __init__(self, name, info, base, local_members, variants):
+    def __init__(self, name, info, doc, base, local_members, variants):
         # struct has local_members, optional base, and no variants
         # flat union has base, variants, and no local_members
         # simple union has local_members, variants, and no base
-        QAPISchemaType.__init__(self, name, info)
+        QAPISchemaType.__init__(self, name, info, doc)
         assert base is None or isinstance(base, str)
         for m in local_members:
             assert isinstance(m, QAPISchemaObjectTypeMember)
@@ -1224,6 +1239,8 @@ class QAPISchemaObjectType(QAPISchemaType):
         for m in self.local_members:
             m.check(schema)
             m.check_clash(self.info, seen)
+            if self.doc:
+                self.doc.connect_member(m)
         self.members = seen.values()
         if self.variants:
             self.variants.check(schema, seen)
@@ -1378,8 +1395,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
 
 
 class QAPISchemaAlternateType(QAPISchemaType):
-    def __init__(self, name, info, variants):
-        QAPISchemaType.__init__(self, name, info)
+    def __init__(self, name, info, doc, variants):
+        QAPISchemaType.__init__(self, name, info, doc)
         assert isinstance(variants, QAPISchemaObjectTypeVariants)
         assert variants.tag_member
         variants.set_owner(name)
@@ -1396,6 +1413,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
         seen = {}
         for v in self.variants.variants:
             v.check_clash(self.info, seen)
+            if self.doc:
+                self.doc.connect_member(v)
 
     def c_type(self):
         return c_name(self.name) + pointer_suffix
@@ -1411,9 +1430,9 @@ class QAPISchemaAlternateType(QAPISchemaType):
 
 
 class QAPISchemaCommand(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type, ret_type, gen, success_response,
-                 boxed):
-        QAPISchemaEntity.__init__(self, name, info)
+    def __init__(self, name, info, doc, arg_type, ret_type,
+                 gen, success_response, boxed):
+        QAPISchemaEntity.__init__(self, name, info, doc)
         assert not arg_type or isinstance(arg_type, str)
         assert not ret_type or isinstance(ret_type, str)
         self._arg_type_name = arg_type
@@ -1450,8 +1469,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
 
 
 class QAPISchemaEvent(QAPISchemaEntity):
-    def __init__(self, name, info, arg_type, boxed):
-        QAPISchemaEntity.__init__(self, name, info)
+    def __init__(self, name, info, doc, arg_type, boxed):
+        QAPISchemaEntity.__init__(self, name, info, doc)
         assert not arg_type or isinstance(arg_type, str)
         self._arg_type_name = arg_type
         self.arg_type = None
@@ -1533,14 +1552,14 @@ class QAPISchema(object):
                   ('bool',   'boolean', 'bool'),
                   ('any',    'value',   'QObject' + pointer_suffix)]:
             self._def_builtin_type(*t)
-        self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
-                                                          None, [], None)
+        self.the_empty_object_type = QAPISchemaObjectType(
+            'q_empty', None, None, None, [], None)
         self._def_entity(self.the_empty_object_type)
         qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
                                                 'qstring', 'qdict', 'qlist',
                                                 'qfloat', 'qbool'])
-        self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
-                                            'QTYPE'))
+        self._def_entity(QAPISchemaEnumType('QType', None, None,
+                                            qtype_values, 'QTYPE'))
 
     def _make_enum_members(self, values):
         return [QAPISchemaMember(v) for v in values]
@@ -1549,7 +1568,7 @@ class QAPISchema(object):
         # See also QAPISchemaObjectTypeMember._pretty_owner()
         name = name + 'Kind'   # Use namespace reserved by add_name()
         self._def_entity(QAPISchemaEnumType(
-            name, info, self._make_enum_members(values), None))
+            name, info, None, self._make_enum_members(values), None))
         return name
 
     def _make_array_type(self, element_type, info):
@@ -1558,22 +1577,22 @@ class QAPISchema(object):
             self._def_entity(QAPISchemaArrayType(name, info, element_type))
         return name
 
-    def _make_implicit_object_type(self, name, info, role, members):
+    def _make_implicit_object_type(self, name, info, doc, role, members):
         if not members:
             return None
         # See also QAPISchemaObjectTypeMember._pretty_owner()
         name = 'q_obj_%s-%s' % (name, role)
         if not self.lookup_entity(name, QAPISchemaObjectType):
-            self._def_entity(QAPISchemaObjectType(name, info, None,
+            self._def_entity(QAPISchemaObjectType(name, info, doc, None,
                                                   members, None))
         return name
 
-    def _def_enum_type(self, expr, info):
+    def _def_enum_type(self, expr, info, doc):
         name = expr['enum']
         data = expr['data']
         prefix = expr.get('prefix')
         self._def_entity(QAPISchemaEnumType(
-            name, info, self._make_enum_members(data), prefix))
+            name, info, doc, self._make_enum_members(data), prefix))
 
     def _make_member(self, name, typ, info):
         optional = False
@@ -1589,11 +1608,11 @@ class QAPISchema(object):
         return [self._make_member(key, value, info)
                 for (key, value) in data.iteritems()]
 
-    def _def_struct_type(self, expr, info):
+    def _def_struct_type(self, expr, info, doc):
         name = expr['struct']
         base = expr.get('base')
         data = expr['data']
-        self._def_entity(QAPISchemaObjectType(name, info, base,
+        self._def_entity(QAPISchemaObjectType(name, info, doc, base,
                                               self._make_members(data, info),
                                               None))
 
@@ -1605,10 +1624,10 @@ class QAPISchema(object):
             assert len(typ) == 1
             typ = self._make_array_type(typ[0], info)
         typ = self._make_implicit_object_type(
-            typ, info, 'wrapper', [self._make_member('data', typ, info)])
+            typ, info, None, 'wrapper', [self._make_member('data', typ, info)])
         return QAPISchemaObjectTypeVariant(case, typ)
 
-    def _def_union_type(self, expr, info):
+    def _def_union_type(self, expr, info, doc):
         name = expr['union']
         data = expr['data']
         base = expr.get('base')
@@ -1616,7 +1635,7 @@ class QAPISchema(object):
         tag_member = None
         if isinstance(base, dict):
             base = (self._make_implicit_object_type(
-                    name, info, 'base', self._make_members(base, info)))
+                    name, info, doc, 'base', self._make_members(base, info)))
         if tag_name:
             variants = [self._make_variant(key, value)
                         for (key, value) in data.iteritems()]
@@ -1629,24 +1648,24 @@ class QAPISchema(object):
             tag_member = QAPISchemaObjectTypeMember('type', typ, False)
             members = [tag_member]
         self._def_entity(
-            QAPISchemaObjectType(name, info, base, members,
+            QAPISchemaObjectType(name, info, doc, base, members,
                                  QAPISchemaObjectTypeVariants(tag_name,
                                                               tag_member,
                                                               variants)))
 
-    def _def_alternate_type(self, expr, info):
+    def _def_alternate_type(self, expr, info, doc):
         name = expr['alternate']
         data = expr['data']
         variants = [self._make_variant(key, value)
                     for (key, value) in data.iteritems()]
         tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
         self._def_entity(
-            QAPISchemaAlternateType(name, info,
+            QAPISchemaAlternateType(name, info, doc,
                                     QAPISchemaObjectTypeVariants(None,
                                                                  tag_member,
                                                                  variants)))
 
-    def _def_command(self, expr, info):
+    def _def_command(self, expr, info, doc):
         name = expr['command']
         data = expr.get('data')
         rets = expr.get('returns')
@@ -1655,38 +1674,39 @@ class QAPISchema(object):
         boxed = expr.get('boxed', False)
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
-                name, info, 'arg', self._make_members(data, info))
+                name, info, doc, 'arg', self._make_members(data, info))
         if isinstance(rets, list):
             assert len(rets) == 1
             rets = self._make_array_type(rets[0], info)
-        self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
-                                           success_response, boxed))
+        self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
+                                           gen, success_response, boxed))
 
-    def _def_event(self, expr, info):
+    def _def_event(self, expr, info, doc):
         name = expr['event']
         data = expr.get('data')
         boxed = expr.get('boxed', False)
         if isinstance(data, OrderedDict):
             data = self._make_implicit_object_type(
-                name, info, 'arg', self._make_members(data, info))
-        self._def_entity(QAPISchemaEvent(name, info, data, boxed))
+                name, info, doc, 'arg', self._make_members(data, info))
+        self._def_entity(QAPISchemaEvent(name, info, doc, data, boxed))
 
     def _def_exprs(self):
         for expr_elem in self.exprs:
             expr = expr_elem['expr']
             info = expr_elem['info']
+            doc = expr_elem.get('doc')
             if 'enum' in expr:
-                self._def_enum_type(expr, info)
+                self._def_enum_type(expr, info, doc)
             elif 'struct' in expr:
-                self._def_struct_type(expr, info)
+                self._def_struct_type(expr, info, doc)
             elif 'union' in expr:
-                self._def_union_type(expr, info)
+                self._def_union_type(expr, info, doc)
             elif 'alternate' in expr:
-                self._def_alternate_type(expr, info)
+                self._def_alternate_type(expr, info, doc)
             elif 'command' in expr:
-                self._def_command(expr, info)
+                self._def_command(expr, info, doc)
             elif 'event' in expr:
-                self._def_event(expr, info)
+                self._def_event(expr, info, doc)
             else:
                 assert False
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (13 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 14/47] qapi: Prepare for requiring more complete documentation Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 17:16   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor Markus Armbruster
                   ` (34 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

qapi2texi.py already conjures up ArgSections for undocumented
enumeration values, in texi_enum).  Drop that, and conjure them up for
all kinds of "arguments" (enumeration values, object and alternate
type members) in qapi.py instead.

Take care to keep generated documentation exactly the same for now.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py      |  5 ++---
 scripts/qapi2texi.py | 31 ++++++++++++++++---------------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 4886417..2a2b33d 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -224,9 +224,8 @@ class QAPIDoc(object):
     def connect_member(self, member):
         if not member.name in self.args:
             # Undocumented TODO outlaw
-            pass
-        else:
-            self.args[member.name].connect(member)
+            self.args[member.name] = QAPIDoc.ArgSection(member.name)
+        self.args[member.name].connect(member)
 
 
 class QAPISchemaParser(object):
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 0aaf45c..299dcf9 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -123,7 +123,7 @@ def texi_format(doc):
     return "\n".join(lines)
 
 
-def texi_body(doc):
+def texi_body(doc, only_documented=False):
     """
     Format the body of a symbol documentation:
     - main body
@@ -131,17 +131,21 @@ def texi_body(doc):
     - followed by "Returns/Notes/Since/Example" sections
     """
     body = texi_format(str(doc.body)) + "\n"
-    if doc.args:
+
+    args = ''
+    for name, section in doc.args.iteritems():
+        if not section.content and not only_documented:
+            continue        # Undocumented TODO require doc and drop
+        desc = str(section)
+        opt = ''
+        if section.optional:
+            desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
+                          '', desc)
+            opt = ' (optional)'
+        args += "@item @code{'%s'}%s\n%s\n" % (name, opt, texi_format(desc))
+    if args:
         body += "@table @asis\n"
-        for arg, section in doc.args.iteritems():
-            desc = str(section)
-            opt = ''
-            if section.optional:
-                desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
-                              '', desc)
-                opt = ' (optional)'
-            body += "@item @code{'%s'}%s\n%s\n" % (arg, opt,
-                                                   texi_format(desc))
+        body += args
         body += "@end table\n"
 
     for section in doc.sections:
@@ -183,10 +187,7 @@ def texi_union(expr, doc):
 
 def texi_enum(expr, doc):
     """Format an enum to texi"""
-    for i in expr['data']:
-        if i not in doc.args:
-            doc.args[i] = qapi.QAPIDoc.ArgSection(i)
-    body = texi_body(doc)
+    body = texi_body(doc, True)
     return TYPE_FMT(type="Enum",
                     name=doc.symbol,
                     body=body)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (14 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 17:31   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop Markus Armbruster
                   ` (33 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

qapi2texi works with schema expression trees.  Such a tight coupling
to schema language syntax is not a good idea.  Convert it to the visitor
interface the other generators use.

No change to generated documentation.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 228 ++++++++++++++++++++++++++-------------------------
 1 file changed, 118 insertions(+), 110 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 299dcf9..6d4e757 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -123,31 +123,39 @@ def texi_format(doc):
     return "\n".join(lines)
 
 
-def texi_body(doc, only_documented=False):
-    """
-    Format the body of a symbol documentation:
-    - main body
-    - table of arguments
-    - followed by "Returns/Notes/Since/Example" sections
-    """
-    body = texi_format(str(doc.body)) + "\n"
-
-    args = ''
-    for name, section in doc.args.iteritems():
-        if not section.content and not only_documented:
-            continue        # Undocumented TODO require doc and drop
-        desc = str(section)
-        opt = ''
-        if section.optional:
-            desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
-                          '', desc)
-            opt = ' (optional)'
-        args += "@item @code{'%s'}%s\n%s\n" % (name, opt, texi_format(desc))
-    if args:
-        body += "@table @asis\n"
-        body += args
-        body += "@end table\n"
+def texi_body(doc):
+    """Format the main documentation body"""
+    return texi_format(str(doc.body)) + '\n'
 
+
+def texi_enum_value(value):
+    """Format a table of members item for an enumeration value"""
+    return "@item @code{'%s'}\n" % value.name
+
+
+def texi_member(member):
+    """Format a table of members item for an object type member"""
+    return "@item @code{'%s'}%s\n" % (
+        member.name, ' (optional)' if member.optional else '')
+
+
+def texi_members(doc, member_func, show_undocumented):
+    """Format the table of members"""
+    items = ''
+    for section in doc.args.itervalues():
+        if not section.content and not show_undocumented:
+            continue          # Undocumented TODO require doc and drop
+        desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
+                      '', str(section))
+        items += member_func(section.member) + texi_format(desc) + '\n'
+    if not items:
+        return ''
+    return '@table @asis\n' + items + '@end table\n'
+
+
+def texi_sections(doc):
+    """Format additional sections following arguments"""
+    body = ''
     for section in doc.sections:
         name, doc = (section.name, str(section))
         func = texi_format
@@ -159,94 +167,94 @@ def texi_body(doc, only_documented=False):
             body += "\n\n@b{%s:}\n" % name
 
         body += func(doc)
-
     return body
 
 
-def texi_alternate(expr, doc):
-    """Format an alternate to texi"""
-    body = texi_body(doc)
-    return TYPE_FMT(type="Alternate",
-                    name=doc.symbol,
-                    body=body)
-
-
-def texi_union(expr, doc):
-    """Format a union to texi"""
-    discriminator = expr.get("discriminator")
-    if discriminator:
-        union = "Flat Union"
-    else:
-        union = "Simple Union"
-
-    body = texi_body(doc)
-    return TYPE_FMT(type=union,
-                    name=doc.symbol,
-                    body=body)
-
-
-def texi_enum(expr, doc):
-    """Format an enum to texi"""
-    body = texi_body(doc, True)
-    return TYPE_FMT(type="Enum",
-                    name=doc.symbol,
-                    body=body)
-
-
-def texi_struct(expr, doc):
-    """Format a struct to texi"""
-    body = texi_body(doc)
-    return TYPE_FMT(type="Struct",
-                    name=doc.symbol,
-                    body=body)
-
-
-def texi_command(expr, doc):
-    """Format a command to texi"""
-    body = texi_body(doc)
-    return MSG_FMT(type="Command",
-                   name=doc.symbol,
-                   body=body)
-
-
-def texi_event(expr, doc):
-    """Format an event to texi"""
-    body = texi_body(doc)
-    return MSG_FMT(type="Event",
-                   name=doc.symbol,
-                   body=body)
-
-
-def texi_expr(expr, doc):
-    """Format an expr to texi"""
-    (kind, _) = expr.items()[0]
-
-    fmt = {"command": texi_command,
-           "struct": texi_struct,
-           "enum": texi_enum,
-           "union": texi_union,
-           "alternate": texi_alternate,
-           "event": texi_event}[kind]
-
-    return fmt(expr, doc)
-
-
-def texi(docs):
-    """Convert QAPI schema expressions to texi documentation"""
-    res = []
-    for doc in docs:
-        expr = doc.expr
-        if not expr:
-            res.append(texi_body(doc))
-            continue
-        try:
-            doc = texi_expr(expr, doc)
-            res.append(doc)
-        except:
-            print >>sys.stderr, "error at @%s" % doc.info
-            raise
-
-    return '\n'.join(res)
+def texi_entity(doc, member_func=texi_member, show_undocumented=False):
+    return (texi_body(doc)
+            + texi_members(doc, member_func, show_undocumented)
+            + texi_sections(doc))
+
+
+class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
+    def __init__(self):
+        self.out = None
+        self.cur_doc = None
+
+    def visit_begin(self, schema):
+        self.out = ''
+
+    def visit_enum_type(self, name, info, values, prefix):
+        doc = self.cur_doc
+        if self.out:
+            self.out += '\n'
+        self.out += TYPE_FMT(type='Enum',
+                             name=doc.symbol,
+                             body=texi_entity(doc,
+                                              member_func=texi_enum_value,
+                                              show_undocumented=True))
+
+    def visit_object_type(self, name, info, base, members, variants):
+        doc = self.cur_doc
+        if not variants:
+            typ = 'Struct'
+        elif variants._tag_name:        # TODO unclean member access
+            typ = 'Flat Union'
+        else:
+            typ = 'Simple Union'
+        if self.out:
+            self.out += '\n'
+        self.out += TYPE_FMT(type=typ,
+                             name=doc.symbol,
+                             body=texi_entity(doc))
+
+    def visit_alternate_type(self, name, info, variants):
+        doc = self.cur_doc
+        if self.out:
+            self.out += '\n'
+        self.out += TYPE_FMT(type='Alternate',
+                             name=doc.symbol,
+                             body=texi_entity(doc))
+
+    def visit_command(self, name, info, arg_type, ret_type,
+                      gen, success_response, boxed):
+        doc = self.cur_doc
+        if self.out:
+            self.out += '\n'
+        self.out += MSG_FMT(type='Command',
+                            name=doc.symbol,
+                            body=texi_entity(doc))
+
+    def visit_event(self, name, info, arg_type, boxed):
+        doc = self.cur_doc
+        if self.out:
+            self.out += '\n'
+        self.out += MSG_FMT(type='Event',
+                            name=doc.symbol,
+                            body=texi_entity(doc))
+
+    def symbol(self, doc, entity):
+        self.cur_doc = doc
+        entity.visit(self)
+        self.cur_doc = None
+
+    def freeform(self, doc):
+        assert not doc.args
+        if self.out:
+            self.out += '\n'
+        self.out += texi_body(doc) + texi_sections(doc)
+
+
+def texi_schema(schema):
+    """Convert QAPI schema documentation to Texinfo"""
+    gen = QAPISchemaGenDocVisitor()
+    gen.visit_begin(schema)
+    for doc in schema.docs:
+        if doc.symbol:
+            gen.symbol(doc, schema.lookup_entity(doc.symbol))
+        else:
+            gen.freeform(doc)
+    return gen.out
 
 
 def main(argv):
@@ -259,7 +267,7 @@ def main(argv):
     if not qapi.doc_required:
         print >>sys.stderr, ("%s: need pragma 'doc-required' "
                              "to generate documentation" % argv[0])
-    print texi(schema.docs)
+    print texi_schema(schema)
 
 
 if __name__ == "__main__":
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (15 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 17:59   ` Eric Blake
  2017-03-14 20:14   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 18/47] qapi: Use raw strings for regular expressions consistently Markus Armbruster
                   ` (32 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

We traditionally mark optional members #optional in the doc comment.
Before commit 3313b61, this was entirely manual.

Commit 3313b61 added some automation because its qapi2texi.py relied
on #optional to determine whether a member is optional.  This is no
longer the case since the previous commit: the only thing qapi2texi.py
still does with #optional is stripping it out.  We still reject bogus
qapi-schema.json and six places for qga/qapi-schema.json.

Thus, you can't actually rely on #optional to see whether something is
optional.  Yet we still make people add it manually.  That's just
busy-work.

Drop the code to check, fix up and strip out #optional, along with all
instances of #optional.  To keep it out, add code to reject it, to be
dropped again once the dust settles.

No change to generated documentation.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 docs/qapi-code-gen.txt              |  16 +-
 docs/writing-qmp-commands.txt       |   4 +-
 qapi-schema.json                    | 378 ++++++++++++++++----------------
 qapi/block-core.json                | 418 ++++++++++++++++++------------------
 qapi/block.json                     |   8 +-
 qapi/crypto.json                    |  22 +-
 qapi/event.json                     |  10 +-
 qapi/introspect.json                |   6 +-
 qapi/rocker.json                    |  70 +++---
 qapi/trace.json                     |   6 +-
 qga/qapi-schema.json                |  38 ++--
 scripts/qapi.py                     |  23 +-
 scripts/qapi2texi.py                |   3 +-
 tests/Makefile.include              |   1 -
 tests/qapi-schema/doc-optional.err  |   1 -
 tests/qapi-schema/doc-optional.exit |   1 -
 tests/qapi-schema/doc-optional.json |   7 -
 tests/qapi-schema/doc-optional.out  |   0
 18 files changed, 491 insertions(+), 521 deletions(-)
 delete mode 100644 tests/qapi-schema/doc-optional.err
 delete mode 100644 tests/qapi-schema/doc-optional.exit
 delete mode 100644 tests/qapi-schema/doc-optional.json
 delete mode 100644 tests/qapi-schema/doc-optional.out

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 349dc02..4767825 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -131,10 +131,8 @@ and optional tagged sections.
 
 FIXME: the parser accepts these things in almost any order.
 
-Optional arguments / members are tagged with the phrase '#optional',
-often with their default value; and extensions added after the
-expression was first released are also given a '(since x.y.z)'
-comment.
+Extensions added after the expression was first released carry a
+'(since x.y.z)' comment.
 
 A tagged section starts with one of the following words:
 "Note:"/"Notes:", "Since:", "Example"/"Examples", "Returns:", "TODO:".
@@ -150,10 +148,10 @@ For example:
 #
 # Statistics of a virtual block device or a block backing device.
 #
-# @device: #optional If the stats are for a virtual block device, the name
-#          corresponding to the virtual block device.
+# @device: If the stats are for a virtual block device, the name
+# corresponding to the virtual block device.
 #
-# @node-name: #optional The node name of the device. (since 2.3)
+# @node-name: The node name of the device. (since 2.3)
 #
 # ... more members ...
 #
@@ -168,8 +166,8 @@ For example:
 #
 # Query the @BlockStats for all virtual block devices.
 #
-# @query-nodes: #optional If true, the command will query all the
-#               block nodes ... explain, explain ...  (since 2.3)
+# @query-nodes: If true, the command will query all the block nodes
+# ... explain, explain ...  (since 2.3)
 #
 # Returns: A list of @BlockStats for each virtual block devices.
 #
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index 44c14db..1e63754 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -252,7 +252,7 @@ here goes "hello-world"'s new entry for the qapi-schema.json file:
 #
 # Print a client provided string to the standard output stream.
 #
-# @message: #optional string to be printed
+# @message: string to be printed
 #
 # Returns: Nothing on success.
 #
@@ -358,7 +358,7 @@ The best way to return that data is to create a new QAPI type, as shown below:
 #
 # @clock-name: The alarm clock method's name.
 #
-# @next-deadline: #optional The time (in nanoseconds) the next alarm will fire.
+# @next-deadline: The time (in nanoseconds) the next alarm will fire.
 #
 # Since: 1.0
 ##
diff --git a/qapi-schema.json b/qapi-schema.json
index 52141cd..d693033 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -150,10 +150,10 @@
 #
 # @fdname: file descriptor name previously passed via 'getfd' command
 #
-# @skipauth: #optional whether to skip authentication. Only applies
+# @skipauth: whether to skip authentication. Only applies
 #            to "vnc" and "spice" protocols
 #
-# @tls: #optional whether to perform TLS. Only applies to the "spice"
+# @tls: whether to perform TLS. Only applies to the "spice"
 #       protocol
 #
 # Returns: nothing on success.
@@ -176,7 +176,7 @@
 #
 # Guest name information.
 #
-# @name: #optional The name of the guest
+# @name: The name of the guest
 #
 # Since: 0.14.0
 ##
@@ -470,7 +470,7 @@
 #
 # @data: data to write
 #
-# @format: #optional data encoding (default 'utf8').
+# @format: data encoding (default 'utf8').
 #          - base64: data must be base64 encoded text.  Its binary
 #            decoding gets written.
 #          - utf8: data's UTF-8 encoding is written
@@ -503,7 +503,7 @@
 #
 # @size: how many bytes to read at most
 #
-# @format: #optional data encoding (default 'utf8').
+# @format: data encoding (default 'utf8').
 #          - base64: the data read is returned in base64 encoding.
 #          - utf8: the data read is interpreted as UTF-8.
 #            Bug: can screw up when the buffer contains invalid UTF-8
@@ -667,45 +667,45 @@
 #
 # Information about current migration process.
 #
-# @status: #optional @MigrationStatus describing the current migration status.
+# @status: @MigrationStatus describing the current migration status.
 #          If this field is not returned, no migration process
 #          has been initiated
 #
-# @ram: #optional @MigrationStats containing detailed migration
+# @ram: @MigrationStats containing detailed migration
 #       status, only returned if status is 'active' or
 #       'completed'(since 1.2)
 #
-# @disk: #optional @MigrationStats containing detailed disk migration
+# @disk: @MigrationStats containing detailed disk migration
 #        status, only returned if status is 'active' and it is a block
 #        migration
 #
-# @xbzrle-cache: #optional @XBZRLECacheStats containing detailed XBZRLE
+# @xbzrle-cache: @XBZRLECacheStats containing detailed XBZRLE
 #                migration statistics, only returned if XBZRLE feature is on and
 #                status is 'active' or 'completed' (since 1.2)
 #
-# @total-time: #optional total amount of milliseconds since migration started.
+# @total-time: total amount of milliseconds since migration started.
 #        If migration has ended, it returns the total migration
 #        time. (since 1.2)
 #
-# @downtime: #optional only present when migration finishes correctly
+# @downtime: only present when migration finishes correctly
 #        total downtime in milliseconds for the guest.
 #        (since 1.3)
 #
-# @expected-downtime: #optional only present while migration is active
+# @expected-downtime: only present while migration is active
 #        expected downtime in milliseconds for the guest in last walk
 #        of the dirty bitmap. (since 1.3)
 #
-# @setup-time: #optional amount of setup time in milliseconds _before_ the
+# @setup-time: amount of setup time in milliseconds _before_ the
 #        iterations begin but _after_ the QMP command is issued. This is designed
 #        to provide an accounting of any activities (such as RDMA pinning) which
 #        may be expensive, but do not actually occur during the iterative
 #        migration rounds themselves. (since 1.6)
 #
-# @cpu-throttle-percentage: #optional percentage of time guest cpus are being
+# @cpu-throttle-percentage: percentage of time guest cpus are being
 #        throttled during auto-converge. This is only present when auto-converge
 #        has started throttling guest cpus. (Since 2.7)
 #
-# @error-desc: #optional the human readable error description string, when
+# @error-desc: the human readable error description string, when
 #              @status is 'failed'. Clients should not attempt to parse the
 #              error strings. (Since 2.7)
 #
@@ -1038,21 +1038,21 @@
 # ('query-migrate-parameters'), with the exception of tls-creds and
 # tls-hostname.
 #
-# @compress-level: #optional compression level
+# @compress-level: compression level
 #
-# @compress-threads: #optional compression thread count
+# @compress-threads: compression thread count
 #
-# @decompress-threads: #optional decompression thread count
+# @decompress-threads: decompression thread count
 #
-# @cpu-throttle-initial: #optional Initial percentage of time guest cpus are
+# @cpu-throttle-initial: Initial percentage of time guest cpus are
 #                        throttledwhen migration auto-converge is activated.
 #                        The default value is 20. (Since 2.7)
 #
-# @cpu-throttle-increment: #optional throttle percentage increase each time
+# @cpu-throttle-increment: throttle percentage increase each time
 #                          auto-converge detects that migration is not making
 #                          progress. The default value is 10. (Since 2.7)
 #
-# @tls-creds: #optional ID of the 'tls-creds' object that provides credentials
+# @tls-creds: ID of the 'tls-creds' object that provides credentials
 #             for establishing a TLS connection over the migration data
 #             channel. On the outgoing side of the migration, the credentials
 #             must be for a 'client' endpoint, while for the incoming side the
@@ -1060,7 +1060,7 @@
 #             will enable TLS for all migrations. The default is unset,
 #             resulting in unsecured migration at the QEMU level. (Since 2.7)
 #
-# @tls-hostname: #optional hostname of the target host for the migration. This
+# @tls-hostname: hostname of the target host for the migration. This
 #                is required when using x509 based TLS credentials and the
 #                migration URI does not already include a hostname. For
 #                example if using fd: or exec: based migration, the
@@ -1125,9 +1125,9 @@
 #
 # @protocol:     must be "spice"
 # @hostname:     migration target hostname
-# @port:         #optional spice tcp port for plaintext channels
-# @tls-port:     #optional spice tcp port for tls-secured channels
-# @cert-subject: #optional server certificate subject
+# @port:         spice tcp port for plaintext channels
+# @tls-port:     spice tcp port for tls-secured channels
+# @cert-subject: server certificate subject
 #
 # Since: 0.14.0
 #
@@ -1547,7 +1547,7 @@
 #
 # The network connection information for server
 #
-# @auth: #optional authentication method used for
+# @auth: authentication method used for
 #        the plain (non-websocket) VNC server
 #
 # Since: 2.1
@@ -1561,10 +1561,10 @@
 #
 # Information about a connected VNC client.
 #
-# @x509_dname: #optional If x509 authentication is in use, the Distinguished
+# @x509_dname: If x509 authentication is in use, the Distinguished
 #              Name of the client.
 #
-# @sasl_username: #optional If SASL authentication is in use, the SASL username
+# @sasl_username: If SASL authentication is in use, the SASL username
 #                 used for authentication.
 #
 # Since: 0.14.0
@@ -1580,19 +1580,19 @@
 #
 # @enabled: true if the VNC server is enabled, false otherwise
 #
-# @host: #optional The hostname the VNC server is bound to.  This depends on
+# @host: The hostname the VNC server is bound to.  This depends on
 #        the name resolution on the host and may be an IP address.
 #
-# @family: #optional 'ipv6' if the host is listening for IPv6 connections
+# @family: 'ipv6' if the host is listening for IPv6 connections
 #                    'ipv4' if the host is listening for IPv4 connections
 #                    'unix' if the host is listening on a unix domain socket
 #                    'unknown' otherwise
 #
-# @service: #optional The service name of the server's port.  This may depends
+# @service: The service name of the server's port.  This may depends
 #           on the host system's service database so symbolic names should not
 #           be relied on.
 #
-# @auth: #optional the current authentication type used by the server
+# @auth: the current authentication type used by the server
 #        'none' if no authentication is being used
 #        'vnc' if VNC authentication is being used
 #        'vencrypt+plain' if VEncrypt is used with plain text authentication
@@ -1647,7 +1647,7 @@
 #
 # @auth: The current authentication type used by the servers
 #
-# @vencrypt: #optional The vencrypt sub authentication type used by the
+# @vencrypt: The vencrypt sub authentication type used by the
 #            servers, only specified in case auth == vencrypt.
 #
 # Since: 2.9
@@ -1675,10 +1675,10 @@
 #
 # @auth: The current authentication type used by the non-websockets servers
 #
-# @vencrypt: #optional The vencrypt authentication type used by the servers,
+# @vencrypt: The vencrypt authentication type used by the servers,
 #            only specified in case auth == vencrypt.
 #
-# @display: #optional The display device the vnc server is linked to.
+# @display: The display device the vnc server is linked to.
 #
 # Since: 2.3
 ##
@@ -1755,7 +1755,7 @@
 #
 # Information about a SPICE server
 #
-# @auth: #optional authentication method
+# @auth: authentication method
 #
 # Since: 2.1
 ##
@@ -1817,16 +1817,16 @@
 # @migrated: true if the last guest migration completed and spice
 #            migration had completed as well. false otherwise. (since 1.4)
 #
-# @host: #optional The hostname the SPICE server is bound to.  This depends on
+# @host: The hostname the SPICE server is bound to.  This depends on
 #        the name resolution on the host and may be an IP address.
 #
-# @port: #optional The SPICE server's port number.
+# @port: The SPICE server's port number.
 #
-# @compiled-version: #optional SPICE server version.
+# @compiled-version: SPICE server version.
 #
-# @tls-port: #optional The SPICE server's TLS port number.
+# @tls-port: The SPICE server's TLS port number.
 #
-# @auth: #optional the current authentication type used by the server
+# @auth: the current authentication type used by the server
 #        'none'  if no authentication is being used
 #        'spice' uses SASL or direct TLS authentication, depending on command
 #                line options
@@ -1951,9 +1951,9 @@
 #
 # @size: memory size
 #
-# @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
+# @prefetch: if @type is 'memory', true if the memory is prefetchable
 #
-# @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
+# @mem_type_64: if @type is 'memory', true if the BAR is 64-bit
 #
 # Since: 0.14.0
 ##
@@ -2009,7 +2009,7 @@
 #
 # Information about the Class of a PCI device
 #
-# @desc: #optional a string description of the device's class
+# @desc: a string description of the device's class
 #
 # @class: the class code of the device
 #
@@ -2047,7 +2047,7 @@
 #
 # @id: the PCI device id
 #
-# @irq: #optional if an IRQ is assigned to the device, the IRQ number
+# @irq: if an IRQ is assigned to the device, the IRQ number
 #
 # @qdev_id: the device name of the PCI device
 #
@@ -2337,7 +2337,7 @@
 #
 # @filename: the file to save the memory to as binary data
 #
-# @cpu-index: #optional the index of the virtual CPU to use for translating the
+# @cpu-index: the index of the virtual CPU to use for translating the
 #                       virtual address (defaults to CPU 0)
 #
 # Returns: Nothing on success
@@ -2566,7 +2566,7 @@
 #
 # Optional arguments to modify the behavior of a Transaction.
 #
-# @completion-mode: #optional Controls how jobs launched asynchronously by
+# @completion-mode: Controls how jobs launched asynchronously by
 #                   Actions will complete or fail as a group.
 #                   See @ActionCompletionMode for details.
 #
@@ -2610,7 +2610,7 @@
 # @actions: List of @TransactionAction;
 #           information needed for the respective operations.
 #
-# @properties: #optional structure of additional options to control the
+# @properties: structure of additional options to control the
 #              execution of the transaction. See @TransactionProperties
 #              for additional detail.
 #
@@ -2659,7 +2659,7 @@
 #
 # @command-line: the command to execute in the human monitor
 #
-# @cpu-index: #optional The CPU to use for commands that require an implicit CPU
+# @cpu-index: The CPU to use for commands that require an implicit CPU
 #
 # Returns: the output of the command as a string
 #
@@ -2895,7 +2895,7 @@
 #
 # @password: the new password
 #
-# @connected: #optional how to handle existing clients when changing the
+# @connected: how to handle existing clients when changing the
 #                       password.  If nothing is specified, defaults to `keep'
 #                       `fail' to fail the command if clients are connected
 #                       `disconnect' to disconnect existing clients
@@ -3054,7 +3054,7 @@
 #
 # @name: the name of the property
 # @type: the typename of the property
-# @description: #optional if specified, the description of the property.
+# @description: if specified, the description of the property.
 #               (since 2.2)
 #
 # Since: 1.2
@@ -3084,9 +3084,9 @@
 #
 # @uri: the Uniform Resource Identifier of the destination VM
 #
-# @blk: #optional do block migration (full disk copy)
+# @blk: do block migration (full disk copy)
 #
-# @inc: #optional incremental disk copy migration
+# @inc: incremental disk copy migration
 #
 # @detach: this argument exists only for compatibility reasons and
 #          is ignored by QEMU
@@ -3195,9 +3195,9 @@
 #
 # @driver: the name of the new device's driver
 #
-# @bus: #optional the device's parent bus (device tree path)
+# @bus: the device's parent bus (device tree path)
 #
-# @id: #optional the device's ID, must be unique
+# @id: the device's ID, must be unique
 #
 # Additional arguments depend on the type.
 #
@@ -3310,17 +3310,17 @@
 #            2. fd: the protocol starts with "fd:", and the following string
 #               is the fd's name.
 #
-# @detach: #optional if true, QMP will return immediately rather than
+# @detach: if true, QMP will return immediately rather than
 #          waiting for the dump to finish. The user can track progress
 #          using "query-dump". (since 2.6).
 #
-# @begin: #optional if specified, the starting physical address.
+# @begin: if specified, the starting physical address.
 #
-# @length: #optional if specified, the memory size, in bytes. If you don't
+# @length: if specified, the memory size, in bytes. If you don't
 #          want to dump all guest's memory, please specify the start @begin
 #          and @length
 #
-# @format: #optional if specified, the format of guest memory dump. But non-elf
+# @format: if specified, the format of guest memory dump. But non-elf
 #          format is conflict with paging and filter, ie. @paging, @begin and
 #          @length is not allowed to be specified with non-elf @format at the
 #          same time (since 2.0)
@@ -3512,7 +3512,7 @@
 #
 # @id: the name of the new object
 #
-# @props: #optional a dictionary of properties to be passed to the backend
+# @props: a dictionary of properties to be passed to the backend
 #
 # Returns: Nothing on success
 #          Error if @qom-type is not a valid class name
@@ -3565,15 +3565,15 @@
 #
 # Create a new Network Interface Card.
 #
-# @netdev: #optional id of -netdev to connect to
+# @netdev: id of -netdev to connect to
 #
-# @macaddr: #optional MAC address
+# @macaddr: MAC address
 #
-# @model: #optional device model (e1000, rtl8139, virtio etc.)
+# @model: device model (e1000, rtl8139, virtio etc.)
 #
-# @addr: #optional PCI device address
+# @addr: PCI device address
 #
-# @vectors: #optional number of MSI-x vectors, 0 to disable MSI-X
+# @vectors: number of MSI-x vectors, 0 to disable MSI-X
 #
 # Since: 1.2
 ##
@@ -3602,57 +3602,57 @@
 # Use the user mode network stack which requires no administrator privilege to
 # run.
 #
-# @hostname: #optional client hostname reported by the builtin DHCP server
+# @hostname: client hostname reported by the builtin DHCP server
 #
-# @restrict: #optional isolate the guest from the host
+# @restrict: isolate the guest from the host
 #
-# @ipv4: #optional whether to support IPv4, default true for enabled
+# @ipv4: whether to support IPv4, default true for enabled
 #        (since 2.6)
 #
-# @ipv6: #optional whether to support IPv6, default true for enabled
+# @ipv6: whether to support IPv6, default true for enabled
 #        (since 2.6)
 #
-# @ip: #optional legacy parameter, use net= instead
+# @ip: legacy parameter, use net= instead
 #
-# @net: #optional IP network address that the guest will see, in the
+# @net: IP network address that the guest will see, in the
 #       form addr[/netmask] The netmask is optional, and can be
 #       either in the form a.b.c.d or as a number of valid top-most
 #       bits. Default is 10.0.2.0/24.
 #
-# @host: #optional guest-visible address of the host
+# @host: guest-visible address of the host
 #
-# @tftp: #optional root directory of the built-in TFTP server
+# @tftp: root directory of the built-in TFTP server
 #
-# @bootfile: #optional BOOTP filename, for use with tftp=
+# @bootfile: BOOTP filename, for use with tftp=
 #
-# @dhcpstart: #optional the first of the 16 IPs the built-in DHCP server can
+# @dhcpstart: the first of the 16 IPs the built-in DHCP server can
 #             assign
 #
-# @dns: #optional guest-visible address of the virtual nameserver
+# @dns: guest-visible address of the virtual nameserver
 #
-# @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
+# @dnssearch: list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
-# @ipv6-prefix: #optional IPv6 network prefix (default is fec0::) (since
+# @ipv6-prefix: IPv6 network prefix (default is fec0::) (since
 #               2.6). The network prefix is given in the usual
 #               hexadecimal IPv6 address notation.
 #
-# @ipv6-prefixlen: #optional IPv6 network prefix length (default is 64)
+# @ipv6-prefixlen: IPv6 network prefix length (default is 64)
 #                  (since 2.6)
 #
-# @ipv6-host: #optional guest-visible IPv6 address of the host (since 2.6)
+# @ipv6-host: guest-visible IPv6 address of the host (since 2.6)
 #
-# @ipv6-dns: #optional guest-visible IPv6 address of the virtual
+# @ipv6-dns: guest-visible IPv6 address of the virtual
 #            nameserver (since 2.6)
 #
-# @smb: #optional root directory of the built-in SMB server
+# @smb: root directory of the built-in SMB server
 #
-# @smbserver: #optional IP address of the built-in SMB server
+# @smbserver: IP address of the built-in SMB server
 #
-# @hostfwd: #optional redirect incoming TCP or UDP host connections to guest
+# @hostfwd: redirect incoming TCP or UDP host connections to guest
 #           endpoints
 #
-# @guestfwd: #optional forward guest TCP connections
+# @guestfwd: forward guest TCP connections
 #
 # Since: 1.2
 ##
@@ -3684,37 +3684,37 @@
 #
 # Connect the host TAP network interface name to the VLAN.
 #
-# @ifname: #optional interface name
+# @ifname: interface name
 #
-# @fd: #optional file descriptor of an already opened tap
+# @fd: file descriptor of an already opened tap
 #
-# @fds: #optional multiple file descriptors of already opened multiqueue capable
+# @fds: multiple file descriptors of already opened multiqueue capable
 # tap
 #
-# @script: #optional script to initialize the interface
+# @script: script to initialize the interface
 #
-# @downscript: #optional script to shut down the interface
+# @downscript: script to shut down the interface
 #
-# @br: #optional bridge name (since 2.8)
+# @br: bridge name (since 2.8)
 #
-# @helper: #optional command to execute to configure bridge
+# @helper: command to execute to configure bridge
 #
-# @sndbuf: #optional send buffer limit. Understands [TGMKkb] suffixes.
+# @sndbuf: send buffer limit. Understands [TGMKkb] suffixes.
 #
-# @vnet_hdr: #optional enable the IFF_VNET_HDR flag on the tap interface
+# @vnet_hdr: enable the IFF_VNET_HDR flag on the tap interface
 #
-# @vhost: #optional enable vhost-net network accelerator
+# @vhost: enable vhost-net network accelerator
 #
-# @vhostfd: #optional file descriptor of an already opened vhost net device
+# @vhostfd: file descriptor of an already opened vhost net device
 #
-# @vhostfds: #optional file descriptors of multiple already opened vhost net
+# @vhostfds: file descriptors of multiple already opened vhost net
 # devices
 #
-# @vhostforce: #optional vhost on for non-MSIX virtio guests
+# @vhostforce: vhost on for non-MSIX virtio guests
 #
-# @queues: #optional number of queues to be created for multiqueue capable tap
+# @queues: number of queues to be created for multiqueue capable tap
 #
-# @poll-us: #optional maximum number of microseconds that could
+# @poll-us: maximum number of microseconds that could
 # be spent on busy polling for tap (since 2.7)
 #
 # Since: 1.2
@@ -3743,17 +3743,17 @@
 # Connect the VLAN to a remote VLAN in another QEMU virtual machine using a TCP
 # socket connection.
 #
-# @fd: #optional file descriptor of an already opened socket
+# @fd: file descriptor of an already opened socket
 #
-# @listen: #optional port number, and optional hostname, to listen on
+# @listen: port number, and optional hostname, to listen on
 #
-# @connect: #optional port number, and optional hostname, to connect to
+# @connect: port number, and optional hostname, to connect to
 #
-# @mcast: #optional UDP multicast address and port number
+# @mcast: UDP multicast address and port number
 #
-# @localaddr: #optional source address and port for multicast and udp packets
+# @localaddr: source address and port for multicast and udp packets
 #
-# @udp: #optional UDP unicast address and port number
+# @udp: UDP unicast address and port number
 #
 # Since: 1.2
 ##
@@ -3775,32 +3775,32 @@
 #
 # @dst: destination address
 #
-# @srcport: #optional source port - mandatory for udp, optional for ip
+# @srcport: source port - mandatory for udp, optional for ip
 #
-# @dstport: #optional destination port - mandatory for udp, optional for ip
+# @dstport: destination port - mandatory for udp, optional for ip
 #
-# @ipv6: #optional force the use of ipv6
+# @ipv6: force the use of ipv6
 #
-# @udp: #optional use the udp version of l2tpv3 encapsulation
+# @udp: use the udp version of l2tpv3 encapsulation
 #
-# @cookie64: #optional use 64 bit coookies
+# @cookie64: use 64 bit coookies
 #
-# @counter: #optional have sequence counter
+# @counter: have sequence counter
 #
-# @pincounter: #optional pin sequence counter to zero -
+# @pincounter: pin sequence counter to zero -
 #              workaround for buggy implementations or
 #              networks with packet reorder
 #
-# @txcookie: #optional 32 or 64 bit transmit cookie
+# @txcookie: 32 or 64 bit transmit cookie
 #
-# @rxcookie: #optional 32 or 64 bit receive cookie
+# @rxcookie: 32 or 64 bit receive cookie
 #
 # @txsession: 32 bit transmit session
 #
-# @rxsession: #optional 32 bit receive session - if not specified
+# @rxsession: 32 bit receive session - if not specified
 #             set to the same value as transmit
 #
-# @offset: #optional additional offset - allows the insertion of
+# @offset: additional offset - allows the insertion of
 #          additional application-specific data before the packet payload
 #
 # Since: 2.1
@@ -3827,13 +3827,13 @@
 #
 # Connect the VLAN to a vde switch running on the host.
 #
-# @sock: #optional socket path
+# @sock: socket path
 #
-# @port: #optional port number
+# @port: port number
 #
-# @group: #optional group owner of socket
+# @group: group owner of socket
 #
-# @mode: #optional permissions for socket
+# @mode: permissions for socket
 #
 # Since: 1.2
 ##
@@ -3849,10 +3849,10 @@
 #
 # Dump VLAN network traffic to a file.
 #
-# @len: #optional per-packet size limit (64k default). Understands [TGMKkb]
+# @len: per-packet size limit (64k default). Understands [TGMKkb]
 # suffixes.
 #
-# @file: #optional dump file path (default is qemu-vlan0.pcap)
+# @file: dump file path (default is qemu-vlan0.pcap)
 #
 # Since: 1.2
 ##
@@ -3866,9 +3866,9 @@
 #
 # Connect a host TAP network interface to a host bridge device.
 #
-# @br: #optional bridge name
+# @br: bridge name
 #
-# @helper: #optional command to execute to configure bridge
+# @helper: command to execute to configure bridge
 #
 # Since: 1.2
 ##
@@ -3902,7 +3902,7 @@
 #          YYY identifies a port of the switch. VALE ports having the
 #          same XXX are therefore connected to the same switch.
 #
-# @devname: #optional path of the netmap device (default: '/dev/netmap').
+# @devname: path of the netmap device (default: '/dev/netmap').
 #
 # Since: 2.0
 ##
@@ -3918,9 +3918,9 @@
 #
 # @chardev: name of a unix socket chardev
 #
-# @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false).
+# @vhostforce: vhost on for non-MSIX virtio guests (default: false).
 #
-# @queues: #optional number of queues to be created for multiqueue vhost-user
+# @queues: number of queues to be created for multiqueue vhost-user
 #          (default: 1) (Since 2.5)
 #
 # Since: 2.1
@@ -3977,11 +3977,11 @@
 #
 # Captures the configuration of a network device; legacy.
 #
-# @vlan: #optional vlan number
+# @vlan: vlan number
 #
-# @id: #optional identifier for monitor commands
+# @id: identifier for monitor commands
 #
-# @name: #optional identifier for monitor commands, ignored if @id is present
+# @name: identifier for monitor commands, ignored if @id is present
 #
 # @opts: device type specific properties (legacy)
 #
@@ -4055,17 +4055,15 @@
 #
 # @port: port part of the address, or lowest port if @to is present
 #
-# @numeric: #optional true if the host/port are guaranteed to be numeric,
+# @numeric: true if the host/port are guaranteed to be numeric,
 #           false if name resolution should be attempted. Defaults to false.
 #           (Since 2.9)
 #
 # @to: highest port to try
 #
 # @ipv4: whether to accept IPv4 addresses, default try both IPv4 and IPv6
-#        #optional
 #
 # @ipv6: whether to accept IPv6 addresses, default try both IPv4 and IPv6
-#        #optional
 #
 # Since: 1.3
 ##
@@ -4213,9 +4211,9 @@
 #
 # @name: the name of the machine
 #
-# @alias: #optional an alias for the machine name
+# @alias: an alias for the machine name
 #
-# @is-default: #optional whether the machine is default
+# @is-default: whether the machine is default
 #
 # @cpu-max: maximum number of CPUs supported by the machine type
 #           (since 1.5.0)
@@ -4247,7 +4245,7 @@
 #
 # @name: the name of the CPU definition
 #
-# @migration-safe: #optional whether a CPU definition can be safely used for
+# @migration-safe: whether a CPU definition can be safely used for
 #                  migration in combination with a QEMU compatibility machine
 #                  when migrating between different QMU versions and between
 #                  hosts with different sets of (hardware or software)
@@ -4259,7 +4257,7 @@
 #          QEMU version, machine type, machine options and accelerator options.
 #          A static model is always migration-safe. (since 2.8)
 #
-# @unavailable-features: #optional List of properties that prevent
+# @unavailable-features: List of properties that prevent
 #                        the CPU model from running in the current
 #                        host. (since 2.8)
 # @typename: Type name that can be used as argument to @device-list-properties,
@@ -4310,7 +4308,7 @@
 # However, if required, architectures can expose relevant properties.
 #
 # @name: the name of the CPU definition the model is based on
-# @props: #optional a dictionary of QOM properties to be applied
+# @props: a dictionary of QOM properties to be applied
 #
 # Since: 2.8.0
 ##
@@ -4559,9 +4557,9 @@
 #
 # Add a file descriptor, that was passed via SCM rights, to an fd set.
 #
-# @fdset-id: #optional The ID of the fd set to add the file descriptor to.
+# @fdset-id: The ID of the fd set to add the file descriptor to.
 #
-# @opaque: #optional A free-form string that can be used to describe the fd.
+# @opaque: A free-form string that can be used to describe the fd.
 #
 # Returns: @AddfdInfo on success
 #
@@ -4591,7 +4589,7 @@
 #
 # @fdset-id: The ID of the fd set that the file descriptor belongs to.
 #
-# @fd: #optional The file descriptor that is to be removed.
+# @fd: The file descriptor that is to be removed.
 #
 # Returns: Nothing on success
 #          If @fdset-id or @fd is not found, FdNotFound
@@ -4618,7 +4616,7 @@
 #
 # @fd: The file descriptor value.
 #
-# @opaque: #optional A free-form string that can be used to describe the fd.
+# @opaque: A free-form string that can be used to describe the fd.
 #
 # Since: 1.2.0
 ##
@@ -4769,7 +4767,7 @@
 #        directly to the guest, while @KeyValue.qcode must be a valid
 #        @QKeyCode value
 #
-# @hold-time: #optional time to delay key up events, milliseconds. Defaults
+# @hold-time: time to delay key up events, milliseconds. Defaults
 #             to 100
 #
 # Returns: Nothing on success
@@ -4815,8 +4813,8 @@
 #
 # Configuration shared across all chardev backends
 #
-# @logfile: #optional The name of a logfile to save output
-# @logappend: #optional true to append instead of truncate
+# @logfile: The name of a logfile to save output
+# @logappend: true to append instead of truncate
 #             (default to false to truncate)
 #
 # Since: 2.6
@@ -4829,9 +4827,9 @@
 #
 # Configuration info for file chardevs.
 #
-# @in:  #optional The name of the input file
+# @in:  The name of the input file
 # @out: The name of the output file
-# @append: #optional Open the file in append mode (default false to
+# @append: Open the file in append mode (default false to
 #          truncate) (Since 2.6)
 #
 # Since: 1.4
@@ -4861,14 +4859,14 @@
 #
 # @addr: socket address to listen on (server=true)
 #        or connect to (server=false)
-# @tls-creds: #optional the ID of the TLS credentials object (since 2.6)
-# @server: #optional create server socket (default: true)
-# @wait: #optional wait for incoming connection on server
+# @tls-creds: the ID of the TLS credentials object (since 2.6)
+# @server: create server socket (default: true)
+# @wait: wait for incoming connection on server
 #        sockets (default: false).
-# @nodelay: #optional set TCP_NODELAY socket option (default: false)
-# @telnet: #optional enable telnet protocol on server
+# @nodelay: set TCP_NODELAY socket option (default: false)
+# @telnet: enable telnet protocol on server
 #          sockets (default: false)
-# @reconnect: #optional For a client socket, if a socket is disconnected,
+# @reconnect: For a client socket, if a socket is disconnected,
 #          then attempt a reconnect after the given number of seconds.
 #          Setting this to zero disables this function. (default: 0)
 #          (Since: 2.2)
@@ -4890,7 +4888,7 @@
 # Configuration info for datagram socket chardevs.
 #
 # @remote: remote address
-# @local: #optional local address
+# @local: local address
 #
 # Since: 1.5
 ##
@@ -4915,7 +4913,7 @@
 #
 # Configuration info for stdio chardevs.
 #
-# @signal: #optional Allow signals (such as SIGINT triggered by ^C)
+# @signal: Allow signals (such as SIGINT triggered by ^C)
 #          be delivered to qemu.  Default: true in -nographic mode,
 #          false otherwise.
 #
@@ -4972,7 +4970,7 @@
 #
 # Configuration info for ring buffer chardevs.
 #
-# @size: #optional ring buffer size, must be power of two, default is 65536
+# @size: ring buffer size, must be power of two, default is 65536
 #
 # Since: 1.5
 ##
@@ -5013,7 +5011,7 @@
 #
 # Return info about the chardev backend just created.
 #
-# @pty: #optional name of the slave pseudoterminal device, present if
+# @pty: name of the slave pseudoterminal device, present if
 #       and only if a chardev of type 'pty' was created
 #
 # Since: 1.4
@@ -5135,9 +5133,9 @@
 #
 # Information about the TPM passthrough type
 #
-# @path: #optional string describing the path used for accessing the TPM device
+# @path: string describing the path used for accessing the TPM device
 #
-# @cancel-path: #optional string showing the TPM's sysfs cancel file
+# @cancel-path: string showing the TPM's sysfs cancel file
 #               for cancellation of TPM commands while they are executing
 #
 # Since: 1.5
@@ -5223,28 +5221,28 @@
 # String fields are copied into the matching ACPI member from lowest address
 # upwards, and silently truncated / NUL-padded to length.
 #
-# @sig: #optional table signature / identifier (4 bytes)
+# @sig: table signature / identifier (4 bytes)
 #
-# @rev: #optional table revision number (dependent on signature, 1 byte)
+# @rev: table revision number (dependent on signature, 1 byte)
 #
-# @oem_id: #optional OEM identifier (6 bytes)
+# @oem_id: OEM identifier (6 bytes)
 #
-# @oem_table_id: #optional OEM table identifier (8 bytes)
+# @oem_table_id: OEM table identifier (8 bytes)
 #
-# @oem_rev: #optional OEM-supplied revision number (4 bytes)
+# @oem_rev: OEM-supplied revision number (4 bytes)
 #
-# @asl_compiler_id: #optional identifier of the utility that created the table
+# @asl_compiler_id: identifier of the utility that created the table
 #                   (4 bytes)
 #
-# @asl_compiler_rev: #optional revision number of the utility that created the
+# @asl_compiler_rev: revision number of the utility that created the
 #                    table (4 bytes)
 #
-# @file: #optional colon (:) separated list of pathnames to load and
+# @file: colon (:) separated list of pathnames to load and
 #        concatenate as table data. The resultant binary blob is expected to
 #        have an ACPI table header. At least one file is required. This field
 #        excludes @data.
 #
-# @data: #optional colon (:) separated list of pathnames to load and
+# @data: colon (:) separated list of pathnames to load and
 #        concatenate as table data. The resultant binary blob must not have an
 #        ACPI table header. At least one file is required. This field excludes
 #        @file.
@@ -5291,9 +5289,9 @@
 #
 # @type: parameter @CommandLineParameterType
 #
-# @help: #optional human readable text string, not suitable for parsing.
+# @help: human readable text string, not suitable for parsing.
 #
-# @default: #optional default value string (since 2.1)
+# @default: default value string (since 2.1)
 #
 # Since: 1.5
 ##
@@ -5322,7 +5320,7 @@
 #
 # Query command line option schema.
 #
-# @option: #optional option name
+# @option: option name
 #
 # Returns: list of @CommandLineOptionInfo for all options (or for the given
 #          @option).  Returns an error if the given @option doesn't exist.
@@ -5371,7 +5369,7 @@
 #
 # @cpuid-input-eax: Input EAX value for CPUID instruction for that feature word
 #
-# @cpuid-input-ecx: #optional Input ECX value for CPUID instruction for that
+# @cpuid-input-ecx: Input ECX value for CPUID instruction for that
 #                   feature word
 #
 # @cpuid-register: Output register containing the feature bits
@@ -5463,7 +5461,7 @@
 #
 # Return rx-filter information for all NICs (or for the given NIC).
 #
-# @name: #optional net client name
+# @name: net client name
 #
 # Returns: list of @RxFilterInfo for all NICs (or for the given NIC).
 #          Returns an error if the given @name doesn't exist, or given
@@ -5597,8 +5595,8 @@
 #
 # Send input event(s) to guest.
 #
-# @device: #optional display device to send event(s) to.
-# @head: #optional head to send event(s) to, in case the
+# @device: display device to send event(s) to.
+# @head: head to send event(s) to, in case the
 #        display device supports multiple scanouts.
 # @events: List of InputEvent union.
 #
@@ -5690,16 +5688,16 @@
 #
 # Create a guest NUMA node. (for OptsVisitor)
 #
-# @nodeid: #optional NUMA node ID (increase by 1 from 0 if omitted)
+# @nodeid: NUMA node ID (increase by 1 from 0 if omitted)
 #
-# @cpus: #optional VCPUs belonging to this node (assign VCPUS round-robin
+# @cpus: VCPUs belonging to this node (assign VCPUS round-robin
 #         if omitted)
 #
-# @mem: #optional memory size of this node; mutually exclusive with @memdev.
+# @mem: memory size of this node; mutually exclusive with @memdev.
 #       Equally divide total memory among nodes if both @mem and @memdev are
 #       omitted.
 #
-# @memdev: #optional memory backend object.  If specified for one node,
+# @memdev: memory backend object.  If specified for one node,
 #          it must be specified for all nodes.
 #
 # Since: 2.1
@@ -5736,7 +5734,7 @@
 #
 # Information about memory backend
 #
-# @id: #optional backend's ID if backend has 'id' property (since 2.9)
+# @id: backend's ID if backend has 'id' property (since 2.9)
 #
 # @size: memory backend size
 #
@@ -5803,7 +5801,7 @@
 #
 # PCDIMMDevice state information
 #
-# @id: #optional device's ID
+# @id: device's ID
 #
 # @addr: physical address, where device is mapped
 #
@@ -5882,7 +5880,7 @@
 # For description of possible values of @source and @status fields
 # see "_OST (OSPM Status Indication)" chapter of ACPI5.0 spec.
 #
-# @device: #optional device ID associated with slot
+# @device: device ID associated with slot
 #
 # @slot: slot ID, unique per slot of a given @slot-type
 #
@@ -6080,7 +6078,7 @@
 #
 # @primary: true for primary or false for secondary.
 #
-# @failover: #optional true to do failover, false to stop. but cannot be
+# @failover: true to do failover, false to stop. but cannot be
 #            specified if 'enable' is true. default value is false.
 #
 # Returns: nothing.
@@ -6103,7 +6101,7 @@
 #
 # @error: true if an error happened, false if replication is normal.
 #
-# @desc: #optional the human readable error description string, when
+# @desc: the human readable error description string, when
 #        @error is 'true'.
 #
 # Since: 2.9
@@ -6194,10 +6192,10 @@
 # it should be passed by management with device_add command when
 # a CPU is being hotplugged.
 #
-# @node-id: #optional NUMA node ID the CPU belongs to
-# @socket-id: #optional socket number within node/board the CPU belongs to
-# @core-id: #optional core number within socket the CPU belongs to
-# @thread-id: #optional thread number within core the CPU belongs to
+# @node-id: NUMA node ID the CPU belongs to
+# @socket-id: socket number within node/board the CPU belongs to
+# @core-id: core number within socket the CPU belongs to
+# @thread-id: thread number within core the CPU belongs to
 #
 # Note: currently there are 4 properties that could be present
 # but management should be prepared to pass through other
@@ -6221,7 +6219,7 @@
 # @type: CPU object type for usage with device_add command
 # @props: list of properties to be used for hotplugging CPU
 # @vcpus-count: number of logical VCPU threads @HotpluggableCPU provides
-# @qom-path: #optional link to existing CPU object if CPU is present or
+# @qom-path: link to existing CPU object if CPU is present or
 #            omitted if CPU is not present.
 #
 # Since: 2.7
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 9bb7f4a..539649c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -37,9 +37,9 @@
 #
 # @compat: compatibility level
 #
-# @lazy-refcounts: #optional on or off; only valid for compat >= 1.1
+# @lazy-refcounts: on or off; only valid for compat >= 1.1
 #
-# @corrupt: #optional true if the image has been marked corrupt; only valid for
+# @corrupt: true if the image has been marked corrupt; only valid for
 #           compat >= 1.1 (since 2.2)
 #
 # @refcount-bits: width of a refcount entry in bits (since 2.3)
@@ -103,27 +103,27 @@
 #
 # @virtual-size: maximum capacity in bytes of the image
 #
-# @actual-size: #optional actual size on disk in bytes of the image
+# @actual-size: actual size on disk in bytes of the image
 #
-# @dirty-flag: #optional true if image is not cleanly closed
+# @dirty-flag: true if image is not cleanly closed
 #
-# @cluster-size: #optional size of a cluster in bytes
+# @cluster-size: size of a cluster in bytes
 #
-# @encrypted: #optional true if the image is encrypted
+# @encrypted: true if the image is encrypted
 #
-# @compressed: #optional true if the image is compressed (Since 1.7)
+# @compressed: true if the image is compressed (Since 1.7)
 #
-# @backing-filename: #optional name of the backing file
+# @backing-filename: name of the backing file
 #
-# @full-backing-filename: #optional full path of the backing file
+# @full-backing-filename: full path of the backing file
 #
-# @backing-filename-format: #optional the format of the backing file
+# @backing-filename-format: the format of the backing file
 #
-# @snapshots: #optional list of VM snapshots
+# @snapshots: list of VM snapshots
 #
-# @backing-image: #optional info of the backing image (since 1.6)
+# @backing-image: info of the backing image (since 1.6)
 #
-# @format-specific: #optional structure supplying additional format-specific
+# @format-specific: structure supplying additional format-specific
 # information (since 1.7)
 #
 # Since: 1.3
@@ -149,31 +149,31 @@
 #
 # @check-errors: number of unexpected errors occurred during check
 #
-# @image-end-offset: #optional offset (in bytes) where the image ends, this
+# @image-end-offset: offset (in bytes) where the image ends, this
 #                    field is present if the driver for the image format
 #                    supports it
 #
-# @corruptions: #optional number of corruptions found during the check if any
+# @corruptions: number of corruptions found during the check if any
 #
-# @leaks: #optional number of leaks found during the check if any
+# @leaks: number of leaks found during the check if any
 #
-# @corruptions-fixed: #optional number of corruptions fixed during the check
+# @corruptions-fixed: number of corruptions fixed during the check
 #                     if any
 #
-# @leaks-fixed: #optional number of leaks fixed during the check if any
+# @leaks-fixed: number of leaks fixed during the check if any
 #
-# @total-clusters: #optional total number of clusters, this field is present
+# @total-clusters: total number of clusters, this field is present
 #                  if the driver for the image format supports it
 #
-# @allocated-clusters: #optional total number of allocated clusters, this
+# @allocated-clusters: total number of allocated clusters, this
 #                      field is present if the driver for the image format
 #                      supports it
 #
-# @fragmented-clusters: #optional total number of fragmented clusters, this
+# @fragmented-clusters: total number of fragmented clusters, this
 #                       field is present if the driver for the image format
 #                       supports it
 #
-# @compressed-clusters: #optional total number of compressed clusters, this
+# @compressed-clusters: total number of compressed clusters, this
 #                       field is present if the driver for the image format
 #                       supports it
 #
@@ -202,9 +202,9 @@
 #
 # @depth: the depth of the mapping
 #
-# @offset: #optional the offset in file that the virtual sectors are mapped to
+# @offset: the offset in file that the virtual sectors are mapped to
 #
-# @filename: #optional filename that is referred to by @offset
+# @filename: filename that is referred to by @offset
 #
 # Since: 2.6
 #
@@ -237,7 +237,7 @@
 #
 # @file: the filename of the backing device
 #
-# @node-name: #optional the name of the block driver node (Since 2.0)
+# @node-name: the name of the block driver node (Since 2.0)
 #
 # @ro: true if the backing device was open read-only
 #
@@ -252,7 +252,7 @@
 #       2.6: 'luks' added
 #       2.8: 'replication' added, 'tftp' dropped
 #
-# @backing_file: #optional the name of the backing file (for copy-on-write)
+# @backing_file: the name of the backing file (for copy-on-write)
 #
 # @backing_file_depth: number of files in the backing file chain (since: 1.2)
 #
@@ -277,45 +277,45 @@
 #
 # @image: the info of image used (since: 1.6)
 #
-# @bps_max: #optional total throughput limit during bursts,
+# @bps_max: total throughput limit during bursts,
 #                     in bytes (Since 1.7)
 #
-# @bps_rd_max: #optional read throughput limit during bursts,
+# @bps_rd_max: read throughput limit during bursts,
 #                        in bytes (Since 1.7)
 #
-# @bps_wr_max: #optional write throughput limit during bursts,
+# @bps_wr_max: write throughput limit during bursts,
 #                        in bytes (Since 1.7)
 #
-# @iops_max: #optional total I/O operations per second during bursts,
+# @iops_max: total I/O operations per second during bursts,
 #                      in bytes (Since 1.7)
 #
-# @iops_rd_max: #optional read I/O operations per second during bursts,
+# @iops_rd_max: read I/O operations per second during bursts,
 #                         in bytes (Since 1.7)
 #
-# @iops_wr_max: #optional write I/O operations per second during bursts,
+# @iops_wr_max: write I/O operations per second during bursts,
 #                         in bytes (Since 1.7)
 #
-# @bps_max_length: #optional maximum length of the @bps_max burst
+# @bps_max_length: maximum length of the @bps_max burst
 #                            period, in seconds. (Since 2.6)
 #
-# @bps_rd_max_length: #optional maximum length of the @bps_rd_max
+# @bps_rd_max_length: maximum length of the @bps_rd_max
 #                               burst period, in seconds. (Since 2.6)
 #
-# @bps_wr_max_length: #optional maximum length of the @bps_wr_max
+# @bps_wr_max_length: maximum length of the @bps_wr_max
 #                               burst period, in seconds. (Since 2.6)
 #
-# @iops_max_length: #optional maximum length of the @iops burst
+# @iops_max_length: maximum length of the @iops burst
 #                             period, in seconds. (Since 2.6)
 #
-# @iops_rd_max_length: #optional maximum length of the @iops_rd_max
+# @iops_rd_max_length: maximum length of the @iops_rd_max
 #                                burst period, in seconds. (Since 2.6)
 #
-# @iops_wr_max_length: #optional maximum length of the @iops_wr_max
+# @iops_wr_max_length: maximum length of the @iops_wr_max
 #                                burst period, in seconds. (Since 2.6)
 #
-# @iops_size: #optional an I/O size in bytes (Since 1.7)
+# @iops_size: an I/O size in bytes (Since 1.7)
 #
-# @group: #optional throttle group name (Since 2.4)
+# @group: throttle group name (Since 2.4)
 #
 # @cache: the cache mode used for the block device (since: 2.3)
 #
@@ -410,7 +410,7 @@
 #
 # Block dirty bitmap information.
 #
-# @name: #optional the name of the dirty bitmap (Since 2.4)
+# @name: the name of the dirty bitmap (Since 2.4)
 #
 # @count: number of dirty bytes according to the dirty bitmap
 #
@@ -440,17 +440,17 @@
 # @locked: True if the guest has locked this device from having its media
 #          removed
 #
-# @tray_open: #optional True if the device's tray is open
+# @tray_open: True if the device's tray is open
 #             (only present if it has a tray)
 #
-# @dirty-bitmaps: #optional dirty bitmaps information (only present if the
+# @dirty-bitmaps: dirty bitmaps information (only present if the
 #                 driver has one or more dirty bitmaps) (Since 2.0)
 #
-# @io-status: #optional @BlockDeviceIoStatus. Only present if the device
+# @io-status: @BlockDeviceIoStatus. Only present if the device
 #             supports it and the VM is configured to stop on errors
 #             (supported device models: virtio-blk, ide, scsi-disk)
 #
-# @inserted: #optional @BlockDeviceInfo describing the device if media is
+# @inserted: @BlockDeviceInfo describing the device if media is
 #            present
 #
 # Since:  0.14.0
@@ -639,7 +639,7 @@
 # @wr_merged: Number of write requests that have been merged into another
 #             request (Since 2.3).
 #
-# @idle_time_ns: #optional Time since the last I/O operation, in
+# @idle_time_ns: Time since the last I/O operation, in
 #                nanoseconds. If the field is absent it means that
 #                there haven't been any operations yet (Since 2.5).
 #
@@ -689,19 +689,19 @@
 #
 # Statistics of a virtual block device or a block backing device.
 #
-# @device: #optional If the stats are for a virtual block device, the name
+# @device: If the stats are for a virtual block device, the name
 #          corresponding to the virtual block device.
 #
-# @node-name: #optional The node name of the device. (Since 2.3)
+# @node-name: The node name of the device. (Since 2.3)
 #
 # @stats:  A @BlockDeviceStats for the device.
 #
-# @parent: #optional This describes the file block device if it has one.
+# @parent: This describes the file block device if it has one.
 #          Contains recursively the statistics of the underlying
 #          protocol (e.g. the host file for a qcow2 image). If there is
 #          no underlying protocol, this field is omitted
 #
-# @backing: #optional This describes the backing block device if it has one.
+# @backing: This describes the backing block device if it has one.
 #           (Since 2.0)
 #
 # Since: 0.14.0
@@ -717,7 +717,7 @@
 #
 # Query the @BlockStats for all virtual block devices.
 #
-# @query-nodes: #optional If true, the command will query all the block nodes
+# @query-nodes: If true, the command will query all the block nodes
 #               that have a node name, in a list which will include "parent"
 #               information, but not "backing".
 #               If false or omitted, the behavior is as before - query all the
@@ -956,9 +956,9 @@
 #
 # Either @device or @node-name must be set but not both.
 #
-# @device: #optional the name of the block backend device to set the password on
+# @device: the name of the block backend device to set the password on
 #
-# @node-name: #optional graph node name to set the password on (Since 2.0)
+# @node-name: graph node name to set the password on (Since 2.0)
 #
 # @password: the password to use for the device
 #
@@ -989,9 +989,9 @@
 #
 # Either @device or @node-name must be set but not both.
 #
-# @device: #optional the name of the device to get the image resized
+# @device: the name of the device to get the image resized
 #
-# @node-name: #optional graph node name to get the image resized (Since 2.0)
+# @node-name: graph node name to get the image resized (Since 2.0)
 #
 # @size:  new image size in bytes
 #
@@ -1033,19 +1033,19 @@
 #
 # Either @device or @node-name must be set but not both.
 #
-# @device: #optional the name of the device to generate the snapshot from.
+# @device: the name of the device to generate the snapshot from.
 #
-# @node-name: #optional graph node name to generate the snapshot from (Since 2.0)
+# @node-name: graph node name to generate the snapshot from (Since 2.0)
 #
 # @snapshot-file: the target of the new image. If the file exists, or
 # if it is a device, the snapshot will be created in the existing
 # file/device. Otherwise, a new file will be created.
 #
-# @snapshot-node-name: #optional the graph node name of the new image (Since 2.0)
+# @snapshot-node-name: the graph node name of the new image (Since 2.0)
 #
-# @format: #optional the format of the snapshot image, default is 'qcow2'.
+# @format: the format of the snapshot image, default is 'qcow2'.
 #
-# @mode: #optional whether and how QEMU should create a new image, default is
+# @mode: whether and how QEMU should create a new image, default is
 #        'absolute-paths'.
 ##
 { 'struct': 'BlockdevSnapshotSync',
@@ -1071,7 +1071,7 @@
 ##
 # @DriveBackup:
 #
-# @job-id: #optional identifier for the newly-created block job. If
+# @job-id: identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
 # @device: the device name or node-name of a root node which should be copied.
@@ -1080,30 +1080,30 @@
 #          is a device, the existing file/device will be used as the new
 #          destination.  If it does not exist, a new file will be created.
 #
-# @format: #optional the format of the new destination, default is to
+# @format: the format of the new destination, default is to
 #          probe if @mode is 'existing', else the format of the source
 #
 # @sync: what parts of the disk image should be copied to the destination
 #        (all the disk, only the sectors allocated in the topmost image, from a
 #        dirty bitmap, or only new I/O).
 #
-# @mode: #optional whether and how QEMU should create a new image, default is
+# @mode: whether and how QEMU should create a new image, default is
 #        'absolute-paths'.
 #
-# @speed: #optional the maximum speed, in bytes per second
+# @speed: the maximum speed, in bytes per second
 #
-# @bitmap: #optional the name of dirty bitmap if sync is "incremental".
+# @bitmap: the name of dirty bitmap if sync is "incremental".
 #          Must be present if sync is "incremental", must NOT be present
 #          otherwise. (Since 2.4)
 #
-# @compress: #optional true to compress data, if the target format supports it.
+# @compress: true to compress data, if the target format supports it.
 #            (default: false) (since 2.8)
 #
-# @on-source-error: #optional the action to take on an error on the source,
+# @on-source-error: the action to take on an error on the source,
 #                   default 'report'.  'stop' and 'enospc' can only be used
 #                   if the block device supports io-status (see BlockInfo).
 #
-# @on-target-error: #optional the action to take on an error on the target,
+# @on-target-error: the action to take on an error on the target,
 #                   default 'report' (no limitations, since this applies to
 #                   a different block device than @device).
 #
@@ -1123,7 +1123,7 @@
 ##
 # @BlockdevBackup:
 #
-# @job-id: #optional identifier for the newly-created block job. If
+# @job-id: identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
 # @device: the device name or node-name of a root node which should be copied.
@@ -1134,17 +1134,17 @@
 #        (all the disk, only the sectors allocated in the topmost image, or
 #        only new I/O).
 #
-# @speed: #optional the maximum speed, in bytes per second. The default is 0,
+# @speed: the maximum speed, in bytes per second. The default is 0,
 #         for unlimited.
 #
-# @compress: #optional true to compress data, if the target format supports it.
+# @compress: true to compress data, if the target format supports it.
 #            (default: false) (since 2.8)
 #
-# @on-source-error: #optional the action to take on an error on the source,
+# @on-source-error: the action to take on an error on the source,
 #                   default 'report'.  'stop' and 'enospc' can only be used
 #                   if the block device supports io-status (see BlockInfo).
 #
-# @on-target-error: #optional the action to take on an error on the target,
+# @on-target-error: the action to take on an error on the target,
 #                   default 'report' (no limitations, since this applies to
 #                   a different block device than @device).
 #
@@ -1261,19 +1261,19 @@
 # Live commit of data from overlay image nodes into backing nodes - i.e.,
 # writes data between 'top' and 'base' into 'base'.
 #
-# @job-id: #optional identifier for the newly-created block job. If
+# @job-id: identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
 # @device:  the device name or node-name of a root node
 #
-# @base:   #optional The file name of the backing image to write data into.
+# @base:   The file name of the backing image to write data into.
 #                    If not specified, this is the deepest backing image.
 #
-# @top:    #optional The file name of the backing image within the image chain,
+# @top:    The file name of the backing image within the image chain,
 #                    which contains the topmost data to be committed down. If
 #                    not specified, this is the active layer.
 #
-# @backing-file:  #optional The backing file string to write into the overlay
+# @backing-file:  The backing file string to write into the overlay
 #                           image of 'top'.  If 'top' is the active layer,
 #                           specifying a backing file string is an error. This
 #                           filename is not validated.
@@ -1302,9 +1302,9 @@
 #                    size of the smaller top, you can safely truncate it
 #                    yourself once the commit operation successfully completes.
 #
-# @speed:  #optional the maximum speed, in bytes per second
+# @speed:  the maximum speed, in bytes per second
 #
-# @filter-node-name: #optional the node name that should be assigned to the
+# @filter-node-name: the node name that should be assigned to the
 #                    filter driver that the commit job inserts into the graph
 #                    above @top. If this option is not given, a node name is
 #                    autogenerated. (Since: 2.9)
@@ -1482,7 +1482,7 @@
 #
 # A set of parameters describing drive mirror setup.
 #
-# @job-id: #optional identifier for the newly-created block job. If
+# @job-id: identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
 # @device:  the device name or node-name of a root node whose writes should be
@@ -1492,41 +1492,41 @@
 #          is a device, the existing file/device will be used as the new
 #          destination.  If it does not exist, a new file will be created.
 #
-# @format: #optional the format of the new destination, default is to
+# @format: the format of the new destination, default is to
 #          probe if @mode is 'existing', else the format of the source
 #
-# @node-name: #optional the new block driver state node name in the graph
+# @node-name: the new block driver state node name in the graph
 #             (Since 2.1)
 #
-# @replaces: #optional with sync=full graph node name to be replaced by the new
+# @replaces: with sync=full graph node name to be replaced by the new
 #            image when a whole image copy is done. This can be used to repair
 #            broken Quorum files. (Since 2.1)
 #
-# @mode: #optional whether and how QEMU should create a new image, default is
+# @mode: whether and how QEMU should create a new image, default is
 #        'absolute-paths'.
 #
-# @speed:  #optional the maximum speed, in bytes per second
+# @speed:  the maximum speed, in bytes per second
 #
 # @sync: what parts of the disk image should be copied to the destination
 #        (all the disk, only the sectors allocated in the topmost image, or
 #        only new I/O).
 #
-# @granularity: #optional granularity of the dirty bitmap, default is 64K
+# @granularity: granularity of the dirty bitmap, default is 64K
 #               if the image format doesn't have clusters, 4K if the clusters
 #               are smaller than that, else the cluster size.  Must be a
 #               power of 2 between 512 and 64M (since 1.4).
 #
-# @buf-size: #optional maximum amount of data in flight from source to
+# @buf-size: maximum amount of data in flight from source to
 #            target (since 1.4).
 #
-# @on-source-error: #optional the action to take on an error on the source,
+# @on-source-error: the action to take on an error on the source,
 #                   default 'report'.  'stop' and 'enospc' can only be used
 #                   if the block device supports io-status (see BlockInfo).
 #
-# @on-target-error: #optional the action to take on an error on the target,
+# @on-target-error: the action to take on an error on the target,
 #                   default 'report' (no limitations, since this applies to
 #                   a different block device than @device).
-# @unmap: #optional Whether to try to unmap target sectors where source has
+# @unmap: Whether to try to unmap target sectors where source has
 #         only zero. If true, and target unallocated sectors will read as zero,
 #         target image sectors will be unmapped; otherwise, zeroes will be
 #         written. Both will result in identical contents.
@@ -1562,7 +1562,7 @@
 #
 # @name: name of the dirty bitmap
 #
-# @granularity: #optional the bitmap granularity, default is 64k for
+# @granularity: the bitmap granularity, default is 64k for
 #               block-dirty-bitmap-add
 #
 # Since: 2.4
@@ -1642,7 +1642,7 @@
 #
 # Start mirroring a block device's writes to a new destination.
 #
-# @job-id: #optional identifier for the newly-created block job. If
+# @job-id: identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
 # @device: The device name or node-name of a root node whose writes should be
@@ -1651,33 +1651,33 @@
 # @target: the id or node-name of the block device to mirror to. This mustn't be
 #          attached to guest.
 #
-# @replaces: #optional with sync=full graph node name to be replaced by the new
+# @replaces: with sync=full graph node name to be replaced by the new
 #            image when a whole image copy is done. This can be used to repair
 #            broken Quorum files.
 #
-# @speed:  #optional the maximum speed, in bytes per second
+# @speed:  the maximum speed, in bytes per second
 #
 # @sync: what parts of the disk image should be copied to the destination
 #        (all the disk, only the sectors allocated in the topmost image, or
 #        only new I/O).
 #
-# @granularity: #optional granularity of the dirty bitmap, default is 64K
+# @granularity: granularity of the dirty bitmap, default is 64K
 #               if the image format doesn't have clusters, 4K if the clusters
 #               are smaller than that, else the cluster size.  Must be a
 #               power of 2 between 512 and 64M
 #
-# @buf-size: #optional maximum amount of data in flight from source to
+# @buf-size: maximum amount of data in flight from source to
 #            target
 #
-# @on-source-error: #optional the action to take on an error on the source,
+# @on-source-error: the action to take on an error on the source,
 #                   default 'report'.  'stop' and 'enospc' can only be used
 #                   if the block device supports io-status (see BlockInfo).
 #
-# @on-target-error: #optional the action to take on an error on the target,
+# @on-target-error: the action to take on an error on the target,
 #                   default 'report' (no limitations, since this applies to
 #                   a different block device than @device).
 #
-# @filter-node-name: #optional the node name that should be assigned to the
+# @filter-node-name: the node name that should be assigned to the
 #                    filter driver that the mirror job inserts into the graph
 #                    above @device. If this option is not given, a node name is
 #                    autogenerated. (Since: 2.9)
@@ -1765,9 +1765,9 @@
 #
 # A set of parameters describing block throttling.
 #
-# @device: #optional Block device name (deprecated, use @id instead)
+# @device: Block device name (deprecated, use @id instead)
 #
-# @id: #optional The name or QOM path of the guest device (since: 2.8)
+# @id: The name or QOM path of the guest device (since: 2.8)
 #
 # @bps: total throughput limit in bytes per second
 #
@@ -1781,57 +1781,57 @@
 #
 # @iops_wr: write I/O operations per second
 #
-# @bps_max: #optional total throughput limit during bursts,
+# @bps_max: total throughput limit during bursts,
 #                     in bytes (Since 1.7)
 #
-# @bps_rd_max: #optional read throughput limit during bursts,
+# @bps_rd_max: read throughput limit during bursts,
 #                        in bytes (Since 1.7)
 #
-# @bps_wr_max: #optional write throughput limit during bursts,
+# @bps_wr_max: write throughput limit during bursts,
 #                        in bytes (Since 1.7)
 #
-# @iops_max: #optional total I/O operations per second during bursts,
+# @iops_max: total I/O operations per second during bursts,
 #                      in bytes (Since 1.7)
 #
-# @iops_rd_max: #optional read I/O operations per second during bursts,
+# @iops_rd_max: read I/O operations per second during bursts,
 #                         in bytes (Since 1.7)
 #
-# @iops_wr_max: #optional write I/O operations per second during bursts,
+# @iops_wr_max: write I/O operations per second during bursts,
 #                         in bytes (Since 1.7)
 #
-# @bps_max_length: #optional maximum length of the @bps_max burst
+# @bps_max_length: maximum length of the @bps_max burst
 #                            period, in seconds. It must only
 #                            be set if @bps_max is set as well.
 #                            Defaults to 1. (Since 2.6)
 #
-# @bps_rd_max_length: #optional maximum length of the @bps_rd_max
+# @bps_rd_max_length: maximum length of the @bps_rd_max
 #                               burst period, in seconds. It must only
 #                               be set if @bps_rd_max is set as well.
 #                               Defaults to 1. (Since 2.6)
 #
-# @bps_wr_max_length: #optional maximum length of the @bps_wr_max
+# @bps_wr_max_length: maximum length of the @bps_wr_max
 #                               burst period, in seconds. It must only
 #                               be set if @bps_wr_max is set as well.
 #                               Defaults to 1. (Since 2.6)
 #
-# @iops_max_length: #optional maximum length of the @iops burst
+# @iops_max_length: maximum length of the @iops burst
 #                             period, in seconds. It must only
 #                             be set if @iops_max is set as well.
 #                             Defaults to 1. (Since 2.6)
 #
-# @iops_rd_max_length: #optional maximum length of the @iops_rd_max
+# @iops_rd_max_length: maximum length of the @iops_rd_max
 #                                burst period, in seconds. It must only
 #                                be set if @iops_rd_max is set as well.
 #                                Defaults to 1. (Since 2.6)
 #
-# @iops_wr_max_length: #optional maximum length of the @iops_wr_max
+# @iops_wr_max_length: maximum length of the @iops_wr_max
 #                                burst period, in seconds. It must only
 #                                be set if @iops_wr_max is set as well.
 #                                Defaults to 1. (Since 2.6)
 #
-# @iops_size: #optional an I/O size in bytes (Since 1.7)
+# @iops_size: an I/O size in bytes (Since 1.7)
 #
-# @group: #optional throttle group name (Since 2.4)
+# @group: throttle group name (Since 2.4)
 #
 # Since: 1.1
 ##
@@ -1872,18 +1872,18 @@
 # On successful completion the image file is updated to drop the backing file
 # and the BLOCK_JOB_COMPLETED event is emitted.
 #
-# @job-id: #optional identifier for the newly-created block job. If
+# @job-id: identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
 #
 # @device: the device or node name of the top image
 #
-# @base:   #optional the common backing file name.
+# @base:   the common backing file name.
 #                    It cannot be set if @base-node is also set.
 #
-# @base-node: #optional the node name of the backing file.
+# @base-node: the node name of the backing file.
 #                       It cannot be set if @base is also set. (Since 2.8)
 #
-# @backing-file: #optional The backing file string to write into the top
+# @backing-file: The backing file string to write into the top
 #                          image. This filename is not validated.
 #
 #                          If a pathname string is such that it cannot be
@@ -1898,9 +1898,9 @@
 #                          protocol.
 #                          (Since 2.1)
 #
-# @speed:  #optional the maximum speed, in bytes per second
+# @speed:  the maximum speed, in bytes per second
 #
-# @on-error: #optional the action to take on an error (default report).
+# @on-error: the action to take on an error (default report).
 #            'stop' and 'enospc' can only be used if the block device
 #            supports io-status (see BlockInfo).  Since 1.3.
 #
@@ -1967,7 +1967,7 @@
 #          the name of the parameter), but since QEMU 2.7 it can have
 #          other values.
 #
-# @force: #optional whether to allow cancellation of a paused job (default
+# @force: whether to allow cancellation of a paused job (default
 #         false).  Since 1.3.
 #
 # Returns: Nothing on success
@@ -2099,9 +2099,9 @@
 #
 # Includes cache-related options for block devices
 #
-# @direct:      #optional enables use of O_DIRECT (bypass the host page cache;
+# @direct:      enables use of O_DIRECT (bypass the host page cache;
 #               default: false)
-# @no-flush:    #optional ignore any flush requests for the device (default:
+# @no-flush:    ignore any flush requests for the device (default:
 #               false)
 #
 # Since: 1.7
@@ -2142,7 +2142,7 @@
 # Driver specific block device options for the file backend.
 #
 # @filename:    path to the image file
-# @aio:         #optional AIO backend (default: threads) (since: 2.8)
+# @aio:         AIO backend (default: threads) (since: 2.8)
 #
 # Since: 1.7
 ##
@@ -2155,8 +2155,8 @@
 #
 # Driver specific block device options for the null backend.
 #
-# @size:    #optional size of the device in bytes.
-# @latency-ns: #optional emulated latency (in nanoseconds) in processing
+# @size:    size of the device in bytes.
+# @latency-ns: emulated latency (in nanoseconds) in processing
 #              requests. Default to zero which completes requests immediately.
 #              (Since 2.4)
 #
@@ -2171,14 +2171,14 @@
 # Driver specific block device options for the vvfat protocol.
 #
 # @dir:         directory to be exported as FAT image
-# @fat-type:    #optional FAT type: 12, 16 or 32
-# @floppy:      #optional whether to export a floppy image (true) or
+# @fat-type:    FAT type: 12, 16 or 32
+# @floppy:      whether to export a floppy image (true) or
 #               partitioned hard disk (false; default)
-# @label:       #optional set the volume label, limited to 11 bytes. FAT16 and
+# @label:       set the volume label, limited to 11 bytes. FAT16 and
 #               FAT32 traditionally have some restrictions on labels, which are
 #               ignored by most operating systems. Defaults to "QEMU VVFAT".
 #               (since 2.4)
-# @rw:          #optional whether to allow write operations (default: false)
+# @rw:          whether to allow write operations (default: false)
 #
 # Since: 1.7
 ##
@@ -2204,7 +2204,7 @@
 #
 # Driver specific block device options for LUKS.
 #
-# @key-secret: #optional the ID of a QCryptoSecret object providing
+# @key-secret: the ID of a QCryptoSecret object providing
 #              the decryption key (since 2.6). Mandatory except when
 #              doing a metadata-only probe of the image.
 #
@@ -2221,7 +2221,7 @@
 # Driver specific block device options for image format that have no option
 # besides their data source and an optional backing file.
 #
-# @backing:     #optional reference to or definition of the backing file block
+# @backing:     reference to or definition of the backing file block
 #               device (if missing, taken from the image file content). It is
 #               allowed to pass an empty string here in order to disable the
 #               default backing file.
@@ -2297,33 +2297,33 @@
 #
 # Driver specific block device options for qcow2.
 #
-# @lazy-refcounts:        #optional whether to enable the lazy refcounts
+# @lazy-refcounts:        whether to enable the lazy refcounts
 #                         feature (default is taken from the image file)
 #
-# @pass-discard-request:  #optional whether discard requests to the qcow2
+# @pass-discard-request:  whether discard requests to the qcow2
 #                         device should be forwarded to the data source
 #
-# @pass-discard-snapshot: #optional whether discard requests for the data source
+# @pass-discard-snapshot: whether discard requests for the data source
 #                         should be issued when a snapshot operation (e.g.
 #                         deleting a snapshot) frees clusters in the qcow2 file
 #
-# @pass-discard-other:    #optional whether discard requests for the data source
+# @pass-discard-other:    whether discard requests for the data source
 #                         should be issued on other occasions where a cluster
 #                         gets freed
 #
-# @overlap-check:         #optional which overlap checks to perform for writes
+# @overlap-check:         which overlap checks to perform for writes
 #                         to the image, defaults to 'cached' (since 2.2)
 #
-# @cache-size:            #optional the maximum total size of the L2 table and
+# @cache-size:            the maximum total size of the L2 table and
 #                         refcount block caches in bytes (since 2.2)
 #
-# @l2-cache-size:         #optional the maximum size of the L2 table cache in
+# @l2-cache-size:         the maximum size of the L2 table cache in
 #                         bytes (since 2.2)
 #
-# @refcount-cache-size:   #optional the maximum size of the refcount block cache
+# @refcount-cache-size:   the maximum size of the refcount block cache
 #                         in bytes (since 2.2)
 #
-# @cache-clean-interval:  #optional clean unused entries in the L2 and refcount
+# @cache-clean-interval:  clean unused entries in the L2 and refcount
 #                         caches. The interval is in seconds. The default value
 #                         is 0 and it disables this feature (since 2.5)
 #
@@ -2349,17 +2349,17 @@
 #
 # @volume:              Name of the Archipelago volume image
 #
-# @mport:               #optional The port number on which mapperd is
+# @mport:               The port number on which mapperd is
 #                       listening. This is optional
 #                       and if not specified, QEMU will make Archipelago
 #                       use the default port (1001).
 #
-# @vport:               #optional The port number on which vlmcd is
+# @vport:               The port number on which vlmcd is
 #                       listening. This is optional
 #                       and if not specified, QEMU will make Archipelago
 #                       use the default port (501).
 #
-# @segment:             #optional The name of the shared memory segment
+# @segment:             The name of the shared memory segment
 #                       Archipelago stack is using. This is optional
 #                       and if not specified, QEMU will make Archipelago
 #                       use the default value, 'archipelago'.
@@ -2378,7 +2378,7 @@
 #
 # @path:                path to the image on the host
 #
-# @user:                #optional user as which to connect, defaults to current
+# @user:                user as which to connect, defaults to current
 #                       local user name
 #
 # TODO: Expose the host_key_check option in QMP
@@ -2421,20 +2421,20 @@
 #
 # @event:       trigger event
 #
-# @state:       #optional the state identifier blkdebug needs to be in to
+# @state:       the state identifier blkdebug needs to be in to
 #               actually trigger the event; defaults to "any"
 #
-# @errno:       #optional error identifier (errno) to be returned; defaults to
+# @errno:       error identifier (errno) to be returned; defaults to
 #               EIO
 #
-# @sector:      #optional specifies the sector index which has to be affected
+# @sector:      specifies the sector index which has to be affected
 #               in order to actually trigger the event; defaults to "any
 #               sector"
 #
-# @once:        #optional disables further events after this one has been
+# @once:        disables further events after this one has been
 #               triggered; defaults to false
 #
-# @immediately: #optional fail immediately; defaults to false
+# @immediately: fail immediately; defaults to false
 #
 # Since: 2.0
 ##
@@ -2453,7 +2453,7 @@
 #
 # @event:       trigger event
 #
-# @state:       #optional the current state identifier blkdebug needs to be in;
+# @state:       the current state identifier blkdebug needs to be in;
 #               defaults to "any"
 #
 # @new_state:   the state identifier blkdebug is supposed to assume if
@@ -2473,14 +2473,14 @@
 #
 # @image:           underlying raw block device (or image file)
 #
-# @config:          #optional filename of the configuration file
+# @config:          filename of the configuration file
 #
-# @align:           #optional required alignment for requests in bytes,
+# @align:           required alignment for requests in bytes,
 #                   must be power of 2, or 0 for default
 #
-# @inject-error:    #optional array of error injection descriptions
+# @inject-error:    array of error injection descriptions
 #
-# @set-state:       #optional array of state-change descriptions
+# @set-state:       array of state-change descriptions
 #
 # Since: 2.0
 ##
@@ -2524,17 +2524,17 @@
 #
 # Driver specific block device options for Quorum
 #
-# @blkverify:      #optional true if the driver must print content mismatch
+# @blkverify:      true if the driver must print content mismatch
 #                  set to false by default
 #
 # @children:       the children block devices to use
 #
 # @vote-threshold: the vote limit under which a read will fail
 #
-# @rewrite-corrupted: #optional rewrite corrupted data when quorum is reached
+# @rewrite-corrupted: rewrite corrupted data when quorum is reached
 #                     (Since 2.1)
 #
-# @read-pattern: #optional choose read pattern and set to quorum by default
+# @read-pattern: choose read pattern and set to quorum by default
 #                (Since 2.2)
 #
 # Since: 2.0
@@ -2557,10 +2557,10 @@
 #
 # @server:      gluster servers description
 #
-# @debug:       #optional libgfapi log level (default '4' which is Error)
+# @debug:       libgfapi log level (default '4' which is Error)
 #               (Since 2.8)
 #
-# @logfile:     #optional libgfapi log file (default /dev/stderr) (Since 2.8)
+# @logfile:     libgfapi log file (default /dev/stderr) (Since 2.8)
 #
 # Since: 2.7
 ##
@@ -2601,23 +2601,23 @@
 #
 # @target:          The target iqn name
 #
-# @lun:             #optional LUN to connect to. Defaults to 0.
+# @lun:             LUN to connect to. Defaults to 0.
 #
-# @user:            #optional User name to log in with. If omitted, no CHAP
+# @user:            User name to log in with. If omitted, no CHAP
 #                   authentication is performed.
 #
-# @password-secret: #optional The ID of a QCryptoSecret object providing
+# @password-secret: The ID of a QCryptoSecret object providing
 #                   the password for the login. This option is required if
 #                   @user is specified.
 #
-# @initiator-name:  #optional The iqn name we want to identify to the target
+# @initiator-name:  The iqn name we want to identify to the target
 #                   as. If this option is not specified, an initiator name is
 #                   generated automatically.
 #
-# @header-digest:   #optional The desired header digest. Defaults to
+# @header-digest:   The desired header digest. Defaults to
 #                   none-crc32c.
 #
-# @timeout:         #optional Timeout in seconds after which a request will
+# @timeout:         Timeout in seconds after which a request will
 #                   timeout. 0 means no timeout and is the default.
 #
 # Driver specific block device options for iscsi
@@ -2664,20 +2664,20 @@
 #
 # @image:              Image name in the Ceph pool.
 #
-# @conf:               #optional path to Ceph configuration file.  Values
+# @conf:               path to Ceph configuration file.  Values
 #                      in the configuration file will be overridden by
 #                      options specified via QAPI.
 #
-# @snapshot:           #optional Ceph snapshot name.
+# @snapshot:           Ceph snapshot name.
 #
-# @user:               #optional Ceph id name.
+# @user:               Ceph id name.
 #
-# @server:             #optional Monitor host address and port.  This maps
+# @server:             Monitor host address and port.  This maps
 #                      to the "mon_host" Ceph option.
 #
-# @auth-supported:     #optional Authentication supported.
+# @auth-supported:     Authentication supported.
 #
-# @password-secret:    #optional The ID of a QCryptoSecret object providing
+# @password-secret:    The ID of a QCryptoSecret object providing
 #                      the password for the login.
 #
 # Since: 2.9
@@ -2732,7 +2732,7 @@
 #
 # @mode: the replication mode
 #
-# @top-id: #optional In secondary mode, node name or device ID of the root
+# @top-id: In secondary mode, node name or device ID of the root
 #          node who owns the replication node chain. Must not be given in
 #          primary mode.
 #
@@ -2779,24 +2779,24 @@
 #
 # @path:                    path of the image on the host
 #
-# @user:                    #optional UID value to use when talking to the
+# @user:                    UID value to use when talking to the
 #                           server (defaults to 65534 on Windows and getuid()
 #                           on unix)
 #
-# @group:                   #optional GID value to use when talking to the
+# @group:                   GID value to use when talking to the
 #                           server (defaults to 65534 on Windows and getgid()
 #                           in unix)
 #
-# @tcp-syn-count:           #optional number of SYNs during the session
+# @tcp-syn-count:           number of SYNs during the session
 #                           establishment (defaults to libnfs default)
 #
-# @readahead-size:          #optional set the readahead size in bytes (defaults
+# @readahead-size:          set the readahead size in bytes (defaults
 #                           to libnfs default)
 #
-# @page-cache-size:         #optional set the pagecache size in bytes (defaults
+# @page-cache-size:         set the pagecache size in bytes (defaults
 #                           to libnfs default)
 #
-# @debug:                   #optional set the NFS debug level (max 2) (defaults
+# @debug:                   set the NFS debug level (max 2) (defaults
 #                           to libnfs default)
 #
 # Since: 2.8
@@ -2830,9 +2830,9 @@
 #
 # @server:      NBD server address
 #
-# @export:      #optional export name
+# @export:      export name
 #
-# @tls-creds:   #optional TLS credentials ID
+# @tls-creds:   TLS credentials ID
 #
 # Since: 2.8
 ##
@@ -2846,8 +2846,8 @@
 #
 # Driver specific block device options for the raw driver.
 #
-# @offset:      #optional position where the block device starts
-# @size:        #optional the assumed size of the device
+# @offset:      position where the block device starts
+# @size:        the assumed size of the device
 #
 # Since: 2.8
 ##
@@ -2862,13 +2862,13 @@
 # block devices, independent of the block driver:
 #
 # @driver:        block driver name
-# @node-name:     #optional the node name of the new node (Since 2.0).
+# @node-name:     the node name of the new node (Since 2.0).
 #                 This option is required on the top level of blockdev-add.
-# @discard:       #optional discard-related options (default: ignore)
-# @cache:         #optional cache-related options
-# @read-only:     #optional whether the block device should be read-only
+# @discard:       discard-related options (default: ignore)
+# @cache:         cache-related options
+# @read-only:     whether the block device should be read-only
 #                 (default: false)
-# @detect-zeroes: #optional detect and optimize zero writes (Since 2.1)
+# @detect-zeroes: detect and optimize zero writes (Since 2.1)
 #                 (default: off)
 #
 # Remaining options are determined by the block driver.
@@ -3050,11 +3050,11 @@
 #   to it
 # - if the guest device does not have an actual tray
 #
-# @device: #optional Block device name (deprecated, use @id instead)
+# @device: Block device name (deprecated, use @id instead)
 #
-# @id:     #optional The name or QOM path of the guest device (since: 2.8)
+# @id:     The name or QOM path of the guest device (since: 2.8)
 #
-# @force:  #optional if false (the default), an eject request will be sent to
+# @force:  if false (the default), an eject request will be sent to
 #          the guest if it has locked the tray (and the tray will not be opened
 #          immediately); if true, the tray will be opened regardless of whether
 #          it is locked
@@ -3090,9 +3090,9 @@
 #
 # If the tray was already closed before, this will be a no-op.
 #
-# @device:  #optional Block device name (deprecated, use @id instead)
+# @device:  Block device name (deprecated, use @id instead)
 #
-# @id:      #optional The name or QOM path of the guest device (since: 2.8)
+# @id:      The name or QOM path of the guest device (since: 2.8)
 #
 # Since: 2.5
 #
@@ -3124,9 +3124,9 @@
 #
 # If the tray is open and there is no medium inserted, this will be a no-op.
 #
-# @device: #optional Block device name (deprecated, use @id instead)
+# @device: Block device name (deprecated, use @id instead)
 #
-# @id:     #optional The name or QOM path of the guest device (since: 2.8)
+# @id:     The name or QOM path of the guest device (since: 2.8)
 #
 # Note: This command is still a work in progress and is considered experimental.
 # Stay away from it unless you want to help with its development.
@@ -3170,9 +3170,9 @@
 # device's tray must currently be open (unless there is no attached guest
 # device) and there must be no medium inserted already.
 #
-# @device:    #optional Block device name (deprecated, use @id instead)
+# @device:    Block device name (deprecated, use @id instead)
 #
-# @id:        #optional The name or QOM path of the guest device (since: 2.8)
+# @id:        The name or QOM path of the guest device (since: 2.8)
 #
 # @node-name: name of a node in the block driver state graph
 #
@@ -3231,17 +3231,17 @@
 # combines blockdev-open-tray, x-blockdev-remove-medium,
 # x-blockdev-insert-medium and blockdev-close-tray).
 #
-# @device:          #optional Block device name (deprecated, use @id instead)
+# @device:          Block device name (deprecated, use @id instead)
 #
-# @id:              #optional The name or QOM path of the guest device
+# @id:              The name or QOM path of the guest device
 #                   (since: 2.8)
 #
 # @filename:        filename of the new image to be loaded
 #
-# @format:          #optional format to open the new image with (defaults to
+# @format:          format to open the new image with (defaults to
 #                   the probed format)
 #
-# @read-only-mode:  #optional change the read-only mode of the device; defaults
+# @read-only-mode:  change the read-only mode of the device; defaults
 #                   to 'retain'
 #
 # Since: 2.5
@@ -3314,16 +3314,16 @@
 #          reasons, but it can be empty ("") if the image does not
 #          have a device name associated.
 #
-# @node-name: #optional node name (Since: 2.4)
+# @node-name: node name (Since: 2.4)
 #
 # @msg: informative message for human consumption, such as the kind of
 #       corruption being detected. It should not be parsed by machine as it is
 #       not guaranteed to be stable
 #
-# @offset: #optional if the corruption resulted from an image access, this is
+# @offset: if the corruption resulted from an image access, this is
 #          the host's access offset into the image
 #
-# @size: #optional if the corruption resulted from an image access, this is
+# @size: if the corruption resulted from an image access, this is
 #        the access size
 #
 # @fatal: if set, the image is marked corrupt and therefore unusable after this
@@ -3368,7 +3368,7 @@
 #
 # @action: action that has been taken
 #
-# @nospace: #optional true if I/O error was caused due to a no-space
+# @nospace: true if I/O error was caused due to a no-space
 #           condition. This key is only present if query-block's
 #           io-status is present, please see query-block documentation
 #           for more information (since: 2.2)
@@ -3414,7 +3414,7 @@
 #
 # @speed: rate limit, bytes per second
 #
-# @error: #optional error message. Only present on failure. This field
+# @error: error message. Only present on failure. This field
 #         contains a human-readable error message. There are no semantics
 #         other than that streaming has failed and clients should not try to
 #         interpret the error string
@@ -3623,9 +3623,9 @@
 #
 # @parent: the id or name of the parent node.
 #
-# @child: #optional the name of a child under the given parent node.
+# @child: the name of a child under the given parent node.
 #
-# @node: #optional the name of the node that will be added.
+# @node: the name of the node that will be added.
 #
 # Note: this command is experimental, and its API is not stable. It
 # does not support all kinds of operations, all kinds of children, nor
diff --git a/qapi/block.json b/qapi/block.json
index 22da914..46fca0e 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -163,11 +163,11 @@
 #
 # Ejects a device from a removable drive.
 #
-# @device:  #optional Block device name (deprecated, use @id instead)
+# @device:  Block device name (deprecated, use @id instead)
 #
-# @id:      #optional The name or QOM path of the guest device (since: 2.8)
+# @id:      The name or QOM path of the guest device (since: 2.8)
 #
-# @force:   #optional If true, eject regardless of whether the drive is locked.
+# @force:   If true, eject regardless of whether the drive is locked.
 #           If not specified, the default value is false.
 #
 # Returns:  Nothing on success
@@ -215,7 +215,7 @@
 # @device: The device name or node name of the node to be exported
 #
 # @writable: Whether clients should be able to write to the device via the
-#     NBD connection (default false). #optional
+#     NBD connection (default false).
 #
 # Returns: error if the device is already marked for export.
 #
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 93a0474..6b6fde3 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -152,7 +152,7 @@
 #
 # The options that apply to QCow/QCow2 AES-CBC encryption format
 #
-# @key-secret: #optional the ID of a QCryptoSecret object providing the
+# @key-secret: the ID of a QCryptoSecret object providing the
 #              decryption key. Mandatory except when probing image for
 #              metadata only.
 #
@@ -166,7 +166,7 @@
 #
 # The options that apply to LUKS encryption format
 #
-# @key-secret: #optional the ID of a QCryptoSecret object providing the
+# @key-secret: the ID of a QCryptoSecret object providing the
 #              decryption key. Mandatory except when probing image for
 #              metadata only.
 # Since: 2.6
@@ -180,17 +180,17 @@
 #
 # The options that apply to LUKS encryption format initialization
 #
-# @cipher-alg: #optional the cipher algorithm for data encryption
+# @cipher-alg: the cipher algorithm for data encryption
 #              Currently defaults to 'aes'.
-# @cipher-mode: #optional the cipher mode for data encryption
+# @cipher-mode: the cipher mode for data encryption
 #               Currently defaults to 'cbc'
-# @ivgen-alg: #optional the initialization vector generator
+# @ivgen-alg: the initialization vector generator
 #             Currently defaults to 'essiv'
-# @ivgen-hash-alg: #optional the initialization vector generator hash
+# @ivgen-hash-alg: the initialization vector generator hash
 #                  Currently defaults to 'sha256'
-# @hash-alg: #optional the master key hash algorithm
+# @hash-alg: the master key hash algorithm
 #            Currently defaults to 'sha256'
-# @iter-time: #optional number of milliseconds to spend in
+# @iter-time: number of milliseconds to spend in
 #             PBKDF passphrase processing. Currently defaults
 #             to 2000. (since 2.8)
 # Since: 2.6
@@ -257,8 +257,8 @@
 #
 # @active: whether the key slot is currently in use
 # @key-offset: offset to the key material in bytes
-# @iters: #optional number of PBKDF2 iterations for key material
-# @stripes: #optional number of stripes for splitting key material
+# @iters: number of PBKDF2 iterations for key material
+# @stripes: number of stripes for splitting key material
 #
 # Since: 2.7
 ##
@@ -277,7 +277,7 @@
 # @cipher-alg: the cipher algorithm for data encryption
 # @cipher-mode: the cipher mode for data encryption
 # @ivgen-alg: the initialization vector generator
-# @ivgen-hash-alg: #optional the initialization vector generator hash
+# @ivgen-hash-alg: the initialization vector generator hash
 # @hash-alg: the master key hash algorithm
 # @payload-offset: offset to the payload data in bytes
 # @master-key-iters: number of PBKDF2 iterations for key material
diff --git a/qapi/event.json b/qapi/event.json
index e02852c..e80f3f4 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -186,7 +186,7 @@
 # At this point, it's safe to reuse the specified device ID. Device removal can
 # be initiated by the guest or by HMP/QMP commands.
 #
-# @device: #optional device name
+# @device: device name
 #
 # @path: device path
 #
@@ -209,7 +209,7 @@
 # Emitted once until the 'query-rx-filter' command is executed, the first event
 # will always be emitted
 #
-# @name: #optional net client name
+# @name: net client name
 #
 # @path: device path
 #
@@ -488,7 +488,7 @@
 #
 # @action: action that has been taken, currently always "pause"
 #
-# @info: #optional information about a panic (since 2.9)
+# @info: information about a panic (since 2.9)
 #
 # Since: 1.5
 #
@@ -533,7 +533,7 @@
 #
 # @type: quorum operation type (Since 2.6)
 #
-# @error: #optional error message. Only present on failure. This field
+# @error: error message. Only present on failure. This field
 #         contains a human-readable error message. There are no semantics other
 #         than that the block layer reported an error and clients should not
 #         try to interpret the error string.
@@ -620,7 +620,7 @@
 #
 # @result: DumpQueryResult type described in qapi-schema.json.
 #
-# @error: #optional human-readable error string that provides
+# @error: human-readable error string that provides
 #         hint on why dump failed. Only presents on failure. The
 #         user should not try to interpret the error string.
 #
diff --git a/qapi/introspect.json b/qapi/introspect.json
index f6adc43..1dbaef5 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -163,10 +163,10 @@
 #
 # @members: the object type's (non-variant) members, in no particular order.
 #
-# @tag: #optional the name of the member serving as type tag.
+# @tag: the name of the member serving as type tag.
 #       An element of @members with this name must exist.
 #
-# @variants: #optional variant members, i.e. additional members that
+# @variants: variant members, i.e. additional members that
 #            depend on the type tag's value.  Present exactly when
 #            @tag is present.  The variants are in no particular order,
 #            and may even differ from the order of the values of the
@@ -190,7 +190,7 @@
 #
 # @type: the name of the member's type.
 #
-# @default: #optional default when used as command parameter.
+# @default: default when used as command parameter.
 #           If absent, the parameter is mandatory.
 #           If present, the value must be null.  The parameter is
 #           optional, and behavior when it's missing is not specified
diff --git a/qapi/rocker.json b/qapi/rocker.json
index f374038..3587661 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -121,23 +121,23 @@
 #
 # @tbl-id: flow table ID
 #
-# @in-pport: #optional physical input port
+# @in-pport: physical input port
 #
-# @tunnel-id: #optional tunnel ID
+# @tunnel-id: tunnel ID
 #
-# @vlan-id: #optional VLAN ID
+# @vlan-id: VLAN ID
 #
-# @eth-type: #optional Ethernet header type
+# @eth-type: Ethernet header type
 #
-# @eth-src: #optional Ethernet header source MAC address
+# @eth-src: Ethernet header source MAC address
 #
-# @eth-dst: #optional Ethernet header destination MAC address
+# @eth-dst: Ethernet header destination MAC address
 #
-# @ip-proto: #optional IP Header protocol field
+# @ip-proto: IP Header protocol field
 #
-# @ip-tos: #optional IP header TOS field
+# @ip-tos: IP header TOS field
 #
-# @ip-dst: #optional IP header destination address
+# @ip-dst: IP header destination address
 #
 # Note: optional members may or may not appear in the flow key
 # depending if they're relevant to the flow key.
@@ -155,19 +155,19 @@
 #
 # Rocker switch OF-DPA flow mask
 #
-# @in-pport: #optional physical input port
+# @in-pport: physical input port
 #
-# @tunnel-id: #optional tunnel ID
+# @tunnel-id: tunnel ID
 #
-# @vlan-id: #optional VLAN ID
+# @vlan-id: VLAN ID
 #
-# @eth-src: #optional Ethernet header source MAC address
+# @eth-src: Ethernet header source MAC address
 #
-# @eth-dst: #optional Ethernet header destination MAC address
+# @eth-dst: Ethernet header destination MAC address
 #
-# @ip-proto: #optional IP Header protocol field
+# @ip-proto: IP Header protocol field
 #
-# @ip-tos: #optional IP header TOS field
+# @ip-tos: IP header TOS field
 #
 # Note: optional members may or may not appear in the flow mask
 # depending if they're relevant to the flow mask.
@@ -184,17 +184,17 @@
 #
 # Rocker switch OF-DPA flow action
 #
-# @goto-tbl: #optional next table ID
+# @goto-tbl: next table ID
 #
-# @group-id: #optional group ID
+# @group-id: group ID
 #
-# @tunnel-lport: #optional tunnel logical port ID
+# @tunnel-lport: tunnel logical port ID
 #
-# @vlan-id: #optional VLAN ID
+# @vlan-id: VLAN ID
 #
-# @new-vlan-id: #optional new VLAN ID
+# @new-vlan-id: new VLAN ID
 #
-# @out-pport: #optional physical output port
+# @out-pport: physical output port
 #
 # Note: optional members may or may not appear in the flow action
 # depending if they're relevant to the flow action.
@@ -234,7 +234,7 @@
 #
 # @name: switch name
 #
-# @tbl-id: #optional flow table ID.  If tbl-id is not specified, returns
+# @tbl-id: flow table ID.  If tbl-id is not specified, returns
 # flow information for all tables.
 #
 # Returns: rocker OF-DPA flow information
@@ -268,27 +268,27 @@
 #
 # @type: group type
 #
-# @vlan-id: #optional VLAN ID
+# @vlan-id: VLAN ID
 #
-# @pport: #optional physical port number
+# @pport: physical port number
 #
-# @index: #optional group index, unique with group type
+# @index: group index, unique with group type
 #
-# @out-pport: #optional output physical port number
+# @out-pport: output physical port number
 #
-# @group-id: #optional next group ID
+# @group-id: next group ID
 #
-# @set-vlan-id: #optional VLAN ID to set
+# @set-vlan-id: VLAN ID to set
 #
-# @pop-vlan: #optional pop VLAN headr from packet
+# @pop-vlan: pop VLAN headr from packet
 #
-# @group-ids: #optional list of next group IDs
+# @group-ids: list of next group IDs
 #
-# @set-eth-src: #optional set source MAC address in Ethernet header
+# @set-eth-src: set source MAC address in Ethernet header
 #
-# @set-eth-dst: #optional set destination MAC address in Ethernet header
+# @set-eth-dst: set destination MAC address in Ethernet header
 #
-# @ttl-check: #optional perform TTL check
+# @ttl-check: perform TTL check
 #
 # Note: optional members may or may not appear in the group depending
 # if they're relevant to the group type.
@@ -310,7 +310,7 @@
 #
 # @name: switch name
 #
-# @type: #optional group type.  If type is not specified, returns
+# @type: group type.  If type is not specified, returns
 # group information for all group types.
 #
 # Returns: rocker OF-DPA group information
diff --git a/qapi/trace.json b/qapi/trace.json
index 2bfda7a..de6588d 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -48,7 +48,7 @@
 # Query the state of events.
 #
 # @name: Event name pattern (case-sensitive glob).
-# @vcpu: #optional The vCPU to query (any by default; since 2.7).
+# @vcpu: The vCPU to query (any by default; since 2.7).
 #
 # Returns: a list of @TraceEventInfo for the matching events
 #
@@ -81,8 +81,8 @@
 #
 # @name: Event name pattern (case-sensitive glob).
 # @enable: Whether to enable tracing.
-# @ignore-unavailable: #optional Do not match unavailable events with @name.
-# @vcpu: #optional The vCPU to act upon (all by default; since 2.7).
+# @ignore-unavailable: Do not match unavailable events with @name.
+# @vcpu: The vCPU to act upon (all by default; since 2.7).
 #
 # An event's state is modified if:
 # - its name matches the @name pattern, and
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index a8e4bda..a02dbf2 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -144,7 +144,7 @@
 # If that's the case users are advised to always pass a
 # value.
 #
-# @time: #optional time of nanoseconds, relative to the Epoch
+# @time: time of nanoseconds, relative to the Epoch
 #        of 1970-01-01 in UTC.
 #
 # Returns: Nothing on success.
@@ -203,7 +203,7 @@
 # Initiate guest-activated shutdown. Note: this is an asynchronous
 # shutdown request, with no guarantee of successful shutdown.
 #
-# @mode: #optional "halt", "powerdown" (default), or "reboot"
+# @mode: "halt", "powerdown" (default), or "reboot"
 #
 # This command does NOT return a response on success. Success condition
 # is indicated by the VM exiting with a zero exit status or, when
@@ -222,7 +222,7 @@
 #
 # @path: Full path to the file in the guest to open.
 #
-# @mode: #optional open mode, as per fopen(), "r" is the default.
+# @mode: open mode, as per fopen(), "r" is the default.
 #
 # Returns: Guest file handle on success.
 #
@@ -270,7 +270,7 @@
 #
 # @handle: filehandle returned by guest-file-open
 #
-# @count: #optional maximum number of bytes to read (default is 4KB)
+# @count: maximum number of bytes to read (default is 4KB)
 #
 # Returns: @GuestFileRead on success.
 #
@@ -304,7 +304,7 @@
 #
 # @buf-b64: base64-encoded string representing data to be written
 #
-# @count: #optional bytes to write (actual bytes, after base64-decode),
+# @count: bytes to write (actual bytes, after base64-decode),
 #         default is all content in buf-b64 buffer after base64 decoding
 #
 # Returns: @GuestFileWrite on success.
@@ -441,7 +441,7 @@
 #
 # Sync and freeze specified guest filesystems
 #
-# @mountpoints: #optional an array of mountpoints of filesystems to be frozen.
+# @mountpoints: an array of mountpoints of filesystems to be frozen.
 #               If omitted, every mounted filesystem is frozen.
 #
 # Returns: Number of file systems currently frozen. On error, all filesystems
@@ -670,7 +670,7 @@
 #
 # @online: Whether the VCPU is enabled.
 #
-# @can-offline: #optional Whether offlining the VCPU is possible. This member
+# @can-offline: Whether offlining the VCPU is possible. This member
 #               is always filled in by the guest agent when the structure is
 #               returned, and always ignored on input (hence it can be omitted
 #               then).
@@ -858,7 +858,7 @@
 #
 # @online: Whether the MEMORY BLOCK is enabled in guest.
 #
-# @can-offline: #optional Whether offlining the MEMORY BLOCK is possible.
+# @can-offline: Whether offlining the MEMORY BLOCK is possible.
 #               This member is always filled in by the guest agent when the
 #               structure is returned, and always ignored on input (hence it
 #               can be omitted then).
@@ -911,7 +911,7 @@
 #
 # @response: the result of memory block operation.
 #
-# @error-code: #optional the error number.
+# @error-code: the error number.
 #               When memory block operation fails, we assign the value of
 #               'errno' to this member, it indicates what goes wrong.
 #               When the operation succeeds, it will be omitted.
@@ -979,16 +979,16 @@
 # @GuestExecStatus:
 #
 # @exited: true if process has already terminated.
-# @exitcode: #optional process exit code if it was normally terminated.
-# @signal: #optional signal number (linux) or unhandled exception code
+# @exitcode: process exit code if it was normally terminated.
+# @signal: signal number (linux) or unhandled exception code
 #       (windows) if the process was abnormally terminated.
-# @out-data: #optional base64-encoded stdout of the process
-# @err-data: #optional base64-encoded stderr of the process
+# @out-data: base64-encoded stdout of the process
+# @err-data: base64-encoded stderr of the process
 #       Note: @out-data and @err-data are present only
 #       if 'capture-output' was specified for 'guest-exec'
-# @out-truncated: #optional true if stdout was not fully captured
+# @out-truncated: true if stdout was not fully captured
 #       due to size limitation.
-# @err-truncated: #optional true if stderr was not fully captured
+# @err-truncated: true if stderr was not fully captured
 #       due to size limitation.
 #
 # Since: 2.5
@@ -1028,10 +1028,10 @@
 # Execute a command in the guest
 #
 # @path: path or executable name to execute
-# @arg: #optional argument list to pass to executable
-# @env: #optional environment variables to pass to executable
-# @input-data: #optional data to be passed to process stdin (base64 encoded)
-# @capture-output: #optional bool flag to enable capture of
+# @arg: argument list to pass to executable
+# @env: environment variables to pass to executable
+# @input-data: data to be passed to process stdin (base64 encoded)
+# @capture-output: bool flag to enable capture of
 #                  stdout/stderr of running process. defaults to false.
 #
 # Returns: PID on success.
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 2a2b33d..c580e76 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -219,6 +219,10 @@ class QAPIDoc(object):
         if (in_arg or not self.section.name
                 or not self.section.name.startswith("Example")):
             line = line.strip()
+        # TODO Drop this once the dust has settled
+        if (isinstance(self.section, QAPIDoc.ArgSection)
+                and '#optional' in line):
+            raise QAPISemError(self.info, "Please drop the #optional tag")
         self.section.append(line)
 
     def connect_member(self, member):
@@ -981,25 +985,6 @@ def check_definition_doc(doc, expr, info):
             or (meta == 'union' and not expr.get('discriminator'))):
         args.append('type')
 
-    for arg in args:
-        if arg[0] == '*':
-            opt = True
-            desc = doc.args.get(arg[1:])
-        else:
-            opt = False
-            desc = doc.args.get(arg)
-        if not desc:
-            continue
-        desc.optional = opt
-        desc_opt = "#optional" in str(desc)
-        if desc_opt and not opt:
-            raise QAPISemError(info, "Description has #optional, "
-                               "but the declaration doesn't")
-        if not desc_opt and opt:
-            # TODO either fix the schema and make this an error,
-            # or drop #optional entirely
-            pass
-
     doc_args = set(doc.args.keys())
     args = set([name.strip('*') for name in args])
     if not doc_args.issubset(args):
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 6d4e757..4583477 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -145,8 +145,7 @@ def texi_members(doc, member_func, show_undocumented):
     for section in doc.args.itervalues():
         if not section.content and not show_undocumented:
             continue          # Undocumented TODO require doc and drop
-        desc = re.sub(r'^ *#optional *\n?|\n? *#optional *$|#optional',
-                      '', str(section))
+        desc = str(section)
         items += member_func(section.member) + texi_format(desc) + '\n'
     if not items:
         return ''
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 9f4e890..7230977 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -385,7 +385,6 @@ qapi-schema += doc-missing.json
 qapi-schema += doc-missing-colon.json
 qapi-schema += doc-missing-expr.json
 qapi-schema += doc-missing-space.json
-qapi-schema += doc-optional.json
 qapi-schema += double-data.json
 qapi-schema += double-type.json
 qapi-schema += duplicate-key.json
diff --git a/tests/qapi-schema/doc-optional.err b/tests/qapi-schema/doc-optional.err
deleted file mode 100644
index 20d405a..0000000
--- a/tests/qapi-schema/doc-optional.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/doc-optional.json:3: Description has #optional, but the declaration doesn't
diff --git a/tests/qapi-schema/doc-optional.exit b/tests/qapi-schema/doc-optional.exit
deleted file mode 100644
index d00491f..0000000
--- a/tests/qapi-schema/doc-optional.exit
+++ /dev/null
@@ -1 +0,0 @@
-1
diff --git a/tests/qapi-schema/doc-optional.json b/tests/qapi-schema/doc-optional.json
deleted file mode 100644
index 06c855e..0000000
--- a/tests/qapi-schema/doc-optional.json
+++ /dev/null
@@ -1,7 +0,0 @@
-# Description #optional should match declaration
-
-##
-# @foo:
-# @a: a #optional
-##
-{ 'command': 'foo', 'data': {'a': 'int'} }
diff --git a/tests/qapi-schema/doc-optional.out b/tests/qapi-schema/doc-optional.out
deleted file mode 100644
index e69de29..0000000
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 18/47] qapi: Use raw strings for regular expressions consistently
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (16 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 18:00   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 19/47] qapi: Prefer single-quoted strings more consistently Markus Armbruster
                   ` (31 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index c580e76..6d39ec9 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -550,7 +550,7 @@ def discriminator_find_enum_define(expr):
 # Names must be letters, numbers, -, and _.  They must start with letter,
 # except for downstream extensions which must start with __RFQDN_.
 # Dots are only valid in the downstream extension prefix.
-valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
+valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
                         '[a-zA-Z][a-zA-Z0-9_-]*$')
 
 
@@ -1827,10 +1827,10 @@ def cgen(code, **kwds):
     if indent_level:
         indent = genindent(indent_level)
         # re.subn() lacks flags support before Python 2.7, use re.compile()
-        raw = re.subn(re.compile("^.", re.MULTILINE),
+        raw = re.subn(re.compile(r'^.', re.MULTILINE),
                       indent + r'\g<0>', raw)
         raw = raw[0]
-    return re.sub(re.escape(eatspace) + ' *', '', raw)
+    return re.sub(re.escape(eatspace) + r' *', '', raw)
 
 
 def mcgen(code, **kwds):
@@ -1964,7 +1964,7 @@ def parse_command_line(extra_options="", extra_long_options=[]):
     for oa in opts:
         o, a = oa
         if o in ("-p", "--prefix"):
-            match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
+            match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
             if match.end() != len(a):
                 print >>sys.stderr, \
                     "%s: 'funny character '%s' in argument of --prefix" \
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 19/47] qapi: Prefer single-quoted strings more consistently
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (17 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 18/47] qapi: Use raw strings for regular expressions consistently Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 18:05   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 20/47] qapi2texi: Plainer enum value and member name formatting Markus Armbruster
                   ` (30 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

PEP 8 advises:

    In Python, single-quoted strings and double-quoted strings are the
    same.  This PEP does not make a recommendation for this.  Pick a
    rule and stick to it.  When a string contains single or double
    quote characters, however, use the other one to avoid backslashes
    in the string.  It improves readability.

The QAPI generators succeed at picking a rule, but fail at sticking to
it.  Convert a bunch of double-quoted strings to single-quoted ones.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi-event.py      |  2 +-
 scripts/qapi-introspect.py |  4 +-
 scripts/qapi-types.py      |  4 +-
 scripts/qapi-visit.py      |  4 +-
 scripts/qapi.py            | 96 +++++++++++++++++++++++-----------------------
 scripts/qapi2texi.py       | 46 +++++++++++-----------
 6 files changed, 78 insertions(+), 78 deletions(-)

diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index f4eb7f8..0485e39 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -223,7 +223,7 @@ fdecl.write(mcgen('''
 ''',
                   prefix=prefix))
 
-event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
+event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
 
 schema = QAPISchema(input_file)
 gen = QAPISchemaGenEventVisitor()
diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
index fb72c61..032bcea 100644
--- a/scripts/qapi-introspect.py
+++ b/scripts/qapi-introspect.py
@@ -170,10 +170,10 @@ const char %(c_name)s[] = %(c_string)s;
 opt_unmask = False
 
 (input_file, output_dir, do_c, do_h, prefix, opts) = \
-    parse_command_line("u", ["unmask-non-abi-names"])
+    parse_command_line('u', ['unmask-non-abi-names'])
 
 for o, a in opts:
-    if o in ("-u", "--unmask-non-abi-names"):
+    if o in ('-u', '--unmask-non-abi-names'):
         opt_unmask = True
 
 c_comment = '''
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index dabc42e..b45e7b5 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -244,10 +244,10 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
 do_builtins = False
 
 (input_file, output_dir, do_c, do_h, prefix, opts) = \
-    parse_command_line("b", ["builtins"])
+    parse_command_line('b', ['builtins'])
 
 for o, a in opts:
-    if o in ("-b", "--builtins"):
+    if o in ('-b', '--builtins'):
         do_builtins = True
 
 c_comment = '''
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 330b9f3..3d3936e 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -335,10 +335,10 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
 do_builtins = False
 
 (input_file, output_dir, do_c, do_h, prefix, opts) = \
-    parse_command_line("b", ["builtins"])
+    parse_command_line('b', ['builtins'])
 
 for o, a in opts:
-    if o in ("-b", "--builtins"):
+    if o in ('-b', '--builtins'):
         do_builtins = True
 
 c_comment = '''
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 6d39ec9..9430493 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -58,9 +58,9 @@ all_names = {}
 
 
 def error_path(parent):
-    res = ""
+    res = ''
     while parent:
-        res = ("In file included from %s:%d:\n" % (parent['file'],
+        res = ('In file included from %s:%d:\n' % (parent['file'],
                                                    parent['line'])) + res
         parent = parent['parent']
     return res
@@ -76,10 +76,10 @@ class QAPIError(Exception):
         self.msg = msg
 
     def __str__(self):
-        loc = "%s:%d" % (self.fname, self.line)
+        loc = '%s:%d' % (self.fname, self.line)
         if self.col is not None:
-            loc += ":%s" % self.col
-        return error_path(self.info) + "%s: %s" % (loc, self.msg)
+            loc += ':%s' % self.col
+        return error_path(self.info) + '%s: %s' % (loc, self.msg)
 
 
 class QAPIParseError(QAPIError):
@@ -113,7 +113,7 @@ class QAPIDoc(object):
             self.content.append(line)
 
         def __repr__(self):
-            return "\n".join(self.content).strip()
+            return '\n'.join(self.content).strip()
 
     class ArgSection(Section):
         def __init__(self, name):
@@ -163,8 +163,8 @@ class QAPIDoc(object):
         # recognized, and get silently treated as ordinary text
         if self.symbol:
             self._append_symbol_line(line)
-        elif not self.body.content and line.startswith("@"):
-            if not line.endswith(":"):
+        elif not self.body.content and line.startswith('@'):
+            if not line.endswith(':'):
                 raise QAPIParseError(self.parser, "Line should end with :")
             self.symbol = line[1:-1]
             # FIXME invalid names other than the empty string aren't flagged
@@ -176,14 +176,14 @@ class QAPIDoc(object):
     def _append_symbol_line(self, line):
         name = line.split(' ', 1)[0]
 
-        if name.startswith("@") and name.endswith(":"):
+        if name.startswith('@') and name.endswith(':'):
             line = line[len(name)+1:]
             self._start_args_section(name[1:-1])
-        elif name in ("Returns:", "Since:",
+        elif name in ('Returns:', 'Since:',
                       # those are often singular or plural
-                      "Note:", "Notes:",
-                      "Example:", "Examples:",
-                      "TODO:"):
+                      'Note:', 'Notes:',
+                      'Example:', 'Examples:',
+                      'TODO:'):
             line = line[len(name)+1:]
             self._start_section(name[:-1])
 
@@ -203,8 +203,8 @@ class QAPIDoc(object):
         self.section = QAPIDoc.ArgSection(name)
         self.args[name] = self.section
 
-    def _start_section(self, name=""):
-        if name in ("Returns", "Since") and self.has_section(name):
+    def _start_section(self, name=''):
+        if name in ('Returns', 'Since') and self.has_section(name):
             raise QAPIParseError(self.parser,
                                  "Duplicated '%s' section" % name)
         self.section = QAPIDoc.Section(name)
@@ -217,7 +217,7 @@ class QAPIDoc(object):
                 and line and not line[0].isspace()):
             self._start_section()
         if (in_arg or not self.section.name
-                or not self.section.name.startswith("Example")):
+                or not self.section.name.startswith('Example')):
             line = line.strip()
         # TODO Drop this once the dust has settled
         if (isinstance(self.section, QAPIDoc.ArgSection)
@@ -262,7 +262,7 @@ class QAPISchemaParser(object):
             if 'include' in expr:
                 if len(expr) != 1:
                     raise QAPISemError(info, "Invalid 'include' directive")
-                include = expr["include"]
+                include = expr['include']
                 if not isinstance(include, str):
                     raise QAPISemError(info,
                                        "Value of 'include' must be a string")
@@ -343,7 +343,7 @@ class QAPISchemaParser(object):
                 if not skip_comment:
                     self.val = self.src[self.pos:self.cursor]
                     return
-            elif self.tok in "{}:,[]":
+            elif self.tok in '{}:,[]':
                 return
             elif self.tok == "'":
                 string = ''
@@ -369,7 +369,7 @@ class QAPISchemaParser(object):
                             for _ in range(0, 4):
                                 ch = self.src[self.cursor]
                                 self.cursor += 1
-                                if ch not in "0123456789abcdefABCDEF":
+                                if ch not in '0123456789abcdefABCDEF':
                                     raise QAPIParseError(self,
                                                          '\\u escape needs 4 '
                                                          'hex digits')
@@ -384,28 +384,28 @@ class QAPISchemaParser(object):
                                                      'only supports non-zero '
                                                      'values up to \\u007f')
                             string += chr(value)
-                        elif ch in "\\/'\"":
+                        elif ch in '\\/\'"':
                             string += ch
                         else:
                             raise QAPIParseError(self,
                                                  "Unknown escape \\%s" % ch)
                         esc = False
-                    elif ch == "\\":
+                    elif ch == '\\':
                         esc = True
                     elif ch == "'":
                         self.val = string
                         return
                     else:
                         string += ch
-            elif self.src.startswith("true", self.pos):
+            elif self.src.startswith('true', self.pos):
                 self.val = True
                 self.cursor += 3
                 return
-            elif self.src.startswith("false", self.pos):
+            elif self.src.startswith('false', self.pos):
                 self.val = False
                 self.cursor += 4
                 return
-            elif self.src.startswith("null", self.pos):
+            elif self.src.startswith('null', self.pos):
                 self.val = None
                 self.cursor += 3
                 return
@@ -519,11 +519,11 @@ def find_alternate_member_qtype(qapi_type):
     if qapi_type in builtin_types:
         return builtin_types[qapi_type]
     elif find_struct(qapi_type):
-        return "QTYPE_QDICT"
+        return 'QTYPE_QDICT'
     elif find_enum(qapi_type):
-        return "QTYPE_QSTRING"
+        return 'QTYPE_QSTRING'
     elif find_union(qapi_type):
-        return "QTYPE_QDICT"
+        return 'QTYPE_QDICT'
     return None
 
 
@@ -624,7 +624,7 @@ def find_union(name):
 def add_enum(name, info, enum_values=None, implicit=False):
     global enum_types
     add_name(name, info, 'enum', implicit)
-    enum_types.append({"enum_name": name, "enum_values": enum_values})
+    enum_types.append({'enum_name': name, 'enum_values': enum_values})
 
 
 def find_enum(name):
@@ -784,7 +784,7 @@ def check_union(expr, info):
                 raise QAPISemError(info,
                                    "Discriminator value '%s' is not found in "
                                    "enum '%s'"
-                                   % (key, enum_define["enum_name"]))
+                                   % (key, enum_define['enum_name']))
 
     # If discriminator is user-defined, ensure all values are covered
     if enum_define:
@@ -989,7 +989,7 @@ def check_definition_doc(doc, expr, info):
     args = set([name.strip('*') for name in args])
     if not doc_args.issubset(args):
         raise QAPISemError(info, "The following documented members are not in "
-                           "the declaration: %s" % ", ".join(doc_args - args))
+                           "the declaration: %s" % ', '.join(doc_args - args))
 
 
 def check_docs(docs):
@@ -1483,7 +1483,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
 class QAPISchema(object):
     def __init__(self, fname):
         try:
-            parser = QAPISchemaParser(open(fname, "r"))
+            parser = QAPISchemaParser(open(fname, 'r'))
             self.exprs = check_exprs(parser.exprs)
             self.docs = check_docs(parser.docs)
             self._entity_dict = {}
@@ -1736,8 +1736,8 @@ def camel_to_upper(value):
     l = len(c_fun_str)
     for i in range(l):
         c = c_fun_str[i]
-        # When c is upper and no "_" appears before, do more checks
-        if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
+        # When c is upper and no '_' appears before, do more checks
+        if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_':
             if i < l - 1 and c_fun_str[i + 1].islower():
                 new_name += '_'
             elif c_fun_str[i - 1].isdigit():
@@ -1756,7 +1756,7 @@ c_name_trans = string.maketrans('.-', '__')
 
 # Map @name to a valid C identifier.
 # If @protect, avoid returning certain ticklish identifiers (like
-# C keywords) by prepending "q_".
+# C keywords) by prepending 'q_'.
 #
 # Used for converting 'name' from a 'name':'type' qapi definition
 # into a generated struct member, as well as converting type names
@@ -1794,7 +1794,7 @@ def c_name(name, protect=True):
     name = name.translate(c_name_trans)
     if protect and (name in c89_words | c99_words | c11_words | gcc_words
                     | cpp_words | polluted_words):
-        return "q_" + name
+        return 'q_' + name
     return name
 
 eatspace = '\033EATSPACE.'
@@ -1802,9 +1802,9 @@ pointer_suffix = ' *' + eatspace
 
 
 def genindent(count):
-    ret = ""
+    ret = ''
     for _ in range(count):
-        ret += " "
+        ret += ' '
     return ret
 
 indent_level = 0
@@ -1944,26 +1944,26 @@ def gen_params(arg_type, boxed, extra):
 #
 
 
-def parse_command_line(extra_options="", extra_long_options=[]):
+def parse_command_line(extra_options='', extra_long_options=[]):
 
     try:
         opts, args = getopt.gnu_getopt(sys.argv[1:],
-                                       "chp:o:" + extra_options,
-                                       ["source", "header", "prefix=",
-                                        "output-dir="] + extra_long_options)
+                                       'chp:o:' + extra_options,
+                                       ['source', 'header', 'prefix=',
+                                        'output-dir='] + extra_long_options)
     except getopt.GetoptError as err:
         print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
         sys.exit(1)
 
-    output_dir = ""
-    prefix = ""
+    output_dir = ''
+    prefix = ''
     do_c = False
     do_h = False
     extra_opts = []
 
     for oa in opts:
         o, a = oa
-        if o in ("-p", "--prefix"):
+        if o in ('-p', '--prefix'):
             match = re.match(r'([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
             if match.end() != len(a):
                 print >>sys.stderr, \
@@ -1971,11 +1971,11 @@ def parse_command_line(extra_options="", extra_long_options=[]):
                     % (sys.argv[0], a[match.end()])
                 sys.exit(1)
             prefix = a
-        elif o in ("-o", "--output-dir"):
-            output_dir = a + "/"
-        elif o in ("-c", "--source"):
+        elif o in ('-o', '--output-dir'):
+            output_dir = a + '/'
+        elif o in ('-c', '--source'):
             do_c = True
-        elif o in ("-h", "--header"):
+        elif o in ('-h', '--header'):
             do_h = True
         else:
             extra_opts.append(oa)
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 4583477..91cd593 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -50,7 +50,7 @@ def subst_vars(doc):
 
 def subst_braces(doc):
     """Replaces {} with @{ @}"""
-    return doc.replace("{", "@{").replace("}", "@}")
+    return doc.replace('{', '@{').replace('}', '@}')
 
 
 def texi_example(doc):
@@ -79,10 +79,10 @@ def texi_format(doc):
     doc = subst_vars(doc)
     doc = subst_emph(doc)
     doc = subst_strong(doc)
-    inlist = ""
+    inlist = ''
     lastempty = False
     for line in doc.split('\n'):
-        empty = line == ""
+        empty = line == ''
 
         # FIXME: Doing this in a single if / elif chain is
         # problematic.  For instance, a line without markup terminates
@@ -92,35 +92,35 @@ def texi_format(doc):
         #
         # Make sure to update section "Documentation markup" in
         # docs/qapi-code-gen.txt when fixing this.
-        if line.startswith("| "):
+        if line.startswith('| '):
             line = EXAMPLE_FMT(code=line[2:])
-        elif line.startswith("= "):
-            line = "@section " + line[2:]
-        elif line.startswith("== "):
-            line = "@subsection " + line[3:]
+        elif line.startswith('= '):
+            line = '@section ' + line[2:]
+        elif line.startswith('== '):
+            line = '@subsection ' + line[3:]
         elif re.match(r'^([0-9]*\.) ', line):
             if not inlist:
-                lines.append("@enumerate")
-                inlist = "enumerate"
-            line = line[line.find(" ")+1:]
-            lines.append("@item")
+                lines.append('@enumerate')
+                inlist = 'enumerate'
+            line = line[line.find(' ')+1:]
+            lines.append('@item')
         elif re.match(r'^[*-] ', line):
             if not inlist:
-                lines.append("@itemize %s" % {'*': "@bullet",
-                                              '-': "@minus"}[line[0]])
-                inlist = "itemize"
-            lines.append("@item")
+                lines.append('@itemize %s' % {'*': '@bullet',
+                                              '-': '@minus'}[line[0]])
+                inlist = 'itemize'
+            lines.append('@item')
             line = line[2:]
         elif lastempty and inlist:
-            lines.append("@end %s\n" % inlist)
-            inlist = ""
+            lines.append('@end %s\n' % inlist)
+            inlist = ''
 
         lastempty = empty
         lines.append(line)
 
     if inlist:
-        lines.append("@end %s\n" % inlist)
-    return "\n".join(lines)
+        lines.append('@end %s\n' % inlist)
+    return '\n'.join(lines)
 
 
 def texi_body(doc):
@@ -158,12 +158,12 @@ def texi_sections(doc):
     for section in doc.sections:
         name, doc = (section.name, str(section))
         func = texi_format
-        if name.startswith("Example"):
+        if name.startswith('Example'):
             func = texi_example
 
         if name:
             # prefer @b over @strong, so txt doesn't translate it to *Foo:*
-            body += "\n\n@b{%s:}\n" % name
+            body += '\n\n@b{%s:}\n' % name
 
         body += func(doc)
     return body
@@ -269,5 +269,5 @@ def main(argv):
     print texi_schema(schema)
 
 
-if __name__ == "__main__":
+if __name__ == '__main__':
     main(sys.argv)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 20/47] qapi2texi: Plainer enum value and member name formatting
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (18 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 19/47] qapi: Prefer single-quoted strings more consistently Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 18:06   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 21/47] qapi2texi: Present the table of members more clearly Markus Armbruster
                   ` (29 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Use @code{%s} instead of @code{'%s'}.  Impact, using @id as example:

* Texinfo
  -@item @code{'id'}
  +@item @code{id}

* HTML
  -<dt><code>'id'</code></dt>
  +<dt><code>id</code></dt>

* POD (for manual pages):
  -=item C<'id'>
  +=item C<id>

* Formatted manual pages:
  -'id'
  +"id"

* Plain text:
  -     ''id''
  +     'id'

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 91cd593..ecfaeda 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -130,12 +130,12 @@ def texi_body(doc):
 
 def texi_enum_value(value):
     """Format a table of members item for an enumeration value"""
-    return "@item @code{'%s'}\n" % value.name
+    return '@item @code{%s}\n' % value.name
 
 
 def texi_member(member):
     """Format a table of members item for an object type member"""
-    return "@item @code{'%s'}%s\n" % (
+    return '@item @code{%s}%s\n' % (
         member.name, ' (optional)' if member.optional else '')
 
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 21/47] qapi2texi: Present the table of members more clearly
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (19 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 20/47] qapi2texi: Plainer enum value and member name formatting Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 18:08   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 22/47] qapi2texi: Explain enum value undocumentedness " Markus Armbruster
                   ` (28 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

The table of members follows the main descriptive text immediately.
Makes it hard to see what it is about.  Start a new paragraph, and
lead with a line "Members:" for object and alternate types, "Values:"
for enumeration types, and "Arguments:" for commands and events.

Example change (qemu-qmp-ref.txt):

  -- Command: set_link

      Sets the link status of a virtual network adapter.
+
+     Arguments:
      'name'
           the device name of the virtual network adapter
      'up'
           true to set the link status to be up

      Returns: Nothing on success If 'name' is not a valid network
      device, DeviceNotFound

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index ecfaeda..35e182d 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -139,7 +139,7 @@ def texi_member(member):
         member.name, ' (optional)' if member.optional else '')
 
 
-def texi_members(doc, member_func, show_undocumented):
+def texi_members(doc, what, member_func, show_undocumented):
     """Format the table of members"""
     items = ''
     for section in doc.args.itervalues():
@@ -149,7 +149,7 @@ def texi_members(doc, member_func, show_undocumented):
         items += member_func(section.member) + texi_format(desc) + '\n'
     if not items:
         return ''
-    return '@table @asis\n' + items + '@end table\n'
+    return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
 
 
 def texi_sections(doc):
@@ -169,9 +169,10 @@ def texi_sections(doc):
     return body
 
 
-def texi_entity(doc, member_func=texi_member, show_undocumented=False):
+def texi_entity(doc, what, member_func=texi_member,
+                show_undocumented=False):
     return (texi_body(doc)
-            + texi_members(doc, member_func, show_undocumented)
+            + texi_members(doc, what, member_func, show_undocumented)
             + texi_sections(doc))
 
 
@@ -189,7 +190,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type='Enum',
                              name=doc.symbol,
-                             body=texi_entity(doc,
+                             body=texi_entity(doc, 'Values',
                                               member_func=texi_enum_value,
                                               show_undocumented=True))
 
@@ -205,7 +206,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type=typ,
                              name=doc.symbol,
-                             body=texi_entity(doc))
+                             body=texi_entity(doc, 'Members'))
 
     def visit_alternate_type(self, name, info, variants):
         doc = self.cur_doc
@@ -213,7 +214,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type='Alternate',
                              name=doc.symbol,
-                             body=texi_entity(doc))
+                             body=texi_entity(doc, 'Members'))
 
     def visit_command(self, name, info, arg_type, ret_type,
                       gen, success_response, boxed):
@@ -222,7 +223,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += MSG_FMT(type='Command',
                             name=doc.symbol,
-                            body=texi_entity(doc))
+                            body=texi_entity(doc, 'Arguments'))
 
     def visit_event(self, name, info, arg_type, boxed):
         doc = self.cur_doc
@@ -230,7 +231,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += MSG_FMT(type='Event',
                             name=doc.symbol,
-                            body=texi_entity(doc))
+                            body=texi_entity(doc, 'Arguments'))
 
     def symbol(self, doc, entity):
         self.cur_doc = doc
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 22/47] qapi2texi: Explain enum value undocumentedness more clearly
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (20 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 21/47] qapi2texi: Present the table of members more clearly Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:00   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 23/47] qapi2texi: Don't hide undocumented members and arguments Markus Armbruster
                   ` (27 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Instead of not saying anything when we have no documentation, say "Not
documented".

Example change (qemu-qmp-ref.txt):

  -- Enum: GuestPanicAction

      An enumeration of the actions taken when guest OS panic is detected

      Values:
      'pause'
           system pauses
      'poweroff'
+          Not documented

      Since: 2.1 (poweroff since 2.8)

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 35e182d..1f01817 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -145,7 +145,10 @@ def texi_members(doc, what, member_func, show_undocumented):
     for section in doc.args.itervalues():
         if not section.content and not show_undocumented:
             continue          # Undocumented TODO require doc and drop
-        desc = str(section)
+        if section.content:
+            desc = str(section)
+        else:
+            desc = 'Not documented'
         items += member_func(section.member) + texi_format(desc) + '\n'
     if not items:
         return ''
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 23/47] qapi2texi: Don't hide undocumented members and arguments
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (21 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 22/47] qapi2texi: Explain enum value undocumentedness " Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:02   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation Markus Armbruster
                   ` (26 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Show undocumented object, alternate type members and command, event
arguments exactly like undocumented enumeration type values.

Example change (qemu-qmp-ref.txt):

  -- Command: query-rocker

      Return rocker switch information.

+     Arguments:
+     'name'
+          Not documented
+
      Returns: 'Rocker' information

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 1f01817..df87441 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -139,12 +139,10 @@ def texi_member(member):
         member.name, ' (optional)' if member.optional else '')
 
 
-def texi_members(doc, what, member_func, show_undocumented):
+def texi_members(doc, what, member_func):
     """Format the table of members"""
     items = ''
     for section in doc.args.itervalues():
-        if not section.content and not show_undocumented:
-            continue          # Undocumented TODO require doc and drop
         if section.content:
             desc = str(section)
         else:
@@ -172,10 +170,9 @@ def texi_sections(doc):
     return body
 
 
-def texi_entity(doc, what, member_func=texi_member,
-                show_undocumented=False):
+def texi_entity(doc, what, member_func=texi_member):
     return (texi_body(doc)
-            + texi_members(doc, what, member_func, show_undocumented)
+            + texi_members(doc, what, member_func)
             + texi_sections(doc))
 
 
@@ -194,8 +191,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
         self.out += TYPE_FMT(type='Enum',
                              name=doc.symbol,
                              body=texi_entity(doc, 'Values',
-                                              member_func=texi_enum_value,
-                                              show_undocumented=True))
+                                              member_func=texi_enum_value))
 
     def visit_object_type(self, name, info, base, members, variants):
         doc = self.cur_doc
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (22 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 23/47] qapi2texi: Don't hide undocumented members and arguments Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:12   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation Markus Armbruster
                   ` (25 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

This replaces manual references like "For the arguments, see the
documentation of ..." by a generated reference "Arguments: the members
of ...".

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 qapi-schema.json     |  2 +-
 qapi/block-core.json | 10 ----------
 scripts/qapi2texi.py |  8 +++++++-
 3 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index d693033..1d7b1cd 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1017,7 +1017,7 @@
 ##
 # @migrate-set-parameters:
 #
-# Set various migration parameters.  See MigrationParameters for details.
+# Set various migration parameters.
 #
 # Since: 2.4
 #
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 539649c..83601db 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1340,8 +1340,6 @@
 # The operation can be stopped before it has completed using the
 # block-job-cancel command.
 #
-# For the arguments, see the documentation of DriveBackup.
-#
 # Returns: nothing on success
 #          If @device is not a valid block device, GenericError
 #
@@ -1368,8 +1366,6 @@
 # The operation can be stopped before it has completed using the
 # block-job-cancel command.
 #
-# For the arguments, see the documentation of BlockdevBackup.
-#
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
 #
@@ -1457,8 +1453,6 @@
 # format of the mirror image, default is to probe if mode='existing',
 # else the format of the source.
 #
-# See DriveMirror for parameter descriptions
-#
 # Returns: nothing on success
 #          If @device is not a valid block device, GenericError
 #
@@ -1730,8 +1724,6 @@
 # the device will be removed from its group and the rest of its
 # members will not be affected. The 'group' parameter is ignored.
 #
-# See BlockIOThrottle for parameter descriptions.
-#
 # Returns: Nothing on success
 #          If @device is not a valid block device, DeviceNotFound
 #
@@ -2944,8 +2936,6 @@
 # BlockBackend will be created; otherwise, @node-name is mandatory at the top
 # level and no BlockBackend will be created.
 #
-# For the arguments, see the documentation of BlockdevOptions.
-#
 # Note: This command is still a work in progress.  It doesn't support all
 # block drivers among other things.  Stay away from it unless you want
 # to help with its development.
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index df87441..3dd0146 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -220,9 +220,15 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
         doc = self.cur_doc
         if self.out:
             self.out += '\n'
+        if boxed:
+            body = texi_body(doc)
+            body += '\n@b{Arguments:} the members of @code{%s}' % arg_type.name
+            body += texi_sections(doc)
+        else:
+            body = texi_entity(doc, 'Arguments')
         self.out += MSG_FMT(type='Command',
                             name=doc.symbol,
-                            body=texi_entity(doc, 'Arguments'))
+                            body=body)
 
     def visit_event(self, name, info, arg_type, boxed):
         doc = self.cur_doc
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (23 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 12:42   ` Marc-André Lureau
  2017-03-14 19:16   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members Markus Armbruster
                   ` (24 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

The recent merge of docs/qmp-commands.txt and docs/qmp-events.txt into
the schema lost type information.  Fix this documentation regression.

Example change (qemu-qmp-ref.txt):

  -- Struct: InputKeyEvent

      Keyboard input event.

      Members:
-     'button'
+     'button: InputButton'
           Which button this event is for.
-     'down'
+     'down: boolean'
           True for key-down and false for key-up events.

      Since: 2.0

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py      | 14 ++++++++++++++
 scripts/qapi2texi.py |  8 ++++++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 9430493..b82a2a6 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1101,6 +1101,11 @@ class QAPISchemaType(QAPISchemaEntity):
         }
         return json2qtype.get(self.json_type())
 
+    def doc_type(self):
+        if self.is_implicit():
+            return None
+        return self.name
+
 
 class QAPISchemaBuiltinType(QAPISchemaType):
     def __init__(self, name, json_type, c_type):
@@ -1125,6 +1130,9 @@ class QAPISchemaBuiltinType(QAPISchemaType):
     def json_type(self):
         return self._json_type_name
 
+    def doc_type(self):
+        return self.json_type()
+
     def visit(self, visitor):
         visitor.visit_builtin_type(self.name, self.info, self.json_type())
 
@@ -1184,6 +1192,12 @@ class QAPISchemaArrayType(QAPISchemaType):
     def json_type(self):
         return 'array'
 
+    def doc_type(self):
+        elt_doc_type = self.element_type.doc_type()
+        if not elt_doc_type:
+            return None
+        return 'array of ' + elt_doc_type
+
     def visit(self, visitor):
         visitor.visit_array_type(self.name, self.info, self.element_type)
 
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 3dd0146..993b652 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -135,8 +135,12 @@ def texi_enum_value(value):
 
 def texi_member(member):
     """Format a table of members item for an object type member"""
-    return '@item @code{%s}%s\n' % (
-        member.name, ' (optional)' if member.optional else '')
+    typ = member.type.doc_type()
+    return '@item @code{%s%s%s}%s\n' % (
+        member.name,
+        ': ' if typ else '',
+        typ if typ else '',
+        ' (optional)' if member.optional else '')
 
 
 def texi_members(doc, what, member_func):
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (24 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:29   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members Markus Armbruster
                   ` (23 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

The generated documentation doesn't mention object type members
inherited from a base type.  Fix that.

Example change (qemu-qmp-ref.txt):

  -- Struct: VncServerInfo

      The network connection information for server

      Members:
      'auth' (optional)
	   authentication method used for the plain (non-websocket) VNC
	   server
+     The members of 'VncBasicInfo'

      Since: 2.1

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 993b652..7083d0c 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -143,7 +143,7 @@ def texi_member(member):
         ' (optional)' if member.optional else '')
 
 
-def texi_members(doc, what, member_func):
+def texi_members(doc, what, base, member_func):
     """Format the table of members"""
     items = ''
     for section in doc.args.itervalues():
@@ -152,6 +152,8 @@ def texi_members(doc, what, member_func):
         else:
             desc = 'Not documented'
         items += member_func(section.member) + texi_format(desc) + '\n'
+    if base:
+        items += '@item The members of @code{%s}\n' % base.doc_type()
     if not items:
         return ''
     return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
@@ -174,9 +176,9 @@ def texi_sections(doc):
     return body
 
 
-def texi_entity(doc, what, member_func=texi_member):
+def texi_entity(doc, what, base=None, member_func=texi_member):
     return (texi_body(doc)
-            + texi_members(doc, what, member_func)
+            + texi_members(doc, what, base, member_func)
             + texi_sections(doc))
 
 
@@ -205,11 +207,13 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             typ = 'Flat Union'
         else:
             typ = 'Simple Union'
+        if base and base.is_implicit():
+            base = None
         if self.out:
             self.out += '\n'
         self.out += TYPE_FMT(type=typ,
                              name=doc.symbol,
-                             body=texi_entity(doc, 'Members'))
+                             body=texi_entity(doc, 'Members', base))
 
     def visit_alternate_type(self, name, info, variants):
         doc = self.cur_doc
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (25 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:36   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 28/47] qapi2texi: Generate descriptions for simple union tags Markus Armbruster
                   ` (22 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

A flat union's branch brings in the members of another type.  Generate
a suitable reference to that type.

Example change (qemu-qmp-ref.txt):

  -- Flat Union: QCryptoBlockOpenOptions

      The options that are available for all encryption formats when
      opening an existing volume

      Members:
      The members of 'QCryptoBlockOptionsBase'
+     The members of 'QCryptoBlockOptionsQCow' when 'format' is "qcow"
+     The members of 'QCryptoBlockOptionsLUKS' when 'format' is "luks"

      Since: 2.6

A simple union's branch adds a member 'data' of some other type.
Generate documentation for that member.

Example change (qemu-qmp-ref.txt):

  -- Simple Union: SocketAddress

      Captures the address of a socket, which could also be a named file
      descriptor

      Members:
      'type'
	   Not documented
+     'data: InetSocketAddress' when 'type' is "inet"
+     'data: UnixSocketAddress' when 'type' is "unix"
+     'data: VsockSocketAddress' when 'type' is "vsock"
+     'data: String' when 'type' is "fd"

      Since: 1.3

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 7083d0c..ab6b6cd 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -133,17 +133,18 @@ def texi_enum_value(value):
     return '@item @code{%s}\n' % value.name
 
 
-def texi_member(member):
+def texi_member(member, suffix=''):
     """Format a table of members item for an object type member"""
     typ = member.type.doc_type()
-    return '@item @code{%s%s%s}%s\n' % (
+    return '@item @code{%s%s%s}%s%s\n' % (
         member.name,
         ': ' if typ else '',
         typ if typ else '',
-        ' (optional)' if member.optional else '')
+        ' (optional)' if member.optional else '',
+        suffix)
 
 
-def texi_members(doc, what, base, member_func):
+def texi_members(doc, what, base, variants, member_func):
     """Format the table of members"""
     items = ''
     for section in doc.args.itervalues():
@@ -154,6 +155,17 @@ def texi_members(doc, what, base, member_func):
         items += member_func(section.member) + texi_format(desc) + '\n'
     if base:
         items += '@item The members of @code{%s}\n' % base.doc_type()
+    if variants:
+        for v in variants.variants:
+            when = ' when @code{%s} is @t{"%s"}' % (
+                variants.tag_member.name, v.name)
+            if v.type.is_implicit():
+                assert not v.type.base and not v.type.variants
+                for m in v.type.local_members:
+                    items += member_func(m, when)
+            else:
+                items += '@item The members of @code{%s}%s\n' % (
+                    v.type.doc_type(), when)
     if not items:
         return ''
     return '\n@b{%s:}\n@table @asis\n%s@end table\n' % (what, items)
@@ -176,9 +188,10 @@ def texi_sections(doc):
     return body
 
 
-def texi_entity(doc, what, base=None, member_func=texi_member):
+def texi_entity(doc, what, base=None, variants=None,
+                member_func=texi_member):
     return (texi_body(doc)
-            + texi_members(doc, what, base, member_func)
+            + texi_members(doc, what, base, variants, member_func)
             + texi_sections(doc))
 
 
@@ -213,7 +226,7 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
             self.out += '\n'
         self.out += TYPE_FMT(type=typ,
                              name=doc.symbol,
-                             body=texi_entity(doc, 'Members', base))
+                             body=texi_entity(doc, 'Members', base, variants))
 
     def visit_alternate_type(self, name, info, variants):
         doc = self.cur_doc
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 28/47] qapi2texi: Generate descriptions for simple union tags
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (26 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:54   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 29/47] qapi2texi: Use category "Object" for all object types Markus Armbruster
                   ` (21 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Simple union tags carry no type information, because their type is
implicit.  Their description should make up for it, but many have
none.  Generate one automatically then.

Example change (qemu-qmp-ref.txt):

  -- Simple Union: ImageInfoSpecific

      A discriminated record of image format specific information
      structures.

      Members:
      'type'
-          Not documented
+          One of "qcow2", "vmdk", "luks"
      'data: ImageInfoSpecificQCow2' when 'type' is "qcow2"
      'data: ImageInfoSpecificVmdk' when 'type' is "vmdk"
      'data: QCryptoBlockInfoLUKS' when 'type' is "luks"

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index ab6b6cd..282adf4 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -148,11 +148,16 @@ def texi_members(doc, what, base, variants, member_func):
     """Format the table of members"""
     items = ''
     for section in doc.args.itervalues():
+        # TODO Drop fallbacks when undocumented members are outlawed
         if section.content:
-            desc = str(section)
+            desc = texi_format(str(section))
+        elif (variants and variants.tag_member == section.member
+              and not section.member.type.doc_type()):
+            values = section.member.type.member_names()
+            desc = 'One of ' + ', '.join(['@t{"%s"}' % v for v in values])
         else:
             desc = 'Not documented'
-        items += member_func(section.member) + texi_format(desc) + '\n'
+        items += member_func(section.member) + desc + '\n'
     if base:
         items += '@item The members of @code{%s}\n' % base.doc_type()
     if variants:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 29/47] qapi2texi: Use category "Object" for all object types
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (27 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 28/47] qapi2texi: Generate descriptions for simple union tags Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 19:56   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage Markus Armbruster
                   ` (20 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

At the protocol level, the distinction between struct, flat union and
simple union is meaningless, they are all JSON objects.  Document them
that way.

Example change (qemu-qmp-ref.txt):

- -- Simple Union: InputEvent
+ -- Object: InputEvent

      Input event union.

This also fixes the completely broken headings for flat and simple
unions in qemu-qmp-ref.7 and qemu-ga-ref.7, by sidestepping a bug in
texi2pod.pl.  For instance, it mistranslates "@deftp {Simple Union}
InputEvent" to "B<Union> (Simple)", but translates "@deftp Object
InputEvent" to "B<SocketAddress> (Object)".

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi2texi.py | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
index 282adf4..8eed11a 100755
--- a/scripts/qapi2texi.py
+++ b/scripts/qapi2texi.py
@@ -219,17 +219,11 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
 
     def visit_object_type(self, name, info, base, members, variants):
         doc = self.cur_doc
-        if not variants:
-            typ = 'Struct'
-        elif variants._tag_name:        # TODO unclean member access
-            typ = 'Flat Union'
-        else:
-            typ = 'Simple Union'
         if base and base.is_implicit():
             base = None
         if self.out:
             self.out += '\n'
-        self.out += TYPE_FMT(type=typ,
+        self.out += TYPE_FMT(type='Object',
                              name=doc.symbol,
                              body=texi_entity(doc, 'Members', base, variants))
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (28 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 29/47] qapi2texi: Use category "Object" for all object types Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:02   ` Eric Blake
  2017-03-14 20:36   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch Markus Armbruster
                   ` (19 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

New test doc-bad-expr.json shows we fail to reject a misplaced
expression comment.

New test doc-no-symbol.json shows a bad error message.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/Makefile.include               | 2 ++
 tests/qapi-schema/doc-bad-expr.err   | 0
 tests/qapi-schema/doc-bad-expr.exit  | 1 +
 tests/qapi-schema/doc-bad-expr.json  | 8 ++++++++
 tests/qapi-schema/doc-bad-expr.out   | 4 ++++
 tests/qapi-schema/doc-no-symbol.err  | 1 +
 tests/qapi-schema/doc-no-symbol.exit | 1 +
 tests/qapi-schema/doc-no-symbol.json | 7 +++++++
 tests/qapi-schema/doc-no-symbol.out  | 0
 9 files changed, 24 insertions(+)
 create mode 100644 tests/qapi-schema/doc-bad-expr.err
 create mode 100644 tests/qapi-schema/doc-bad-expr.exit
 create mode 100644 tests/qapi-schema/doc-bad-expr.json
 create mode 100644 tests/qapi-schema/doc-bad-expr.out
 create mode 100644 tests/qapi-schema/doc-no-symbol.err
 create mode 100644 tests/qapi-schema/doc-no-symbol.exit
 create mode 100644 tests/qapi-schema/doc-no-symbol.json
 create mode 100644 tests/qapi-schema/doc-no-symbol.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 7230977..800acbf 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -368,6 +368,7 @@ qapi-schema += base-cycle-indirect.json
 qapi-schema += command-int.json
 qapi-schema += comments.json
 qapi-schema += doc-bad-args.json
+qapi-schema += doc-bad-expr.json
 qapi-schema += doc-bad-symbol.json
 qapi-schema += doc-duplicated-arg.json
 qapi-schema += doc-duplicated-return.json
@@ -385,6 +386,7 @@ qapi-schema += doc-missing.json
 qapi-schema += doc-missing-colon.json
 qapi-schema += doc-missing-expr.json
 qapi-schema += doc-missing-space.json
+qapi-schema += doc-no-symbol.json
 qapi-schema += double-data.json
 qapi-schema += double-type.json
 qapi-schema += duplicate-key.json
diff --git a/tests/qapi-schema/doc-bad-expr.err b/tests/qapi-schema/doc-bad-expr.err
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/doc-bad-expr.exit b/tests/qapi-schema/doc-bad-expr.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-expr.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/doc-bad-expr.json b/tests/qapi-schema/doc-bad-expr.json
new file mode 100644
index 0000000..ec1fbf2
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-expr.json
@@ -0,0 +1,8 @@
+# Doc comment separated from defining expression by non-defining expression
+# BUG: not rejected
+
+##
+# @foo:
+##
+{ 'include': 'empty.json' }
+{ 'struct': 'foo', 'data': {} }
diff --git a/tests/qapi-schema/doc-bad-expr.out b/tests/qapi-schema/doc-bad-expr.out
new file mode 100644
index 0000000..236a849
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-expr.out
@@ -0,0 +1,4 @@
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+    prefix QTYPE
+object foo
+object q_empty
diff --git a/tests/qapi-schema/doc-no-symbol.err b/tests/qapi-schema/doc-no-symbol.err
new file mode 100644
index 0000000..727966c
--- /dev/null
+++ b/tests/qapi-schema/doc-no-symbol.err
@@ -0,0 +1 @@
+tests/qapi-schema/doc-no-symbol.json:4: Definition of 'foo' follows documentation for 'None'
diff --git a/tests/qapi-schema/doc-no-symbol.exit b/tests/qapi-schema/doc-no-symbol.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/doc-no-symbol.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/doc-no-symbol.json b/tests/qapi-schema/doc-no-symbol.json
new file mode 100644
index 0000000..ee86ca1
--- /dev/null
+++ b/tests/qapi-schema/doc-no-symbol.json
@@ -0,0 +1,7 @@
+# Documentation for expression lacks symbol
+# BUG: Error message claims it has symbol 'None'
+
+##
+# foo:
+##
+{ 'command': 'foo', 'data': {'a': 'int'} }
diff --git a/tests/qapi-schema/doc-no-symbol.out b/tests/qapi-schema/doc-no-symbol.out
new file mode 100644
index 0000000..e69de29
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (29 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:35   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch Markus Armbruster
                   ` (18 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

This fixes the errors uncovered by the previous commit.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                        | 34 +++++++++++++++++++++-------------
 tests/qapi-schema/doc-bad-expr.err     |  1 +
 tests/qapi-schema/doc-bad-expr.exit    |  2 +-
 tests/qapi-schema/doc-bad-expr.json    |  1 -
 tests/qapi-schema/doc-bad-expr.out     |  4 ----
 tests/qapi-schema/doc-missing-expr.err |  2 +-
 tests/qapi-schema/doc-no-symbol.err    |  2 +-
 tests/qapi-schema/doc-no-symbol.json   |  1 -
 8 files changed, 25 insertions(+), 22 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index b82a2a6..1052274 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -248,18 +248,21 @@ class QAPISchemaParser(object):
         self.line_pos = 0
         self.exprs = []
         self.docs = []
+        self.cur_doc = None
         self.accept()
 
         while self.tok is not None:
             info = {'file': fname, 'line': self.line,
                     'parent': self.incl_info}
             if self.tok == '#':
-                doc = self.get_doc(info)
-                self.docs.append(doc)
+                self.reject_expr_doc()
+                self.cur_doc = self.get_doc(info)
+                self.docs.append(self.cur_doc)
                 continue
 
             expr = self.get_expr(False)
             if 'include' in expr:
+                self.reject_expr_doc()
                 if len(expr) != 1:
                     raise QAPISemError(info, "Invalid 'include' directive")
                 include = expr['include']
@@ -276,13 +279,23 @@ class QAPISchemaParser(object):
             else:
                 expr_elem = {'expr': expr,
                              'info': info}
-                if (self.docs
-                        and self.docs[-1].info['file'] == fname
-                        and not self.docs[-1].expr):
-                    self.docs[-1].expr = expr
-                    expr_elem['doc'] = self.docs[-1]
-
+                if self.cur_doc:
+                    if not self.cur_doc.symbol:
+                        raise QAPISemError(
+                            self.cur_doc.info,
+                            "Expression documentation required")
+                    self.cur_doc.expr = expr
+                    expr_elem['doc'] = self.cur_doc
                 self.exprs.append(expr_elem)
+            self.cur_doc = None
+        self.reject_expr_doc()
+
+    def reject_expr_doc(self):
+        if self.cur_doc and self.cur_doc.symbol:
+            raise QAPISemError(
+                self.cur_doc.info,
+                "Documentation for '%s' is not followed by the definition"
+                % self.cur_doc.symbol)
 
     def _include(self, include, info, base_dir, previously_included):
         incl_abs_fname = os.path.join(base_dir, include)
@@ -946,11 +959,6 @@ def check_exprs(exprs):
 
 
 def check_freeform_doc(doc):
-    if doc.symbol:
-        raise QAPISemError(doc.info,
-                           "Documention for '%s' is not followed"
-                           " by the definition" % doc.symbol)
-
     body = str(doc.body)
     if re.search(r'@\S+:', body, re.MULTILINE):
         raise QAPISemError(doc.info,
diff --git a/tests/qapi-schema/doc-bad-expr.err b/tests/qapi-schema/doc-bad-expr.err
index e69de29..65e9d1f 100644
--- a/tests/qapi-schema/doc-bad-expr.err
+++ b/tests/qapi-schema/doc-bad-expr.err
@@ -0,0 +1 @@
+tests/qapi-schema/doc-bad-expr.json:3: Documentation for 'foo' is not followed by the definition
diff --git a/tests/qapi-schema/doc-bad-expr.exit b/tests/qapi-schema/doc-bad-expr.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/doc-bad-expr.exit
+++ b/tests/qapi-schema/doc-bad-expr.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/doc-bad-expr.json b/tests/qapi-schema/doc-bad-expr.json
index ec1fbf2..0caa0ae 100644
--- a/tests/qapi-schema/doc-bad-expr.json
+++ b/tests/qapi-schema/doc-bad-expr.json
@@ -1,5 +1,4 @@
 # Doc comment separated from defining expression by non-defining expression
-# BUG: not rejected
 
 ##
 # @foo:
diff --git a/tests/qapi-schema/doc-bad-expr.out b/tests/qapi-schema/doc-bad-expr.out
index 236a849..e69de29 100644
--- a/tests/qapi-schema/doc-bad-expr.out
+++ b/tests/qapi-schema/doc-bad-expr.out
@@ -1,4 +0,0 @@
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
-    prefix QTYPE
-object foo
-object q_empty
diff --git a/tests/qapi-schema/doc-missing-expr.err b/tests/qapi-schema/doc-missing-expr.err
index c0e687c..c909e26 100644
--- a/tests/qapi-schema/doc-missing-expr.err
+++ b/tests/qapi-schema/doc-missing-expr.err
@@ -1 +1 @@
-tests/qapi-schema/doc-missing-expr.json:3: Documention for 'bar' is not followed by the definition
+tests/qapi-schema/doc-missing-expr.json:3: Documentation for 'bar' is not followed by the definition
diff --git a/tests/qapi-schema/doc-no-symbol.err b/tests/qapi-schema/doc-no-symbol.err
index 727966c..75f032a 100644
--- a/tests/qapi-schema/doc-no-symbol.err
+++ b/tests/qapi-schema/doc-no-symbol.err
@@ -1 +1 @@
-tests/qapi-schema/doc-no-symbol.json:4: Definition of 'foo' follows documentation for 'None'
+tests/qapi-schema/doc-no-symbol.json:3: Expression documentation required
diff --git a/tests/qapi-schema/doc-no-symbol.json b/tests/qapi-schema/doc-no-symbol.json
index ee86ca1..98605ba 100644
--- a/tests/qapi-schema/doc-no-symbol.json
+++ b/tests/qapi-schema/doc-no-symbol.json
@@ -1,5 +1,4 @@
 # Documentation for expression lacks symbol
-# BUG: Error message claims it has symbol 'None'
 
 ##
 # foo:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (30 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:43   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 33/47] qapi: Improve error message on @NAME: in free-form doc Markus Armbruster
                   ` (17 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Move the check whether the doc matches the expression name from
check_definition_doc() to check_exprs().  This changes the error
location from the comment to the expression.  Makes sense as the
message talks about the expresion: "Definition of '%s' follows
documentation for '%s'".  It's also a step towards getting rid of
check_docs().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                      | 28 ++++++++++++++++++----------
 tests/qapi-schema/doc-bad-symbol.err |  2 +-
 2 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 1052274..ca8d1f0 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -889,40 +889,52 @@ def check_keys(expr_elem, meta, required, optional=[]):
 def check_exprs(exprs):
     global all_names
 
-    # Learn the types and check for valid expression keys
+    # Populate name table with names of built-in types
     for builtin in builtin_types.keys():
         all_names[builtin] = 'built-in'
+
+    # Learn the types and check for valid expression keys
     for expr_elem in exprs:
         expr = expr_elem['expr']
         info = expr_elem['info']
+        doc = expr_elem.get('doc')
 
-        if 'doc' not in expr_elem and doc_required:
+        if not doc and doc_required:
             raise QAPISemError(info,
                                "Expression missing documentation comment")
 
         if 'enum' in expr:
+            name = expr['enum']
             check_keys(expr_elem, 'enum', ['data'], ['prefix'])
-            add_enum(expr['enum'], info, expr['data'])
+            add_enum(name, info, expr['data'])
         elif 'union' in expr:
+            name = expr['union']
             check_keys(expr_elem, 'union', ['data'],
                        ['base', 'discriminator'])
             add_union(expr, info)
         elif 'alternate' in expr:
+            name = expr['alternate']
             check_keys(expr_elem, 'alternate', ['data'])
-            add_name(expr['alternate'], info, 'alternate')
+            add_name(name, info, 'alternate')
         elif 'struct' in expr:
+            name = expr['struct']
             check_keys(expr_elem, 'struct', ['data'], ['base'])
             add_struct(expr, info)
         elif 'command' in expr:
+            name = expr['command']
             check_keys(expr_elem, 'command', [],
                        ['data', 'returns', 'gen', 'success-response', 'boxed'])
-            add_name(expr['command'], info, 'command')
+            add_name(name, info, 'command')
         elif 'event' in expr:
+            name = expr['event']
             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
-            add_name(expr['event'], info, 'event')
+            add_name(name, info, 'event')
         else:
             raise QAPISemError(expr_elem['info'],
                                "Expression is missing metatype")
+        if doc and doc.symbol != name:
+            raise QAPISemError(info, "Definition of '%s' follows documentation"
+                               " for '%s'" % (name, doc.symbol))
 
     # Try again for hidden UnionKind enum
     for expr_elem in exprs:
@@ -972,10 +984,6 @@ def check_definition_doc(doc, expr, info):
             meta = i
             break
 
-    name = expr[meta]
-    if doc.symbol != name:
-        raise QAPISemError(info, "Definition of '%s' follows documentation"
-                           " for '%s'" % (name, doc.symbol))
     if doc.has_section('Returns') and 'command' not in expr:
         raise QAPISemError(info, "'Returns:' is only valid for commands")
 
diff --git a/tests/qapi-schema/doc-bad-symbol.err b/tests/qapi-schema/doc-bad-symbol.err
index ac4e566..8472030 100644
--- a/tests/qapi-schema/doc-bad-symbol.err
+++ b/tests/qapi-schema/doc-bad-symbol.err
@@ -1 +1 @@
-tests/qapi-schema/doc-bad-symbol.json:3: Definition of 'foo' follows documentation for 'food'
+tests/qapi-schema/doc-bad-symbol.json:6: Definition of 'foo' follows documentation for 'food'
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 33/47] qapi: Improve error message on @NAME: in free-form doc
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (31 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:46   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser Markus Armbruster
                   ` (16 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                           | 17 ++++++-----------
 tests/qapi-schema/doc-invalid-section.err |  2 +-
 2 files changed, 7 insertions(+), 12 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index ca8d1f0..8d34651 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -219,6 +219,11 @@ class QAPIDoc(object):
         if (in_arg or not self.section.name
                 or not self.section.name.startswith('Example')):
             line = line.strip()
+        match = re.match(r'(@\S+:)', line)
+        if match:
+            raise QAPIParseError(self.parser,
+                                 "'%s' not allowed in free-form documentation"
+                                 % match.group(1))
         # TODO Drop this once the dust has settled
         if (isinstance(self.section, QAPIDoc.ArgSection)
                 and '#optional' in line):
@@ -970,14 +975,6 @@ def check_exprs(exprs):
     return exprs
 
 
-def check_freeform_doc(doc):
-    body = str(doc.body)
-    if re.search(r'@\S+:', body, re.MULTILINE):
-        raise QAPISemError(doc.info,
-                           "Free-form documentation block must not contain"
-                           " @NAME: sections")
-
-
 def check_definition_doc(doc, expr, info):
     for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
         if i in expr:
@@ -1016,9 +1013,7 @@ def check_docs(docs):
                 raise QAPISemError(doc.info,
                                    "Empty doc section '%s'" % section.name)
 
-        if not doc.expr:
-            check_freeform_doc(doc)
-        else:
+        if doc.expr:
             check_definition_doc(doc, doc.expr, doc.info)
 
     return docs
diff --git a/tests/qapi-schema/doc-invalid-section.err b/tests/qapi-schema/doc-invalid-section.err
index 85bb67b..bda93b4 100644
--- a/tests/qapi-schema/doc-invalid-section.err
+++ b/tests/qapi-schema/doc-invalid-section.err
@@ -1 +1 @@
-tests/qapi-schema/doc-invalid-section.json:3: Free-form documentation block must not contain @NAME: sections
+tests/qapi-schema/doc-invalid-section.json:5:1: '@note:' not allowed in free-form documentation
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (32 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 33/47] qapi: Improve error message on @NAME: in free-form doc Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-13  6:23   ` Markus Armbruster
  2017-03-15  1:37   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 35/47] tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg Markus Armbruster
                   ` (15 subsequent siblings)
  49 siblings, 2 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Results in a more precise error location, but the real reason is
emptying out check_docs() step by step.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                         | 20 ++++++++++++++------
 tests/qapi-schema/doc-empty-section.err |  2 +-
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 8d34651..e53701a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -173,6 +173,9 @@ class QAPIDoc(object):
         else:
             self._append_freeform(line)
 
+    def end_comment(self):
+        self._end_section()
+
     def _append_symbol_line(self, line):
         name = line.split(' ', 1)[0]
 
@@ -200,6 +203,7 @@ class QAPIDoc(object):
             raise QAPIParseError(self.parser,
                                  "'@%s:' can't follow '%s' section"
                                  % (name, self.sections[0].name))
+        self._end_section()
         self.section = QAPIDoc.ArgSection(name)
         self.args[name] = self.section
 
@@ -207,9 +211,18 @@ class QAPIDoc(object):
         if name in ('Returns', 'Since') and self.has_section(name):
             raise QAPIParseError(self.parser,
                                  "Duplicated '%s' section" % name)
+        self._end_section()
         self.section = QAPIDoc.Section(name)
         self.sections.append(self.section)
 
+    def _end_section(self):
+        if self.section:
+            contents = str(self.section)
+            if self.section.name and (not contents or contents.isspace()):
+                raise QAPIParseError(self.parser, "Empty doc section '%s'"
+                                     % self.section.name)
+            self.section = None
+
     def _append_freeform(self, line):
         in_arg = isinstance(self.section, QAPIDoc.ArgSection)
         if (in_arg and self.section.content
@@ -507,6 +520,7 @@ class QAPISchemaParser(object):
                 if self.val != '##':
                     raise QAPIParseError(self, "Junk after '##' at end of "
                                          "documentation comment")
+                doc.end_comment()
                 self.accept()
                 return doc
             else:
@@ -1007,12 +1021,6 @@ def check_definition_doc(doc, expr, info):
 
 def check_docs(docs):
     for doc in docs:
-        for section in doc.args.values() + doc.sections:
-            content = str(section)
-            if not content or content.isspace():
-                raise QAPISemError(doc.info,
-                                   "Empty doc section '%s'" % section.name)
-
         if doc.expr:
             check_definition_doc(doc, doc.expr, doc.info)
 
diff --git a/tests/qapi-schema/doc-empty-section.err b/tests/qapi-schema/doc-empty-section.err
index 00ad625..b61e4a7 100644
--- a/tests/qapi-schema/doc-empty-section.err
+++ b/tests/qapi-schema/doc-empty-section.err
@@ -1 +1 @@
-tests/qapi-schema/doc-empty-section.json:3: Empty doc section 'Note'
+tests/qapi-schema/doc-empty-section.json:7:1: Empty doc section 'Note'
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 35/47] tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (33 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:47   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 36/47] tests/qapi-schema: Improve coverage of bogus member docs Markus Armbruster
                   ` (14 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/Makefile.include                                            | 2 +-
 tests/qapi-schema/doc-bad-args.err                                | 1 -
 tests/qapi-schema/doc-bad-command-arg.err                         | 1 +
 tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit} | 0
 tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json} | 0
 tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out}   | 0
 6 files changed, 2 insertions(+), 2 deletions(-)
 delete mode 100644 tests/qapi-schema/doc-bad-args.err
 create mode 100644 tests/qapi-schema/doc-bad-command-arg.err
 rename tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit} (100%)
 rename tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json} (100%)
 rename tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out} (100%)

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 800acbf..8ce9d3d 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -367,7 +367,7 @@ qapi-schema += base-cycle-direct.json
 qapi-schema += base-cycle-indirect.json
 qapi-schema += command-int.json
 qapi-schema += comments.json
-qapi-schema += doc-bad-args.json
+qapi-schema += doc-bad-command-arg.json
 qapi-schema += doc-bad-expr.json
 qapi-schema += doc-bad-symbol.json
 qapi-schema += doc-duplicated-arg.json
diff --git a/tests/qapi-schema/doc-bad-args.err b/tests/qapi-schema/doc-bad-args.err
deleted file mode 100644
index 5d44d9b..0000000
--- a/tests/qapi-schema/doc-bad-args.err
+++ /dev/null
@@ -1 +0,0 @@
-tests/qapi-schema/doc-bad-args.json:3: The following documented members are not in the declaration: b
diff --git a/tests/qapi-schema/doc-bad-command-arg.err b/tests/qapi-schema/doc-bad-command-arg.err
new file mode 100644
index 0000000..8075b14
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-command-arg.err
@@ -0,0 +1 @@
+tests/qapi-schema/doc-bad-command-arg.json:3: The following documented members are not in the declaration: b
diff --git a/tests/qapi-schema/doc-bad-args.exit b/tests/qapi-schema/doc-bad-command-arg.exit
similarity index 100%
rename from tests/qapi-schema/doc-bad-args.exit
rename to tests/qapi-schema/doc-bad-command-arg.exit
diff --git a/tests/qapi-schema/doc-bad-args.json b/tests/qapi-schema/doc-bad-command-arg.json
similarity index 100%
rename from tests/qapi-schema/doc-bad-args.json
rename to tests/qapi-schema/doc-bad-command-arg.json
diff --git a/tests/qapi-schema/doc-bad-args.out b/tests/qapi-schema/doc-bad-command-arg.out
similarity index 100%
rename from tests/qapi-schema/doc-bad-args.out
rename to tests/qapi-schema/doc-bad-command-arg.out
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 36/47] tests/qapi-schema: Improve coverage of bogus member docs
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (34 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 35/47] tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:55   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation Markus Armbruster
                   ` (13 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

New test doc-bad-union-member.json shows we can fail to reject
documentation for nonexistent members.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 tests/Makefile.include                          |  2 ++
 tests/qapi-schema/doc-bad-alternate-member.err  |  1 +
 tests/qapi-schema/doc-bad-alternate-member.exit |  1 +
 tests/qapi-schema/doc-bad-alternate-member.json |  9 +++++++++
 tests/qapi-schema/doc-bad-alternate-member.out  |  0
 tests/qapi-schema/doc-bad-union-member.err      |  0
 tests/qapi-schema/doc-bad-union-member.exit     |  1 +
 tests/qapi-schema/doc-bad-union-member.json     | 19 +++++++++++++++++++
 tests/qapi-schema/doc-bad-union-member.out      | 11 +++++++++++
 9 files changed, 44 insertions(+)
 create mode 100644 tests/qapi-schema/doc-bad-alternate-member.err
 create mode 100644 tests/qapi-schema/doc-bad-alternate-member.exit
 create mode 100644 tests/qapi-schema/doc-bad-alternate-member.json
 create mode 100644 tests/qapi-schema/doc-bad-alternate-member.out
 create mode 100644 tests/qapi-schema/doc-bad-union-member.err
 create mode 100644 tests/qapi-schema/doc-bad-union-member.exit
 create mode 100644 tests/qapi-schema/doc-bad-union-member.json
 create mode 100644 tests/qapi-schema/doc-bad-union-member.out

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 8ce9d3d..5edf3fa 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -367,9 +367,11 @@ qapi-schema += base-cycle-direct.json
 qapi-schema += base-cycle-indirect.json
 qapi-schema += command-int.json
 qapi-schema += comments.json
+qapi-schema += doc-bad-alternate-member.json
 qapi-schema += doc-bad-command-arg.json
 qapi-schema += doc-bad-expr.json
 qapi-schema += doc-bad-symbol.json
+qapi-schema += doc-bad-union-member.json
 qapi-schema += doc-duplicated-arg.json
 qapi-schema += doc-duplicated-return.json
 qapi-schema += doc-duplicated-since.json
diff --git a/tests/qapi-schema/doc-bad-alternate-member.err b/tests/qapi-schema/doc-bad-alternate-member.err
new file mode 100644
index 0000000..387f782
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-alternate-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/doc-bad-alternate-member.json:3: The following documented members are not in the declaration: aa, bb
diff --git a/tests/qapi-schema/doc-bad-alternate-member.exit b/tests/qapi-schema/doc-bad-alternate-member.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-alternate-member.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/doc-bad-alternate-member.json b/tests/qapi-schema/doc-bad-alternate-member.json
new file mode 100644
index 0000000..738635c
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-alternate-member.json
@@ -0,0 +1,9 @@
+# Arguments listed in the doc comment must exist in the actual schema
+
+##
+# @AorB:
+# @aa: a
+# @bb: b
+##
+{ 'alternate': 'AorB',
+  'data': { 'a': 'str', 'b': 'int' } }
diff --git a/tests/qapi-schema/doc-bad-alternate-member.out b/tests/qapi-schema/doc-bad-alternate-member.out
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/doc-bad-union-member.err b/tests/qapi-schema/doc-bad-union-member.err
new file mode 100644
index 0000000..e69de29
diff --git a/tests/qapi-schema/doc-bad-union-member.exit b/tests/qapi-schema/doc-bad-union-member.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-union-member.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/doc-bad-union-member.json b/tests/qapi-schema/doc-bad-union-member.json
new file mode 100644
index 0000000..d611435
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-union-member.json
@@ -0,0 +1,19 @@
+# Arguments listed in the doc comment must exist in the actual schema
+
+##
+# @Frob:
+# @a: a
+# @b: b
+##
+{ 'union': 'Frob',
+  'base': 'Base',
+  'discriminator': 'type',
+  'data': { 'nothing': 'Empty' } }
+
+{ 'struct': 'Base',
+  'data': { 'type': 'T' } }
+
+{ 'struct': 'Empty',
+  'data': { } }
+
+{ 'enum': 'T', 'data': ['nothing'] }
diff --git a/tests/qapi-schema/doc-bad-union-member.out b/tests/qapi-schema/doc-bad-union-member.out
new file mode 100644
index 0000000..2576ecd
--- /dev/null
+++ b/tests/qapi-schema/doc-bad-union-member.out
@@ -0,0 +1,11 @@
+object Base
+    member type: T optional=False
+object Empty
+object Frob
+    base Base
+    tag type
+    case nothing: Empty
+enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
+    prefix QTYPE
+enum T ['nothing']
+object q_empty
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (35 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 36/47] tests/qapi-schema: Improve coverage of bogus member docs Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 20:58   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 38/47] qapi: Eliminate check_docs() and drop QAPIDoc.expr Markus Armbruster
                   ` (12 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

check_definition_doc() checks for member documentation without a
matching member.  It laboriously second-guesses what members
QAPISchema._def_exprs() will create.  That's a stupid game.

Move the check into QAPISchema.check(), where the members are known.
Delegate the actual checking to new QAPIDoc.check().

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                             | 38 ++++++++++-------------------
 tests/qapi-schema/doc-bad-union-member.err  |  1 +
 tests/qapi-schema/doc-bad-union-member.exit |  2 +-
 tests/qapi-schema/doc-bad-union-member.out  | 11 ---------
 4 files changed, 15 insertions(+), 37 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index e53701a..0b0ba59 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -249,6 +249,15 @@ class QAPIDoc(object):
             self.args[member.name] = QAPIDoc.ArgSection(member.name)
         self.args[member.name].connect(member)
 
+    def check(self):
+        bogus = [name for name, section in self.args.iteritems()
+                 if not section.member]
+        if bogus:
+            raise QAPISemError(
+                self.info,
+                "The following documented members are not in "
+                "the declaration: %s" % ", ".join(bogus))
+
 
 class QAPISchemaParser(object):
 
@@ -990,34 +999,9 @@ def check_exprs(exprs):
 
 
 def check_definition_doc(doc, expr, info):
-    for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
-        if i in expr:
-            meta = i
-            break
-
     if doc.has_section('Returns') and 'command' not in expr:
         raise QAPISemError(info, "'Returns:' is only valid for commands")
 
-    if meta == 'union':
-        args = expr.get('base', [])
-    else:
-        args = expr.get('data', [])
-    if isinstance(args, str):
-        return
-    if isinstance(args, dict):
-        args = args.keys()
-    assert isinstance(args, list)
-
-    if (meta == 'alternate'
-            or (meta == 'union' and not expr.get('discriminator'))):
-        args.append('type')
-
-    doc_args = set(doc.args.keys())
-    args = set([name.strip('*') for name in args])
-    if not doc_args.issubset(args):
-        raise QAPISemError(info, "The following documented members are not in "
-                           "the declaration: %s" % ', '.join(doc_args - args))
-
 
 def check_docs(docs):
     for doc in docs:
@@ -1263,6 +1247,8 @@ class QAPISchemaObjectType(QAPISchemaType):
             self.variants.check(schema, seen)
             assert self.variants.tag_member in self.members
             self.variants.check_clash(schema, self.info, seen)
+        if self.doc:
+            self.doc.check()
 
     # Check that the members of this type do not cause duplicate JSON members,
     # and update seen to track the members seen so far. Report any errors
@@ -1432,6 +1418,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
             v.check_clash(self.info, seen)
             if self.doc:
                 self.doc.connect_member(v)
+        if self.doc:
+            self.doc.check()
 
     def c_type(self):
         return c_name(self.name) + pointer_suffix
diff --git a/tests/qapi-schema/doc-bad-union-member.err b/tests/qapi-schema/doc-bad-union-member.err
index e69de29..4b016df 100644
--- a/tests/qapi-schema/doc-bad-union-member.err
+++ b/tests/qapi-schema/doc-bad-union-member.err
@@ -0,0 +1 @@
+tests/qapi-schema/doc-bad-union-member.json:3: The following documented members are not in the declaration: a, b
diff --git a/tests/qapi-schema/doc-bad-union-member.exit b/tests/qapi-schema/doc-bad-union-member.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/doc-bad-union-member.exit
+++ b/tests/qapi-schema/doc-bad-union-member.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/doc-bad-union-member.out b/tests/qapi-schema/doc-bad-union-member.out
index 2576ecd..e69de29 100644
--- a/tests/qapi-schema/doc-bad-union-member.out
+++ b/tests/qapi-schema/doc-bad-union-member.out
@@ -1,11 +0,0 @@
-object Base
-    member type: T optional=False
-object Empty
-object Frob
-    base Base
-    tag type
-    case nothing: Empty
-enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool']
-    prefix QTYPE
-enum T ['nothing']
-object q_empty
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 38/47] qapi: Eliminate check_docs() and drop QAPIDoc.expr
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (36 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 21:00   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 39/47] qapi: Drop unused variable events Markus Armbruster
                   ` (11 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Move what's left in check_docs() to check_expr().  Delegate the actual
checking to new QAPIDoc.check_expr().

QAPIDoc.expr is now unused; drop it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 27 ++++++++++-----------------
 1 file changed, 10 insertions(+), 17 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0b0ba59..0da426a 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -138,8 +138,6 @@ class QAPIDoc(object):
         self.sections = []
         # the current section
         self.section = self.body
-        # associated expression (to be set by expression parser)
-        self.expr = None
 
     def has_section(self, name):
         """Return True if we have a section with this name."""
@@ -249,6 +247,11 @@ class QAPIDoc(object):
             self.args[member.name] = QAPIDoc.ArgSection(member.name)
         self.args[member.name].connect(member)
 
+    def check_expr(self, expr):
+        if self.has_section('Returns') and 'command' not in expr:
+            raise QAPISemError(self.info,
+                               "'Returns:' is only valid for commands")
+
     def check(self):
         bogus = [name for name, section in self.args.iteritems()
                  if not section.member]
@@ -311,7 +314,6 @@ class QAPISchemaParser(object):
                         raise QAPISemError(
                             self.cur_doc.info,
                             "Expression documentation required")
-                    self.cur_doc.expr = expr
                     expr_elem['doc'] = self.cur_doc
                 self.exprs.append(expr_elem)
             self.cur_doc = None
@@ -979,6 +981,7 @@ def check_exprs(exprs):
     for expr_elem in exprs:
         expr = expr_elem['expr']
         info = expr_elem['info']
+        doc = expr_elem.get('doc')
 
         if 'enum' in expr:
             check_enum(expr, info)
@@ -995,22 +998,12 @@ def check_exprs(exprs):
         else:
             assert False, 'unexpected meta type'
 
+        if doc:
+            doc.check_expr(expr)
+
     return exprs
 
 
-def check_definition_doc(doc, expr, info):
-    if doc.has_section('Returns') and 'command' not in expr:
-        raise QAPISemError(info, "'Returns:' is only valid for commands")
-
-
-def check_docs(docs):
-    for doc in docs:
-        if doc.expr:
-            check_definition_doc(doc, doc.expr, doc.info)
-
-    return docs
-
-
 #
 # Schema compiler frontend
 #
@@ -1506,7 +1499,7 @@ class QAPISchema(object):
         try:
             parser = QAPISchemaParser(open(fname, 'r'))
             self.exprs = check_exprs(parser.exprs)
-            self.docs = check_docs(parser.docs)
+            self.docs = parser.docs
             self._entity_dict = {}
             self._predefining = True
             self._def_predefineds()
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 39/47] qapi: Drop unused variable events
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (37 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 38/47] qapi: Eliminate check_docs() and drop QAPIDoc.expr Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-14 21:02   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 40/47] qapi: Simplify what gets stored in enum_types Markus Armbruster
                   ` (10 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Missed in commit e98859a

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 0da426a..12b1bda 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -49,7 +49,6 @@ name_case_whitelist = []
 enum_types = []
 struct_types = []
 union_types = []
-events = []
 all_names = {}
 
 #
@@ -751,14 +750,12 @@ def check_command(expr, info):
 
 
 def check_event(expr, info):
-    global events
     name = expr['event']
     boxed = expr.get('boxed', False)
 
     meta = ['struct']
     if boxed:
         meta += ['union', 'alternate']
-    events.append(name)
     check_type(info, "'data' for event '%s'" % name,
                expr.get('data'), allow_dict=not boxed, allow_optional=True,
                allow_metas=meta)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 40/47] qapi: Simplify what gets stored in enum_types
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (38 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 39/47] qapi: Drop unused variable events Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  0:34   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 41/47] qapi: Factor add_name() calls out of the meta conditional Markus Armbruster
                   ` (9 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Don't invent a new dictionary structure just for enum_types, simply
store the defining expression, like we do for struct_types and
union_types.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 12b1bda..ffd30d2 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -663,16 +663,17 @@ def find_union(name):
     return None
 
 
-def add_enum(name, info, enum_values=None, implicit=False):
+def add_enum(definition, info):
     global enum_types
-    add_name(name, info, 'enum', implicit)
-    enum_types.append({'enum_name': name, 'enum_values': enum_values})
+    name = definition['enum']
+    add_name(name, info, 'enum', 'data' not in definition)
+    enum_types.append(definition)
 
 
 def find_enum(name):
     global enum_types
     for enum in enum_types:
-        if enum['enum_name'] == name:
+        if enum['enum'] == name:
             return enum
     return None
 
@@ -820,15 +821,15 @@ def check_union(expr, info):
         # If the discriminator names an enum type, then all members
         # of 'data' must also be members of the enum type.
         if enum_define:
-            if key not in enum_define['enum_values']:
+            if key not in enum_define['data']:
                 raise QAPISemError(info,
                                    "Discriminator value '%s' is not found in "
                                    "enum '%s'"
-                                   % (key, enum_define['enum_name']))
+                                   % (key, enum_define['enum']))
 
     # If discriminator is user-defined, ensure all values are covered
     if enum_define:
-        for value in enum_define['enum_values']:
+        for value in enum_define['data']:
             if value not in members.keys():
                 raise QAPISemError(info, "Union '%s' data missing '%s' branch"
                                    % (name, value))
@@ -933,7 +934,7 @@ def check_exprs(exprs):
         if 'enum' in expr:
             name = expr['enum']
             check_keys(expr_elem, 'enum', ['data'], ['prefix'])
-            add_enum(name, info, expr['data'])
+            add_enum(expr, info)
         elif 'union' in expr:
             name = expr['union']
             check_keys(expr_elem, 'union', ['data'],
@@ -966,13 +967,13 @@ def check_exprs(exprs):
     # Try again for hidden UnionKind enum
     for expr_elem in exprs:
         expr = expr_elem['expr']
-        if 'union' in expr:
-            if not discriminator_find_enum_define(expr):
-                add_enum('%sKind' % expr['union'], expr_elem['info'],
-                         implicit=True)
+        if 'union' in expr and not discriminator_find_enum_define(expr):
+            name = '%sKind' % expr['union']
         elif 'alternate' in expr:
-            add_enum('%sKind' % expr['alternate'], expr_elem['info'],
-                     implicit=True)
+            name = '%sKind' % expr['alternate']
+        else:
+            continue
+        add_enum({ 'enum': name }, expr_elem['info'])
 
     # Validate that exprs make sense
     for expr_elem in exprs:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 41/47] qapi: Factor add_name() calls out of the meta conditional
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (39 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 40/47] qapi: Simplify what gets stored in enum_types Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  0:39   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 42/47] qapi: enum_types is a list used like a dict, make it one Markus Armbruster
                   ` (8 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 24 +++++++++---------------
 1 file changed, 9 insertions(+), 15 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index ffd30d2..f06e3c4 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -635,8 +635,6 @@ def add_name(name, info, meta, implicit=False):
 
 def add_struct(definition, info):
     global struct_types
-    name = definition['struct']
-    add_name(name, info, 'struct')
     struct_types.append(definition)
 
 
@@ -650,8 +648,6 @@ def find_struct(name):
 
 def add_union(definition, info):
     global union_types
-    name = definition['union']
-    add_name(name, info, 'union')
     union_types.append(definition)
 
 
@@ -665,8 +661,6 @@ def find_union(name):
 
 def add_enum(definition, info):
     global enum_types
-    name = definition['enum']
-    add_name(name, info, 'enum', 'data' not in definition)
     enum_types.append(definition)
 
 
@@ -932,34 +926,33 @@ def check_exprs(exprs):
                                "Expression missing documentation comment")
 
         if 'enum' in expr:
-            name = expr['enum']
+            meta = 'enum'
             check_keys(expr_elem, 'enum', ['data'], ['prefix'])
             add_enum(expr, info)
         elif 'union' in expr:
-            name = expr['union']
+            meta = 'union'
             check_keys(expr_elem, 'union', ['data'],
                        ['base', 'discriminator'])
             add_union(expr, info)
         elif 'alternate' in expr:
-            name = expr['alternate']
+            meta = 'alternate'
             check_keys(expr_elem, 'alternate', ['data'])
-            add_name(name, info, 'alternate')
         elif 'struct' in expr:
-            name = expr['struct']
+            meta = 'struct'
             check_keys(expr_elem, 'struct', ['data'], ['base'])
             add_struct(expr, info)
         elif 'command' in expr:
-            name = expr['command']
+            meta = 'command'
             check_keys(expr_elem, 'command', [],
                        ['data', 'returns', 'gen', 'success-response', 'boxed'])
-            add_name(name, info, 'command')
         elif 'event' in expr:
-            name = expr['event']
+            meta = 'event'
             check_keys(expr_elem, 'event', [], ['data', 'boxed'])
-            add_name(name, info, 'event')
         else:
             raise QAPISemError(expr_elem['info'],
                                "Expression is missing metatype")
+        name = expr[meta]
+        add_name(name, info, meta)
         if doc and doc.symbol != name:
             raise QAPISemError(info, "Definition of '%s' follows documentation"
                                " for '%s'" % (name, doc.symbol))
@@ -974,6 +967,7 @@ def check_exprs(exprs):
         else:
             continue
         add_enum({ 'enum': name }, expr_elem['info'])
+        add_name(name, info, 'enum', implicit=True)
 
     # Validate that exprs make sense
     for expr_elem in exprs:
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 42/47] qapi: enum_types is a list used like a dict, make it one
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (40 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 41/47] qapi: Factor add_name() calls out of the meta conditional Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  0:47   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 43/47] qapi: struct_types " Markus Armbruster
                   ` (7 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 29 ++++++-----------------------
 1 file changed, 6 insertions(+), 23 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index f06e3c4..5a3a606 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -46,7 +46,7 @@ returns_whitelist = []
 # Whitelist of entities allowed to violate case conventions
 name_case_whitelist = []
 
-enum_types = []
+enum_types = {}
 struct_types = []
 union_types = []
 all_names = {}
@@ -562,7 +562,7 @@ def find_alternate_member_qtype(qapi_type):
         return builtin_types[qapi_type]
     elif find_struct(qapi_type):
         return 'QTYPE_QDICT'
-    elif find_enum(qapi_type):
+    elif qapi_type in enum_types:
         return 'QTYPE_QSTRING'
     elif find_union(qapi_type):
         return 'QTYPE_QDICT'
@@ -586,7 +586,7 @@ def discriminator_find_enum_define(expr):
     if not discriminator_type:
         return None
 
-    return find_enum(discriminator_type)
+    return enum_types.get(discriminator_type)
 
 
 # Names must be letters, numbers, -, and _.  They must start with letter,
@@ -659,23 +659,6 @@ def find_union(name):
     return None
 
 
-def add_enum(definition, info):
-    global enum_types
-    enum_types.append(definition)
-
-
-def find_enum(name):
-    global enum_types
-    for enum in enum_types:
-        if enum['enum'] == name:
-            return enum
-    return None
-
-
-def is_enum(name):
-    return find_enum(name) is not None
-
-
 def check_type(info, source, value, allow_array=False,
                allow_dict=False, allow_optional=False,
                allow_metas=[]):
@@ -794,7 +777,7 @@ def check_union(expr, info):
                                "Discriminator '%s' is not a member of base "
                                "struct '%s'"
                                % (discriminator, base))
-        enum_define = find_enum(discriminator_type)
+        enum_define = enum_types.get(discriminator_type)
         allow_metas = ['struct']
         # Do not allow string discriminator
         if not enum_define:
@@ -928,7 +911,7 @@ def check_exprs(exprs):
         if 'enum' in expr:
             meta = 'enum'
             check_keys(expr_elem, 'enum', ['data'], ['prefix'])
-            add_enum(expr, info)
+            enum_types[expr[meta]] = expr
         elif 'union' in expr:
             meta = 'union'
             check_keys(expr_elem, 'union', ['data'],
@@ -966,7 +949,7 @@ def check_exprs(exprs):
             name = '%sKind' % expr['alternate']
         else:
             continue
-        add_enum({ 'enum': name }, expr_elem['info'])
+        enum_types[name] = { 'enum': name }
         add_name(name, info, 'enum', implicit=True)
 
     # Validate that exprs make sense
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 43/47] qapi: struct_types is a list used like a dict, make it one
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (41 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 42/47] qapi: enum_types is a list used like a dict, make it one Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  1:31   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 44/47] qapi: union_types " Markus Armbruster
                   ` (6 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 5a3a606..ab266db 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -47,7 +47,7 @@ returns_whitelist = []
 name_case_whitelist = []
 
 enum_types = {}
-struct_types = []
+struct_types = {}
 union_types = []
 all_names = {}
 
@@ -550,7 +550,7 @@ class QAPISchemaParser(object):
 def find_base_members(base):
     if isinstance(base, dict):
         return base
-    base_struct_define = find_struct(base)
+    base_struct_define = struct_types.get(base)
     if not base_struct_define:
         return None
     return base_struct_define['data']
@@ -560,7 +560,7 @@ def find_base_members(base):
 def find_alternate_member_qtype(qapi_type):
     if qapi_type in builtin_types:
         return builtin_types[qapi_type]
-    elif find_struct(qapi_type):
+    elif qapi_type in struct_types:
         return 'QTYPE_QDICT'
     elif qapi_type in enum_types:
         return 'QTYPE_QSTRING'
@@ -633,19 +633,6 @@ def add_name(name, info, meta, implicit=False):
     all_names[name] = meta
 
 
-def add_struct(definition, info):
-    global struct_types
-    struct_types.append(definition)
-
-
-def find_struct(name):
-    global struct_types
-    for struct in struct_types:
-        if struct['struct'] == name:
-            return struct
-    return None
-
-
 def add_union(definition, info):
     global union_types
     union_types.append(definition)
@@ -923,7 +910,7 @@ def check_exprs(exprs):
         elif 'struct' in expr:
             meta = 'struct'
             check_keys(expr_elem, 'struct', ['data'], ['base'])
-            add_struct(expr, info)
+            struct_types[expr[meta]] = expr
         elif 'command' in expr:
             meta = 'command'
             check_keys(expr_elem, 'command', [],
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 44/47] qapi: union_types is a list used like a dict, make it one
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (42 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 43/47] qapi: struct_types " Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  1:34   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 45/47] qapi: Drop unused .check_clash() parameter schema Markus Armbruster
                   ` (5 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 19 +++----------------
 1 file changed, 3 insertions(+), 16 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index ab266db..870ff4e 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -48,7 +48,7 @@ name_case_whitelist = []
 
 enum_types = {}
 struct_types = {}
-union_types = []
+union_types = {}
 all_names = {}
 
 #
@@ -564,7 +564,7 @@ def find_alternate_member_qtype(qapi_type):
         return 'QTYPE_QDICT'
     elif qapi_type in enum_types:
         return 'QTYPE_QSTRING'
-    elif find_union(qapi_type):
+    elif qapi_type in union_types:
         return 'QTYPE_QDICT'
     return None
 
@@ -633,19 +633,6 @@ def add_name(name, info, meta, implicit=False):
     all_names[name] = meta
 
 
-def add_union(definition, info):
-    global union_types
-    union_types.append(definition)
-
-
-def find_union(name):
-    global union_types
-    for union in union_types:
-        if union['union'] == name:
-            return union
-    return None
-
-
 def check_type(info, source, value, allow_array=False,
                allow_dict=False, allow_optional=False,
                allow_metas=[]):
@@ -903,7 +890,7 @@ def check_exprs(exprs):
             meta = 'union'
             check_keys(expr_elem, 'union', ['data'],
                        ['base', 'discriminator'])
-            add_union(expr, info)
+            union_types[expr[meta]] = expr
         elif 'alternate' in expr:
             meta = 'alternate'
             check_keys(expr_elem, 'alternate', ['data'])
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 45/47] qapi: Drop unused .check_clash() parameter schema
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (43 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 44/47] qapi: union_types " Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  1:46   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 46/47] qapi: Make pylint a bit happier Markus Armbruster
                   ` (4 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 870ff4e..4102011 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1178,7 +1178,7 @@ class QAPISchemaObjectType(QAPISchemaType):
             self.base = schema.lookup_type(self._base_name)
             assert isinstance(self.base, QAPISchemaObjectType)
             self.base.check(schema)
-            self.base.check_clash(schema, self.info, seen)
+            self.base.check_clash(self.info, seen)
         for m in self.local_members:
             m.check(schema)
             m.check_clash(self.info, seen)
@@ -1188,14 +1188,14 @@ class QAPISchemaObjectType(QAPISchemaType):
         if self.variants:
             self.variants.check(schema, seen)
             assert self.variants.tag_member in self.members
-            self.variants.check_clash(schema, self.info, seen)
+            self.variants.check_clash(self.info, seen)
         if self.doc:
             self.doc.check()
 
     # Check that the members of this type do not cause duplicate JSON members,
     # and update seen to track the members seen so far. Report any errors
     # on behalf of info, which is not necessarily self.info
-    def check_clash(self, schema, info, seen):
+    def check_clash(self, info, seen):
         assert not self.variants       # not implemented
         for m in self.members:
             m.check_clash(info, seen)
@@ -1324,12 +1324,12 @@ class QAPISchemaObjectTypeVariants(object):
                 assert isinstance(v.type, QAPISchemaObjectType)
                 v.type.check(schema)
 
-    def check_clash(self, schema, info, seen):
+    def check_clash(self, info, seen):
         for v in self.variants:
             # Reset seen map for each variant, since qapi names from one
             # branch do not affect another branch
             assert isinstance(v.type, QAPISchemaObjectType)
-            v.type.check_clash(schema, info, dict(seen))
+            v.type.check_clash(info, dict(seen))
 
 
 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 46/47] qapi: Make pylint a bit happier
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (44 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 45/47] qapi: Drop unused .check_clash() parameter schema Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  1:47   ` Eric Blake
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 47/47] qapi: Fix a misleading parser error message Markus Armbruster
                   ` (3 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi-commands.py | 6 +++---
 scripts/qapi-visit.py    | 1 -
 scripts/qapi.py          | 8 ++++----
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index 0c05449..1943de4 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -13,7 +13,6 @@
 # See the COPYING file in the top-level directory.
 
 from qapi import *
-import re
 
 
 def gen_command_decl(name, arg_type, boxed, ret_type):
@@ -84,7 +83,8 @@ static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out,
 
 
 def gen_marshal_proto(name):
-    return 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
+    return ('void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)'
+            % c_name(name))
 
 
 def gen_marshal_decl(name):
@@ -198,7 +198,7 @@ def gen_register_command(name, success_response):
         options = 'QCO_NO_SUCCESS_RESP'
 
     ret = mcgen('''
-    qmp_register_command(cmds, "%(name)s", 
+    qmp_register_command(cmds, "%(name)s",
                          qmp_marshal_%(c_name)s, %(opts)s);
 ''',
                 name=name, c_name=c_name(name),
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 3d3936e..5737aef 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -13,7 +13,6 @@
 # See the COPYING file in the top-level directory.
 
 from qapi import *
-import re
 
 
 def gen_visit_decl(name, scalar=False):
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 4102011..a4bf1ea 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -11,13 +11,13 @@
 # This work is licensed under the terms of the GNU GPL, version 2.
 # See the COPYING file in the top-level directory.
 
-import re
-from ordereddict import OrderedDict
 import errno
 import getopt
 import os
-import sys
+import re
 import string
+import sys
+from ordereddict import OrderedDict
 
 builtin_types = {
     'str':      'QTYPE_QSTRING',
@@ -1582,7 +1582,7 @@ class QAPISchema(object):
         tag_member = None
         if isinstance(base, dict):
             base = (self._make_implicit_object_type(
-                    name, info, doc, 'base', self._make_members(base, info)))
+                name, info, doc, 'base', self._make_members(base, info)))
         if tag_name:
             variants = [self._make_variant(key, value)
                         for (key, value) in data.iteritems()]
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* [Qemu-devel] [PATCH for-2.9 47/47] qapi: Fix a misleading parser error message
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (45 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 46/47] qapi: Make pylint a bit happier Markus Armbruster
@ 2017-03-13  6:18 ` Markus Armbruster
  2017-03-15  1:48   ` Eric Blake
  2017-03-13 10:32 ` [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Marc-André Lureau
                   ` (2 subsequent siblings)
  49 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

When choking on a token where an expression is expected, we report
'Expected "{", "[" or string'.  Close, but no cigar.  Fix it to
Expected '"{", "[", string, boolean or "null"'.

Missed in commit e53188a.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 scripts/qapi.py                           | 3 ++-
 tests/qapi-schema/trailing-comma-list.err | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index a4bf1ea..1dc33c9 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -514,7 +514,8 @@ class QAPISchemaParser(object):
             expr = self.val
             self.accept()
         else:
-            raise QAPIParseError(self, 'Expected "{", "[" or string')
+            raise QAPIParseError(self, 'Expected "{", "[", string, '
+                                 'boolean or "null"')
         return expr
 
     def get_doc(self, info):
diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err
index 24c24b0..212e14a 100644
--- a/tests/qapi-schema/trailing-comma-list.err
+++ b/tests/qapi-schema/trailing-comma-list.err
@@ -1 +1 @@
-tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[" or string
+tests/qapi-schema/trailing-comma-list.json:2:36: Expected "{", "[", string, boolean or "null"
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser Markus Armbruster
@ 2017-03-13  6:23   ` Markus Armbruster
  2017-03-15  1:40     ` Eric Blake
  2017-03-15  1:37   ` Eric Blake
  1 sibling, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13  6:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: marcandre.lureau, eblake, mdroth

Markus Armbruster <armbru@redhat.com> writes:

> Results in a more precise error location, but the real reason is
> emptying out check_docs() step by step.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>

Perhaps we should simply drop this error condition.  Are empty sections
this a mistake users make accidentally?

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (46 preceding siblings ...)
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 47/47] qapi: Fix a misleading parser error message Markus Armbruster
@ 2017-03-13 10:32 ` Marc-André Lureau
  2017-03-13 12:14   ` Markus Armbruster
  2017-03-14 13:24 ` Marc-André Lureau
  2017-04-27 18:16 ` Eric Blake
  49 siblings, 1 reply; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-13 10:32 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
wrote:

> I'm proposing this is 2.9 because it fixes a documentation regression.
> It affects only documentation; generated C code is unchanged except
> for the removal of trailing space in PATCH 46.
>
> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
>
> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
> the QAPI schema and generate their replacements from the schema
> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
> also was a step back: the documentation lost information on JSON
> types, because I didn't like Marc-André's patch to add it.  He
> reposted it for further review afterwards:
>
>     Subject: [PATCH 0/2] qapi2texi: add type information
>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
>     https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
>
> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
> descriptions in a new formal language to the generated documentation.
> Quoting the commit message:
>
>     Array types have the following syntax: type[]. Ex: str[].
>
>     - Struct, commands and events use the following members syntax:
>
>       { 'member': type, ('foo': str), ... }
>
>     Optional members are under parentheses.
>
>     A structure with a base type will have 'BaseStruct +' prepended.
>
>     - Alternates use the following syntax:
>
>       [ 'foo': type, 'bar': type, ... ]
>
>     - Simple unions use the following syntax:
>
>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }
>
>     - Flat unions use the following syntax:
>
>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
>
> End quote.  Looks like this in generated documentation:
>
>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
>           VncBasicInfo}
>
>      Emitted when a VNC client establishes a connection
>      ''server''
>           server information
>      ''client''
>           client information
>
>      Note: This event is emitted before any authentication takes place,
>      thus the authentication ID is not provided
> [...]
>
>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
>
>      The network connection information for server
>      ''auth'' (optional)
>           authentication method used for the plain (non-websocket) VNC
>           server
>
>      Since: 2.1
>
>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>           VsockSocketAddress, 'fd': String] }
>
>      Captures the address of a socket, which could also be a named file
>      descriptor
>
>      Since: 1.3
>
> Here's my counter-proposal: instead of inventing a formal language,
> fix the natural language documentation to actually mention *all*
> members, and add type information in a plain, easy-to-understand way.
> Looks like this:
>
>  -- Event: VNC_CONNECTED
>
>      Emitted when a VNC client establishes a connection
>
>      Arguments:
>      'server: VncServerInfo'
>           server information
>      'client: VncBasicInfo'
>           client information
>
>      Note: This event is emitted before any authentication takes place,
>      thus the authentication ID is not provided
> [...]
>
>  -- Object: VncServerInfo
>
>      The network connection information for server
>
>      Members:
>      'auth: string' (optional)
>           authentication method used for the plain (non-websocket) VNC
>           server
>      The members of 'VncBasicInfo'
>
>      Since: 2.1
>
>  -- Object: SocketAddress
>
>      Captures the address of a socket, which could also be a named file
>      descriptor
>
>      Members:
>      'type'
>           One of "inet", "unix", "vsock", "fd"
>      'data: InetSocketAddress' when 'type' is "inet"
>      'data: UnixSocketAddress' when 'type' is "unix"
>      'data: VsockSocketAddress' when 'type' is "vsock"
>      'data: String' when 'type' is "fd"
>
>      Since: 1.3
>
>
I like both, to me they serve different purposes. I like to have a short
overview / signature and then a more detailed documentation for each field.

Additionally, my series fixes a number of bugs and cleans up along the
> way.  In particular, it converts qapi2texi.py from parse trees to the
> visitor interface the other generators use.
>
>
Your series failed to apply in patchew, and I can't find the branch in your
repo. Could you publish it?


> Future generated documentation work includes eliding types that aren't
> visible in QMP (like introspection does), and making uses of type
> names links in HTML.
>
>
Yes, links would be really nice.

Thanks


> Markus Armbruster (47):
>   qapi: Factor QAPISchemaParser._include() out of .__init__()
>   qapi: Make doc comments optional where we don't need them
>   qapi: Back out doc comments added just to please qapi.py
>   docs/qapi-code-gen.txt: Drop confusing reference to 'gen'
>   qapi: Have each QAPI schema declare its returns white-list
>   qapi: Have each QAPI schema declare its name rule violations
>   qapi: Clean up build of generated documentation
>   tests/qapi-schema: Cover empty union base
>   qapi: Fix to reject empty union base gracefully
>   qapi2texi: Fix up output around #optional
>   qapi: Avoid unwanted blank lines in QAPIDoc
>   qapi/rocker: Fix up doc comment notes on optional members
>   qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType'
>   qapi: Prepare for requiring more complete documentation
>   qapi: Conjure up QAPIDoc.ArgSection for undocumented members
>   qapi2texi: Convert to QAPISchemaVisitor
>   qapi: The #optional tag is redundant, drop
>   qapi: Use raw strings for regular expressions consistently
>   qapi: Prefer single-quoted strings more consistently
>   qapi2texi: Plainer enum value and member name formatting
>   qapi2texi: Present the table of members more clearly
>   qapi2texi: Explain enum value undocumentedness more clearly
>   qapi2texi: Don't hide undocumented members and arguments
>   qapi2texi: Implement boxed argument documentation
>   qapi2texi: Include member type in generated documentation
>   qapi2texi: Generate reference to base type members
>   qapi2texi: Generate documentation for variant members
>   qapi2texi: Generate descriptions for simple union tags
>   qapi2texi: Use category "Object" for all object types
>   tests/qapi-schema: Improve doc / expression mismatch coverage
>   qapi: Fix detection of doc / expression mismatch
>   qapi: Move detection of doc / expression name mismatch
>   qapi: Improve error message on @NAME: in free-form doc
>   qapi: Move empty doc section checking to doc parser
>   tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg
>   tests/qapi-schema: Improve coverage of bogus member docs
>   qapi: Fix detection of bogus member documentation
>   qapi: Eliminate check_docs() and drop QAPIDoc.expr
>   qapi: Drop unused variable events
>   qapi: Simplify what gets stored in enum_types
>   qapi: Factor add_name() calls out of the meta conditional
>   qapi: enum_types is a list used like a dict, make it one
>   qapi: struct_types is a list used like a dict, make it one
>   qapi: union_types is a list used like a dict, make it one
>   qapi: Drop unused .check_clash() parameter schema
>   qapi: Make pylint a bit happier
>   qapi: Fix a misleading parser error message
>
>  .gitignore                                         |  10 +-
>  Makefile                                           |  27 +-
>  docs/qapi-code-gen.txt                             |  81 +--
>  docs/qemu-qmp-ref.texi                             |   2 +-
>  docs/writing-qmp-commands.txt                      |   4 +-
>  qapi-schema.json                                   | 403 ++++++-------
>  qapi/block-core.json                               | 428 +++++++-------
>  qapi/block.json                                    |   8 +-
>  qapi/crypto.json                                   |  22 +-
>  qapi/event.json                                    |  10 +-
>  qapi/introspect.json                               |   6 +-
>  qapi/rocker.json                                   |  88 +--
>  qapi/trace.json                                    |   6 +-
>  qga/qapi-schema.json                               |  55 +-
>  rules.mak                                          |   2 +-
>  scripts/qapi-commands.py                           |   6 +-
>  scripts/qapi-event.py                              |   2 +-
>  scripts/qapi-introspect.py                         |   4 +-
>  scripts/qapi-types.py                              |   4 +-
>  scripts/qapi-visit.py                              |   5 +-
>  scripts/qapi.py                                    | 632
> ++++++++++-----------
>  scripts/qapi2texi.py                               | 298 +++++-----
>  tests/Makefile.include                             |   9 +-
>  tests/qapi-schema/alternate-any.err                |   2 +-
>  tests/qapi-schema/alternate-any.json               |   4 -
>  tests/qapi-schema/alternate-array.err              |   2 +-
>  tests/qapi-schema/alternate-array.json             |   7 -
>  tests/qapi-schema/alternate-base.err               |   2 +-
>  tests/qapi-schema/alternate-base.json              |   7 -
>  tests/qapi-schema/alternate-clash.err              |   2 +-
>  tests/qapi-schema/alternate-clash.json             |   4 -
>  tests/qapi-schema/alternate-conflict-dict.err      |   2 +-
>  tests/qapi-schema/alternate-conflict-dict.json     |  10 -
>  tests/qapi-schema/alternate-conflict-string.err    |   2 +-
>  tests/qapi-schema/alternate-conflict-string.json   |   7 -
>  tests/qapi-schema/alternate-empty.err              |   2 +-
>  tests/qapi-schema/alternate-empty.json             |   4 -
>  tests/qapi-schema/alternate-nested.err             |   2 +-
>  tests/qapi-schema/alternate-nested.json            |   7 -
>  tests/qapi-schema/alternate-unknown.err            |   2 +-
>  tests/qapi-schema/alternate-unknown.json           |   4 -
>  tests/qapi-schema/args-alternate.err               |   2 +-
>  tests/qapi-schema/args-alternate.json              |   8 -
>  tests/qapi-schema/args-any.err                     |   2 +-
>  tests/qapi-schema/args-any.json                    |   4 -
>  tests/qapi-schema/args-array-empty.err             |   2 +-
>  tests/qapi-schema/args-array-empty.json            |   4 -
>  tests/qapi-schema/args-array-unknown.err           |   2 +-
>  tests/qapi-schema/args-array-unknown.json          |   4 -
>  tests/qapi-schema/args-bad-boxed.err               |   2 +-
>  tests/qapi-schema/args-bad-boxed.json              |   4 -
>  tests/qapi-schema/args-boxed-anon.err              |   2 +-
>  tests/qapi-schema/args-boxed-anon.json             |   4 -
>  tests/qapi-schema/args-boxed-empty.err             |   2 +-
>  tests/qapi-schema/args-boxed-empty.json            |   8 -
>  tests/qapi-schema/args-boxed-string.err            |   2 +-
>  tests/qapi-schema/args-boxed-string.json           |   4 -
>  tests/qapi-schema/args-int.err                     |   2 +-
>  tests/qapi-schema/args-int.json                    |   4 -
>  tests/qapi-schema/args-invalid.err                 |   2 +-
>  tests/qapi-schema/args-invalid.json                |   3 -
>  tests/qapi-schema/args-member-array-bad.err        |   2 +-
>  tests/qapi-schema/args-member-array-bad.json       |   4 -
>  tests/qapi-schema/args-member-case.err             |   2 +-
>  tests/qapi-schema/args-member-case.json            |   4 -
>  tests/qapi-schema/args-member-unknown.err          |   2 +-
>  tests/qapi-schema/args-member-unknown.json         |   4 -
>  tests/qapi-schema/args-name-clash.err              |   2 +-
>  tests/qapi-schema/args-name-clash.json             |   4 -
>  tests/qapi-schema/args-union.err                   |   2 +-
>  tests/qapi-schema/args-union.json                  |   7 -
>  tests/qapi-schema/args-unknown.err                 |   2 +-
>  tests/qapi-schema/args-unknown.json                |   4 -
>  tests/qapi-schema/bad-base.err                     |   2 +-
>  tests/qapi-schema/bad-base.json                    |   7 -
>  tests/qapi-schema/bad-data.err                     |   2 +-
>  tests/qapi-schema/bad-data.json                    |   4 -
>  tests/qapi-schema/bad-ident.err                    |   2 +-
>  tests/qapi-schema/bad-ident.json                   |   4 -
>  tests/qapi-schema/bad-type-bool.err                |   2 +-
>  tests/qapi-schema/bad-type-bool.json               |   4 -
>  tests/qapi-schema/bad-type-dict.err                |   2 +-
>  tests/qapi-schema/bad-type-dict.json               |   4 -
>  tests/qapi-schema/base-cycle-direct.err            |   2 +-
>  tests/qapi-schema/base-cycle-direct.json           |   4 -
>  tests/qapi-schema/base-cycle-indirect.err          |   2 +-
>  tests/qapi-schema/base-cycle-indirect.json         |   7 -
>  tests/qapi-schema/command-int.err                  |   2 +-
>  tests/qapi-schema/command-int.json                 |   4 -
>  tests/qapi-schema/comments.json                    |   4 -
>  tests/qapi-schema/comments.out                     |   1 -
>  tests/qapi-schema/doc-bad-alternate-member.err     |   1 +
>  ...optional.exit => doc-bad-alternate-member.exit} |   0
>  tests/qapi-schema/doc-bad-alternate-member.json    |   9 +
>  ...c-optional.out => doc-bad-alternate-member.out} |   0
>  tests/qapi-schema/doc-bad-args.err                 |   1 -
>  tests/qapi-schema/doc-bad-command-arg.err          |   1 +
>  ...{doc-bad-args.exit => doc-bad-command-arg.exit} |   0
>  ...{doc-bad-args.json => doc-bad-command-arg.json} |   0
>  .../{doc-bad-args.out => doc-bad-command-arg.out}  |   0
>  tests/qapi-schema/doc-bad-expr.err                 |   1 +
>  tests/qapi-schema/doc-bad-expr.exit                |   1 +
>  tests/qapi-schema/doc-bad-expr.json                |   7 +
>  tests/qapi-schema/doc-bad-expr.out                 |   0
>  tests/qapi-schema/doc-bad-symbol.err               |   2 +-
>  tests/qapi-schema/doc-bad-union-member.err         |   1 +
>  tests/qapi-schema/doc-bad-union-member.exit        |   1 +
>  tests/qapi-schema/doc-bad-union-member.json        |  19 +
>  tests/qapi-schema/doc-bad-union-member.out         |   0
>  tests/qapi-schema/doc-empty-section.err            |   2 +-
>  tests/qapi-schema/doc-invalid-section.err          |   2 +-
>  tests/qapi-schema/doc-missing-expr.err             |   2 +-
>  tests/qapi-schema/doc-missing.err                  |   1 +
>  tests/qapi-schema/doc-missing.exit                 |   1 +
>  tests/qapi-schema/doc-missing.json                 |   5 +
>  tests/qapi-schema/doc-missing.out                  |   0
>  tests/qapi-schema/doc-no-symbol.err                |   1 +
>  tests/qapi-schema/doc-no-symbol.exit               |   1 +
>  tests/qapi-schema/doc-no-symbol.json               |   6 +
>  tests/qapi-schema/doc-no-symbol.out                |   0
>  tests/qapi-schema/doc-optional.err                 |   1 -
>  tests/qapi-schema/doc-optional.json                |   7 -
>  tests/qapi-schema/double-type.err                  |   2 +-
>  tests/qapi-schema/double-type.json                 |   4 -
>  tests/qapi-schema/enum-bad-name.err                |   2 +-
>  tests/qapi-schema/enum-bad-name.json               |   4 -
>  tests/qapi-schema/enum-bad-prefix.err              |   2 +-
>  tests/qapi-schema/enum-bad-prefix.json             |   4 -
>  tests/qapi-schema/enum-clash-member.err            |   2 +-
>  tests/qapi-schema/enum-clash-member.json           |   4 -
>  tests/qapi-schema/enum-dict-member.err             |   2 +-
>  tests/qapi-schema/enum-dict-member.json            |   4 -
>  tests/qapi-schema/enum-member-case.err             |   2 +-
>  tests/qapi-schema/enum-member-case.json            |   8 +-
>  tests/qapi-schema/enum-missing-data.err            |   2 +-
>  tests/qapi-schema/enum-missing-data.json           |   4 -
>  tests/qapi-schema/enum-wrong-data.err              |   2 +-
>  tests/qapi-schema/enum-wrong-data.json             |   4 -
>  tests/qapi-schema/event-boxed-empty.err            |   2 +-
>  tests/qapi-schema/event-boxed-empty.json           |   4 -
>  tests/qapi-schema/event-case.json                  |   4 -
>  tests/qapi-schema/event-case.out                   |   1 -
>  tests/qapi-schema/event-nest-struct.err            |   2 +-
>  tests/qapi-schema/event-nest-struct.json           |   4 -
>  tests/qapi-schema/flat-union-array-branch.err      |   2 +-
>  tests/qapi-schema/flat-union-array-branch.json     |  12 -
>  tests/qapi-schema/flat-union-bad-base.err          |   2 +-
>  tests/qapi-schema/flat-union-bad-base.json         |  13 -
>  tests/qapi-schema/flat-union-bad-discriminator.err |   2 +-
>  .../qapi-schema/flat-union-bad-discriminator.json  |  16 -
>  tests/qapi-schema/flat-union-base-any.err          |   2 +-
>  tests/qapi-schema/flat-union-base-any.json         |  13 -
>  tests/qapi-schema/flat-union-base-union.err        |   2 +-
>  tests/qapi-schema/flat-union-base-union.json       |  16 -
>  tests/qapi-schema/flat-union-clash-member.err      |   2 +-
>  tests/qapi-schema/flat-union-clash-member.json     |  16 -
>  tests/qapi-schema/flat-union-empty.err             |   2 +-
>  tests/qapi-schema/flat-union-empty.json            |  10 -
>  tests/qapi-schema/flat-union-incomplete-branch.err |   2 +-
>  .../qapi-schema/flat-union-incomplete-branch.json  |  10 -
>  tests/qapi-schema/flat-union-inline.err            |   2 +-
>  tests/qapi-schema/flat-union-inline.json           |  10 -
>  tests/qapi-schema/flat-union-int-branch.err        |   2 +-
>  tests/qapi-schema/flat-union-int-branch.json       |  13 -
>  .../qapi-schema/flat-union-invalid-branch-key.err  |   2 +-
>  .../qapi-schema/flat-union-invalid-branch-key.json |  15 -
>  .../flat-union-invalid-discriminator.err           |   2 +-
>  .../flat-union-invalid-discriminator.json          |  15 -
>  tests/qapi-schema/flat-union-no-base.err           |   2 +-
>  tests/qapi-schema/flat-union-no-base.json          |  13 -
>  .../flat-union-optional-discriminator.err          |   2 +-
>  .../flat-union-optional-discriminator.json         |  13 -
>  .../flat-union-string-discriminator.err            |   2 +-
>  .../flat-union-string-discriminator.json           |  15 -
>  tests/qapi-schema/ident-with-escape.json           |   4 -
>  tests/qapi-schema/ident-with-escape.out            |   1 -
>  tests/qapi-schema/include-relpath-sub.json         |   3 -
>  tests/qapi-schema/include-relpath.out              |   1 -
>  tests/qapi-schema/include-repetition.out           |   1 -
>  tests/qapi-schema/include-simple-sub.json          |   3 -
>  tests/qapi-schema/include-simple.out               |   1 -
>  tests/qapi-schema/indented-expr.json               |   6 -
>  tests/qapi-schema/indented-expr.out                |   2 -
>  tests/qapi-schema/missing-type.err                 |   2 +-
>  tests/qapi-schema/missing-type.json                |   4 -
>  tests/qapi-schema/nested-struct-data.err           |   2 +-
>  tests/qapi-schema/nested-struct-data.json          |   4 -
>  tests/qapi-schema/qapi-schema-test.json            | 218 +------
>  tests/qapi-schema/qapi-schema-test.out             | 130 -----
>  tests/qapi-schema/redefined-builtin.err            |   2 +-
>  tests/qapi-schema/redefined-builtin.json           |   4 -
>  tests/qapi-schema/redefined-command.err            |   2 +-
>  tests/qapi-schema/redefined-command.json           |   7 -
>  tests/qapi-schema/redefined-event.err              |   2 +-
>  tests/qapi-schema/redefined-event.json             |   7 -
>  tests/qapi-schema/redefined-type.err               |   2 +-
>  tests/qapi-schema/redefined-type.json              |   7 -
>  tests/qapi-schema/reserved-command-q.err           |   2 +-
>  tests/qapi-schema/reserved-command-q.json          |   7 -
>  tests/qapi-schema/reserved-enum-q.err              |   2 +-
>  tests/qapi-schema/reserved-enum-q.json             |   4 -
>  tests/qapi-schema/reserved-member-has.err          |   2 +-
>  tests/qapi-schema/reserved-member-has.json         |   4 -
>  tests/qapi-schema/reserved-member-q.err            |   2 +-
>  tests/qapi-schema/reserved-member-q.json           |   4 -
>  tests/qapi-schema/reserved-member-u.err            |   2 +-
>  tests/qapi-schema/reserved-member-u.json           |   4 -
>  tests/qapi-schema/reserved-member-underscore.err   |   2 +-
>  tests/qapi-schema/reserved-member-underscore.json  |   4 -
>  tests/qapi-schema/reserved-type-kind.err           |   2 +-
>  tests/qapi-schema/reserved-type-kind.json          |   4 -
>  tests/qapi-schema/reserved-type-list.err           |   2 +-
>  tests/qapi-schema/reserved-type-list.json          |   4 -
>  tests/qapi-schema/returns-alternate.err            |   2 +-
>  tests/qapi-schema/returns-alternate.json           |   7 -
>  tests/qapi-schema/returns-array-bad.err            |   2 +-
>  tests/qapi-schema/returns-array-bad.json           |   4 -
>  tests/qapi-schema/returns-dict.err                 |   2 +-
>  tests/qapi-schema/returns-dict.json                |   4 -
>  tests/qapi-schema/returns-unknown.err              |   2 +-
>  tests/qapi-schema/returns-unknown.json             |   4 -
>  tests/qapi-schema/returns-whitelist.err            |   2 +-
>  tests/qapi-schema/returns-whitelist.json           |  18 +-
>  tests/qapi-schema/struct-base-clash-deep.err       |   2 +-
>  tests/qapi-schema/struct-base-clash-deep.json      |  10 -
>  tests/qapi-schema/struct-base-clash.err            |   2 +-
>  tests/qapi-schema/struct-base-clash.json           |   7 -
>  tests/qapi-schema/struct-data-invalid.err          |   2 +-
>  tests/qapi-schema/struct-data-invalid.json         |   3 -
>  tests/qapi-schema/struct-member-invalid.err        |   2 +-
>  tests/qapi-schema/struct-member-invalid.json       |   3 -
>  tests/qapi-schema/test-qapi.py                     |  14 -
>  tests/qapi-schema/trailing-comma-list.err          |   2 +-
>  tests/qapi-schema/type-bypass-bad-gen.err          |   2 +-
>  tests/qapi-schema/type-bypass-bad-gen.json         |   4 -
>  tests/qapi-schema/unicode-str.err                  |   2 +-
>  tests/qapi-schema/unicode-str.json                 |   4 -
>  tests/qapi-schema/union-base-empty.err             |   1 +
>  tests/qapi-schema/union-base-empty.exit            |   1 +
>  tests/qapi-schema/union-base-empty.json            |   9 +
>  tests/qapi-schema/union-base-empty.out             |   0
>  tests/qapi-schema/union-base-no-discriminator.err  |   2 +-
>  tests/qapi-schema/union-base-no-discriminator.json |  12 -
>  tests/qapi-schema/union-branch-case.err            |   2 +-
>  tests/qapi-schema/union-branch-case.json           |   4 -
>  tests/qapi-schema/union-clash-branches.err         |   2 +-
>  tests/qapi-schema/union-clash-branches.json        |   4 -
>  tests/qapi-schema/union-empty.err                  |   2 +-
>  tests/qapi-schema/union-empty.json                 |   4 -
>  tests/qapi-schema/union-invalid-base.err           |   2 +-
>  tests/qapi-schema/union-invalid-base.json          |  10 -
>  tests/qapi-schema/union-optional-branch.err        |   2 +-
>  tests/qapi-schema/union-optional-branch.json       |   4 -
>  tests/qapi-schema/union-unknown.err                |   2 +-
>  tests/qapi-schema/union-unknown.json               |   4 -
>  tests/qapi-schema/unknown-escape.err               |   2 +-
>  tests/qapi-schema/unknown-escape.json              |   4 -
>  tests/qapi-schema/unknown-expr-key.err             |   2 +-
>  tests/qapi-schema/unknown-expr-key.json            |   4 -
>  259 files changed, 1263 insertions(+), 2109 deletions(-)
>  create mode 100644 tests/qapi-schema/doc-bad-alternate-member.err
>  rename tests/qapi-schema/{doc-optional.exit =>
> doc-bad-alternate-member.exit} (100%)
>  create mode 100644 tests/qapi-schema/doc-bad-alternate-member.json
>  rename tests/qapi-schema/{doc-optional.out =>
> doc-bad-alternate-member.out} (100%)
>  delete mode 100644 tests/qapi-schema/doc-bad-args.err
>  create mode 100644 tests/qapi-schema/doc-bad-command-arg.err
>  rename tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit}
> (100%)
>  rename tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json}
> (100%)
>  rename tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out}
> (100%)
>  create mode 100644 tests/qapi-schema/doc-bad-expr.err
>  create mode 100644 tests/qapi-schema/doc-bad-expr.exit
>  create mode 100644 tests/qapi-schema/doc-bad-expr.json
>  create mode 100644 tests/qapi-schema/doc-bad-expr.out
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.err
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.exit
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.json
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.out
>  create mode 100644 tests/qapi-schema/doc-missing.err
>  create mode 100644 tests/qapi-schema/doc-missing.exit
>  create mode 100644 tests/qapi-schema/doc-missing.json
>  create mode 100644 tests/qapi-schema/doc-missing.out
>  create mode 100644 tests/qapi-schema/doc-no-symbol.err
>  create mode 100644 tests/qapi-schema/doc-no-symbol.exit
>  create mode 100644 tests/qapi-schema/doc-no-symbol.json
>  create mode 100644 tests/qapi-schema/doc-no-symbol.out
>  delete mode 100644 tests/qapi-schema/doc-optional.err
>  delete mode 100644 tests/qapi-schema/doc-optional.json
>  create mode 100644 tests/qapi-schema/union-base-empty.err
>  create mode 100644 tests/qapi-schema/union-base-empty.exit
>  create mode 100644 tests/qapi-schema/union-base-empty.json
>  create mode 100644 tests/qapi-schema/union-base-empty.out
>
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13 10:32 ` [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Marc-André Lureau
@ 2017-03-13 12:14   ` Markus Armbruster
  2017-03-13 12:21     ` Marc-André Lureau
  0 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13 12:14 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, mdroth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
> wrote:
>
>> I'm proposing this is 2.9 because it fixes a documentation regression.
>> It affects only documentation; generated C code is unchanged except
>> for the removal of trailing space in PATCH 46.
>>
>> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
>>
>> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
>> the QAPI schema and generate their replacements from the schema
>> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
>> also was a step back: the documentation lost information on JSON
>> types, because I didn't like Marc-André's patch to add it.  He
>> reposted it for further review afterwards:
>>
>>     Subject: [PATCH 0/2] qapi2texi: add type information
>>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
>>     https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
>>
>> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
>> descriptions in a new formal language to the generated documentation.
>> Quoting the commit message:
>>
>>     Array types have the following syntax: type[]. Ex: str[].
>>
>>     - Struct, commands and events use the following members syntax:
>>
>>       { 'member': type, ('foo': str), ... }
>>
>>     Optional members are under parentheses.
>>
>>     A structure with a base type will have 'BaseStruct +' prepended.
>>
>>     - Alternates use the following syntax:
>>
>>       [ 'foo': type, 'bar': type, ... ]
>>
>>     - Simple unions use the following syntax:
>>
>>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }
>>
>>     - Flat unions use the following syntax:
>>
>>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
>>
>> End quote.  Looks like this in generated documentation:
>>
>>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
>>           VncBasicInfo}
>>
>>      Emitted when a VNC client establishes a connection
>>      ''server''
>>           server information
>>      ''client''
>>           client information
>>
>>      Note: This event is emitted before any authentication takes place,
>>      thus the authentication ID is not provided
>> [...]
>>
>>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
>>
>>      The network connection information for server
>>      ''auth'' (optional)
>>           authentication method used for the plain (non-websocket) VNC
>>           server
>>
>>      Since: 2.1
>>
>>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>>           VsockSocketAddress, 'fd': String] }
>>
>>      Captures the address of a socket, which could also be a named file
>>      descriptor
>>
>>      Since: 1.3
>>
>> Here's my counter-proposal: instead of inventing a formal language,
>> fix the natural language documentation to actually mention *all*
>> members, and add type information in a plain, easy-to-understand way.
>> Looks like this:
>>
>>  -- Event: VNC_CONNECTED
>>
>>      Emitted when a VNC client establishes a connection
>>
>>      Arguments:
>>      'server: VncServerInfo'
>>           server information
>>      'client: VncBasicInfo'
>>           client information
>>
>>      Note: This event is emitted before any authentication takes place,
>>      thus the authentication ID is not provided
>> [...]
>>
>>  -- Object: VncServerInfo
>>
>>      The network connection information for server
>>
>>      Members:
>>      'auth: string' (optional)
>>           authentication method used for the plain (non-websocket) VNC
>>           server
>>      The members of 'VncBasicInfo'
>>
>>      Since: 2.1
>>
>>  -- Object: SocketAddress
>>
>>      Captures the address of a socket, which could also be a named file
>>      descriptor
>>
>>      Members:
>>      'type'
>>           One of "inet", "unix", "vsock", "fd"
>>      'data: InetSocketAddress' when 'type' is "inet"
>>      'data: UnixSocketAddress' when 'type' is "unix"
>>      'data: VsockSocketAddress' when 'type' is "vsock"
>>      'data: String' when 'type' is "fd"
>>
>>      Since: 1.3
>>
>>
> I like both, to me they serve different purposes. I like to have a short
> overview / signature and then a more detailed documentation for each field.

I sympathize with the argument.  Unfortunately, the "short" signatures
are anything but for real-world QAPI:

 -- Flat Union: BlockdevOptions {'driver': BlockdevDriver, ('node-name':
          str), ('discard': BlockdevDiscardOptions), ('cache':
          BlockdevCacheOptions), ('read-only': bool), ('detect-zeroes':
          BlockdevDetectZeroesOptions)} + 'driver' = ['archipelago':
          BlockdevOptionsArchipelago, 'blkdebug':
          BlockdevOptionsBlkdebug, 'blkverify':
          BlockdevOptionsBlkverify, 'bochs':
          BlockdevOptionsGenericFormat, 'cloop':
          BlockdevOptionsGenericFormat, 'dmg':
          BlockdevOptionsGenericFormat, 'file': BlockdevOptionsFile,
          'ftp': BlockdevOptionsCurl, 'ftps': BlockdevOptionsCurl,
          'gluster': BlockdevOptionsGluster, 'host_cdrom':
          BlockdevOptionsFile, 'host_device': BlockdevOptionsFile,
          'http': BlockdevOptionsCurl, 'https': BlockdevOptionsCurl,
          'iscsi': BlockdevOptionsIscsi, 'luks': BlockdevOptionsLUKS,
          'nbd': BlockdevOptionsNbd, 'nfs': BlockdevOptionsNfs,
          'null-aio': BlockdevOptionsNull, 'null-co':
          BlockdevOptionsNull, 'parallels':
          BlockdevOptionsGenericFormat, 'qcow2': BlockdevOptionsQcow2,
          'qcow': BlockdevOptionsGenericCOWFormat, 'qed':
          BlockdevOptionsGenericCOWFormat, 'quorum':
          BlockdevOptionsQuorum, 'raw': BlockdevOptionsRaw, 'rbd':
          BlockdevOptionsRbd, 'replication': BlockdevOptionsReplication,
          'sheepdog': BlockdevOptionsSheepdog, 'ssh':
          BlockdevOptionsSsh, 'vdi': BlockdevOptionsGenericFormat,
          'vhdx': BlockdevOptionsGenericFormat, 'vmdk':
          BlockdevOptionsGenericCOWFormat, 'vpc':
          BlockdevOptionsGenericFormat, 'vvfat': BlockdevOptionsVVFAT]

     Options for creating a block device.  Many options are available
     for all block devices, independent of the block driver:
     ''driver''
          block driver name
     ''node-name'' (optional)
          the node name of the new node (Since 2.0).  This option is
          required on the top level of blockdev-add.
     ''discard'' (optional)
          discard-related options (default: ignore)
     ''cache'' (optional)
          cache-related options
     ''read-only'' (optional)
          whether the block device should be read-only (default: false)
     ''detect-zeroes'' (optional)
          detect and optimize zero writes (Since 2.1) (default: off)
     Remaining options are determined by the block driver.

     Since: 1.7

>> Additionally, my series fixes a number of bugs and cleans up along the
>> way.  In particular, it converts qapi2texi.py from parse trees to the
>> visitor interface the other generators use.
>>
>>
> Your series failed to apply in patchew, and I can't find the branch in your
> repo. Could you publish it?

Done: branch qapi-doc at http://repo.or.cz/w/qemu/armbru.git

>> Future generated documentation work includes eliding types that aren't
>> visible in QMP (like introspection does), and making uses of type
>> names links in HTML.
>>
>>
> Yes, links would be really nice.

Your work brought them into reach, let's grab them :)

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13 12:14   ` Markus Armbruster
@ 2017-03-13 12:21     ` Marc-André Lureau
  2017-03-13 13:12       ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-13 12:21 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, mdroth

Hi

On Mon, Mar 13, 2017 at 4:14 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
> > Hi
> >
> > On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
> > wrote:
> >
> >> I'm proposing this is 2.9 because it fixes a documentation regression.
> >> It affects only documentation; generated C code is unchanged except
> >> for the removal of trailing space in PATCH 46.
> >>
> >> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
> >>
> >> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
> >> the QAPI schema and generate their replacements from the schema
> >> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
> >> also was a step back: the documentation lost information on JSON
> >> types, because I didn't like Marc-André's patch to add it.  He
> >> reposted it for further review afterwards:
> >>
> >>     Subject: [PATCH 0/2] qapi2texi: add type information
> >>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
> >>     https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
> >>
> >> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
> >> descriptions in a new formal language to the generated documentation.
> >> Quoting the commit message:
> >>
> >>     Array types have the following syntax: type[]. Ex: str[].
> >>
> >>     - Struct, commands and events use the following members syntax:
> >>
> >>       { 'member': type, ('foo': str), ... }
> >>
> >>     Optional members are under parentheses.
> >>
> >>     A structure with a base type will have 'BaseStruct +' prepended.
> >>
> >>     - Alternates use the following syntax:
> >>
> >>       [ 'foo': type, 'bar': type, ... ]
> >>
> >>     - Simple unions use the following syntax:
> >>
> >>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }
> >>
> >>     - Flat unions use the following syntax:
> >>
> >>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
> >>
> >> End quote.  Looks like this in generated documentation:
> >>
> >>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
> >>           VncBasicInfo}
> >>
> >>      Emitted when a VNC client establishes a connection
> >>      ''server''
> >>           server information
> >>      ''client''
> >>           client information
> >>
> >>      Note: This event is emitted before any authentication takes place,
> >>      thus the authentication ID is not provided
> >> [...]
> >>
> >>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
> >>
> >>      The network connection information for server
> >>      ''auth'' (optional)
> >>           authentication method used for the plain (non-websocket) VNC
> >>           server
> >>
> >>      Since: 2.1
> >>
> >>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
> >>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
> >>           VsockSocketAddress, 'fd': String] }
> >>
> >>      Captures the address of a socket, which could also be a named file
> >>      descriptor
> >>
> >>      Since: 1.3
> >>
> >> Here's my counter-proposal: instead of inventing a formal language,
> >> fix the natural language documentation to actually mention *all*
> >> members, and add type information in a plain, easy-to-understand way.
> >> Looks like this:
> >>
> >>  -- Event: VNC_CONNECTED
> >>
> >>      Emitted when a VNC client establishes a connection
> >>
> >>      Arguments:
> >>      'server: VncServerInfo'
> >>           server information
> >>      'client: VncBasicInfo'
> >>           client information
> >>
> >>      Note: This event is emitted before any authentication takes place,
> >>      thus the authentication ID is not provided
> >> [...]
> >>
> >>  -- Object: VncServerInfo
> >>
> >>      The network connection information for server
> >>
> >>      Members:
> >>      'auth: string' (optional)
> >>           authentication method used for the plain (non-websocket) VNC
> >>           server
> >>      The members of 'VncBasicInfo'
> >>
> >>      Since: 2.1
> >>
> >>  -- Object: SocketAddress
> >>
> >>      Captures the address of a socket, which could also be a named file
> >>      descriptor
> >>
> >>      Members:
> >>      'type'
> >>           One of "inet", "unix", "vsock", "fd"
> >>      'data: InetSocketAddress' when 'type' is "inet"
> >>      'data: UnixSocketAddress' when 'type' is "unix"
> >>      'data: VsockSocketAddress' when 'type' is "vsock"
> >>      'data: String' when 'type' is "fd"
> >>
> >>      Since: 1.3
> >>
> >>
> > I like both, to me they serve different purposes. I like to have a short
> > overview / signature and then a more detailed documentation for each
> field.
>
> I sympathize with the argument.  Unfortunately, the "short" signatures
> are anything but for real-world QAPI:
>

That's a worse case, a regular case is more readable. And it is still
useful anyway since the common members would be listed first.


>  -- Flat Union: BlockdevOptions {'driver': BlockdevDriver, ('node-name':
>           str), ('discard': BlockdevDiscardOptions), ('cache':
>           BlockdevCacheOptions), ('read-only': bool), ('detect-zeroes':
>           BlockdevDetectZeroesOptions)} + 'driver' = ['archipelago':
>           BlockdevOptionsArchipelago, 'blkdebug':
>           BlockdevOptionsBlkdebug, 'blkverify':
>           BlockdevOptionsBlkverify, 'bochs':
>           BlockdevOptionsGenericFormat, 'cloop':
>           BlockdevOptionsGenericFormat, 'dmg':
>           BlockdevOptionsGenericFormat, 'file': BlockdevOptionsFile,
>           'ftp': BlockdevOptionsCurl, 'ftps': BlockdevOptionsCurl,
>           'gluster': BlockdevOptionsGluster, 'host_cdrom':
>           BlockdevOptionsFile, 'host_device': BlockdevOptionsFile,
>           'http': BlockdevOptionsCurl, 'https': BlockdevOptionsCurl,
>           'iscsi': BlockdevOptionsIscsi, 'luks': BlockdevOptionsLUKS,
>           'nbd': BlockdevOptionsNbd, 'nfs': BlockdevOptionsNfs,
>           'null-aio': BlockdevOptionsNull, 'null-co':
>           BlockdevOptionsNull, 'parallels':
>           BlockdevOptionsGenericFormat, 'qcow2': BlockdevOptionsQcow2,
>           'qcow': BlockdevOptionsGenericCOWFormat, 'qed':
>           BlockdevOptionsGenericCOWFormat, 'quorum':
>           BlockdevOptionsQuorum, 'raw': BlockdevOptionsRaw, 'rbd':
>           BlockdevOptionsRbd, 'replication': BlockdevOptionsReplication,
>           'sheepdog': BlockdevOptionsSheepdog, 'ssh':
>           BlockdevOptionsSsh, 'vdi': BlockdevOptionsGenericFormat,
>           'vhdx': BlockdevOptionsGenericFormat, 'vmdk':
>           BlockdevOptionsGenericCOWFormat, 'vpc':
>           BlockdevOptionsGenericFormat, 'vvfat': BlockdevOptionsVVFAT]
>
>      Options for creating a block device.  Many options are available
>      for all block devices, independent of the block driver:
>      ''driver''
>           block driver name
>      ''node-name'' (optional)
>           the node name of the new node (Since 2.0).  This option is
>           required on the top level of blockdev-add.
>      ''discard'' (optional)
>           discard-related options (default: ignore)
>      ''cache'' (optional)
>           cache-related options
>      ''read-only'' (optional)
>           whether the block device should be read-only (default: false)
>      ''detect-zeroes'' (optional)
>           detect and optimize zero writes (Since 2.1) (default: off)
>      Remaining options are determined by the block driver.
>
>      Since: 1.7
>
> >> Additionally, my series fixes a number of bugs and cleans up along the
> >> way.  In particular, it converts qapi2texi.py from parse trees to the
> >> visitor interface the other generators use.
> >>
> >>
> > Your series failed to apply in patchew, and I can't find the branch in
> your
> > repo. Could you publish it?
>
> Done: branch qapi-doc at http://repo.or.cz/w/qemu/armbru.git
>
>
thanks


> >> Future generated documentation work includes eliding types that aren't
> >> visible in QMP (like introspection does), and making uses of type
> >> names links in HTML.
> >>
> >>
> > Yes, links would be really nice.
>
> Your work brought them into reach, let's grab them :)
>
-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13 12:21     ` Marc-André Lureau
@ 2017-03-13 13:12       ` Markus Armbruster
  2017-03-14 13:22         ` Marc-André Lureau
  0 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-13 13:12 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, mdroth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Mon, Mar 13, 2017 at 4:14 PM Markus Armbruster <armbru@redhat.com> wrote:
>
>> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>>
>> > Hi
>> >
>> > On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
>> > wrote:
>> >
>> >> I'm proposing this is 2.9 because it fixes a documentation regression.
>> >> It affects only documentation; generated C code is unchanged except
>> >> for the removal of trailing space in PATCH 46.
>> >>
>> >> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
>> >>
>> >> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
>> >> the QAPI schema and generate their replacements from the schema
>> >> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
>> >> also was a step back: the documentation lost information on JSON
>> >> types, because I didn't like Marc-André's patch to add it.  He
>> >> reposted it for further review afterwards:
>> >>
>> >>     Subject: [PATCH 0/2] qapi2texi: add type information
>> >>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
>> >>     https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
>> >>
>> >> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
>> >> descriptions in a new formal language to the generated documentation.
>> >> Quoting the commit message:
>> >>
>> >>     Array types have the following syntax: type[]. Ex: str[].
>> >>
>> >>     - Struct, commands and events use the following members syntax:
>> >>
>> >>       { 'member': type, ('foo': str), ... }
>> >>
>> >>     Optional members are under parentheses.
>> >>
>> >>     A structure with a base type will have 'BaseStruct +' prepended.
>> >>
>> >>     - Alternates use the following syntax:
>> >>
>> >>       [ 'foo': type, 'bar': type, ... ]
>> >>
>> >>     - Simple unions use the following syntax:
>> >>
>> >>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }
>> >>
>> >>     - Flat unions use the following syntax:
>> >>
>> >>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
>> >>
>> >> End quote.  Looks like this in generated documentation:
>> >>
>> >>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
>> >>           VncBasicInfo}
>> >>
>> >>      Emitted when a VNC client establishes a connection
>> >>      ''server''
>> >>           server information
>> >>      ''client''
>> >>           client information
>> >>
>> >>      Note: This event is emitted before any authentication takes place,
>> >>      thus the authentication ID is not provided
>> >> [...]
>> >>
>> >>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
>> >>
>> >>      The network connection information for server
>> >>      ''auth'' (optional)
>> >>           authentication method used for the plain (non-websocket) VNC
>> >>           server
>> >>
>> >>      Since: 2.1
>> >>
>> >>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>> >>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>> >>           VsockSocketAddress, 'fd': String] }
>> >>
>> >>      Captures the address of a socket, which could also be a named file
>> >>      descriptor
>> >>
>> >>      Since: 1.3
>> >>
>> >> Here's my counter-proposal: instead of inventing a formal language,
>> >> fix the natural language documentation to actually mention *all*
>> >> members, and add type information in a plain, easy-to-understand way.
>> >> Looks like this:
>> >>
>> >>  -- Event: VNC_CONNECTED
>> >>
>> >>      Emitted when a VNC client establishes a connection
>> >>
>> >>      Arguments:
>> >>      'server: VncServerInfo'
>> >>           server information
>> >>      'client: VncBasicInfo'
>> >>           client information
>> >>
>> >>      Note: This event is emitted before any authentication takes place,
>> >>      thus the authentication ID is not provided
>> >> [...]
>> >>
>> >>  -- Object: VncServerInfo
>> >>
>> >>      The network connection information for server
>> >>
>> >>      Members:
>> >>      'auth: string' (optional)
>> >>           authentication method used for the plain (non-websocket) VNC
>> >>           server
>> >>      The members of 'VncBasicInfo'
>> >>
>> >>      Since: 2.1
>> >>
>> >>  -- Object: SocketAddress
>> >>
>> >>      Captures the address of a socket, which could also be a named file
>> >>      descriptor
>> >>
>> >>      Members:
>> >>      'type'
>> >>           One of "inet", "unix", "vsock", "fd"
>> >>      'data: InetSocketAddress' when 'type' is "inet"
>> >>      'data: UnixSocketAddress' when 'type' is "unix"
>> >>      'data: VsockSocketAddress' when 'type' is "vsock"
>> >>      'data: String' when 'type' is "fd"
>> >>
>> >>      Since: 1.3
>> >>
>> >>
>> > I like both, to me they serve different purposes. I like to have a short
>> > overview / signature and then a more detailed documentation for each
>> field.
>>
>> I sympathize with the argument.  Unfortunately, the "short" signatures
>> are anything but for real-world QAPI:
>>
>
> That's a worse case, a regular case is more readable.

There are readable cases, but there are plenty of cases that plainly
aren't.

102 out of 472 signatures don't count because they're empty.

Roughly half the non-empty signatures fit on a single line.  That's short.

A bit under a third take two lines.  I guess that's still short enough.

More than one in six signatures is three lines or more.

>                                                       And it is still
> useful anyway since the common members would be listed first.

Whatever comes first in signatures comes first in the table of members,
too.  The names are easier to spot there, because they're all on the
left.

Compare

 -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
          InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
          VsockSocketAddress, 'fd': String] }

     Captures the address of a socket, which could also be a named file
     descriptor

     Since: 1.3

to

 -- Object: SocketAddress

     Captures the address of a socket, which could also be a named file
     descriptor

     Members:
     'type'
          One of "inet", "unix", "vsock", "fd"
     'data: InetSocketAddress' when 'type' is "inet"
     'data: UnixSocketAddress' when 'type' is "unix"
     'data: VsockSocketAddress' when 'type' is "vsock"
     'data: String' when 'type' is "fd"

     Since: 1.3

In my opinion, the three lines of signature add nothing but noise to the
six lines of member table.

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__()
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__() Markus Armbruster
@ 2017-03-13 19:34   ` Eric Blake
  2017-03-14  8:28   ` Marc-André Lureau
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-13 19:34 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 939 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 45 +++++++++++++++++++++++----------------------
>  1 file changed, 23 insertions(+), 22 deletions(-)
> 

> 
> +++ b/scripts/qapi.py
> @@ -268,34 +268,15 @@ class QAPISchemaParser(object):
>                  continue
>  
>              expr = self.get_expr(False)
> -            if isinstance(expr, dict) and "include" in expr:
> +            if 'include' in expr:

What happens when expr is not a dict?
/me goes and reads get_expr()...
aha - get_expr() can only return a dict at the top level, and we are
only checking for includes at the top level (it can return non-dict when
nested, but this part of __init__ is not nested).

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them Markus Armbruster
@ 2017-03-13 21:00   ` Eric Blake
  2017-03-14  7:21     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-13 21:00 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 3617 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Since we added the documentation generator in commit 3313b61, doc
> comments are mandatory.  That's a very good idea for a schema that
> needs to be documented, but has proven to be annoying for testing.

As I've found out while rebasing my JSON output visitor as well as
patches to allow anonymous bases to flat unions.  Thanks, this will help me!

> 
> Make doc comments optional again, but add a new directive
> 
>     { 'pragma': { 'doc-required': true } }
> 
> to let a QAPI schema require them.

I like it.  It's extensible to other pragmas, as well; and reading
ahead, it looks like you did a good job of flagging unknown pragmas.

> 
> Require documentation in the schemas we actually want documented:
> qapi-schema.json and qga/qapi-schema.json.
> 
> We could probably make qapi2texi.py cope with incomplete
> documentation, but for now, simply make it refuse to run unless the
> schema has 'doc-required': true.

I'd rather fail early on our non-documented stuff then risk broken
corner cases; so I think you made the right decision.

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  docs/qapi-code-gen.txt             | 40 +++++++++++++++++++++++++-------------

> @@ -277,6 +280,11 @@ class QAPISchemaParser(object):
>                                         "Value of 'include' must be a string")
>                  self._include(include, info, os.path.dirname(abs_fname),
>                                previously_included)
> +            elif "pragma" in expr:
> +                if len(expr) != 1:
> +                    raise QAPISemError(info, "Invalid 'pragma' directive")

You may also want to check that you have an actual dictionary; otherwise...

> +                for name, value in expr['pragma'].iteritems():

calling .iteritems() can lead to some funky python messages. For
example, tweaking qapi-schema.json to use

{ 'pragma': [ { 'doc-required': true } ] }

=>

$ make
  GEN     qmp-commands.h
Traceback (most recent call last):
  File "/home/eblake/qemu/scripts/qapi-commands.py", line 317, in <module>
    schema = QAPISchema(input_file)
  File "/home/eblake/qemu/scripts/qapi.py", line 1496, in __init__
    parser = QAPISchemaParser(open(fname, "r"))
  File "/home/eblake/qemu/scripts/qapi.py", line 286, in __init__
    for name, value in expr['pragma'].iteritems():
AttributeError: 'list' object has no attribute 'iteritems'
Makefile:431: recipe for target 'qmp-commands.h' failed

Not the end of the world, but we've done a nice job elsewhere of
avoiding cryptic python traces.

> +        global doc_required
> +        if name == 'doc-required':
> +            if not isinstance(value, bool):
> +                raise QAPISemError(info,
> +                                   "Pragma 'doc-required' must be boolean")
> +            doc_required = value

No testsuite coverage of this message?

If you decide to not bother, or to defer error message(s) cleanup to
followups (especially since we are running short on time for fixing the
actual doc regression from going into 2.9), then using this patch as-is
can have:

Reviewed-by: Eric Blake <eblake@redhat.com>

Of course, if you spin a v2 that actually addresses my concerns, it
probably will be more involved than something that can trivially keep my
R-b (in part because you'll probably also want a testsuite addition to
cover any new error message...).

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py Markus Armbruster
@ 2017-03-13 21:13   ` Eric Blake
  2017-03-14  7:26     ` Markus Armbruster
  2017-03-14  8:28   ` Marc-André Lureau
  1 sibling, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-13 21:13 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 957 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> This reverts commit 3313b61's changes to tests/qapi-schema/, except
> for tests/qapi-schema/doc-*.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

Tested by doing:

$ git checkout 3313b61
$ git cherry-pick 07c7b92 # the current id on your qapi-doc branch
$ git diff HEAD^^ --stat tests/qapi-schema | grep -v /doc-
 72 files changed, 164 insertions(+)

Reviewed-by: Eric Blake <eblake@redhat.com>

>  200 files changed, 92 insertions(+), 1074 deletions(-)

It's a shame we did that much busywork adding test documentation in the
first place.  But it was incomplete (as I found out when trying to
convert some existing tests of failures into new tests of success, by
adding features like anonymous bases to flat unions), and indeed does
not add much value.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen'
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen' Markus Armbruster
@ 2017-03-13 22:17   ` Eric Blake
  2017-03-14  8:30   ` Marc-André Lureau
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-13 22:17 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 599 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Section "Commands" qualifies its rules on permitted argument and
> return types "with one exception noted below when 'gen' is used".  The
> note went away in commit 2d21291.  Clean up the dangling references.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  docs/qapi-code-gen.txt | 18 ++++++++----------
>  1 file changed, 8 insertions(+), 10 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>


-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list Markus Armbruster
@ 2017-03-13 22:41   ` Eric Blake
  2017-03-14  7:40     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-13 22:41 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 3270 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> qapi.py has a hardcoded white-list of command names that may violate
> the rules on permitted return types.  Add a new pragma directive
> 'returns-whitelist', and use it to replace the hard-coded white-list.

So now the list is per-client, rather than global. Nice idea!

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

> +++ b/qapi-schema.json
> @@ -51,6 +51,18 @@
>  
>  { 'pragma': { 'doc-required': true } }
>  
> +# Whitelists to permit QAPI rule violations; think twice before you
> +# add to them!
> +{ 'pragma': {
> +    # Commands allowed to return a non-dictionary:
> +    'returns-whitelist': [
> +        'human-monitor-command',
> +        'qom-get',
> +        'query-migrate-cache-size',
> +        'query-tpm-models',
> +        'query-tpm-types',
> +        'ringbuf-read' ] } }
> +

If I'm understanding the code right, we could have also written this all
as one pragma with a larger dict instead of two pragmas with one-element
dicts:

{ 'pragma': { 'doc-required': true,
              'returns-whitelist': [ ... ] } }

But see below about another potential for rewriting that I thought of
before reading your full patch [1]...

> @@ -317,12 +298,19 @@ class QAPISchemaParser(object):
>          self.docs.extend(exprs_include.docs)
>  
>      def _pragma(self, name, value, info):
> -        global doc_required
> +        global doc_required, returns_whitelist
>          if name == 'doc-required':
>              if not isinstance(value, bool):
>                  raise QAPISemError(info,
>                                     "Pragma 'doc-required' must be boolean")
>              doc_required = value
> +        elif name == 'returns-whitelist':
> +            if (not isinstance(value, list)
> +                    or any([not isinstance(elt, str) for elt in value])):
> +                raise QAPISemError(info,
> +                                   "Pragma returns-whitelist must be"
> +                                   " a list of strings")

Again, a new error message with no testsuite coverage.

> +            returns_whitelist = value

[1] Hmm, this precludes the converse direction of specifying things.
You cannot usefully list the whitelist pragma more than once, because
only the last one wins.  Why would we want to allow it to be more than
once? because we could do:

{ 'pragma': 'returns-whitelist': [ 'human-monitor-command' ] }
{ 'pragma': 'returns-whitelist': [ 'qom-get' ] }

and then spread out the uses of the pragma to be closer to the
violations, rather than bunched up front.

Or maybe you want to consider rejecting a second whitelist, instead of
silently losing the first one, if you want to force that all violations
are bunched up front into a single pragma.

But that's food for thought - I'm leaving it up to you if you want to
spin a v2 (making non-trivial changes based on my comments), or leave
improvements (like any testsuite additions) for a followup patch.  If
you use this patch as-is, you can add:

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations Markus Armbruster
@ 2017-03-13 22:46   ` Eric Blake
  2017-03-14  7:51     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-13 22:46 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 3031 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> qapi.py has a hardcoded white-list of type names that may violate the
> rule on use of upper and lower case.  Add a new pragma directive
> 'name-case-whitelist', and use it to replace the hard-coded
> white-list.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  docs/qapi-code-gen.txt                  |  6 ++++++
>  qapi-schema.json                        | 11 ++++++++++-
>  scripts/qapi.py                         | 22 ++++++++++------------
>  tests/qapi-schema/enum-member-case.err  |  2 +-
>  tests/qapi-schema/enum-member-case.json |  1 +
>  5 files changed, 28 insertions(+), 14 deletions(-)
> 

> +++ b/qapi-schema.json
> @@ -61,7 +61,16 @@
>          'query-migrate-cache-size',
>          'query-tpm-models',
>          'query-tpm-types',
> -        'ringbuf-read' ] } }
> +        'ringbuf-read' ],
> +    'name-case-whitelist': [
> +        'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
> +        'CpuInfoMIPS',          # PC, visible through query-cpu
> +        'CpuInfoTricore',       # PC, visible through query-cpu
> +        'QapiErrorClass',       # all members, visible through errors
> +        'UuidInfo',             # UUID, visible through query-uuid
> +        'X86CPURegister32',     # all members, visible indirectly through qom-get
> +        'q_obj_CpuInfo-base'    # CPU, visible through query-cpu
> +    ] } }

Interesting - here you bunch up 2 of the 3 pragmas into one dict, while
still leaving the third related to documentation in its own dict.

That 'q_obj_CpuInfo-base' is ugly, and I had a patch around previously
that used a saner name rather than making callers reverse-engineer the
implicit naming rules.  Related to my work on anonymous bases to flat
unions, so I'll get to rebase that work and post it on top of yours.
But not a show-stopper for this patch, where it is just moving the location.


> @@ -311,6 +302,13 @@ class QAPISchemaParser(object):
>                                     "Pragma returns-whitelist must be"
>                                     " a list of strings")
>              returns_whitelist = value
> +        elif name == 'name-case-whitelist':
> +            if (not isinstance(value, list)
> +                    or any([not isinstance(elt, str) for elt in value])):
> +                raise QAPISemError(info,
> +                                   "Pragma name-case-whitelist must be"
> +                                   " a list of strings")
> +            name_case_whitelist = value

Same comments as before - new error message with no testsuite coverage,
and no checking for duplicate assignment where last one silently wins;
but where I'm okay with deferring if you don't want to delay 2.9 for a
v2 respin.

So if you use it unchanged,
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them
  2017-03-13 21:00   ` Eric Blake
@ 2017-03-14  7:21     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14  7:21 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> Since we added the documentation generator in commit 3313b61, doc
>> comments are mandatory.  That's a very good idea for a schema that
>> needs to be documented, but has proven to be annoying for testing.
>
> As I've found out while rebasing my JSON output visitor as well as
> patches to allow anonymous bases to flat unions.  Thanks, this will help me!
>
>> 
>> Make doc comments optional again, but add a new directive
>> 
>>     { 'pragma': { 'doc-required': true } }
>> 
>> to let a QAPI schema require them.
>
> I like it.  It's extensible to other pragmas, as well; and reading
> ahead, it looks like you did a good job of flagging unknown pragmas.
>
>> 
>> Require documentation in the schemas we actually want documented:
>> qapi-schema.json and qga/qapi-schema.json.
>> 
>> We could probably make qapi2texi.py cope with incomplete
>> documentation, but for now, simply make it refuse to run unless the
>> schema has 'doc-required': true.
>
> I'd rather fail early on our non-documented stuff then risk broken
> corner cases; so I think you made the right decision.

I figure making qapi2texi.py robust wouldn't be hard, but decided not to
try for 2.9.

>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  docs/qapi-code-gen.txt             | 40 +++++++++++++++++++++++++-------------
>
>> @@ -277,6 +280,11 @@ class QAPISchemaParser(object):
>>                                         "Value of 'include' must be a string")
>>                  self._include(include, info, os.path.dirname(abs_fname),
>>                                previously_included)
>> +            elif "pragma" in expr:
>> +                if len(expr) != 1:
>> +                    raise QAPISemError(info, "Invalid 'pragma' directive")
>
> You may also want to check that you have an actual dictionary; otherwise...
>
>> +                for name, value in expr['pragma'].iteritems():
>
> calling .iteritems() can lead to some funky python messages. For
> example, tweaking qapi-schema.json to use
>
> { 'pragma': [ { 'doc-required': true } ] }
>
> =>
>
> $ make
>   GEN     qmp-commands.h
> Traceback (most recent call last):
>   File "/home/eblake/qemu/scripts/qapi-commands.py", line 317, in <module>
>     schema = QAPISchema(input_file)
>   File "/home/eblake/qemu/scripts/qapi.py", line 1496, in __init__
>     parser = QAPISchemaParser(open(fname, "r"))
>   File "/home/eblake/qemu/scripts/qapi.py", line 286, in __init__
>     for name, value in expr['pragma'].iteritems():
> AttributeError: 'list' object has no attribute 'iteritems'
> Makefile:431: recipe for target 'qmp-commands.h' failed

You're right.  Need to decide whether to fix it in a respin or on top.

> Not the end of the world, but we've done a nice job elsewhere of
> avoiding cryptic python traces.
>
>> +        global doc_required
>> +        if name == 'doc-required':
>> +            if not isinstance(value, bool):
>> +                raise QAPISemError(info,
>> +                                   "Pragma 'doc-required' must be boolean")
>> +            doc_required = value
>
> No testsuite coverage of this message?

Not yet, i.e. you're right, test coverage is advisable even for exotic
stuff that's expected not to change like pragma.

> If you decide to not bother, or to defer error message(s) cleanup to
> followups (especially since we are running short on time for fixing the
> actual doc regression from going into 2.9), then using this patch as-is
> can have:
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

> Of course, if you spin a v2 that actually addresses my concerns, it
> probably will be more involved than something that can trivially keep my
> R-b (in part because you'll probably also want a testsuite addition to
> cover any new error message...).

Possible :)

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py
  2017-03-13 21:13   ` Eric Blake
@ 2017-03-14  7:26     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14  7:26 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> This reverts commit 3313b61's changes to tests/qapi-schema/, except
>> for tests/qapi-schema/doc-*.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
> Tested by doing:
>
> $ git checkout 3313b61
> $ git cherry-pick 07c7b92 # the current id on your qapi-doc branch
> $ git diff HEAD^^ --stat tests/qapi-schema | grep -v /doc-
>  72 files changed, 164 insertions(+)
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
>>  200 files changed, 92 insertions(+), 1074 deletions(-)
>
> It's a shame we did that much busywork adding test documentation in the
> first place.  But it was incomplete (as I found out when trying to
> convert some existing tests of failures into new tests of success, by
> adding features like anonymous bases to flat unions), and indeed does
> not add much value.

Marc-André initially reported missing documentation errors only in
qapi2texi.py.  I asked why in review of v5, he pointed to tests, I said
"good point" and asked to put the explanation in the commit message.
Got back "I fixed the tests instead (after all, we have complete control
on what to accept or not. that was boring but now it's done)", felt a
bit bad, and then felt bad some more when I made this patch.

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list
  2017-03-13 22:41   ` Eric Blake
@ 2017-03-14  7:40     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14  7:40 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> qapi.py has a hardcoded white-list of command names that may violate
>> the rules on permitted return types.  Add a new pragma directive
>> 'returns-whitelist', and use it to replace the hard-coded white-list.
>
> So now the list is per-client, rather than global. Nice idea!
>
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
>> +++ b/qapi-schema.json
>> @@ -51,6 +51,18 @@
>>  
>>  { 'pragma': { 'doc-required': true } }
>>  
>> +# Whitelists to permit QAPI rule violations; think twice before you
>> +# add to them!
>> +{ 'pragma': {
>> +    # Commands allowed to return a non-dictionary:
>> +    'returns-whitelist': [
>> +        'human-monitor-command',
>> +        'qom-get',
>> +        'query-migrate-cache-size',
>> +        'query-tpm-models',
>> +        'query-tpm-types',
>> +        'ringbuf-read' ] } }
>> +
>
> If I'm understanding the code right, we could have also written this all
> as one pragma with a larger dict instead of two pragmas with one-element
> dicts:
>
> { 'pragma': { 'doc-required': true,
>               'returns-whitelist': [ ... ] } }

Yes.  Separating them let me make the comment stand out more.

> But see below about another potential for rewriting that I thought of
> before reading your full patch [1]...
>
>> @@ -317,12 +298,19 @@ class QAPISchemaParser(object):
>>          self.docs.extend(exprs_include.docs)
>>  
>>      def _pragma(self, name, value, info):
>> -        global doc_required
>> +        global doc_required, returns_whitelist
>>          if name == 'doc-required':
>>              if not isinstance(value, bool):
>>                  raise QAPISemError(info,
>>                                     "Pragma 'doc-required' must be boolean")
>>              doc_required = value
>> +        elif name == 'returns-whitelist':
>> +            if (not isinstance(value, list)
>> +                    or any([not isinstance(elt, str) for elt in value])):
>> +                raise QAPISemError(info,
>> +                                   "Pragma returns-whitelist must be"
>> +                                   " a list of strings")
>
> Again, a new error message with no testsuite coverage.

Okay.

    $ git-ls-files tests/qapi-schema/ | grep -c 'json$'
    157

What's half a dozen more...

>> +            returns_whitelist = value
>
> [1] Hmm, this precludes the converse direction of specifying things.
> You cannot usefully list the whitelist pragma more than once, because
> only the last one wins.  Why would we want to allow it to be more than
> once? because we could do:
>
> { 'pragma': 'returns-whitelist': [ 'human-monitor-command' ] }
> { 'pragma': 'returns-whitelist': [ 'qom-get' ] }
>
> and then spread out the uses of the pragma to be closer to the
> violations, rather than bunched up front.
>
> Or maybe you want to consider rejecting a second whitelist, instead of
> silently losing the first one, if you want to force that all violations
> are bunched up front into a single pragma.

Where to put the pragma is a question of style.  As is, the patch
supports only "put them first", because we actually use the white-list
in a later pass, where only the last pragma value is visible.  To fix
that, we'd have to compute *current* pragma values throughout that later
pass.

As long as we don't, accepting only one whitelist is better than
silently ignoring all but the last.

Computing current pragma values shouldn't be hard, but I'm not sure it's
worthwhile.

> But that's food for thought - I'm leaving it up to you if you want to
> spin a v2 (making non-trivial changes based on my comments), or leave
> improvements (like any testsuite additions) for a followup patch.  If
> you use this patch as-is, you can add:
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations
  2017-03-13 22:46   ` Eric Blake
@ 2017-03-14  7:51     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14  7:51 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> qapi.py has a hardcoded white-list of type names that may violate the
>> rule on use of upper and lower case.  Add a new pragma directive
>> 'name-case-whitelist', and use it to replace the hard-coded
>> white-list.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  docs/qapi-code-gen.txt                  |  6 ++++++
>>  qapi-schema.json                        | 11 ++++++++++-
>>  scripts/qapi.py                         | 22 ++++++++++------------
>>  tests/qapi-schema/enum-member-case.err  |  2 +-
>>  tests/qapi-schema/enum-member-case.json |  1 +
>>  5 files changed, 28 insertions(+), 14 deletions(-)
>> 
>
>> +++ b/qapi-schema.json
>> @@ -61,7 +61,16 @@
>>          'query-migrate-cache-size',
>>          'query-tpm-models',
>>          'query-tpm-types',
>> -        'ringbuf-read' ] } }
>> +        'ringbuf-read' ],
>> +    'name-case-whitelist': [
>> +        'ACPISlotType',         # DIMM, visible through query-acpi-ospm-status
>> +        'CpuInfoMIPS',          # PC, visible through query-cpu
>> +        'CpuInfoTricore',       # PC, visible through query-cpu
>> +        'QapiErrorClass',       # all members, visible through errors
>> +        'UuidInfo',             # UUID, visible through query-uuid
>> +        'X86CPURegister32',     # all members, visible indirectly through qom-get
>> +        'q_obj_CpuInfo-base'    # CPU, visible through query-cpu
>> +    ] } }
>
> Interesting - here you bunch up 2 of the 3 pragmas into one dict, while
> still leaving the third related to documentation in its own dict.
>
> That 'q_obj_CpuInfo-base' is ugly, and I had a patch around previously
> that used a saner name rather than making callers reverse-engineer the
> implicit naming rules.  Related to my work on anonymous bases to flat
> unions, so I'll get to rebase that work and post it on top of yours.
> But not a show-stopper for this patch, where it is just moving the location.

... to a more visible place :)

Regarding flat unions: what I really want is unifying struct and both
kinds of unions into a single object type.  Something like

    { 'object': STRING,        # type name
      '*base': STRING-OR-DICT, # base type
      '*data': DICT,           # common members
      '*tag': STRING,          # tag name, must be in base or common
      '*variant': DICT }       # map tag value -> variant members

Introspection already works that way.

Note no sugar for "simple" unions.  They become syntactically
non-simple.  Feature.

Flat unions become syntactically non-horrible.

>> @@ -311,6 +302,13 @@ class QAPISchemaParser(object):
>>                                     "Pragma returns-whitelist must be"
>>                                     " a list of strings")
>>              returns_whitelist = value
>> +        elif name == 'name-case-whitelist':
>> +            if (not isinstance(value, list)
>> +                    or any([not isinstance(elt, str) for elt in value])):
>> +                raise QAPISemError(info,
>> +                                   "Pragma name-case-whitelist must be"
>> +                                   " a list of strings")
>> +            name_case_whitelist = value
>
> Same comments as before - new error message with no testsuite coverage,
> and no checking for duplicate assignment where last one silently wins;
> but where I'm okay with deferring if you don't want to delay 2.9 for a
> v2 respin.
>
> So if you use it unchanged,
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py Markus Armbruster
  2017-03-13 21:13   ` Eric Blake
@ 2017-03-14  8:28   ` Marc-André Lureau
  2017-03-14  9:45     ` Markus Armbruster
  1 sibling, 1 reply; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:28 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:36 AM Markus Armbruster <armbru@redhat.com>
wrote:

> This reverts commit 3313b61's changes to tests/qapi-schema/, except
> for tests/qapi-schema/doc-*.
>
>
Do we expect those files to change? If not, or not much, I think i't s
rather better to keep the docs to exercise the parser in various
situations. It doesn't reduce the merits of the doc pragma though for other
cases, which I wish I would have suggested (but I didn't like the  initial
series to grow more features)


> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  tests/qapi-schema/alternate-any.err                |   2 +-
>  tests/qapi-schema/alternate-any.json               |   4 -
>  tests/qapi-schema/alternate-array.err              |   2 +-
>  tests/qapi-schema/alternate-array.json             |   7 -
>  tests/qapi-schema/alternate-base.err               |   2 +-
>  tests/qapi-schema/alternate-base.json              |   7 -
>  tests/qapi-schema/alternate-clash.err              |   2 +-
>  tests/qapi-schema/alternate-clash.json             |   4 -
>  tests/qapi-schema/alternate-conflict-dict.err      |   2 +-
>  tests/qapi-schema/alternate-conflict-dict.json     |  10 -
>  tests/qapi-schema/alternate-conflict-string.err    |   2 +-
>  tests/qapi-schema/alternate-conflict-string.json   |   7 -
>  tests/qapi-schema/alternate-empty.err              |   2 +-
>  tests/qapi-schema/alternate-empty.json             |   4 -
>  tests/qapi-schema/alternate-nested.err             |   2 +-
>  tests/qapi-schema/alternate-nested.json            |   7 -
>  tests/qapi-schema/alternate-unknown.err            |   2 +-
>  tests/qapi-schema/alternate-unknown.json           |   4 -
>  tests/qapi-schema/args-alternate.err               |   2 +-
>  tests/qapi-schema/args-alternate.json              |   8 -
>  tests/qapi-schema/args-any.err                     |   2 +-
>  tests/qapi-schema/args-any.json                    |   4 -
>  tests/qapi-schema/args-array-empty.err             |   2 +-
>  tests/qapi-schema/args-array-empty.json            |   4 -
>  tests/qapi-schema/args-array-unknown.err           |   2 +-
>  tests/qapi-schema/args-array-unknown.json          |   4 -
>  tests/qapi-schema/args-bad-boxed.err               |   2 +-
>  tests/qapi-schema/args-bad-boxed.json              |   4 -
>  tests/qapi-schema/args-boxed-anon.err              |   2 +-
>  tests/qapi-schema/args-boxed-anon.json             |   4 -
>  tests/qapi-schema/args-boxed-empty.err             |   2 +-
>  tests/qapi-schema/args-boxed-empty.json            |   8 -
>  tests/qapi-schema/args-boxed-string.err            |   2 +-
>  tests/qapi-schema/args-boxed-string.json           |   4 -
>  tests/qapi-schema/args-int.err                     |   2 +-
>  tests/qapi-schema/args-int.json                    |   4 -
>  tests/qapi-schema/args-invalid.err                 |   2 +-
>  tests/qapi-schema/args-invalid.json                |   3 -
>  tests/qapi-schema/args-member-array-bad.err        |   2 +-
>  tests/qapi-schema/args-member-array-bad.json       |   4 -
>  tests/qapi-schema/args-member-case.err             |   2 +-
>  tests/qapi-schema/args-member-case.json            |   4 -
>  tests/qapi-schema/args-member-unknown.err          |   2 +-
>  tests/qapi-schema/args-member-unknown.json         |   4 -
>  tests/qapi-schema/args-name-clash.err              |   2 +-
>  tests/qapi-schema/args-name-clash.json             |   4 -
>  tests/qapi-schema/args-union.err                   |   2 +-
>  tests/qapi-schema/args-union.json                  |   7 -
>  tests/qapi-schema/args-unknown.err                 |   2 +-
>  tests/qapi-schema/args-unknown.json                |   4 -
>  tests/qapi-schema/bad-base.err                     |   2 +-
>  tests/qapi-schema/bad-base.json                    |   7 -
>  tests/qapi-schema/bad-data.err                     |   2 +-
>  tests/qapi-schema/bad-data.json                    |   4 -
>  tests/qapi-schema/bad-ident.err                    |   2 +-
>  tests/qapi-schema/bad-ident.json                   |   4 -
>  tests/qapi-schema/bad-type-bool.err                |   2 +-
>  tests/qapi-schema/bad-type-bool.json               |   4 -
>  tests/qapi-schema/bad-type-dict.err                |   2 +-
>  tests/qapi-schema/bad-type-dict.json               |   4 -
>  tests/qapi-schema/base-cycle-direct.err            |   2 +-
>  tests/qapi-schema/base-cycle-direct.json           |   4 -
>  tests/qapi-schema/base-cycle-indirect.err          |   2 +-
>  tests/qapi-schema/base-cycle-indirect.json         |   7 -
>  tests/qapi-schema/command-int.err                  |   2 +-
>  tests/qapi-schema/command-int.json                 |   4 -
>  tests/qapi-schema/comments.json                    |   4 -
>  tests/qapi-schema/comments.out                     |   1 -
>  tests/qapi-schema/double-type.err                  |   2 +-
>  tests/qapi-schema/double-type.json                 |   4 -
>  tests/qapi-schema/enum-bad-name.err                |   2 +-
>  tests/qapi-schema/enum-bad-name.json               |   4 -
>  tests/qapi-schema/enum-bad-prefix.err              |   2 +-
>  tests/qapi-schema/enum-bad-prefix.json             |   4 -
>  tests/qapi-schema/enum-clash-member.err            |   2 +-
>  tests/qapi-schema/enum-clash-member.json           |   4 -
>  tests/qapi-schema/enum-dict-member.err             |   2 +-
>  tests/qapi-schema/enum-dict-member.json            |   4 -
>  tests/qapi-schema/enum-member-case.err             |   2 +-
>  tests/qapi-schema/enum-member-case.json            |   7 -
>  tests/qapi-schema/enum-missing-data.err            |   2 +-
>  tests/qapi-schema/enum-missing-data.json           |   4 -
>  tests/qapi-schema/enum-wrong-data.err              |   2 +-
>  tests/qapi-schema/enum-wrong-data.json             |   4 -
>  tests/qapi-schema/event-boxed-empty.err            |   2 +-
>  tests/qapi-schema/event-boxed-empty.json           |   4 -
>  tests/qapi-schema/event-case.json                  |   4 -
>  tests/qapi-schema/event-case.out                   |   1 -
>  tests/qapi-schema/event-nest-struct.err            |   2 +-
>  tests/qapi-schema/event-nest-struct.json           |   4 -
>  tests/qapi-schema/flat-union-array-branch.err      |   2 +-
>  tests/qapi-schema/flat-union-array-branch.json     |  12 --
>  tests/qapi-schema/flat-union-bad-base.err          |   2 +-
>  tests/qapi-schema/flat-union-bad-base.json         |  13 --
>  tests/qapi-schema/flat-union-bad-discriminator.err |   2 +-
>  .../qapi-schema/flat-union-bad-discriminator.json  |  16 --
>  tests/qapi-schema/flat-union-base-any.err          |   2 +-
>  tests/qapi-schema/flat-union-base-any.json         |  13 --
>  tests/qapi-schema/flat-union-base-union.err        |   2 +-
>  tests/qapi-schema/flat-union-base-union.json       |  16 --
>  tests/qapi-schema/flat-union-clash-member.err      |   2 +-
>  tests/qapi-schema/flat-union-clash-member.json     |  16 --
>  tests/qapi-schema/flat-union-empty.err             |   2 +-
>  tests/qapi-schema/flat-union-empty.json            |  10 -
>  tests/qapi-schema/flat-union-incomplete-branch.err |   2 +-
>  .../qapi-schema/flat-union-incomplete-branch.json  |  10 -
>  tests/qapi-schema/flat-union-inline.err            |   2 +-
>  tests/qapi-schema/flat-union-inline.json           |  10 -
>  tests/qapi-schema/flat-union-int-branch.err        |   2 +-
>  tests/qapi-schema/flat-union-int-branch.json       |  13 --
>  .../qapi-schema/flat-union-invalid-branch-key.err  |   2 +-
>  .../qapi-schema/flat-union-invalid-branch-key.json |  15 --
>  .../flat-union-invalid-discriminator.err           |   2 +-
>  .../flat-union-invalid-discriminator.json          |  15 --
>  tests/qapi-schema/flat-union-no-base.err           |   2 +-
>  tests/qapi-schema/flat-union-no-base.json          |  13 --
>  .../flat-union-optional-discriminator.err          |   2 +-
>  .../flat-union-optional-discriminator.json         |  13 --
>  .../flat-union-string-discriminator.err            |   2 +-
>  .../flat-union-string-discriminator.json           |  15 --
>  tests/qapi-schema/ident-with-escape.json           |   4 -
>  tests/qapi-schema/ident-with-escape.out            |   1 -
>  tests/qapi-schema/include-relpath-sub.json         |   3 -
>  tests/qapi-schema/include-relpath.out              |   1 -
>  tests/qapi-schema/include-repetition.out           |   1 -
>  tests/qapi-schema/include-simple-sub.json          |   3 -
>  tests/qapi-schema/include-simple.out               |   1 -
>  tests/qapi-schema/indented-expr.json               |   6 -
>  tests/qapi-schema/indented-expr.out                |   2 -
>  tests/qapi-schema/missing-type.err                 |   2 +-
>  tests/qapi-schema/missing-type.json                |   4 -
>  tests/qapi-schema/nested-struct-data.err           |   2 +-
>  tests/qapi-schema/nested-struct-data.json          |   4 -
>  tests/qapi-schema/qapi-schema-test.json            | 213
> ---------------------
>  tests/qapi-schema/qapi-schema-test.out             | 130 -------------
>

At least here some docs should probably remain, or there won't be much
positive cases left.


>  tests/qapi-schema/redefined-builtin.err            |   2 +-
>  tests/qapi-schema/redefined-builtin.json           |   4 -
>  tests/qapi-schema/redefined-command.err            |   2 +-
>  tests/qapi-schema/redefined-command.json           |   7 -
>  tests/qapi-schema/redefined-event.err              |   2 +-
>  tests/qapi-schema/redefined-event.json             |   7 -
>  tests/qapi-schema/redefined-type.err               |   2 +-
>  tests/qapi-schema/redefined-type.json              |   7 -
>  tests/qapi-schema/reserved-command-q.err           |   2 +-
>  tests/qapi-schema/reserved-command-q.json          |   7 -
>  tests/qapi-schema/reserved-enum-q.err              |   2 +-
>  tests/qapi-schema/reserved-enum-q.json             |   4 -
>  tests/qapi-schema/reserved-member-has.err          |   2 +-
>  tests/qapi-schema/reserved-member-has.json         |   4 -
>  tests/qapi-schema/reserved-member-q.err            |   2 +-
>  tests/qapi-schema/reserved-member-q.json           |   4 -
>  tests/qapi-schema/reserved-member-u.err            |   2 +-
>  tests/qapi-schema/reserved-member-u.json           |   4 -
>  tests/qapi-schema/reserved-member-underscore.err   |   2 +-
>  tests/qapi-schema/reserved-member-underscore.json  |   4 -
>  tests/qapi-schema/reserved-type-kind.err           |   2 +-
>  tests/qapi-schema/reserved-type-kind.json          |   4 -
>  tests/qapi-schema/reserved-type-list.err           |   2 +-
>  tests/qapi-schema/reserved-type-list.json          |   4 -
>  tests/qapi-schema/returns-alternate.err            |   2 +-
>  tests/qapi-schema/returns-alternate.json           |   7 -
>  tests/qapi-schema/returns-array-bad.err            |   2 +-
>  tests/qapi-schema/returns-array-bad.json           |   4 -
>  tests/qapi-schema/returns-dict.err                 |   2 +-
>  tests/qapi-schema/returns-dict.json                |   4 -
>  tests/qapi-schema/returns-unknown.err              |   2 +-
>  tests/qapi-schema/returns-unknown.json             |   4 -
>  tests/qapi-schema/returns-whitelist.err            |   2 +-
>  tests/qapi-schema/returns-whitelist.json           |  16 --
>  tests/qapi-schema/struct-base-clash-deep.err       |   2 +-
>  tests/qapi-schema/struct-base-clash-deep.json      |  10 -
>  tests/qapi-schema/struct-base-clash.err            |   2 +-
>  tests/qapi-schema/struct-base-clash.json           |   7 -
>  tests/qapi-schema/struct-data-invalid.err          |   2 +-
>  tests/qapi-schema/struct-data-invalid.json         |   3 -
>  tests/qapi-schema/struct-member-invalid.err        |   2 +-
>  tests/qapi-schema/struct-member-invalid.json       |   3 -
>  tests/qapi-schema/test-qapi.py                     |  14 --
>  tests/qapi-schema/type-bypass-bad-gen.err          |   2 +-
>  tests/qapi-schema/type-bypass-bad-gen.json         |   4 -
>  tests/qapi-schema/unicode-str.err                  |   2 +-
>  tests/qapi-schema/unicode-str.json                 |   4 -
>  tests/qapi-schema/union-base-no-discriminator.err  |   2 +-
>  tests/qapi-schema/union-base-no-discriminator.json |  12 --
>  tests/qapi-schema/union-branch-case.err            |   2 +-
>  tests/qapi-schema/union-branch-case.json           |   4 -
>  tests/qapi-schema/union-clash-branches.err         |   2 +-
>  tests/qapi-schema/union-clash-branches.json        |   4 -
>  tests/qapi-schema/union-empty.err                  |   2 +-
>  tests/qapi-schema/union-empty.json                 |   4 -
>  tests/qapi-schema/union-invalid-base.err           |   2 +-
>  tests/qapi-schema/union-invalid-base.json          |  10 -
>  tests/qapi-schema/union-optional-branch.err        |   2 +-
>  tests/qapi-schema/union-optional-branch.json       |   4 -
>  tests/qapi-schema/union-unknown.err                |   2 +-
>  tests/qapi-schema/union-unknown.json               |   4 -
>  tests/qapi-schema/unknown-escape.err               |   2 +-
>  tests/qapi-schema/unknown-escape.json              |   4 -
>  tests/qapi-schema/unknown-expr-key.err             |   2 +-
>  tests/qapi-schema/unknown-expr-key.json            |   4 -
>  200 files changed, 92 insertions(+), 1074 deletions(-)
>
> diff --git a/tests/qapi-schema/alternate-any.err
> b/tests/qapi-schema/alternate-any.err
> index 395c8ab..aaa0154 100644
> --- a/tests/qapi-schema/alternate-any.err
> +++ b/tests/qapi-schema/alternate-any.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-any.json:6: Alternate 'Alt' member 'one'
> cannot use type 'any'
> +tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one'
> cannot use type 'any'
> diff --git a/tests/qapi-schema/alternate-any.json
> b/tests/qapi-schema/alternate-any.json
> index c958776..e47a73a 100644
> --- a/tests/qapi-schema/alternate-any.json
> +++ b/tests/qapi-schema/alternate-any.json
> @@ -1,8 +1,4 @@
>  # we do not allow the 'any' type as an alternate branch
> -
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt',
>    'data': { 'one': 'any',
>              'two': 'int' } }
> diff --git a/tests/qapi-schema/alternate-array.err
> b/tests/qapi-schema/alternate-array.err
> index 09628e9..7b930c6 100644
> --- a/tests/qapi-schema/alternate-array.err
> +++ b/tests/qapi-schema/alternate-array.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-array.json:12: Member 'two' of alternate
> 'Alt' cannot be an array
> +tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt'
> cannot be an array
> diff --git a/tests/qapi-schema/alternate-array.json
> b/tests/qapi-schema/alternate-array.json
> index c2f98ad..f241aac 100644
> --- a/tests/qapi-schema/alternate-array.json
> +++ b/tests/qapi-schema/alternate-array.json
> @@ -1,14 +1,7 @@
>  # we do not allow array branches in alternates
> -
> -##
> -# @One:
> -##
>  # TODO: should we support this?
>  { 'struct': 'One',
>    'data': { 'name': 'str' } }
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt',
>    'data': { 'one': 'One',
>              'two': [ 'int' ] } }
> diff --git a/tests/qapi-schema/alternate-base.err
> b/tests/qapi-schema/alternate-base.err
> index 3b67914..30d8a34 100644
> --- a/tests/qapi-schema/alternate-base.err
> +++ b/tests/qapi-schema/alternate-base.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-base.json:11: Unknown key 'base' in alternate
> 'Alt'
> +tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate
> 'Alt'
> diff --git a/tests/qapi-schema/alternate-base.json
> b/tests/qapi-schema/alternate-base.json
> index 9612b79..529430ec 100644
> --- a/tests/qapi-schema/alternate-base.json
> +++ b/tests/qapi-schema/alternate-base.json
> @@ -1,13 +1,6 @@
>  # we reject alternate with base type
> -
> -##
> -# @Base:
> -##
>  { 'struct': 'Base',
>    'data': { 'string': 'str' } }
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt',
>    'base': 'Base',
>    'data': { 'number': 'int' } }
> diff --git a/tests/qapi-schema/alternate-clash.err
> b/tests/qapi-schema/alternate-clash.err
> index f07c3e8..604d849 100644
> --- a/tests/qapi-schema/alternate-clash.err
> +++ b/tests/qapi-schema/alternate-clash.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-clash.json:11: 'a_b' (branch of Alt1)
> collides with 'a-b' (branch of Alt1)
> +tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides
> with 'a-b' (branch of Alt1)
> diff --git a/tests/qapi-schema/alternate-clash.json
> b/tests/qapi-schema/alternate-clash.json
> index 97ca7c8..6d73bc5 100644
> --- a/tests/qapi-schema/alternate-clash.json
> +++ b/tests/qapi-schema/alternate-clash.json
> @@ -4,9 +4,5 @@
>  # TODO: In the future, if alternates are simplified to not generate
>  # the implicit Alt1Kind enum, we would still have a collision with the
>  # resulting C union trying to have two members named 'a_b'.
> -
> -##
> -# @Alt1:
> -##
>  { 'alternate': 'Alt1',
>    'data': { 'a-b': 'str', 'a_b': 'int' } }
> diff --git a/tests/qapi-schema/alternate-conflict-dict.err
> b/tests/qapi-schema/alternate-conflict-dict.err
> index 7cb023f..0f411f4 100644
> --- a/tests/qapi-schema/alternate-conflict-dict.err
> +++ b/tests/qapi-schema/alternate-conflict-dict.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-conflict-dict.json:16: Alternate 'Alt' member
> 'two' can't be distinguished from member 'one'
> +tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member
> 'two' can't be distinguished from member 'one'
> diff --git a/tests/qapi-schema/alternate-conflict-dict.json
> b/tests/qapi-schema/alternate-conflict-dict.json
> index 9f9d97f..d566cca 100644
> --- a/tests/qapi-schema/alternate-conflict-dict.json
> +++ b/tests/qapi-schema/alternate-conflict-dict.json
> @@ -1,18 +1,8 @@
>  # we reject alternates with multiple object branches
> -
> -##
> -# @One:
> -##
>  { 'struct': 'One',
>    'data': { 'name': 'str' } }
> -##
> -# @Two:
> -##
>  { 'struct': 'Two',
>    'data': { 'value': 'int' } }
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt',
>    'data': { 'one': 'One',
>              'two': 'Two' } }
> diff --git a/tests/qapi-schema/alternate-conflict-string.err
> b/tests/qapi-schema/alternate-conflict-string.err
> index 6dbbacd..fc523b0 100644
> --- a/tests/qapi-schema/alternate-conflict-string.err
> +++ b/tests/qapi-schema/alternate-conflict-string.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-conflict-string.json:11: Alternate 'Alt'
> member 'two' can't be distinguished from member 'one'
> +tests/qapi-schema/alternate-conflict-string.json:4: Alternate 'Alt'
> member 'two' can't be distinguished from member 'one'
> diff --git a/tests/qapi-schema/alternate-conflict-string.json
> b/tests/qapi-schema/alternate-conflict-string.json
> index 12aafab..72f04a8 100644
> --- a/tests/qapi-schema/alternate-conflict-string.json
> +++ b/tests/qapi-schema/alternate-conflict-string.json
> @@ -1,13 +1,6 @@
>  # we reject alternates with multiple string-like branches
> -
> -##
> -# @Enum:
> -##
>  { 'enum': 'Enum',
>    'data': [ 'hello', 'world' ] }
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt',
>    'data': { 'one': 'str',
>              'two': 'Enum' } }
> diff --git a/tests/qapi-schema/alternate-empty.err
> b/tests/qapi-schema/alternate-empty.err
> index 8245ce3..bb06c5b 100644
> --- a/tests/qapi-schema/alternate-empty.err
> +++ b/tests/qapi-schema/alternate-empty.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-empty.json:6: Alternate 'Alt' should have at
> least two branches in 'data'
> +tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at
> least two branches in 'data'
> diff --git a/tests/qapi-schema/alternate-empty.json
> b/tests/qapi-schema/alternate-empty.json
> index db54405..fff15ba 100644
> --- a/tests/qapi-schema/alternate-empty.json
> +++ b/tests/qapi-schema/alternate-empty.json
> @@ -1,6 +1,2 @@
>  # alternates must list at least two types to be useful
> -
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt', 'data': { 'i': 'int' } }
> diff --git a/tests/qapi-schema/alternate-nested.err
> b/tests/qapi-schema/alternate-nested.err
> index 1804ffb..4d1187e 100644
> --- a/tests/qapi-schema/alternate-nested.err
> +++ b/tests/qapi-schema/alternate-nested.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-nested.json:11: Member 'nested' of alternate
> 'Alt2' cannot use alternate type 'Alt1'
> +tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate
> 'Alt2' cannot use alternate type 'Alt1'
> diff --git a/tests/qapi-schema/alternate-nested.json
> b/tests/qapi-schema/alternate-nested.json
> index 9f83ebe..8e22186 100644
> --- a/tests/qapi-schema/alternate-nested.json
> +++ b/tests/qapi-schema/alternate-nested.json
> @@ -1,12 +1,5 @@
>  # we reject a nested alternate branch
> -
> -##
> -# @Alt1:
> -##
>  { 'alternate': 'Alt1',
>    'data': { 'name': 'str', 'value': 'int' } }
> -##
> -# @Alt2:
> -##
>  { 'alternate': 'Alt2',
>    'data': { 'nested': 'Alt1', 'b': 'bool' } }
> diff --git a/tests/qapi-schema/alternate-unknown.err
> b/tests/qapi-schema/alternate-unknown.err
> index cf5b9b6..dea45dc 100644
> --- a/tests/qapi-schema/alternate-unknown.err
> +++ b/tests/qapi-schema/alternate-unknown.err
> @@ -1 +1 @@
> -tests/qapi-schema/alternate-unknown.json:6: Member 'unknown' of alternate
> 'Alt' uses unknown type 'MissingType'
> +tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate
> 'Alt' uses unknown type 'MissingType'
> diff --git a/tests/qapi-schema/alternate-unknown.json
> b/tests/qapi-schema/alternate-unknown.json
> index 941ba1f..08c80dc 100644
> --- a/tests/qapi-schema/alternate-unknown.json
> +++ b/tests/qapi-schema/alternate-unknown.json
> @@ -1,7 +1,3 @@
>  # we reject an alternate with unknown type in branch
> -
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt',
>    'data': { 'unknown': 'MissingType', 'i': 'int' } }
> diff --git a/tests/qapi-schema/args-alternate.err
> b/tests/qapi-schema/args-alternate.err
> index 2e6bf54..3086eae 100644
> --- a/tests/qapi-schema/args-alternate.err
> +++ b/tests/qapi-schema/args-alternate.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-alternate.json:11: 'data' for command 'oops'
> cannot use alternate type 'Alt'
> +tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot
> use alternate type 'Alt'
> diff --git a/tests/qapi-schema/args-alternate.json
> b/tests/qapi-schema/args-alternate.json
> index 49d0211..69e94d4 100644
> --- a/tests/qapi-schema/args-alternate.json
> +++ b/tests/qapi-schema/args-alternate.json
> @@ -1,11 +1,3 @@
>  # we do not allow alternate arguments
> -
> -##
> -# @Alt:
> -##
>  { 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } }
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': 'Alt' }
> diff --git a/tests/qapi-schema/args-any.err
> b/tests/qapi-schema/args-any.err
> index 955504b..bf9b5e0 100644
> --- a/tests/qapi-schema/args-any.err
> +++ b/tests/qapi-schema/args-any.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-any.json:6: 'data' for command 'oops' cannot use
> built-in type 'any'
> +tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use
> built-in type 'any'
> diff --git a/tests/qapi-schema/args-any.json
> b/tests/qapi-schema/args-any.json
> index f494479..58fe5e4 100644
> --- a/tests/qapi-schema/args-any.json
> +++ b/tests/qapi-schema/args-any.json
> @@ -1,6 +1,2 @@
>  # we do not allow an 'any' argument
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': 'any' }
> diff --git a/tests/qapi-schema/args-array-empty.err
> b/tests/qapi-schema/args-array-empty.err
> index e85f791..cb7ed33 100644
> --- a/tests/qapi-schema/args-array-empty.err
> +++ b/tests/qapi-schema/args-array-empty.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-array-empty.json:6: Member 'empty' of 'data' for
> command 'oops': array type must contain single type name
> +tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for
> command 'oops': array type must contain single type name
> diff --git a/tests/qapi-schema/args-array-empty.json
> b/tests/qapi-schema/args-array-empty.json
> index 78a0b88..652dcfb 100644
> --- a/tests/qapi-schema/args-array-empty.json
> +++ b/tests/qapi-schema/args-array-empty.json
> @@ -1,6 +1,2 @@
>  # we reject an array for data if it does not contain a known type
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': { 'empty': [ ] } }
> diff --git a/tests/qapi-schema/args-array-unknown.err
> b/tests/qapi-schema/args-array-unknown.err
> index 77788de..cd7a0f9 100644
> --- a/tests/qapi-schema/args-array-unknown.err
> +++ b/tests/qapi-schema/args-array-unknown.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-array-unknown.json:6: Member 'array' of 'data' for
> command 'oops' uses unknown type 'NoSuchType'
> +tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for
> command 'oops' uses unknown type 'NoSuchType'
> diff --git a/tests/qapi-schema/args-array-unknown.json
> b/tests/qapi-schema/args-array-unknown.json
> index f680fc1..6f3e883 100644
> --- a/tests/qapi-schema/args-array-unknown.json
> +++ b/tests/qapi-schema/args-array-unknown.json
> @@ -1,6 +1,2 @@
>  # we reject an array for data if it does not contain a known type
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': { 'array': [ 'NoSuchType' ] } }
> diff --git a/tests/qapi-schema/args-bad-boxed.err
> b/tests/qapi-schema/args-bad-boxed.err
> index 87a9061..ad0d417 100644
> --- a/tests/qapi-schema/args-bad-boxed.err
> +++ b/tests/qapi-schema/args-bad-boxed.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-bad-boxed.json:6: 'boxed' of command 'foo' should
> only use true value
> +tests/qapi-schema/args-bad-boxed.json:2: 'boxed' of command 'foo' should
> only use true value
> diff --git a/tests/qapi-schema/args-bad-boxed.json
> b/tests/qapi-schema/args-bad-boxed.json
> index 4c0b28f..dea0cd0 100644
> --- a/tests/qapi-schema/args-bad-boxed.json
> +++ b/tests/qapi-schema/args-bad-boxed.json
> @@ -1,6 +1,2 @@
>  # 'boxed' should only appear with value true
> -
> -##
> -# @foo:
> -##
>  { 'command': 'foo', 'boxed': false }
> diff --git a/tests/qapi-schema/args-boxed-anon.err
> b/tests/qapi-schema/args-boxed-anon.err
> index 3cfac0b..f24f345 100644
> --- a/tests/qapi-schema/args-boxed-anon.err
> +++ b/tests/qapi-schema/args-boxed-anon.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-boxed-anon.json:6: 'data' for command 'foo' should
> be a type name
> +tests/qapi-schema/args-boxed-anon.json:2: 'data' for command 'foo' should
> be a type name
> diff --git a/tests/qapi-schema/args-boxed-anon.json
> b/tests/qapi-schema/args-boxed-anon.json
> index 2358e6a..95f60da 100644
> --- a/tests/qapi-schema/args-boxed-anon.json
> +++ b/tests/qapi-schema/args-boxed-anon.json
> @@ -1,6 +1,2 @@
>  # 'boxed' can only be used with named types
> -
> -##
> -# @foo:
> -##
>  { 'command': 'foo', 'boxed': true, 'data': { 'string': 'str' } }
> diff --git a/tests/qapi-schema/args-boxed-empty.err
> b/tests/qapi-schema/args-boxed-empty.err
> index 963f495..039603e 100644
> --- a/tests/qapi-schema/args-boxed-empty.err
> +++ b/tests/qapi-schema/args-boxed-empty.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-boxed-empty.json:11: Cannot use 'boxed' with empty
> type
> +tests/qapi-schema/args-boxed-empty.json:3: Cannot use 'boxed' with empty
> type
> diff --git a/tests/qapi-schema/args-boxed-empty.json
> b/tests/qapi-schema/args-boxed-empty.json
> index 8e8cc26..52717e0 100644
> --- a/tests/qapi-schema/args-boxed-empty.json
> +++ b/tests/qapi-schema/args-boxed-empty.json
> @@ -1,11 +1,3 @@
>  # 'boxed' requires a non-empty type
> -
> -##
> -# @Empty:
> -##
>  { 'struct': 'Empty', 'data': {} }
> -
> -##
> -# @foo:
> -##
>  { 'command': 'foo', 'boxed': true, 'data': 'Empty' }
> diff --git a/tests/qapi-schema/args-boxed-string.err
> b/tests/qapi-schema/args-boxed-string.err
> index 7623755..d326b48 100644
> --- a/tests/qapi-schema/args-boxed-string.err
> +++ b/tests/qapi-schema/args-boxed-string.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-boxed-string.json:6: 'data' for command 'foo'
> cannot use built-in type 'str'
> +tests/qapi-schema/args-boxed-string.json:2: 'data' for command 'foo'
> cannot use built-in type 'str'
> diff --git a/tests/qapi-schema/args-boxed-string.json
> b/tests/qapi-schema/args-boxed-string.json
> index aecdf97..f91a150 100644
> --- a/tests/qapi-schema/args-boxed-string.json
> +++ b/tests/qapi-schema/args-boxed-string.json
> @@ -1,6 +1,2 @@
>  # 'boxed' requires a complex (not built-in) type
> -
> -##
> -# @foo:
> -##
>  { 'command': 'foo', 'boxed': true, 'data': 'str' }
> diff --git a/tests/qapi-schema/args-int.err
> b/tests/qapi-schema/args-int.err
> index 38b3202..dc1d250 100644
> --- a/tests/qapi-schema/args-int.err
> +++ b/tests/qapi-schema/args-int.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-int.json:6: 'data' for command 'oops' cannot use
> built-in type 'int'
> +tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use
> built-in type 'int'
> diff --git a/tests/qapi-schema/args-int.json
> b/tests/qapi-schema/args-int.json
> index 7f4e1b7..a334d92 100644
> --- a/tests/qapi-schema/args-int.json
> +++ b/tests/qapi-schema/args-int.json
> @@ -1,6 +1,2 @@
>  # we reject commands where data is not an array or complex type
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': 'int' }
> diff --git a/tests/qapi-schema/args-invalid.err
> b/tests/qapi-schema/args-invalid.err
> index 5d3568d..fe1e949 100644
> --- a/tests/qapi-schema/args-invalid.err
> +++ b/tests/qapi-schema/args-invalid.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-invalid.json:4: 'data' for command 'foo' should be
> a dictionary or type name
> +tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be
> a dictionary or type name
> diff --git a/tests/qapi-schema/args-invalid.json
> b/tests/qapi-schema/args-invalid.json
> index 1a7e63b..db09813 100644
> --- a/tests/qapi-schema/args-invalid.json
> +++ b/tests/qapi-schema/args-invalid.json
> @@ -1,5 +1,2 @@
> -##
> -# @foo:
> -##
>  { 'command': 'foo',
>    'data': false }
> diff --git a/tests/qapi-schema/args-member-array-bad.err
> b/tests/qapi-schema/args-member-array-bad.err
> index 825ffca..881b4d9 100644
> --- a/tests/qapi-schema/args-member-array-bad.err
> +++ b/tests/qapi-schema/args-member-array-bad.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-member-array-bad.json:6: Member 'member' of 'data'
> for command 'oops': array type must contain single type name
> +tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data'
> for command 'oops': array type must contain single type name
> diff --git a/tests/qapi-schema/args-member-array-bad.json
> b/tests/qapi-schema/args-member-array-bad.json
> index e934f5c..b2ff144 100644
> --- a/tests/qapi-schema/args-member-array-bad.json
> +++ b/tests/qapi-schema/args-member-array-bad.json
> @@ -1,6 +1,2 @@
>  # we reject data if it does not contain a valid array type
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': { 'member': [ { 'nested': 'str' } ] } }
> diff --git a/tests/qapi-schema/args-member-case.err
> b/tests/qapi-schema/args-member-case.err
> index a3fb2bd..19c4426 100644
> --- a/tests/qapi-schema/args-member-case.err
> +++ b/tests/qapi-schema/args-member-case.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-member-case.json:6: 'Arg' (parameter of
> no-way-this-will-get-whitelisted) should not use uppercase
> +tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of
> no-way-this-will-get-whitelisted) should not use uppercase
> diff --git a/tests/qapi-schema/args-member-case.json
> b/tests/qapi-schema/args-member-case.json
> index 811e658..93439be 100644
> --- a/tests/qapi-schema/args-member-case.json
> +++ b/tests/qapi-schema/args-member-case.json
> @@ -1,6 +1,2 @@
>  # Member names should be 'lower-case' unless the struct/command is
> whitelisted
> -
> -##
> -# @no-way-this-will-get-whitelisted:
> -##
>  { 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' }
> }
> diff --git a/tests/qapi-schema/args-member-unknown.err
> b/tests/qapi-schema/args-member-unknown.err
> index 3db452b..f6f8282 100644
> --- a/tests/qapi-schema/args-member-unknown.err
> +++ b/tests/qapi-schema/args-member-unknown.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-member-unknown.json:6: Member 'member' of 'data'
> for command 'oops' uses unknown type 'NoSuchType'
> +tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data'
> for command 'oops' uses unknown type 'NoSuchType'
> diff --git a/tests/qapi-schema/args-member-unknown.json
> b/tests/qapi-schema/args-member-unknown.json
> index e2fef9c..342a41e 100644
> --- a/tests/qapi-schema/args-member-unknown.json
> +++ b/tests/qapi-schema/args-member-unknown.json
> @@ -1,6 +1,2 @@
>  # we reject data if it does not contain a known type
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': { 'member': 'NoSuchType' } }
> diff --git a/tests/qapi-schema/args-name-clash.err
> b/tests/qapi-schema/args-name-clash.err
> index 23988cb..d953e8d 100644
> --- a/tests/qapi-schema/args-name-clash.err
> +++ b/tests/qapi-schema/args-name-clash.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-name-clash.json:8: 'a_b' (parameter of oops)
> collides with 'a-b' (parameter of oops)
> +tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops)
> collides with 'a-b' (parameter of oops)
> diff --git a/tests/qapi-schema/args-name-clash.json
> b/tests/qapi-schema/args-name-clash.json
> index 991323b..61423cb 100644
> --- a/tests/qapi-schema/args-name-clash.json
> +++ b/tests/qapi-schema/args-name-clash.json
> @@ -1,8 +1,4 @@
>  # C member name collision
>  # Reject members that clash when mapped to C names (we would have two
> 'a_b'
>  # members).
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }
> diff --git a/tests/qapi-schema/args-union.err
> b/tests/qapi-schema/args-union.err
> index ce0a34e..f8ad223 100644
> --- a/tests/qapi-schema/args-union.err
> +++ b/tests/qapi-schema/args-union.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-union.json:10: 'data' for command 'oops' cannot
> use union type 'Uni'
> +tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use
> union type 'Uni'
> diff --git a/tests/qapi-schema/args-union.json
> b/tests/qapi-schema/args-union.json
> index 57284b4..2fcaeaa 100644
> --- a/tests/qapi-schema/args-union.json
> +++ b/tests/qapi-schema/args-union.json
> @@ -1,10 +1,3 @@
>  # use of union arguments requires 'boxed':true
> -
> -##
> -# @Uni:
> -##
>  { 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } }
> -##
> -# oops:
> -##
>  { 'command': 'oops', 'data': 'Uni' }
> diff --git a/tests/qapi-schema/args-unknown.err
> b/tests/qapi-schema/args-unknown.err
> index ba6c6cf..4d91ec8 100644
> --- a/tests/qapi-schema/args-unknown.err
> +++ b/tests/qapi-schema/args-unknown.err
> @@ -1 +1 @@
> -tests/qapi-schema/args-unknown.json:6: 'data' for command 'oops' uses
> unknown type 'NoSuchType'
> +tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses
> unknown type 'NoSuchType'
> diff --git a/tests/qapi-schema/args-unknown.json
> b/tests/qapi-schema/args-unknown.json
> index 12666dc..32aba43 100644
> --- a/tests/qapi-schema/args-unknown.json
> +++ b/tests/qapi-schema/args-unknown.json
> @@ -1,6 +1,2 @@
>  # we reject data if it does not contain a known type
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': 'NoSuchType' }
> diff --git a/tests/qapi-schema/bad-base.err
> b/tests/qapi-schema/bad-base.err
> index e668761..154274b 100644
> --- a/tests/qapi-schema/bad-base.err
> +++ b/tests/qapi-schema/bad-base.err
> @@ -1 +1 @@
> -tests/qapi-schema/bad-base.json:10: 'base' for struct 'MyType' cannot use
> union type 'Union'
> +tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use
> union type 'Union'
> diff --git a/tests/qapi-schema/bad-base.json
> b/tests/qapi-schema/bad-base.json
> index c3faa82..a634331 100644
> --- a/tests/qapi-schema/bad-base.json
> +++ b/tests/qapi-schema/bad-base.json
> @@ -1,10 +1,3 @@
>  # we reject a base that is not a struct
> -
> -##
> -# @Union:
> -##
>  { 'union': 'Union', 'data': { 'a': 'int', 'b': 'str' } }
> -##
> -# @MyType:
> -##
>  { 'struct': 'MyType', 'base': 'Union', 'data': { 'c': 'int' } }
> diff --git a/tests/qapi-schema/bad-data.err
> b/tests/qapi-schema/bad-data.err
> index c1b9e35..8523ac4 100644
> --- a/tests/qapi-schema/bad-data.err
> +++ b/tests/qapi-schema/bad-data.err
> @@ -1 +1 @@
> -tests/qapi-schema/bad-data.json:6: 'data' for command 'oops' cannot be an
> array
> +tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an
> array
> diff --git a/tests/qapi-schema/bad-data.json
> b/tests/qapi-schema/bad-data.json
> index 51c444f..832eeb7 100644
> --- a/tests/qapi-schema/bad-data.json
> +++ b/tests/qapi-schema/bad-data.json
> @@ -1,6 +1,2 @@
>  # we ensure 'data' is a dictionary for all but enums
> -
> -##
> -# @oops:
> -##
>  { 'command': 'oops', 'data': [ ] }
> diff --git a/tests/qapi-schema/bad-ident.err
> b/tests/qapi-schema/bad-ident.err
> index b757aa2..c419060 100644
> --- a/tests/qapi-schema/bad-ident.err
> +++ b/tests/qapi-schema/bad-ident.err
> @@ -1 +1 @@
> -tests/qapi-schema/bad-ident.json:6: 'struct' does not allow optional name
> '*oops'
> +tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name
> '*oops'
> diff --git a/tests/qapi-schema/bad-ident.json
> b/tests/qapi-schema/bad-ident.json
> index b43df7a..763627a 100644
> --- a/tests/qapi-schema/bad-ident.json
> +++ b/tests/qapi-schema/bad-ident.json
> @@ -1,6 +1,2 @@
>  # we reject creating a type name with bad name
> -
> -##
> -# @*oops:
> -##
>  { 'struct': '*oops', 'data': { 'i': 'int' } }
> diff --git a/tests/qapi-schema/bad-type-bool.err
> b/tests/qapi-schema/bad-type-bool.err
> index 72e026b..62fd70b 100644
> --- a/tests/qapi-schema/bad-type-bool.err
> +++ b/tests/qapi-schema/bad-type-bool.err
> @@ -1 +1 @@
> -tests/qapi-schema/bad-type-bool.json:6: 'struct' key must have a string
> value
> +tests/qapi-schema/bad-type-bool.json:2: 'struct' key must have a string
> value
> diff --git a/tests/qapi-schema/bad-type-bool.json
> b/tests/qapi-schema/bad-type-bool.json
> index 1f9eddf..bde17b5 100644
> --- a/tests/qapi-schema/bad-type-bool.json
> +++ b/tests/qapi-schema/bad-type-bool.json
> @@ -1,6 +1,2 @@
>  # we reject an expression with a metatype that is not a string
> -
> -##
> -# @true:
> -##
>  { 'struct': true, 'data': { } }
> diff --git a/tests/qapi-schema/bad-type-dict.err
> b/tests/qapi-schema/bad-type-dict.err
> index d0d1f60..0b2a2ae 100644
> --- a/tests/qapi-schema/bad-type-dict.err
> +++ b/tests/qapi-schema/bad-type-dict.err
> @@ -1 +1 @@
> -tests/qapi-schema/bad-type-dict.json:6: 'command' key must have a string
> value
> +tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string
> value
> diff --git a/tests/qapi-schema/bad-type-dict.json
> b/tests/qapi-schema/bad-type-dict.json
> index 5952caa..2a91b24 100644
> --- a/tests/qapi-schema/bad-type-dict.json
> +++ b/tests/qapi-schema/bad-type-dict.json
> @@ -1,6 +1,2 @@
>  # we reject an expression with a metatype that is not a string
> -
> -##
> -# @foo:
> -##
>  { 'command': { } }
> diff --git a/tests/qapi-schema/base-cycle-direct.err
> b/tests/qapi-schema/base-cycle-direct.err
> index dd7f5aa..9c68f65 100644
> --- a/tests/qapi-schema/base-cycle-direct.err
> +++ b/tests/qapi-schema/base-cycle-direct.err
> @@ -1 +1 @@
> -tests/qapi-schema/base-cycle-direct.json:6: Object Loopy contains itself
> +tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself
> diff --git a/tests/qapi-schema/base-cycle-direct.json
> b/tests/qapi-schema/base-cycle-direct.json
> index 9780f7e..4fc66d0 100644
> --- a/tests/qapi-schema/base-cycle-direct.json
> +++ b/tests/qapi-schema/base-cycle-direct.json
> @@ -1,6 +1,2 @@
>  # we reject a loop in base classes
> -
> -##
> -# @Loopy:
> -##
>  { 'struct': 'Loopy', 'base': 'Loopy', 'data': {} }
> diff --git a/tests/qapi-schema/base-cycle-indirect.err
> b/tests/qapi-schema/base-cycle-indirect.err
> index f4198e4..fc92fe4 100644
> --- a/tests/qapi-schema/base-cycle-indirect.err
> +++ b/tests/qapi-schema/base-cycle-indirect.err
> @@ -1 +1 @@
> -tests/qapi-schema/base-cycle-indirect.json:6: Object Base1 contains itself
> +tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself
> diff --git a/tests/qapi-schema/base-cycle-indirect.json
> b/tests/qapi-schema/base-cycle-indirect.json
> index 99926c4..2866772 100644
> --- a/tests/qapi-schema/base-cycle-indirect.json
> +++ b/tests/qapi-schema/base-cycle-indirect.json
> @@ -1,10 +1,3 @@
>  # we reject a loop in base classes
> -
> -##
> -# @Base1:
> -##
>  { 'struct': 'Base1', 'base': 'Base2', 'data': {} }
> -##
> -# @Base2:
> -##
>  { 'struct': 'Base2', 'base': 'Base1', 'data': {} }
> diff --git a/tests/qapi-schema/command-int.err
> b/tests/qapi-schema/command-int.err
> index 3c834a9..0f93006 100644
> --- a/tests/qapi-schema/command-int.err
> +++ b/tests/qapi-schema/command-int.err
> @@ -1 +1 @@
> -tests/qapi-schema/command-int.json:6: built-in 'int' is already defined
> +tests/qapi-schema/command-int.json:2: built-in 'int' is already defined
> diff --git a/tests/qapi-schema/command-int.json
> b/tests/qapi-schema/command-int.json
> index 5b51bf1..9a62554 100644
> --- a/tests/qapi-schema/command-int.json
> +++ b/tests/qapi-schema/command-int.json
> @@ -1,6 +1,2 @@
>  # we reject collisions between commands and types
> -
> -##
> -# @int:
> -##
>  { 'command': 'int', 'data': { 'character': 'str' } }
> diff --git a/tests/qapi-schema/comments.json
> b/tests/qapi-schema/comments.json
> index d31ef0d..e643f3a 100644
> --- a/tests/qapi-schema/comments.json
> +++ b/tests/qapi-schema/comments.json
> @@ -1,8 +1,4 @@
>  # Unindented comment
> -
> -##
> -# @Status:
> -##
>  { 'enum': 'Status',             # Comment to the right of code
>    # Indented comment
>    'data': [ 'good', 'bad', 'ugly' ] }
> diff --git a/tests/qapi-schema/comments.out
> b/tests/qapi-schema/comments.out
> index a962fb2..5d7c13c 100644
> --- a/tests/qapi-schema/comments.out
> +++ b/tests/qapi-schema/comments.out
> @@ -2,4 +2,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict',
> 'qlist', 'qfloat', 'qbo
>      prefix QTYPE
>  enum Status ['good', 'bad', 'ugly']
>  object q_empty
> -doc symbol=Status expr=('enum', 'Status')
> diff --git a/tests/qapi-schema/double-type.err
> b/tests/qapi-schema/double-type.err
> index 424df9b..f9613c6 100644
> --- a/tests/qapi-schema/double-type.err
> +++ b/tests/qapi-schema/double-type.err
> @@ -1 +1 @@
> -tests/qapi-schema/double-type.json:6: Unknown key 'command' in struct
> 'bar'
> +tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct
> 'bar'
> diff --git a/tests/qapi-schema/double-type.json
> b/tests/qapi-schema/double-type.json
> index ab59523..911fa7a 100644
> --- a/tests/qapi-schema/double-type.json
> +++ b/tests/qapi-schema/double-type.json
> @@ -1,6 +1,2 @@
>  # we reject an expression with ambiguous metatype
> -
> -##
> -# @foo:
> -##
>  { 'command': 'foo', 'struct': 'bar', 'data': { } }
> diff --git a/tests/qapi-schema/enum-bad-name.err
> b/tests/qapi-schema/enum-bad-name.err
> index 157d1b0..9c3c100 100644
> --- a/tests/qapi-schema/enum-bad-name.err
> +++ b/tests/qapi-schema/enum-bad-name.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-bad-name.json:6: Member of enum 'MyEnum' uses
> invalid name 'not^possible'
> +tests/qapi-schema/enum-bad-name.json:2: Member of enum 'MyEnum' uses
> invalid name 'not^possible'
> diff --git a/tests/qapi-schema/enum-bad-name.json
> b/tests/qapi-schema/enum-bad-name.json
> index 978cb88..8506562 100644
> --- a/tests/qapi-schema/enum-bad-name.json
> +++ b/tests/qapi-schema/enum-bad-name.json
> @@ -1,6 +1,2 @@
>  # we ensure all enum names can map to C
> -
> -##
> -# @MyEnum:
> -##
>  { 'enum': 'MyEnum', 'data': [ 'not^possible' ] }
> diff --git a/tests/qapi-schema/enum-bad-prefix.err
> b/tests/qapi-schema/enum-bad-prefix.err
> index 918915f..399f5f7 100644
> --- a/tests/qapi-schema/enum-bad-prefix.err
> +++ b/tests/qapi-schema/enum-bad-prefix.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-bad-prefix.json:6: Enum 'MyEnum' requires a string
> for 'prefix'
> +tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string
> for 'prefix'
> diff --git a/tests/qapi-schema/enum-bad-prefix.json
> b/tests/qapi-schema/enum-bad-prefix.json
> index 25f17a7..996f628 100644
> --- a/tests/qapi-schema/enum-bad-prefix.json
> +++ b/tests/qapi-schema/enum-bad-prefix.json
> @@ -1,6 +1,2 @@
>  # The prefix must be a string type
> -
> -##
> -# @MyEnum:
> -##
>  { 'enum': 'MyEnum', 'data': [ 'one' ], 'prefix': [ 'fish' ] }
> diff --git a/tests/qapi-schema/enum-clash-member.err
> b/tests/qapi-schema/enum-clash-member.err
> index 25249b6..5403c78 100644
> --- a/tests/qapi-schema/enum-clash-member.err
> +++ b/tests/qapi-schema/enum-clash-member.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-clash-member.json:6: 'one_two' (member of MyEnum)
> collides with 'one-two' (member of MyEnum)
> +tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum)
> collides with 'one-two' (member of MyEnum)
> diff --git a/tests/qapi-schema/enum-clash-member.json
> b/tests/qapi-schema/enum-clash-member.json
> index fd52751..b6928b8 100644
> --- a/tests/qapi-schema/enum-clash-member.json
> +++ b/tests/qapi-schema/enum-clash-member.json
> @@ -1,6 +1,2 @@
>  # we reject enums where members will clash when mapped to C enum
> -
> -##
> -# @MyEnum:
> -##
>  { 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] }
> diff --git a/tests/qapi-schema/enum-dict-member.err
> b/tests/qapi-schema/enum-dict-member.err
> index 9b7d2f1..8ca146e 100644
> --- a/tests/qapi-schema/enum-dict-member.err
> +++ b/tests/qapi-schema/enum-dict-member.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-dict-member.json:6: Member of enum 'MyEnum'
> requires a string name
> +tests/qapi-schema/enum-dict-member.json:2: Member of enum 'MyEnum'
> requires a string name
> diff --git a/tests/qapi-schema/enum-dict-member.json
> b/tests/qapi-schema/enum-dict-member.json
> index 69d30f0..79672e0 100644
> --- a/tests/qapi-schema/enum-dict-member.json
> +++ b/tests/qapi-schema/enum-dict-member.json
> @@ -1,6 +1,2 @@
>  # we reject any enum member that is not a string
> -
> -##
> -# @MyEnum:
> -##
>  { 'enum': 'MyEnum', 'data': [ { 'value': 'str' } ] }
> diff --git a/tests/qapi-schema/enum-member-case.err
> b/tests/qapi-schema/enum-member-case.err
> index df96e22..b652e9a 100644
> --- a/tests/qapi-schema/enum-member-case.err
> +++ b/tests/qapi-schema/enum-member-case.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-member-case.json:10: 'Value' (member of
> NoWayThisWillGetWhitelisted) should not use uppercase
> +tests/qapi-schema/enum-member-case.json:3: 'Value' (member of
> NoWayThisWillGetWhitelisted) should not use uppercase
> diff --git a/tests/qapi-schema/enum-member-case.json
> b/tests/qapi-schema/enum-member-case.json
> index d2e4aba..2096b35 100644
> --- a/tests/qapi-schema/enum-member-case.json
> +++ b/tests/qapi-schema/enum-member-case.json
> @@ -1,10 +1,3 @@
>  # Member names should be 'lower-case' unless the enum is whitelisted
> -
> -##
> -# @UuidInfo:
> -##
>  { 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted
> -##
> -# @NoWayThisWillGetWhitelisted:
> -##
>  { 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] }
> diff --git a/tests/qapi-schema/enum-missing-data.err
> b/tests/qapi-schema/enum-missing-data.err
> index de4b9e8..ba4873a 100644
> --- a/tests/qapi-schema/enum-missing-data.err
> +++ b/tests/qapi-schema/enum-missing-data.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-missing-data.json:6: Key 'data' is missing from
> enum 'MyEnum'
> +tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from
> enum 'MyEnum'
> diff --git a/tests/qapi-schema/enum-missing-data.json
> b/tests/qapi-schema/enum-missing-data.json
> index d7601f9..558fd35 100644
> --- a/tests/qapi-schema/enum-missing-data.json
> +++ b/tests/qapi-schema/enum-missing-data.json
> @@ -1,6 +1,2 @@
>  # we require that all QAPI enums have a data array
> -
> -##
> -# @MyEnum:
> -##
>  { 'enum': 'MyEnum' }
> diff --git a/tests/qapi-schema/enum-wrong-data.err
> b/tests/qapi-schema/enum-wrong-data.err
> index c44e9b5..11b4347 100644
> --- a/tests/qapi-schema/enum-wrong-data.err
> +++ b/tests/qapi-schema/enum-wrong-data.err
> @@ -1 +1 @@
> -tests/qapi-schema/enum-wrong-data.json:6: Enum 'MyEnum' requires an array
> for 'data'
> +tests/qapi-schema/enum-wrong-data.json:2: Enum 'MyEnum' requires an array
> for 'data'
> diff --git a/tests/qapi-schema/enum-wrong-data.json
> b/tests/qapi-schema/enum-wrong-data.json
> index 4b9e978..7b3e255 100644
> --- a/tests/qapi-schema/enum-wrong-data.json
> +++ b/tests/qapi-schema/enum-wrong-data.json
> @@ -1,6 +1,2 @@
>  # we require that all qapi enums have an array for data
> -
> -##
> -# @MyEnum:
> -##
>  { 'enum': 'MyEnum', 'data': { 'value': 'str' } }
> diff --git a/tests/qapi-schema/event-boxed-empty.err
> b/tests/qapi-schema/event-boxed-empty.err
> index defe656..68ec6f2 100644
> --- a/tests/qapi-schema/event-boxed-empty.err
> +++ b/tests/qapi-schema/event-boxed-empty.err
> @@ -1 +1 @@
> -tests/qapi-schema/event-boxed-empty.json:6: Use of 'boxed' requires 'data'
> +tests/qapi-schema/event-boxed-empty.json:2: Use of 'boxed' requires 'data'
> diff --git a/tests/qapi-schema/event-boxed-empty.json
> b/tests/qapi-schema/event-boxed-empty.json
> index 63b870b..cb145f1 100644
> --- a/tests/qapi-schema/event-boxed-empty.json
> +++ b/tests/qapi-schema/event-boxed-empty.json
> @@ -1,6 +1,2 @@
>  # 'boxed' requires a non-empty type
> -
> -##
> -# @FOO:
> -##
>  { 'event': 'FOO', 'boxed': true }
> diff --git a/tests/qapi-schema/event-case.json
> b/tests/qapi-schema/event-case.json
> index 6b05c5d..3a92d8b 100644
> --- a/tests/qapi-schema/event-case.json
> +++ b/tests/qapi-schema/event-case.json
> @@ -1,7 +1,3 @@
>  # TODO: might be nice to enforce naming conventions; but until then this
> works
>  # even though events should usually be ALL_CAPS
> -
> -##
> -# @oops:
> -##
>  { 'event': 'oops' }
> diff --git a/tests/qapi-schema/event-case.out
> b/tests/qapi-schema/event-case.out
> index 2865714..5a0f2bf 100644
> --- a/tests/qapi-schema/event-case.out
> +++ b/tests/qapi-schema/event-case.out
> @@ -3,4 +3,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict',
> 'qlist', 'qfloat', 'qbo
>  event oops None
>     boxed=False
>  object q_empty
> -doc symbol=oops expr=('event', 'oops')
> diff --git a/tests/qapi-schema/event-nest-struct.err
> b/tests/qapi-schema/event-nest-struct.err
> index 17a6c3c..5a42701 100644
> --- a/tests/qapi-schema/event-nest-struct.err
> +++ b/tests/qapi-schema/event-nest-struct.err
> @@ -1 +1 @@
> -tests/qapi-schema/event-nest-struct.json:5: Member 'a' of 'data' for
> event 'EVENT_A' should be a type name
> +tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for
> event 'EVENT_A' should be a type name
> diff --git a/tests/qapi-schema/event-nest-struct.json
> b/tests/qapi-schema/event-nest-struct.json
> index 328e0a6..ee6f3ec 100644
> --- a/tests/qapi-schema/event-nest-struct.json
> +++ b/tests/qapi-schema/event-nest-struct.json
> @@ -1,6 +1,2 @@
> -##
> -# @EVENT_A:
> -# event-nest-struct
> -##
>  { 'event': 'EVENT_A',
>    'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
> diff --git a/tests/qapi-schema/flat-union-array-branch.err
> b/tests/qapi-schema/flat-union-array-branch.err
> index e456094..8ea91ea 100644
> --- a/tests/qapi-schema/flat-union-array-branch.err
> +++ b/tests/qapi-schema/flat-union-array-branch.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-array-branch.json:20: Member 'value1' of
> union 'TestUnion' cannot be an array
> +tests/qapi-schema/flat-union-array-branch.json:8: Member 'value1' of
> union 'TestUnion' cannot be an array
> diff --git a/tests/qapi-schema/flat-union-array-branch.json
> b/tests/qapi-schema/flat-union-array-branch.json
> index 51dde10..0b98820 100644
> --- a/tests/qapi-schema/flat-union-array-branch.json
> +++ b/tests/qapi-schema/flat-union-array-branch.json
> @@ -1,22 +1,10 @@
> -##
> -# @TestEnum:
> -##
>  # we require flat union branches to be a struct
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @Base:
> -##
>  { 'struct': 'Base',
>    'data': { 'enum1': 'TestEnum' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'Base',
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-bad-base.err
> b/tests/qapi-schema/flat-union-bad-base.err
> index 072ffba..bee24a2 100644
> --- a/tests/qapi-schema/flat-union-bad-base.err
> +++ b/tests/qapi-schema/flat-union-bad-base.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-bad-base.json:21: 'string' (member of
> TestTypeA) collides with 'string' (base of TestUnion)
> +tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of
> TestTypeA) collides with 'string' (base of TestUnion)
> diff --git a/tests/qapi-schema/flat-union-bad-base.json
> b/tests/qapi-schema/flat-union-bad-base.json
> index 7713e7f..74dd421 100644
> --- a/tests/qapi-schema/flat-union-bad-base.json
> +++ b/tests/qapi-schema/flat-union-bad-base.json
> @@ -1,23 +1,10 @@
>  # we allow anonymous base, but enforce no duplicate keys
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': { 'enum1': 'TestEnum', 'string': 'str' },
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-bad-discriminator.err
> b/tests/qapi-schema/flat-union-bad-discriminator.err
> index 1be4e7b..c38cc8e 100644
> --- a/tests/qapi-schema/flat-union-bad-discriminator.err
> +++ b/tests/qapi-schema/flat-union-bad-discriminator.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-bad-discriminator.json:27: Discriminator of
> flat union 'TestUnion' requires a string name
> +tests/qapi-schema/flat-union-bad-discriminator.json:11: Discriminator of
> flat union 'TestUnion' requires a string name
> diff --git a/tests/qapi-schema/flat-union-bad-discriminator.json
> b/tests/qapi-schema/flat-union-bad-discriminator.json
> index ef92f9b..cd10b9d 100644
> --- a/tests/qapi-schema/flat-union-bad-discriminator.json
> +++ b/tests/qapi-schema/flat-union-bad-discriminator.json
> @@ -1,29 +1,13 @@
>  # we require the discriminator to be a string naming a base-type member
>  # this tests the old syntax for anonymous unions before we added
> alternates
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @TestBase:
> -##
>  { 'struct': 'TestBase',
>    'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'TestBase',
>    'discriminator': {},
> diff --git a/tests/qapi-schema/flat-union-base-any.err
> b/tests/qapi-schema/flat-union-base-any.err
> index c1ea2d7..646f1c9 100644
> --- a/tests/qapi-schema/flat-union-base-any.err
> +++ b/tests/qapi-schema/flat-union-base-any.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-base-any.json:21: 'base' for union
> 'TestUnion' cannot use built-in type 'any'
> +tests/qapi-schema/flat-union-base-any.json:8: 'base' for union
> 'TestUnion' cannot use built-in type 'any'
> diff --git a/tests/qapi-schema/flat-union-base-any.json
> b/tests/qapi-schema/flat-union-base-any.json
> index 3dfb02f..fe66b71 100644
> --- a/tests/qapi-schema/flat-union-base-any.json
> +++ b/tests/qapi-schema/flat-union-base-any.json
> @@ -1,23 +1,10 @@
>  # we require the base to be an existing struct
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'any',
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-base-union.err
> b/tests/qapi-schema/flat-union-base-union.err
> index ccc5e85..f138395 100644
> --- a/tests/qapi-schema/flat-union-base-union.err
> +++ b/tests/qapi-schema/flat-union-base-union.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-base-union.json:30: 'base' for union
> 'TestUnion' cannot use union type 'UnionBase'
> +tests/qapi-schema/flat-union-base-union.json:14: 'base' for union
> 'TestUnion' cannot use union type 'UnionBase'
> diff --git a/tests/qapi-schema/flat-union-base-union.json
> b/tests/qapi-schema/flat-union-base-union.json
> index c63c613..98b4eba 100644
> --- a/tests/qapi-schema/flat-union-base-union.json
> +++ b/tests/qapi-schema/flat-union-base-union.json
> @@ -2,31 +2,15 @@
>  # TODO: It would be possible to allow a union as a base, as long as all
>  # permutations of QMP names exposed by base do not clash with any QMP
>  # member names added by local variants.
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @UnionBase:
> -##
>  { 'union': 'UnionBase',
>    'data': { 'kind1': 'TestTypeA',
>              'kind2': 'TestTypeB' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'UnionBase',
>    'discriminator': 'type',
> diff --git a/tests/qapi-schema/flat-union-clash-member.err
> b/tests/qapi-schema/flat-union-clash-member.err
> index fe12a07..2adf697 100644
> --- a/tests/qapi-schema/flat-union-clash-member.err
> +++ b/tests/qapi-schema/flat-union-clash-member.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-clash-member.json:27: 'name' (member of
> Branch1) collides with 'name' (member of Base)
> +tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of
> Branch1) collides with 'name' (member of Base)
> diff --git a/tests/qapi-schema/flat-union-clash-member.json
> b/tests/qapi-schema/flat-union-clash-member.json
> index 9000b94..9efc771 100644
> --- a/tests/qapi-schema/flat-union-clash-member.json
> +++ b/tests/qapi-schema/flat-union-clash-member.json
> @@ -1,29 +1,13 @@
>  # We check for no duplicate keys between branch members and base
>  # base's member 'name' clashes with Branch1's
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @Base:
> -##
>  { 'struct': 'Base',
>    'data': { 'enum1': 'TestEnum', '*name': 'str' } }
> -##
> -# @Branch1:
> -##
>  { 'struct': 'Branch1',
>    'data': { 'name': 'str' } }
> -##
> -# @Branch2:
> -##
>  { 'struct': 'Branch2',
>    'data': { 'value': 'int' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'Base',
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-empty.err
> b/tests/qapi-schema/flat-union-empty.err
> index ead7bd4..15754f5 100644
> --- a/tests/qapi-schema/flat-union-empty.err
> +++ b/tests/qapi-schema/flat-union-empty.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-empty.json:14: Union 'Union' cannot have
> empty 'data'
> +tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have
> empty 'data'
> diff --git a/tests/qapi-schema/flat-union-empty.json
> b/tests/qapi-schema/flat-union-empty.json
> index afa8988..77f1d9a 100644
> --- a/tests/qapi-schema/flat-union-empty.json
> +++ b/tests/qapi-schema/flat-union-empty.json
> @@ -1,14 +1,4 @@
>  # flat unions cannot be empty
> -
> -##
> -# @Empty:
> -##
>  { 'enum': 'Empty', 'data': [ ] }
> -##
> -# @Base:
> -##
>  { 'struct': 'Base', 'data': { 'type': 'Empty' } }
> -##
> -# @Union:
> -##
>  { 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } }
> diff --git a/tests/qapi-schema/flat-union-incomplete-branch.err
> b/tests/qapi-schema/flat-union-incomplete-branch.err
> index c655bbf..e826bf0 100644
> --- a/tests/qapi-schema/flat-union-incomplete-branch.err
> +++ b/tests/qapi-schema/flat-union-incomplete-branch.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-incomplete-branch.json:16: Union 'TestUnion'
> data missing 'value2' branch
> +tests/qapi-schema/flat-union-incomplete-branch.json:6: Union 'TestUnion'
> data missing 'value2' branch
> diff --git a/tests/qapi-schema/flat-union-incomplete-branch.json
> b/tests/qapi-schema/flat-union-incomplete-branch.json
> index dea0377..25a411b 100644
> --- a/tests/qapi-schema/flat-union-incomplete-branch.json
> +++ b/tests/qapi-schema/flat-union-incomplete-branch.json
> @@ -1,18 +1,8 @@
>  # we require all branches of the union to be covered
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': { 'type': 'TestEnum' },
>    'discriminator': 'type',
> diff --git a/tests/qapi-schema/flat-union-inline.err
> b/tests/qapi-schema/flat-union-inline.err
> index c2c3f76..2333358 100644
> --- a/tests/qapi-schema/flat-union-inline.err
> +++ b/tests/qapi-schema/flat-union-inline.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-inline.json:17: Member 'value1' of union
> 'TestUnion' should be a type name
> +tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union
> 'TestUnion' should be a type name
> diff --git a/tests/qapi-schema/flat-union-inline.json
> b/tests/qapi-schema/flat-union-inline.json
> index 400f081..62c7cda 100644
> --- a/tests/qapi-schema/flat-union-inline.json
> +++ b/tests/qapi-schema/flat-union-inline.json
> @@ -1,19 +1,9 @@
>  # we require branches to be a struct name
>  # TODO: should we allow anonymous inline branch types?
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @Base:
> -##
>  { 'struct': 'Base',
>    'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'Base',
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-int-branch.err
> b/tests/qapi-schema/flat-union-int-branch.err
> index 299cbb2..faf0157 100644
> --- a/tests/qapi-schema/flat-union-int-branch.err
> +++ b/tests/qapi-schema/flat-union-int-branch.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-int-branch.json:21: Member 'value1' of union
> 'TestUnion' cannot use built-in type 'int'
> +tests/qapi-schema/flat-union-int-branch.json:8: Member 'value1' of union
> 'TestUnion' cannot use built-in type 'int'
> diff --git a/tests/qapi-schema/flat-union-int-branch.json
> b/tests/qapi-schema/flat-union-int-branch.json
> index 9603e17..9370c34 100644
> --- a/tests/qapi-schema/flat-union-int-branch.json
> +++ b/tests/qapi-schema/flat-union-int-branch.json
> @@ -1,23 +1,10 @@
>  # we require flat union branches to be a struct
> -
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @Base:
> -##
>  { 'struct': 'Base',
>    'data': { 'enum1': 'TestEnum' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'Base',
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err
> b/tests/qapi-schema/flat-union-invalid-branch-key.err
> index 455f2dc..ccf72d2 100644
> --- a/tests/qapi-schema/flat-union-invalid-branch-key.err
> +++ b/tests/qapi-schema/flat-union-invalid-branch-key.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-invalid-branch-key.json:28: Discriminator
> value 'value_wrong' is not found in enum 'TestEnum'
> +tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator
> value 'value_wrong' is not found in enum 'TestEnum'
> diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.json
> b/tests/qapi-schema/flat-union-invalid-branch-key.json
> index 00f2896..95ff774 100644
> --- a/tests/qapi-schema/flat-union-invalid-branch-key.json
> +++ b/tests/qapi-schema/flat-union-invalid-branch-key.json
> @@ -1,30 +1,15 @@
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
>
> -##
> -# @TestBase:
> -##
>  { 'struct': 'TestBase',
>    'data': { 'enum1': 'TestEnum' } }
>
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
>
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
>
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'TestBase',
>    'discriminator': 'enum1',
> diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err
> b/tests/qapi-schema/flat-union-invalid-discriminator.err
> index f0e427b..5f40556 100644
> --- a/tests/qapi-schema/flat-union-invalid-discriminator.err
> +++ b/tests/qapi-schema/flat-union-invalid-discriminator.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-invalid-discriminator.json:28: Discriminator
> 'enum_wrong' is not a member of base struct 'TestBase'
> +tests/qapi-schema/flat-union-invalid-discriminator.json:13: Discriminator
> 'enum_wrong' is not a member of base struct 'TestBase'
> diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json
> b/tests/qapi-schema/flat-union-invalid-discriminator.json
> index c8700c7..48b94c3 100644
> --- a/tests/qapi-schema/flat-union-invalid-discriminator.json
> +++ b/tests/qapi-schema/flat-union-invalid-discriminator.json
> @@ -1,30 +1,15 @@
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
>
> -##
> -# @TestBase:
> -##
>  { 'struct': 'TestBase',
>    'data': { 'enum1': 'TestEnum' } }
>
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
>
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
>
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'TestBase',
>    'discriminator': 'enum_wrong',
> diff --git a/tests/qapi-schema/flat-union-no-base.err
> b/tests/qapi-schema/flat-union-no-base.err
> index a2d0a81..841c93b 100644
> --- a/tests/qapi-schema/flat-union-no-base.err
> +++ b/tests/qapi-schema/flat-union-no-base.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-no-base.json:22: Flat union 'TestUnion' must
> have a base
> +tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must
> have a base
> diff --git a/tests/qapi-schema/flat-union-no-base.json
> b/tests/qapi-schema/flat-union-no-base.json
> index 641f68a..ffc4c6f 100644
> --- a/tests/qapi-schema/flat-union-no-base.json
> +++ b/tests/qapi-schema/flat-union-no-base.json
> @@ -1,24 +1,11 @@
>  # flat unions require a base
>  # TODO: simple unions should be able to use an enum discriminator
> -
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
> -##
> -# @Enum:
> -##
>  { 'enum': 'Enum',
>    'data': [ 'value1', 'value2' ] }
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'discriminator': 'Enum',
>    'data': { 'value1': 'TestTypeA',
> diff --git a/tests/qapi-schema/flat-union-optional-discriminator.err
> b/tests/qapi-schema/flat-union-optional-discriminator.err
> index e15f856..aaabedb 100644
> --- a/tests/qapi-schema/flat-union-optional-discriminator.err
> +++ b/tests/qapi-schema/flat-union-optional-discriminator.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-optional-discriminator.json:19:
> Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
> +tests/qapi-schema/flat-union-optional-discriminator.json:6: Discriminator
> of flat union 'MyUnion' does not allow optional name '*switch'
> diff --git a/tests/qapi-schema/flat-union-optional-discriminator.json
> b/tests/qapi-schema/flat-union-optional-discriminator.json
> index 9f19af5..08a8f7e 100644
> --- a/tests/qapi-schema/flat-union-optional-discriminator.json
> +++ b/tests/qapi-schema/flat-union-optional-discriminator.json
> @@ -1,21 +1,8 @@
>  # we require the discriminator to be non-optional
> -
> -##
> -# @Enum:
> -##
>  { 'enum': 'Enum', 'data': [ 'one', 'two' ] }
> -##
> -# @Base:
> -##
>  { 'struct': 'Base',
>    'data': { '*switch': 'Enum' } }
> -##
> -# @Branch:
> -##
>  { 'struct': 'Branch', 'data': { 'name': 'str' } }
> -##
> -# @MyUnion:
> -##
>  { 'union': 'MyUnion',
>    'base': 'Base',
>    'discriminator': '*switch',
> diff --git a/tests/qapi-schema/flat-union-string-discriminator.err
> b/tests/qapi-schema/flat-union-string-discriminator.err
> index bc0c133..200016b 100644
> --- a/tests/qapi-schema/flat-union-string-discriminator.err
> +++ b/tests/qapi-schema/flat-union-string-discriminator.err
> @@ -1 +1 @@
> -tests/qapi-schema/flat-union-string-discriminator.json:28: Discriminator
> 'kind' must be of enumeration type
> +tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator
> 'kind' must be of enumeration type
> diff --git a/tests/qapi-schema/flat-union-string-discriminator.json
> b/tests/qapi-schema/flat-union-string-discriminator.json
> index 47a17d2..8af6033 100644
> --- a/tests/qapi-schema/flat-union-string-discriminator.json
> +++ b/tests/qapi-schema/flat-union-string-discriminator.json
> @@ -1,30 +1,15 @@
> -##
> -# @TestEnum:
> -##
>  { 'enum': 'TestEnum',
>    'data': [ 'value1', 'value2' ] }
>
> -##
> -# @TestBase:
> -##
>  { 'struct': 'TestBase',
>    'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
>
> -##
> -# @TestTypeA:
> -##
>  { 'struct': 'TestTypeA',
>    'data': { 'string': 'str' } }
>
> -##
> -# @TestTypeB:
> -##
>  { 'struct': 'TestTypeB',
>    'data': { 'integer': 'int' } }
>
> -##
> -# @TestUnion:
> -##
>  { 'union': 'TestUnion',
>    'base': 'TestBase',
>    'discriminator': 'kind',
> diff --git a/tests/qapi-schema/ident-with-escape.json
> b/tests/qapi-schema/ident-with-escape.json
> index c03404b..5661750 100644
> --- a/tests/qapi-schema/ident-with-escape.json
> +++ b/tests/qapi-schema/ident-with-escape.json
> @@ -1,8 +1,4 @@
>  # we allow escape sequences in strings, if they map back to ASCII
>  # { 'command': 'fooA', 'data': { 'bar1': 'str' } }
> -
> -##
> -# @fooA:
> -##
>  { 'c\u006fmmand': '\u0066\u006f\u006FA',
>    'd\u0061ta': { '\u0062\u0061\u00721': '\u0073\u0074\u0072' } }
> diff --git a/tests/qapi-schema/ident-with-escape.out
> b/tests/qapi-schema/ident-with-escape.out
> index 69fc908..1d2722c 100644
> --- a/tests/qapi-schema/ident-with-escape.out
> +++ b/tests/qapi-schema/ident-with-escape.out
> @@ -5,4 +5,3 @@ command fooA q_obj_fooA-arg -> None
>  object q_empty
>  object q_obj_fooA-arg
>      member bar1: str optional=False
> -doc symbol=fooA expr=('command', 'fooA')
> diff --git a/tests/qapi-schema/include-relpath-sub.json
> b/tests/qapi-schema/include-relpath-sub.json
> index b4bd8a2..4bd4af4 100644
> --- a/tests/qapi-schema/include-relpath-sub.json
> +++ b/tests/qapi-schema/include-relpath-sub.json
> @@ -1,5 +1,2 @@
> -##
> -# @Status:
> -##
>  { 'enum': 'Status',
>    'data': [ 'good', 'bad', 'ugly' ] }
> diff --git a/tests/qapi-schema/include-relpath.out
> b/tests/qapi-schema/include-relpath.out
> index a962fb2..5d7c13c 100644
> --- a/tests/qapi-schema/include-relpath.out
> +++ b/tests/qapi-schema/include-relpath.out
> @@ -2,4 +2,3 @@ enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict',
> 'qlist', 'qfloat', 'qbo
>      prefix QTYPE
>  enum Status ['good', 'bad', 'ugly']
>  object q_empty
> -doc symbol=Status expr=('enum', 'Status')
> diff --git a/tests/qapi-schema/inc

-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__()
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__() Markus Armbruster
  2017-03-13 19:34   ` Eric Blake
@ 2017-03-14  8:28   ` Marc-André Lureau
  1 sibling, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:28 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

On Mon, Mar 13, 2017 at 10:20 AM Markus Armbruster <armbru@redhat.com>
wrote:

Signed-off-by: Markus Armbruster <armbru@redhat.com>



Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>



---
 scripts/qapi.py | 45 +++++++++++++++++++++++----------------------
 1 file changed, 23 insertions(+), 22 deletions(-)

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 53a4477..345cde1 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -268,34 +268,15 @@ class QAPISchemaParser(object):
                 continue

             expr = self.get_expr(False)
-            if isinstance(expr, dict) and "include" in expr:
+            if 'include' in expr:
                 if len(expr) != 1:
                     raise QAPISemError(info, "Invalid 'include' directive")
                 include = expr["include"]
                 if not isinstance(include, str):
                     raise QAPISemError(info,
                                        "Value of 'include' must be a
string")
-                incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
-                                              include)
-                # catch inclusion cycle
-                inf = info
-                while inf:
-                    if incl_abs_fname == os.path.abspath(inf['file']):
-                        raise QAPISemError(info, "Inclusion loop for %s"
-                                           % include)
-                    inf = inf['parent']
-
-                # skip multiple include of the same file
-                if incl_abs_fname in previously_included:
-                    continue
-                try:
-                    fobj = open(incl_abs_fname, 'r')
-                except IOError as e:
-                    raise QAPISemError(info, '%s: %s' % (e.strerror,
include))
-                exprs_include = QAPISchemaParser(fobj, previously_included,
-                                                 info)
-                self.exprs.extend(exprs_include.exprs)
-                self.docs.extend(exprs_include.docs)
+                self._include(include, info, os.path.dirname(abs_fname),
+                              previously_included)
             else:
                 expr_elem = {'expr': expr,
                              'info': info}
@@ -307,6 +288,26 @@ class QAPISchemaParser(object):

                 self.exprs.append(expr_elem)

+    def _include(self, include, info, base_dir, previously_included):
+        incl_abs_fname = os.path.join(base_dir, include)
+        # catch inclusion cycle
+        inf = info
+        while inf:
+            if incl_abs_fname == os.path.abspath(inf['file']):
+                raise QAPISemError(info, "Inclusion loop for %s" % include)
+            inf = inf['parent']
+
+        # skip multiple include of the same file
+        if incl_abs_fname in previously_included:
+            return
+        try:
+            fobj = open(incl_abs_fname, 'r')
+        except IOError as e:
+            raise QAPISemError(info, '%s: %s' % (e.strerror, include))
+        exprs_include = QAPISchemaParser(fobj, previously_included, info)
+        self.exprs.extend(exprs_include.exprs)
+        self.docs.extend(exprs_include.docs)
+
     def accept(self, skip_comment=True):
         while True:
             self.tok = self.src[self.cursor]
--
2.7.4


-- 
Marc-André Lureau

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen'
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen' Markus Armbruster
  2017-03-13 22:17   ` Eric Blake
@ 2017-03-14  8:30   ` Marc-André Lureau
  1 sibling, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:30 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:20 AM Markus Armbruster <armbru@redhat.com>
wrote:

> Section "Commands" qualifies its rules on permitted argument and
> return types "with one exception noted below when 'gen' is used".  The
> note went away in commit 2d21291.  Clean up the dangling references.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  docs/qapi-code-gen.txt | 18 ++++++++----------
>  1 file changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index 88de5c7..d9c1f91 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -555,22 +555,20 @@ The 'data' argument maps to the "arguments"
> dictionary passed in as
>  part of a Client JSON Protocol command.  The 'data' member is optional
>  and defaults to {} (an empty dictionary).  If present, it must be the
>  string name of a complex type, or a dictionary that declares an
> -anonymous type with the same semantics as a 'struct' expression, with
> -one exception noted below when 'gen' is used.
> +anonymous type with the same semantics as a 'struct' expression.
>
>  The 'returns' member describes what will appear in the "return" member
>  of a Client JSON Protocol reply on successful completion of a command.
>  The member is optional from the command declaration; if absent, the
>  "return" member will be an empty dictionary.  If 'returns' is present,
>  it must be the string name of a complex or built-in type, a
> -one-element array containing the name of a complex or built-in type,
> -with one exception noted below when 'gen' is used.  Although it is
> -permitted to have the 'returns' member name a built-in type or an
> -array of built-in types, any command that does this cannot be extended
> -to return additional information in the future; thus, new commands
> -should strongly consider returning a dictionary-based type or an array
> -of dictionaries, even if the dictionary only contains one member at the
> -present.
> +one-element array containing the name of a complex or built-in type.
> +Although it is permitted to have the 'returns' member name a built-in
> +type or an array of built-in types, any command that does this cannot
> +be extended to return additional information in the future; thus, new
> +commands should strongly consider returning a dictionary-based type or
> +an array of dictionaries, even if the dictionary only contains one
> +member at the present.
>
>  All commands in Client JSON Protocol use a dictionary to report
>  failure, with no way to specify that in QAPI.  Where the error return
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 10/47] qapi2texi: Fix up output around #optional
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 10/47] qapi2texi: Fix up output around #optional Markus Armbruster
@ 2017-03-14  8:37   ` Marc-André Lureau
  0 siblings, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:37 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
wrote:

> We use tag #optional to mark optional members, like this:
>
>     # @name: #optional The name of the guest
>
> texi_body() strips #optional, but not whitespace around it.  For the
> above, we get in qemu-qmp-qapi.texi
>
>     @item @code{'name'} (optional)
>      The name of the guest
>     @end table
>
> The extra space can lead to artifacts in output, e.g in
> qemu-qmp-ref.7.pod
>
>     =item C<'name'> (optional)
>
>      The name of the guest
>
> and then in qemu-qmp-ref.7
>
>     .IX Item "name (optional)"
>     .Vb 1
>     \& The name of the guest
>     .Ve
>
> instead of intended plain
>
>     .IX Item "name (optional)"
>     The name of the guest
>
> Get rid of these artifacts by removing whitespace around #optional
> along with it.
>
> This turns three minus signs in qapi-schema.json into markup, because
> they're now at the beginning of the line.  Drop them, they're unwanted
> there.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  qapi-schema.json     | 6 +++---
>  scripts/qapi2texi.py | 3 ++-
>  2 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 17c766e..52141cd 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -3779,11 +3779,11 @@
>  #
>  # @dstport: #optional destination port - mandatory for udp, optional for
> ip
>  #
> -# @ipv6: #optional - force the use of ipv6
> +# @ipv6: #optional force the use of ipv6
>  #
> -# @udp: #optional - use the udp version of l2tpv3 encapsulation
> +# @udp: #optional use the udp version of l2tpv3 encapsulation
>  #
> -# @cookie64: #optional - use 64 bit coookies
> +# @cookie64: #optional use 64 bit coookies
>  #
>  # @counter: #optional have sequence counter
>  #
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index 06d6abf..0f3e573 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -137,7 +137,8 @@ def texi_body(doc):
>              desc = str(section)
>              opt = ''
>              if "#optional" in desc:
> -                desc = desc.replace("#optional", "")
> +                desc = re.sub(r'^ *#optional *\n?|\n? *#optional
> *$|#optional',
> +                              '', desc)
>                  opt = ' (optional)'
>              body += "@item @code{'%s'}%s\n%s\n" % (arg, opt,
>                                                     texi_format(desc))
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully Markus Armbruster
@ 2017-03-14  8:40   ` Marc-André Lureau
  2017-03-14 15:58   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:40 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:19 AM Markus Armbruster <armbru@redhat.com>
wrote:

> Common Python pitfall: 'assert base_members' fires on [] in addition
> to None.  Correct to 'assert base_members is not None'.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  scripts/qapi.py                        |  2 +-
>  tests/qapi-schema/union-base-empty.err | 11 +----------
>  2 files changed, 2 insertions(+), 11 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index e98fd0c..eec7bfb 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -731,7 +731,7 @@ def check_union(expr, info):
>              raise QAPISemError(info, "Flat union '%s' must have a base"
>                                 % name)
>          base_members = find_base_members(base)
> -        assert base_members
> +        assert base_members is not None
>
>          # The value of member 'discriminator' must name a non-optional
>          # member of the base struct.
> diff --git a/tests/qapi-schema/union-base-empty.err
> b/tests/qapi-schema/union-base-empty.err
> index 61e6ec6..7695806 100644
> --- a/tests/qapi-schema/union-base-empty.err
> +++ b/tests/qapi-schema/union-base-empty.err
> @@ -1,10 +1 @@
> -Traceback (most recent call last):
> -  File "tests/qapi-schema/test-qapi.py", line 56, in <module>
> -    schema = QAPISchema(sys.argv[1])
> -  File "scripts/qapi.py", line 1483, in __init__
> -    self.exprs = check_exprs(parser.exprs)
> -  File "scripts/qapi.py", line 917, in check_exprs
> -    check_union(expr, info)
> -  File "scripts/qapi.py", line 734, in check_union
> -    assert base_members
> -AssertionError
> +tests/qapi-schema/union-base-empty.json:5: Discriminator 'type' is not a
> member of base struct 'Empty'
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base Markus Armbruster
@ 2017-03-14  8:41   ` Marc-André Lureau
  2017-03-14 15:56   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:41 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

On Mon, Mar 13, 2017 at 10:19 AM Markus Armbruster <armbru@redhat.com>
wrote:

> The new test case shows off qapi.py choking on an empty union base.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  tests/Makefile.include                  |  1 +
>  tests/qapi-schema/union-base-empty.err  | 10 ++++++++++
>  tests/qapi-schema/union-base-empty.exit |  1 +
>  tests/qapi-schema/union-base-empty.json |  9 +++++++++
>  tests/qapi-schema/union-base-empty.out  |  0
>  5 files changed, 21 insertions(+)
>  create mode 100644 tests/qapi-schema/union-base-empty.err
>  create mode 100644 tests/qapi-schema/union-base-empty.exit
>  create mode 100644 tests/qapi-schema/union-base-empty.json
>  create mode 100644 tests/qapi-schema/union-base-empty.out
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 736dd15..9f4e890 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -470,6 +470,7 @@ qapi-schema += unclosed-list.json
>  qapi-schema += unclosed-object.json
>  qapi-schema += unclosed-string.json
>  qapi-schema += unicode-str.json
> +qapi-schema += union-base-empty.json
>  qapi-schema += union-base-no-discriminator.json
>  qapi-schema += union-branch-case.json
>  qapi-schema += union-clash-branches.json
> diff --git a/tests/qapi-schema/union-base-empty.err
> b/tests/qapi-schema/union-base-empty.err
> new file mode 100644
> index 0000000..61e6ec6
> --- /dev/null
> +++ b/tests/qapi-schema/union-base-empty.err
> @@ -0,0 +1,10 @@
> +Traceback (most recent call last):
> +  File "tests/qapi-schema/test-qapi.py", line 56, in <module>
> +    schema = QAPISchema(sys.argv[1])
> +  File "scripts/qapi.py", line 1483, in __init__
> +    self.exprs = check_exprs(parser.exprs)
> +  File "scripts/qapi.py", line 917, in check_exprs
> +    check_union(expr, info)
> +  File "scripts/qapi.py", line 734, in check_union
> +    assert base_members
> +AssertionError
> diff --git a/tests/qapi-schema/union-base-empty.exit
> b/tests/qapi-schema/union-base-empty.exit
> new file mode 100644
> index 0000000..d00491f
> --- /dev/null
> +++ b/tests/qapi-schema/union-base-empty.exit
> @@ -0,0 +1 @@
> +1
> diff --git a/tests/qapi-schema/union-base-empty.json
> b/tests/qapi-schema/union-base-empty.json
> new file mode 100644
> index 0000000..d1843d3
> --- /dev/null
> +++ b/tests/qapi-schema/union-base-empty.json
> @@ -0,0 +1,9 @@
> +# Flat union with empty base and therefore without discriminator
> +
> +{ 'struct': 'Empty', 'data': { } }
> +
> +{ 'union': 'TestUnion',
> +  'base': 'Empty',
> +  'discriminator': 'type',
> +  'data': { 'value1': 'int',
> +            'value2': 'str' } }
> diff --git a/tests/qapi-schema/union-base-empty.out
> b/tests/qapi-schema/union-base-empty.out
> new file mode 100644
> index 0000000..e69de29
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 11/47] qapi: Avoid unwanted blank lines in QAPIDoc
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 11/47] qapi: Avoid unwanted blank lines in QAPIDoc Markus Armbruster
@ 2017-03-14  8:46   ` Marc-André Lureau
  0 siblings, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:46 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:25 AM Markus Armbruster <armbru@redhat.com>
wrote:

> We silently fix missing #optional tags for QAPIDoc by appending a line
> "#optional" to the section's .content.  However, this interferes with
> .__repr__ stripping trailing blank lines from .content.
>
> Use new ArgSection instance variable .optional instead, and leave
> .content alone.
>
> To permit testing .optional in texi_body(), clean up texi_enum()'s
> hack to add empty documentation for undocumented enum values: add an
> ArgSection instead of ''.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  scripts/qapi.py      | 5 +++--
>  scripts/qapi2texi.py | 4 ++--
>  2 files changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index eec7bfb..e6d023f 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -107,6 +107,7 @@ class QAPIDoc(object):
>              self.name = name
>              # the list of lines for this section
>              self.content = []
> +            self.optional = False
>
>          def append(self, line):
>              self.content.append(line)
> @@ -978,15 +979,15 @@ def check_definition_doc(doc, expr, info):
>              desc = doc.args.get(arg)
>          if not desc:
>              continue
> +        desc.optional = opt
>          desc_opt = "#optional" in str(desc)
>          if desc_opt and not opt:
>              raise QAPISemError(info, "Description has #optional, "
>                                 "but the declaration doesn't")
>          if not desc_opt and opt:
> -            # silently fix the doc
>              # TODO either fix the schema and make this an error,
>              # or drop #optional entirely
> -            desc.append("#optional")
> +            pass
>
>      doc_args = set(doc.args.keys())
>      args = set([name.strip('*') for name in args])
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index 0f3e573..0aaf45c 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -136,7 +136,7 @@ def texi_body(doc):
>          for arg, section in doc.args.iteritems():
>              desc = str(section)
>              opt = ''
> -            if "#optional" in desc:
> +            if section.optional:
>                  desc = re.sub(r'^ *#optional *\n?|\n? *#optional
> *$|#optional',
>                                '', desc)
>                  opt = ' (optional)'
> @@ -185,7 +185,7 @@ def texi_enum(expr, doc):
>      """Format an enum to texi"""
>      for i in expr['data']:
>          if i not in doc.args:
> -            doc.args[i] = ''
> +            doc.args[i] = qapi.QAPIDoc.ArgSection(i)

     body = texi_body(doc)
>      return TYPE_FMT(type="Enum",
>                      name=doc.symbol,
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 12/47] qapi/rocker: Fix up doc comment notes on optional members
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 12/47] qapi/rocker: Fix up doc comment notes on optional members Markus Armbruster
@ 2017-03-14  8:49   ` Marc-André Lureau
  0 siblings, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14  8:49 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:31 AM Markus Armbruster <armbru@redhat.com>
wrote:

> Talking about #optional like this
>
>     # Note: fields are marked #optional to indicate that they may or may
>     # not appear ...
>
> doesn't work so well in generated documentation, because the #optional
> tag is not visible there.  Replace by
>
>     # Note: optional members may or may not appear ...
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>

indeed,
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>


> ---
>  qapi/rocker.json | 18 ++++++++++--------
>  1 file changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/qapi/rocker.json b/qapi/rocker.json
> index 97e2b83..f374038 100644
> --- a/qapi/rocker.json
> +++ b/qapi/rocker.json
> @@ -1,3 +1,5 @@
> +# -*- Mode: Python -*-
> +
>  ##
>  # = Rocker switch device
>  ##
> @@ -137,8 +139,8 @@
>  #
>  # @ip-dst: #optional IP header destination address
>  #
> -# Note: fields are marked #optional to indicate that they may or may not
> -# appear in the flow key depending if they're relevant to the flow key.
> +# Note: optional members may or may not appear in the flow key
> +# depending if they're relevant to the flow key.
>  #
>  # Since: 2.4
>  ##
> @@ -167,8 +169,8 @@
>  #
>  # @ip-tos: #optional IP header TOS field
>  #
> -# Note: fields are marked #optional to indicate that they may or may not
> -# appear in the flow mask depending if they're relevant to the flow mask.
> +# Note: optional members may or may not appear in the flow mask
> +# depending if they're relevant to the flow mask.
>  #
>  # Since: 2.4
>  ##
> @@ -194,8 +196,8 @@
>  #
>  # @out-pport: #optional physical output port
>  #
> -# Note: fields are marked #optional to indicate that they may or may not
> -# appear in the flow action depending if they're relevant to the flow
> action.
> +# Note: optional members may or may not appear in the flow action
> +# depending if they're relevant to the flow action.
>  #
>  # Since: 2.4
>  ##
> @@ -288,8 +290,8 @@
>  #
>  # @ttl-check: #optional perform TTL check
>  #
> -# Note: fields are marked #optional to indicate that they may or may not
> -# appear in the group depending if they're relevant to the group type.
> +# Note: optional members may or may not appear in the group depending
> +# if they're relevant to the group type.
>  #
>  # Since: 2.4
>  ##
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py
  2017-03-14  8:28   ` Marc-André Lureau
@ 2017-03-14  9:45     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14  9:45 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, mdroth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Mon, Mar 13, 2017 at 10:36 AM Markus Armbruster <armbru@redhat.com>
> wrote:
>
>> This reverts commit 3313b61's changes to tests/qapi-schema/, except
>> for tests/qapi-schema/doc-*.
>>
>>
> Do we expect those files to change? If not, or not much, I think i't s
> rather better to keep the docs to exercise the parser in various
> situations.

Point taken, but I think the proper way to exercise doc comments is
systematic test cases in qapi-schema-test.json, or perhaps a separate
test schema we create just for exercising doc comments.  Probably should
include a qapi2texi.py run complete with diff to golden .texi.


>             It doesn't reduce the merits of the doc pragma though for other
> cases, which I wish I would have suggested (but I didn't like the  initial
> series to grow more features)

We were both pretty desperate to get your work in without further delays.

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation Markus Armbruster
@ 2017-03-14 12:42   ` Marc-André Lureau
  2017-03-14 15:16     ` Markus Armbruster
  2017-03-14 19:16   ` Eric Blake
  1 sibling, 1 reply; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14 12:42 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:31 AM Markus Armbruster <armbru@redhat.com>
wrote:

> The recent merge of docs/qmp-commands.txt and docs/qmp-events.txt into
> the schema lost type information.  Fix this documentation regression.
>
> Example change (qemu-qmp-ref.txt):
>
>   -- Struct: InputKeyEvent
>
>       Keyboard input event.
>
>       Members:
> -     'button'
> +     'button: InputButton'
>            Which button this event is for.
> -     'down'
> +     'down: boolean'
>            True for key-down and false for key-up events.
>
>       Since: 2.0
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py      | 14 ++++++++++++++
>  scripts/qapi2texi.py |  8 ++++++--
>  2 files changed, 20 insertions(+), 2 deletions(-)
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 9430493..b82a2a6 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1101,6 +1101,11 @@ class QAPISchemaType(QAPISchemaEntity):
>          }
>          return json2qtype.get(self.json_type())
>
> +    def doc_type(self):
> +        if self.is_implicit():
> +            return None
> +        return self.name
> +
>
>  class QAPISchemaBuiltinType(QAPISchemaType):
>      def __init__(self, name, json_type, c_type):
> @@ -1125,6 +1130,9 @@ class QAPISchemaBuiltinType(QAPISchemaType):
>      def json_type(self):
>          return self._json_type_name
>
> +    def doc_type(self):
> +        return self.json_type()
> +
>      def visit(self, visitor):
>          visitor.visit_builtin_type(self.name, self.info,
> self.json_type())
>
> @@ -1184,6 +1192,12 @@ class QAPISchemaArrayType(QAPISchemaType):
>      def json_type(self):
>          return 'array'
>
> +    def doc_type(self):
> +        elt_doc_type = self.element_type.doc_type()
> +        if not elt_doc_type:
> +            return None
>

In which case is this expected to happen? place an assert here instead?


Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>




> +        return 'array of ' + elt_doc_type
> +
>      def visit(self, visitor):
>          visitor.visit_array_type(self.name, self.info, self.element_type)
>
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index 3dd0146..993b652 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -135,8 +135,12 @@ def texi_enum_value(value):
>
>  def texi_member(member):
>      """Format a table of members item for an object type member"""
> -    return '@item @code{%s}%s\n' % (
> -        member.name, ' (optional)' if member.optional else '')
> +    typ = member.type.doc_type()
> +    return '@item @code{%s%s%s}%s\n' % (
> +        member.name,
> +        ': ' if typ else '',
> +        typ if typ else '',
> +        ' (optional)' if member.optional else '')
>
>
>  def texi_members(doc, what, member_func):
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13 13:12       ` Markus Armbruster
@ 2017-03-14 13:22         ` Marc-André Lureau
  2017-03-14 16:14           ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14 13:22 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, mdroth

Hi

On Mon, Mar 13, 2017 at 5:12 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
> > Hi
> >
> > On Mon, Mar 13, 2017 at 4:14 PM Markus Armbruster <armbru@redhat.com>
> wrote:
> >
> >> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
> >>
> >> > Hi
> >> >
> >> > On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com
> >
> >> > wrote:
> >> >
> >> >> I'm proposing this is 2.9 because it fixes a documentation
> regression.
> >> >> It affects only documentation; generated C code is unchanged except
> >> >> for the removal of trailing space in PATCH 46.
> >> >>
> >> >> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
> >> >>
> >> >> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
> >> >> the QAPI schema and generate their replacements from the schema
> >> >> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
> >> >> also was a step back: the documentation lost information on JSON
> >> >> types, because I didn't like Marc-André's patch to add it.  He
> >> >> reposted it for further review afterwards:
> >> >>
> >> >>     Subject: [PATCH 0/2] qapi2texi: add type information
> >> >>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
> >> >>
> https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
> >> >>
> >> >> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
> >> >> descriptions in a new formal language to the generated documentation.
> >> >> Quoting the commit message:
> >> >>
> >> >>     Array types have the following syntax: type[]. Ex: str[].
> >> >>
> >> >>     - Struct, commands and events use the following members syntax:
> >> >>
> >> >>       { 'member': type, ('foo': str), ... }
> >> >>
> >> >>     Optional members are under parentheses.
> >> >>
> >> >>     A structure with a base type will have 'BaseStruct +' prepended.
> >> >>
> >> >>     - Alternates use the following syntax:
> >> >>
> >> >>       [ 'foo': type, 'bar': type, ... ]
> >> >>
> >> >>     - Simple unions use the following syntax:
> >> >>
> >> >>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type...
> ] }
> >> >>
> >> >>     - Flat unions use the following syntax:
> >> >>
> >> >>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
> >> >>
> >> >> End quote.  Looks like this in generated documentation:
> >> >>
> >> >>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
> >> >>           VncBasicInfo}
> >> >>
> >> >>      Emitted when a VNC client establishes a connection
> >> >>      ''server''
> >> >>           server information
> >> >>      ''client''
> >> >>           client information
> >> >>
> >> >>      Note: This event is emitted before any authentication takes
> place,
> >> >>      thus the authentication ID is not provided
> >> >> [...]
> >> >>
> >> >>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
> >> >>
> >> >>      The network connection information for server
> >> >>      ''auth'' (optional)
> >> >>           authentication method used for the plain (non-websocket)
> VNC
> >> >>           server
> >> >>
> >> >>      Since: 2.1
> >> >>
> >> >>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' =
> ['inet':
> >> >>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
> >> >>           VsockSocketAddress, 'fd': String] }
> >> >>
> >> >>      Captures the address of a socket, which could also be a named
> file
> >> >>      descriptor
> >> >>
> >> >>      Since: 1.3
> >> >>
> >> >> Here's my counter-proposal: instead of inventing a formal language,
> >> >> fix the natural language documentation to actually mention *all*
> >> >> members, and add type information in a plain, easy-to-understand way.
> >> >> Looks like this:
> >> >>
> >> >>  -- Event: VNC_CONNECTED
> >> >>
> >> >>      Emitted when a VNC client establishes a connection
> >> >>
> >> >>      Arguments:
> >> >>      'server: VncServerInfo'
> >> >>           server information
> >> >>      'client: VncBasicInfo'
> >> >>           client information
> >> >>
> >> >>      Note: This event is emitted before any authentication takes
> place,
> >> >>      thus the authentication ID is not provided
> >> >> [...]
> >> >>
> >> >>  -- Object: VncServerInfo
> >> >>
> >> >>      The network connection information for server
> >> >>
> >> >>      Members:
> >> >>      'auth: string' (optional)
> >> >>           authentication method used for the plain (non-websocket)
> VNC
> >> >>           server
> >> >>      The members of 'VncBasicInfo'
> >> >>
> >> >>      Since: 2.1
> >> >>
> >> >>  -- Object: SocketAddress
> >> >>
> >> >>      Captures the address of a socket, which could also be a named
> file
> >> >>      descriptor
> >> >>
> >> >>      Members:
> >> >>      'type'
> >> >>           One of "inet", "unix", "vsock", "fd"
> >> >>      'data: InetSocketAddress' when 'type' is "inet"
> >> >>      'data: UnixSocketAddress' when 'type' is "unix"
> >> >>      'data: VsockSocketAddress' when 'type' is "vsock"
> >> >>      'data: String' when 'type' is "fd"
> >> >>
> >> >>      Since: 1.3
> >> >>
> >> >>
> >> > I like both, to me they serve different purposes. I like to have a
> short
> >> > overview / signature and then a more detailed documentation for each
> >> field.
> >>
> >> I sympathize with the argument.  Unfortunately, the "short" signatures
> >> are anything but for real-world QAPI:
> >>
> >
> > That's a worse case, a regular case is more readable.
>
> There are readable cases, but there are plenty of cases that plainly
> aren't.
>
> 102 out of 472 signatures don't count because they're empty.
>
> Roughly half the non-empty signatures fit on a single line.  That's short.
>
> A bit under a third take two lines.  I guess that's still short enough.
>
> More than one in six signatures is three lines or more.
>
> >                                                       And it is still
> > useful anyway since the common members would be listed first.
>
> Whatever comes first in signatures comes first in the table of members,
> too.  The names are easier to spot there, because they're all on the
> left.
>
> Compare
>
>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>           VsockSocketAddress, 'fd': String] }
>
>      Captures the address of a socket, which could also be a named file
>      descriptor
>
>      Since: 1.3
>
> to
>
>  -- Object: SocketAddress
>
>      Captures the address of a socket, which could also be a named file
>      descriptor
>
>      Members:
>      'type'
>           One of "inet", "unix", "vsock", "fd"
>      'data: InetSocketAddress' when 'type' is "inet"
>      'data: UnixSocketAddress' when 'type' is "unix"
>      'data: VsockSocketAddress' when 'type' is "vsock"
>      'data: String' when 'type' is "fd"
>
>      Since: 1.3
>
> In my opinion, the three lines of signature add nothing but noise to the
> six lines of member table.
>

It is more natural and faster to read to me for commands and events for
example.  The verbose description is mixing description and sometime even
providing redundant information (ex: keys: array of KeyValue,  An array of
'KeyValue' elements...), slowing reading even more. Often you don't need to
read the documentation / description, you want to quickly check the return
type, and remind you the arguments.

struct/objects are more commonly declared with a line per member, so it
doesn't bother me as much.

I would appreciate if can have the declarative form for commands and events
at least. Other types are usually more complex or long, so that may clear
your concerns for the long declarations.
-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (47 preceding siblings ...)
  2017-03-13 10:32 ` [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Marc-André Lureau
@ 2017-03-14 13:24 ` Marc-André Lureau
  2017-03-15 13:06   ` Markus Armbruster
  2017-04-27 18:16 ` Eric Blake
  49 siblings, 1 reply; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-14 13:24 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: mdroth

Hi

On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
wrote:

> I'm proposing this is 2.9 because it fixes a documentation regression.
> It affects only documentation; generated C code is unchanged except
> for the removal of trailing space in PATCH 46.
>
> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
>
> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
> the QAPI schema and generate their replacements from the schema
> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
> also was a step back: the documentation lost information on JSON
> types, because I didn't like Marc-André's patch to add it.  He
> reposted it for further review afterwards:
>
>     Subject: [PATCH 0/2] qapi2texi: add type information
>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
>     https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
>
> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
> descriptions in a new formal language to the generated documentation.
> Quoting the commit message:
>
>     Array types have the following syntax: type[]. Ex: str[].
>
>     - Struct, commands and events use the following members syntax:
>
>       { 'member': type, ('foo': str), ... }
>
>     Optional members are under parentheses.
>
>     A structure with a base type will have 'BaseStruct +' prepended.
>
>     - Alternates use the following syntax:
>
>       [ 'foo': type, 'bar': type, ... ]
>
>     - Simple unions use the following syntax:
>
>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }
>
>     - Flat unions use the following syntax:
>
>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
>
> End quote.  Looks like this in generated documentation:
>
>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
>           VncBasicInfo}
>
>      Emitted when a VNC client establishes a connection
>      ''server''
>           server information
>      ''client''
>           client information
>
>      Note: This event is emitted before any authentication takes place,
>      thus the authentication ID is not provided
> [...]
>
>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
>
>      The network connection information for server
>      ''auth'' (optional)
>           authentication method used for the plain (non-websocket) VNC
>           server
>
>      Since: 2.1
>
>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>           VsockSocketAddress, 'fd': String] }
>
>      Captures the address of a socket, which could also be a named file
>      descriptor
>
>      Since: 1.3
>
> Here's my counter-proposal: instead of inventing a formal language,
> fix the natural language documentation to actually mention *all*
> members, and add type information in a plain, easy-to-understand way.
> Looks like this:
>
>  -- Event: VNC_CONNECTED
>
>      Emitted when a VNC client establishes a connection
>
>      Arguments:
>      'server: VncServerInfo'
>           server information
>      'client: VncBasicInfo'
>           client information
>
>      Note: This event is emitted before any authentication takes place,
>      thus the authentication ID is not provided
> [...]
>
>  -- Object: VncServerInfo
>
>      The network connection information for server
>
>      Members:
>      'auth: string' (optional)
>           authentication method used for the plain (non-websocket) VNC
>           server
>      The members of 'VncBasicInfo'
>
>      Since: 2.1
>
>  -- Object: SocketAddress
>
>      Captures the address of a socket, which could also be a named file
>      descriptor
>
>      Members:
>      'type'
>           One of "inet", "unix", "vsock", "fd"
>      'data: InetSocketAddress' when 'type' is "inet"
>      'data: UnixSocketAddress' when 'type' is "unix"
>      'data: VsockSocketAddress' when 'type' is "vsock"
>      'data: String' when 'type' is "fd"
>
>      Since: 1.3
>
> Additionally, my series fixes a number of bugs and cleans up along the
> way.  In particular, it converts qapi2texi.py from parse trees to the
> visitor interface the other generators use.
>
> Future generated documentation work includes eliding types that aren't
> visible in QMP (like introspection does), and making uses of type
> names links in HTML.
>
> Markus Armbruster (47):
>   qapi: Factor QAPISchemaParser._include() out of .__init__()
>   qapi: Make doc comments optional where we don't need them
>   qapi: Back out doc comments added just to please qapi.py
>   docs/qapi-code-gen.txt: Drop confusing reference to 'gen'
>   qapi: Have each QAPI schema declare its returns white-list
>   qapi: Have each QAPI schema declare its name rule violations
>   qapi: Clean up build of generated documentation
>   tests/qapi-schema: Cover empty union base
>   qapi: Fix to reject empty union base gracefully
>   qapi2texi: Fix up output around #optional
>   qapi: Avoid unwanted blank lines in QAPIDoc
>   qapi/rocker: Fix up doc comment notes on optional members
>   qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType'
>   qapi: Prepare for requiring more complete documentation
>   qapi: Conjure up QAPIDoc.ArgSection for undocumented members
>   qapi2texi: Convert to QAPISchemaVisitor
>   qapi: The #optional tag is redundant, drop
>   qapi: Use raw strings for regular expressions consistently
>   qapi: Prefer single-quoted strings more consistently
>   qapi2texi: Plainer enum value and member name formatting
>   qapi2texi: Present the table of members more clearly
>   qapi2texi: Explain enum value undocumentedness more clearly
>   qapi2texi: Don't hide undocumented members and arguments
>   qapi2texi: Implement boxed argument documentation
>   qapi2texi: Include member type in generated documentation
>   qapi2texi: Generate reference to base type members
>   qapi2texi: Generate documentation for variant members
>   qapi2texi: Generate descriptions for simple union tags
>   qapi2texi: Use category "Object" for all object types
>   tests/qapi-schema: Improve doc / expression mismatch coverage
>   qapi: Fix detection of doc / expression mismatch
>   qapi: Move detection of doc / expression name mismatch
>   qapi: Improve error message on @NAME: in free-form doc
>   qapi: Move empty doc section checking to doc parser
>   tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg
>   tests/qapi-schema: Improve coverage of bogus member docs
>   qapi: Fix detection of bogus member documentation
>   qapi: Eliminate check_docs() and drop QAPIDoc.expr
>   qapi: Drop unused variable events
>   qapi: Simplify what gets stored in enum_types
>   qapi: Factor add_name() calls out of the meta conditional
>   qapi: enum_types is a list used like a dict, make it one
>   qapi: struct_types is a list used like a dict, make it one
>   qapi: union_types is a list used like a dict, make it one
>   qapi: Drop unused .check_clash() parameter schema
>   qapi: Make pylint a bit happier
>   qapi: Fix a misleading parser error message
>
>
Except the few comments and questions I left, the series looks good to me.
I don't think we need to rush it in the 2.9 release though, but I will let
the maintainers decide how to deal with the planning and rules.


>  .gitignore                                         |  10 +-
>  Makefile                                           |  27 +-
>  docs/qapi-code-gen.txt                             |  81 +--
>  docs/qemu-qmp-ref.texi                             |   2 +-
>  docs/writing-qmp-commands.txt                      |   4 +-
>  qapi-schema.json                                   | 403 ++++++-------
>  qapi/block-core.json                               | 428 +++++++-------
>  qapi/block.json                                    |   8 +-
>  qapi/crypto.json                                   |  22 +-
>  qapi/event.json                                    |  10 +-
>  qapi/introspect.json                               |   6 +-
>  qapi/rocker.json                                   |  88 +--
>  qapi/trace.json                                    |   6 +-
>  qga/qapi-schema.json                               |  55 +-
>  rules.mak                                          |   2 +-
>  scripts/qapi-commands.py                           |   6 +-
>  scripts/qapi-event.py                              |   2 +-
>  scripts/qapi-introspect.py                         |   4 +-
>  scripts/qapi-types.py                              |   4 +-
>  scripts/qapi-visit.py                              |   5 +-
>  scripts/qapi.py                                    | 632
> ++++++++++-----------
>  scripts/qapi2texi.py                               | 298 +++++-----
>  tests/Makefile.include                             |   9 +-
>  tests/qapi-schema/alternate-any.err                |   2 +-
>  tests/qapi-schema/alternate-any.json               |   4 -
>  tests/qapi-schema/alternate-array.err              |   2 +-
>  tests/qapi-schema/alternate-array.json             |   7 -
>  tests/qapi-schema/alternate-base.err               |   2 +-
>  tests/qapi-schema/alternate-base.json              |   7 -
>  tests/qapi-schema/alternate-clash.err              |   2 +-
>  tests/qapi-schema/alternate-clash.json             |   4 -
>  tests/qapi-schema/alternate-conflict-dict.err      |   2 +-
>  tests/qapi-schema/alternate-conflict-dict.json     |  10 -
>  tests/qapi-schema/alternate-conflict-string.err    |   2 +-
>  tests/qapi-schema/alternate-conflict-string.json   |   7 -
>  tests/qapi-schema/alternate-empty.err              |   2 +-
>  tests/qapi-schema/alternate-empty.json             |   4 -
>  tests/qapi-schema/alternate-nested.err             |   2 +-
>  tests/qapi-schema/alternate-nested.json            |   7 -
>  tests/qapi-schema/alternate-unknown.err            |   2 +-
>  tests/qapi-schema/alternate-unknown.json           |   4 -
>  tests/qapi-schema/args-alternate.err               |   2 +-
>  tests/qapi-schema/args-alternate.json              |   8 -
>  tests/qapi-schema/args-any.err                     |   2 +-
>  tests/qapi-schema/args-any.json                    |   4 -
>  tests/qapi-schema/args-array-empty.err             |   2 +-
>  tests/qapi-schema/args-array-empty.json            |   4 -
>  tests/qapi-schema/args-array-unknown.err           |   2 +-
>  tests/qapi-schema/args-array-unknown.json          |   4 -
>  tests/qapi-schema/args-bad-boxed.err               |   2 +-
>  tests/qapi-schema/args-bad-boxed.json              |   4 -
>  tests/qapi-schema/args-boxed-anon.err              |   2 +-
>  tests/qapi-schema/args-boxed-anon.json             |   4 -
>  tests/qapi-schema/args-boxed-empty.err             |   2 +-
>  tests/qapi-schema/args-boxed-empty.json            |   8 -
>  tests/qapi-schema/args-boxed-string.err            |   2 +-
>  tests/qapi-schema/args-boxed-string.json           |   4 -
>  tests/qapi-schema/args-int.err                     |   2 +-
>  tests/qapi-schema/args-int.json                    |   4 -
>  tests/qapi-schema/args-invalid.err                 |   2 +-
>  tests/qapi-schema/args-invalid.json                |   3 -
>  tests/qapi-schema/args-member-array-bad.err        |   2 +-
>  tests/qapi-schema/args-member-array-bad.json       |   4 -
>  tests/qapi-schema/args-member-case.err             |   2 +-
>  tests/qapi-schema/args-member-case.json            |   4 -
>  tests/qapi-schema/args-member-unknown.err          |   2 +-
>  tests/qapi-schema/args-member-unknown.json         |   4 -
>  tests/qapi-schema/args-name-clash.err              |   2 +-
>  tests/qapi-schema/args-name-clash.json             |   4 -
>  tests/qapi-schema/args-union.err                   |   2 +-
>  tests/qapi-schema/args-union.json                  |   7 -
>  tests/qapi-schema/args-unknown.err                 |   2 +-
>  tests/qapi-schema/args-unknown.json                |   4 -
>  tests/qapi-schema/bad-base.err                     |   2 +-
>  tests/qapi-schema/bad-base.json                    |   7 -
>  tests/qapi-schema/bad-data.err                     |   2 +-
>  tests/qapi-schema/bad-data.json                    |   4 -
>  tests/qapi-schema/bad-ident.err                    |   2 +-
>  tests/qapi-schema/bad-ident.json                   |   4 -
>  tests/qapi-schema/bad-type-bool.err                |   2 +-
>  tests/qapi-schema/bad-type-bool.json               |   4 -
>  tests/qapi-schema/bad-type-dict.err                |   2 +-
>  tests/qapi-schema/bad-type-dict.json               |   4 -
>  tests/qapi-schema/base-cycle-direct.err            |   2 +-
>  tests/qapi-schema/base-cycle-direct.json           |   4 -
>  tests/qapi-schema/base-cycle-indirect.err          |   2 +-
>  tests/qapi-schema/base-cycle-indirect.json         |   7 -
>  tests/qapi-schema/command-int.err                  |   2 +-
>  tests/qapi-schema/command-int.json                 |   4 -
>  tests/qapi-schema/comments.json                    |   4 -
>  tests/qapi-schema/comments.out                     |   1 -
>  tests/qapi-schema/doc-bad-alternate-member.err     |   1 +
>  ...optional.exit => doc-bad-alternate-member.exit} |   0
>  tests/qapi-schema/doc-bad-alternate-member.json    |   9 +
>  ...c-optional.out => doc-bad-alternate-member.out} |   0
>  tests/qapi-schema/doc-bad-args.err                 |   1 -
>  tests/qapi-schema/doc-bad-command-arg.err          |   1 +
>  ...{doc-bad-args.exit => doc-bad-command-arg.exit} |   0
>  ...{doc-bad-args.json => doc-bad-command-arg.json} |   0
>  .../{doc-bad-args.out => doc-bad-command-arg.out}  |   0
>  tests/qapi-schema/doc-bad-expr.err                 |   1 +
>  tests/qapi-schema/doc-bad-expr.exit                |   1 +
>  tests/qapi-schema/doc-bad-expr.json                |   7 +
>  tests/qapi-schema/doc-bad-expr.out                 |   0
>  tests/qapi-schema/doc-bad-symbol.err               |   2 +-
>  tests/qapi-schema/doc-bad-union-member.err         |   1 +
>  tests/qapi-schema/doc-bad-union-member.exit        |   1 +
>  tests/qapi-schema/doc-bad-union-member.json        |  19 +
>  tests/qapi-schema/doc-bad-union-member.out         |   0
>  tests/qapi-schema/doc-empty-section.err            |   2 +-
>  tests/qapi-schema/doc-invalid-section.err          |   2 +-
>  tests/qapi-schema/doc-missing-expr.err             |   2 +-
>  tests/qapi-schema/doc-missing.err                  |   1 +
>  tests/qapi-schema/doc-missing.exit                 |   1 +
>  tests/qapi-schema/doc-missing.json                 |   5 +
>  tests/qapi-schema/doc-missing.out                  |   0
>  tests/qapi-schema/doc-no-symbol.err                |   1 +
>  tests/qapi-schema/doc-no-symbol.exit               |   1 +
>  tests/qapi-schema/doc-no-symbol.json               |   6 +
>  tests/qapi-schema/doc-no-symbol.out                |   0
>  tests/qapi-schema/doc-optional.err                 |   1 -
>  tests/qapi-schema/doc-optional.json                |   7 -
>  tests/qapi-schema/double-type.err                  |   2 +-
>  tests/qapi-schema/double-type.json                 |   4 -
>  tests/qapi-schema/enum-bad-name.err                |   2 +-
>  tests/qapi-schema/enum-bad-name.json               |   4 -
>  tests/qapi-schema/enum-bad-prefix.err              |   2 +-
>  tests/qapi-schema/enum-bad-prefix.json             |   4 -
>  tests/qapi-schema/enum-clash-member.err            |   2 +-
>  tests/qapi-schema/enum-clash-member.json           |   4 -
>  tests/qapi-schema/enum-dict-member.err             |   2 +-
>  tests/qapi-schema/enum-dict-member.json            |   4 -
>  tests/qapi-schema/enum-member-case.err             |   2 +-
>  tests/qapi-schema/enum-member-case.json            |   8 +-
>  tests/qapi-schema/enum-missing-data.err            |   2 +-
>  tests/qapi-schema/enum-missing-data.json           |   4 -
>  tests/qapi-schema/enum-wrong-data.err              |   2 +-
>  tests/qapi-schema/enum-wrong-data.json             |   4 -
>  tests/qapi-schema/event-boxed-empty.err            |   2 +-
>  tests/qapi-schema/event-boxed-empty.json           |   4 -
>  tests/qapi-schema/event-case.json                  |   4 -
>  tests/qapi-schema/event-case.out                   |   1 -
>  tests/qapi-schema/event-nest-struct.err            |   2 +-
>  tests/qapi-schema/event-nest-struct.json           |   4 -
>  tests/qapi-schema/flat-union-array-branch.err      |   2 +-
>  tests/qapi-schema/flat-union-array-branch.json     |  12 -
>  tests/qapi-schema/flat-union-bad-base.err          |   2 +-
>  tests/qapi-schema/flat-union-bad-base.json         |  13 -
>  tests/qapi-schema/flat-union-bad-discriminator.err |   2 +-
>  .../qapi-schema/flat-union-bad-discriminator.json  |  16 -
>  tests/qapi-schema/flat-union-base-any.err          |   2 +-
>  tests/qapi-schema/flat-union-base-any.json         |  13 -
>  tests/qapi-schema/flat-union-base-union.err        |   2 +-
>  tests/qapi-schema/flat-union-base-union.json       |  16 -
>  tests/qapi-schema/flat-union-clash-member.err      |   2 +-
>  tests/qapi-schema/flat-union-clash-member.json     |  16 -
>  tests/qapi-schema/flat-union-empty.err             |   2 +-
>  tests/qapi-schema/flat-union-empty.json            |  10 -
>  tests/qapi-schema/flat-union-incomplete-branch.err |   2 +-
>  .../qapi-schema/flat-union-incomplete-branch.json  |  10 -
>  tests/qapi-schema/flat-union-inline.err            |   2 +-
>  tests/qapi-schema/flat-union-inline.json           |  10 -
>  tests/qapi-schema/flat-union-int-branch.err        |   2 +-
>  tests/qapi-schema/flat-union-int-branch.json       |  13 -
>  .../qapi-schema/flat-union-invalid-branch-key.err  |   2 +-
>  .../qapi-schema/flat-union-invalid-branch-key.json |  15 -
>  .../flat-union-invalid-discriminator.err           |   2 +-
>  .../flat-union-invalid-discriminator.json          |  15 -
>  tests/qapi-schema/flat-union-no-base.err           |   2 +-
>  tests/qapi-schema/flat-union-no-base.json          |  13 -
>  .../flat-union-optional-discriminator.err          |   2 +-
>  .../flat-union-optional-discriminator.json         |  13 -
>  .../flat-union-string-discriminator.err            |   2 +-
>  .../flat-union-string-discriminator.json           |  15 -
>  tests/qapi-schema/ident-with-escape.json           |   4 -
>  tests/qapi-schema/ident-with-escape.out            |   1 -
>  tests/qapi-schema/include-relpath-sub.json         |   3 -
>  tests/qapi-schema/include-relpath.out              |   1 -
>  tests/qapi-schema/include-repetition.out           |   1 -
>  tests/qapi-schema/include-simple-sub.json          |   3 -
>  tests/qapi-schema/include-simple.out               |   1 -
>  tests/qapi-schema/indented-expr.json               |   6 -
>  tests/qapi-schema/indented-expr.out                |   2 -
>  tests/qapi-schema/missing-type.err                 |   2 +-
>  tests/qapi-schema/missing-type.json                |   4 -
>  tests/qapi-schema/nested-struct-data.err           |   2 +-
>  tests/qapi-schema/nested-struct-data.json          |   4 -
>  tests/qapi-schema/qapi-schema-test.json            | 218 +------
>  tests/qapi-schema/qapi-schema-test.out             | 130 -----
>  tests/qapi-schema/redefined-builtin.err            |   2 +-
>  tests/qapi-schema/redefined-builtin.json           |   4 -
>  tests/qapi-schema/redefined-command.err            |   2 +-
>  tests/qapi-schema/redefined-command.json           |   7 -
>  tests/qapi-schema/redefined-event.err              |   2 +-
>  tests/qapi-schema/redefined-event.json             |   7 -
>  tests/qapi-schema/redefined-type.err               |   2 +-
>  tests/qapi-schema/redefined-type.json              |   7 -
>  tests/qapi-schema/reserved-command-q.err           |   2 +-
>  tests/qapi-schema/reserved-command-q.json          |   7 -
>  tests/qapi-schema/reserved-enum-q.err              |   2 +-
>  tests/qapi-schema/reserved-enum-q.json             |   4 -
>  tests/qapi-schema/reserved-member-has.err          |   2 +-
>  tests/qapi-schema/reserved-member-has.json         |   4 -
>  tests/qapi-schema/reserved-member-q.err            |   2 +-
>  tests/qapi-schema/reserved-member-q.json           |   4 -
>  tests/qapi-schema/reserved-member-u.err            |   2 +-
>  tests/qapi-schema/reserved-member-u.json           |   4 -
>  tests/qapi-schema/reserved-member-underscore.err   |   2 +-
>  tests/qapi-schema/reserved-member-underscore.json  |   4 -
>  tests/qapi-schema/reserved-type-kind.err           |   2 +-
>  tests/qapi-schema/reserved-type-kind.json          |   4 -
>  tests/qapi-schema/reserved-type-list.err           |   2 +-
>  tests/qapi-schema/reserved-type-list.json          |   4 -
>  tests/qapi-schema/returns-alternate.err            |   2 +-
>  tests/qapi-schema/returns-alternate.json           |   7 -
>  tests/qapi-schema/returns-array-bad.err            |   2 +-
>  tests/qapi-schema/returns-array-bad.json           |   4 -
>  tests/qapi-schema/returns-dict.err                 |   2 +-
>  tests/qapi-schema/returns-dict.json                |   4 -
>  tests/qapi-schema/returns-unknown.err              |   2 +-
>  tests/qapi-schema/returns-unknown.json             |   4 -
>  tests/qapi-schema/returns-whitelist.err            |   2 +-
>  tests/qapi-schema/returns-whitelist.json           |  18 +-
>  tests/qapi-schema/struct-base-clash-deep.err       |   2 +-
>  tests/qapi-schema/struct-base-clash-deep.json      |  10 -
>  tests/qapi-schema/struct-base-clash.err            |   2 +-
>  tests/qapi-schema/struct-base-clash.json           |   7 -
>  tests/qapi-schema/struct-data-invalid.err          |   2 +-
>  tests/qapi-schema/struct-data-invalid.json         |   3 -
>  tests/qapi-schema/struct-member-invalid.err        |   2 +-
>  tests/qapi-schema/struct-member-invalid.json       |   3 -
>  tests/qapi-schema/test-qapi.py                     |  14 -
>  tests/qapi-schema/trailing-comma-list.err          |   2 +-
>  tests/qapi-schema/type-bypass-bad-gen.err          |   2 +-
>  tests/qapi-schema/type-bypass-bad-gen.json         |   4 -
>  tests/qapi-schema/unicode-str.err                  |   2 +-
>  tests/qapi-schema/unicode-str.json                 |   4 -
>  tests/qapi-schema/union-base-empty.err             |   1 +
>  tests/qapi-schema/union-base-empty.exit            |   1 +
>  tests/qapi-schema/union-base-empty.json            |   9 +
>  tests/qapi-schema/union-base-empty.out             |   0
>  tests/qapi-schema/union-base-no-discriminator.err  |   2 +-
>  tests/qapi-schema/union-base-no-discriminator.json |  12 -
>  tests/qapi-schema/union-branch-case.err            |   2 +-
>  tests/qapi-schema/union-branch-case.json           |   4 -
>  tests/qapi-schema/union-clash-branches.err         |   2 +-
>  tests/qapi-schema/union-clash-branches.json        |   4 -
>  tests/qapi-schema/union-empty.err                  |   2 +-
>  tests/qapi-schema/union-empty.json                 |   4 -
>  tests/qapi-schema/union-invalid-base.err           |   2 +-
>  tests/qapi-schema/union-invalid-base.json          |  10 -
>  tests/qapi-schema/union-optional-branch.err        |   2 +-
>  tests/qapi-schema/union-optional-branch.json       |   4 -
>  tests/qapi-schema/union-unknown.err                |   2 +-
>  tests/qapi-schema/union-unknown.json               |   4 -
>  tests/qapi-schema/unknown-escape.err               |   2 +-
>  tests/qapi-schema/unknown-escape.json              |   4 -
>  tests/qapi-schema/unknown-expr-key.err             |   2 +-
>  tests/qapi-schema/unknown-expr-key.json            |   4 -
>  259 files changed, 1263 insertions(+), 2109 deletions(-)
>  create mode 100644 tests/qapi-schema/doc-bad-alternate-member.err
>  rename tests/qapi-schema/{doc-optional.exit =>
> doc-bad-alternate-member.exit} (100%)
>  create mode 100644 tests/qapi-schema/doc-bad-alternate-member.json
>  rename tests/qapi-schema/{doc-optional.out =>
> doc-bad-alternate-member.out} (100%)
>  delete mode 100644 tests/qapi-schema/doc-bad-args.err
>  create mode 100644 tests/qapi-schema/doc-bad-command-arg.err
>  rename tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit}
> (100%)
>  rename tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json}
> (100%)
>  rename tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out}
> (100%)
>  create mode 100644 tests/qapi-schema/doc-bad-expr.err
>  create mode 100644 tests/qapi-schema/doc-bad-expr.exit
>  create mode 100644 tests/qapi-schema/doc-bad-expr.json
>  create mode 100644 tests/qapi-schema/doc-bad-expr.out
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.err
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.exit
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.json
>  create mode 100644 tests/qapi-schema/doc-bad-union-member.out
>  create mode 100644 tests/qapi-schema/doc-missing.err
>  create mode 100644 tests/qapi-schema/doc-missing.exit
>  create mode 100644 tests/qapi-schema/doc-missing.json
>  create mode 100644 tests/qapi-schema/doc-missing.out
>  create mode 100644 tests/qapi-schema/doc-no-symbol.err
>  create mode 100644 tests/qapi-schema/doc-no-symbol.exit
>  create mode 100644 tests/qapi-schema/doc-no-symbol.json
>  create mode 100644 tests/qapi-schema/doc-no-symbol.out
>  delete mode 100644 tests/qapi-schema/doc-optional.err
>  delete mode 100644 tests/qapi-schema/doc-optional.json
>  create mode 100644 tests/qapi-schema/union-base-empty.err
>  create mode 100644 tests/qapi-schema/union-base-empty.exit
>  create mode 100644 tests/qapi-schema/union-base-empty.json
>  create mode 100644 tests/qapi-schema/union-base-empty.out
>
> --
> 2.7.4
>
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation
  2017-03-14 12:42   ` Marc-André Lureau
@ 2017-03-14 15:16     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14 15:16 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, mdroth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Mon, Mar 13, 2017 at 10:31 AM Markus Armbruster <armbru@redhat.com>
> wrote:
>
>> The recent merge of docs/qmp-commands.txt and docs/qmp-events.txt into
>> the schema lost type information.  Fix this documentation regression.
>>
>> Example change (qemu-qmp-ref.txt):
>>
>>   -- Struct: InputKeyEvent
>>
>>       Keyboard input event.
>>
>>       Members:
>> -     'button'
>> +     'button: InputButton'
>>            Which button this event is for.
>> -     'down'
>> +     'down: boolean'
>>            True for key-down and false for key-up events.
>>
>>       Since: 2.0
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi.py      | 14 ++++++++++++++
>>  scripts/qapi2texi.py |  8 ++++++--
>>  2 files changed, 20 insertions(+), 2 deletions(-)
>>
>> diff --git a/scripts/qapi.py b/scripts/qapi.py
>> index 9430493..b82a2a6 100644
>> --- a/scripts/qapi.py
>> +++ b/scripts/qapi.py
>> @@ -1101,6 +1101,11 @@ class QAPISchemaType(QAPISchemaEntity):
>>          }
>>          return json2qtype.get(self.json_type())
>>
>> +    def doc_type(self):
>> +        if self.is_implicit():
>> +            return None
>> +        return self.name
>> +
>>
>>  class QAPISchemaBuiltinType(QAPISchemaType):
>>      def __init__(self, name, json_type, c_type):
>> @@ -1125,6 +1130,9 @@ class QAPISchemaBuiltinType(QAPISchemaType):
>>      def json_type(self):
>>          return self._json_type_name
>>
>> +    def doc_type(self):
>> +        return self.json_type()
>> +
>>      def visit(self, visitor):
>>          visitor.visit_builtin_type(self.name, self.info,
>> self.json_type())
>>
>> @@ -1184,6 +1192,12 @@ class QAPISchemaArrayType(QAPISchemaType):
>>      def json_type(self):
>>          return 'array'
>>
>> +    def doc_type(self):
>> +        elt_doc_type = self.element_type.doc_type()
>> +        if not elt_doc_type:
>> +            return None
>>
>
> In which case is this expected to happen? place an assert here instead?

I think assert should work now, the argument is a bit longwinded, and it
won't let us simplify code.

First the argument.

T.doc_type() returns None for a non-array type T when T.is_implicit()
and T isn't a built-in type, because:

* QAPISchemaType.doc_type() returns None when self.is_implicit(), but

* QAPISchemaBuiltinType().doc_type() overrides, and never returns None.

T.is_implicit() is true for the following non-array, non-builtin T:

* the implicitly defined enumeration type of a simple union's tag

* the implicitly defined variant type of a simple union

* an implicitly defined base type of a union

* an implicitly defined argument type of a command or event

We can't actually make arrays of these.

Now let's see whether we can use it to simplify code.

There are four calls of .doc_type() besides the one shown above:

* texi_member() calls it for types of

  - the (common) members of object types (including command and event
    arguments) and members of alternate types.  None happens for the
    implicitly defined tag member of simple unions.  The easiest way to
    cope with it is to cope with None for any member.

  - the members of variant members of simple unions.  It doesn't bother
    to handle None, because a member type can only be a built-in or
    explictly defined type, or an array thereof.

* texi_members() calls it and checks for None to help identify
  undocumented members where we can do better than say "Not documented".

* texi_members() calls it for the base type, except when it's implicitly
  defined.  It doesn't bother to handle None, because it can only be an
  explictly defined struct type.

* texi_members() calls it for the types of variant members of flat
  unions.  It doesn't bother to handle None, because a member type can
  only be a built-in or explictly defined type.

Adding the assertion makes no case of None go away.

> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation Markus Armbruster
@ 2017-03-14 15:55   ` Eric Blake
  2017-03-15  7:08     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 15:55 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1910 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Rename intermediate qemu-qapi.texi to qemu-qmp-qapi.texi to match its
> user qemu-qmp-ref.texi, just like qemu-ga-qapi.texi matches
> qemu-ga-ref.texi.
> 
> Build the intermediate .texi next to the sources and the final output
> in docs/ instead of dumping them into the build root.
> 
> Fix version.texi dependencies so that only the targets that actually
> need it depend on it.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  .gitignore             | 10 +++++-----
>  Makefile               | 27 +++++++++++++++------------
>  docs/qemu-qmp-ref.texi |  2 +-
>  rules.mak              |  2 +-
>  4 files changed, 22 insertions(+), 19 deletions(-)
> 
> diff --git a/.gitignore b/.gitignore
> index 2849d75..0e99e6a 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -103,11 +103,11 @@
>  /docs/qemu-ga-ref.txt

[1]

>  /docs/qemu-qmp-ref.html
>  /docs/qemu-qmp-ref.txt
> -docs/qemu-ga-ref.info*
> -docs/qemu-qmp-ref.info*
> -/qemu-ga-qapi.texi
> -/qemu-qapi.texi
> -/version.texi
> +/docs/qemu-ga-ref.info*

worth sorting this line up by [1]?

> +/docs/qemu-qmp-ref.info*
> +/docs/qemu-ga-qapi.texi
> +/docs/qemu-qmp-qapi.texi
> +/docs/version.texi
>  *.tps
>  .stgit-*
>  cscope.*
> @@ -663,25 +663,28 @@ ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
>  
>  # documentation
>  MAKEINFO=makeinfo
> -MAKEINFOFLAGS=--no-split --number-sections
> +MAKEINFOFLAGS=--no-split --number-sections -I docs

Will this cause grief on any older makinfo versions (such as RHEL 6)?  I
didn't test myself on those setups.  I guess if a buildbot doesn't flag
you, it's okay.

The sorting issue is worth fixing, but trivial, so you can add:

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base Markus Armbruster
  2017-03-14  8:41   ` Marc-André Lureau
@ 2017-03-14 15:56   ` Eric Blake
  2017-03-15  7:11     ` Markus Armbruster
  1 sibling, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 15:56 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 399 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> The new test case shows off qapi.py choking on an empty union base.

We're still finding ways to choke the parser ;)

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully Markus Armbruster
  2017-03-14  8:40   ` Marc-André Lureau
@ 2017-03-14 15:58   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 15:58 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1206 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Common Python pitfall: 'assert base_members' fires on [] in addition
> to None.  Correct to 'assert base_members is not None'.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py                        |  2 +-
>  tests/qapi-schema/union-base-empty.err | 11 +----------
>  2 files changed, 2 insertions(+), 11 deletions(-)
> 

> +++ b/tests/qapi-schema/union-base-empty.err
> @@ -1,10 +1 @@
> -Traceback (most recent call last):
> -  File "tests/qapi-schema/test-qapi.py", line 56, in <module>
> -    schema = QAPISchema(sys.argv[1])
> -  File "scripts/qapi.py", line 1483, in __init__
> -    self.exprs = check_exprs(parser.exprs)
> -  File "scripts/qapi.py", line 917, in check_exprs
> -    check_union(expr, info)
> -  File "scripts/qapi.py", line 734, in check_union
> -    assert base_members
> -AssertionError
> +tests/qapi-schema/union-base-empty.json:5: Discriminator 'type' is not a member of base struct 'Empty'

Much nicer message.
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 13/47] qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType'
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 13/47] qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType' Markus Armbruster
@ 2017-03-14 16:03   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 16:03 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1173 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Missed in commit 7264f5c.  Harmless, because nothing checks whether an
> enumeration type is implicit so far.

Obviously, a later patch will care about implicit types, and choked
without this ;)

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

> 
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index e6d023f..7a2b6ab 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1148,8 +1148,8 @@ class QAPISchemaEnumType(QAPISchemaType):
>              v.check_clash(self.info, seen)
>  
>      def is_implicit(self):
> -        # See QAPISchema._make_implicit_enum_type()
> -        return self.name.endswith('Kind')
> +        # See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
> +        return self.name.endswith('Kind') or self.name == 'QType'
>  
>      def c_type(self):
>          return c_name(self.name)
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 14/47] qapi: Prepare for requiring more complete documentation
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 14/47] qapi: Prepare for requiring more complete documentation Markus Armbruster
@ 2017-03-14 16:08   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 16:08 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 922 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> We currently neglect to check all enumeration values, common members
> of object types and members of alternate types are documented.
> Unsurprisingly, many aren't.

And some, like QKeyCode, would be a pain to document.

> 
> Add the necessary plumbing to find undocumented ones, except for
> variant members of object types.  Don't enforce anything just yet, but
> connect each QAPIDoc.ArgSection to its QAPISchemaMember.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 110 +++++++++++++++++++++++++++++++++-----------------------
>  1 file changed, 65 insertions(+), 45 deletions(-)
> 

Lots of plumbing added, but I'm not spotting any obvious omissions.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-14 13:22         ` Marc-André Lureau
@ 2017-03-14 16:14           ` Markus Armbruster
  2017-03-15 14:00             ` Marc-André Lureau
  0 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-14 16:14 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, mdroth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Mon, Mar 13, 2017 at 5:12 PM Markus Armbruster <armbru@redhat.com> wrote:
>
>> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>>
>> > Hi
>> >
>> > On Mon, Mar 13, 2017 at 4:14 PM Markus Armbruster <armbru@redhat.com> wrote:
>> >
>> >> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>> >>
>> >> > Hi
>> >> >
>> >> > On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com
>> >
>> >> > wrote:
>> >> >
>> >> >> I'm proposing this is 2.9 because it fixes a documentation regression.
>> >> >> It affects only documentation; generated C code is unchanged except
>> >> >> for the removal of trailing space in PATCH 46.
>> >> >>
>> >> >> Based on my qapi-next branch, which contains Marc-André's PATCH 1/2.
>> >> >>
>> >> >> Marc-André's work to merge qmp-commands.txt and qmp-events.txt into
>> >> >> the QAPI schema and generate their replacements from the schema
>> >> >> (commit b6af8ea..56e8bdd) was a big step forward.  As committed, it
>> >> >> also was a step back: the documentation lost information on JSON
>> >> >> types, because I didn't like Marc-André's patch to add it.  He
>> >> >> reposted it for further review afterwards:
>> >> >>
>> >> >>     Subject: [PATCH 0/2] qapi2texi: add type information
>> >> >>     Message-Id: <20170125130308.16104-1-marcandre.lureau@redhat.com>
>> >> >>     https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
>> >> >>
>> >> >> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds type
>> >> >> descriptions in a new formal language to the generated documentation.
>> >> >> Quoting the commit message:
>> >> >>
>> >> >>     Array types have the following syntax: type[]. Ex: str[].
>> >> >>
>> >> >>     - Struct, commands and events use the following members syntax:
>> >> >>
>> >> >>       { 'member': type, ('foo': str), ... }
>> >> >>
>> >> >>     Optional members are under parentheses.
>> >> >>
>> >> >>     A structure with a base type will have 'BaseStruct +' prepended.
>> >> >>
>> >> >>     - Alternates use the following syntax:
>> >> >>
>> >> >>       [ 'foo': type, 'bar': type, ... ]
>> >> >>
>> >> >>     - Simple unions use the following syntax:
>> >> >>
>> >> >>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar': type... ] }
>> >> >>
>> >> >>     - Flat unions use the following syntax:
>> >> >>
>> >> >>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar': type... ]
>> >> >>
>> >> >> End quote.  Looks like this in generated documentation:
>> >> >>
>> >> >>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
>> >> >>           VncBasicInfo}
>> >> >>
>> >> >>      Emitted when a VNC client establishes a connection
>> >> >>      ''server''
>> >> >>           server information
>> >> >>      ''client''
>> >> >>           client information
>> >> >>
>> >> >>      Note: This event is emitted before any authentication takes place,
>> >> >>      thus the authentication ID is not provided
>> >> >> [...]
>> >> >>
>> >> >>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
>> >> >>
>> >> >>      The network connection information for server
>> >> >>      ''auth'' (optional)
>> >> >>           authentication method used for the plain (non-websocket) VNC
>> >> >>           server
>> >> >>
>> >> >>      Since: 2.1
>> >> >>
>> >> >>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>> >> >>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>> >> >>           VsockSocketAddress, 'fd': String] }
>> >> >>
>> >> >>      Captures the address of a socket, which could also be a named file
>> >> >>      descriptor
>> >> >>
>> >> >>      Since: 1.3
>> >> >>
>> >> >> Here's my counter-proposal: instead of inventing a formal language,
>> >> >> fix the natural language documentation to actually mention *all*
>> >> >> members, and add type information in a plain, easy-to-understand way.
>> >> >> Looks like this:
>> >> >>
>> >> >>  -- Event: VNC_CONNECTED
>> >> >>
>> >> >>      Emitted when a VNC client establishes a connection
>> >> >>
>> >> >>      Arguments:
>> >> >>      'server: VncServerInfo'
>> >> >>           server information
>> >> >>      'client: VncBasicInfo'
>> >> >>           client information
>> >> >>
>> >> >>      Note: This event is emitted before any authentication takes place,
>> >> >>      thus the authentication ID is not provided
>> >> >> [...]
>> >> >>
>> >> >>  -- Object: VncServerInfo
>> >> >>
>> >> >>      The network connection information for server
>> >> >>
>> >> >>      Members:
>> >> >>      'auth: string' (optional)
>> >> >>           authentication method used for the plain (non-websocket) VNC
>> >> >>           server
>> >> >>      The members of 'VncBasicInfo'
>> >> >>
>> >> >>      Since: 2.1
>> >> >>
>> >> >>  -- Object: SocketAddress
>> >> >>
>> >> >>      Captures the address of a socket, which could also be a named file
>> >> >>      descriptor
>> >> >>
>> >> >>      Members:
>> >> >>      'type'
>> >> >>           One of "inet", "unix", "vsock", "fd"
>> >> >>      'data: InetSocketAddress' when 'type' is "inet"
>> >> >>      'data: UnixSocketAddress' when 'type' is "unix"
>> >> >>      'data: VsockSocketAddress' when 'type' is "vsock"
>> >> >>      'data: String' when 'type' is "fd"
>> >> >>
>> >> >>      Since: 1.3
>> >> >>
>> >> >>
>> >> > I like both, to me they serve different purposes. I like to have a short
>> >> > overview / signature and then a more detailed documentation for each
>> >> field.
>> >>
>> >> I sympathize with the argument.  Unfortunately, the "short" signatures
>> >> are anything but for real-world QAPI:
>> >>
>> >
>> > That's a worse case, a regular case is more readable.
>>
>> There are readable cases, but there are plenty of cases that plainly
>> aren't.
>>
>> 102 out of 472 signatures don't count because they're empty.
>>
>> Roughly half the non-empty signatures fit on a single line.  That's short.
>>
>> A bit under a third take two lines.  I guess that's still short enough.
>>
>> More than one in six signatures is three lines or more.
>>
>> >                                                       And it is still
>> > useful anyway since the common members would be listed first.
>>
>> Whatever comes first in signatures comes first in the table of members,
>> too.  The names are easier to spot there, because they're all on the
>> left.
>>
>> Compare
>>
>>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
>>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
>>           VsockSocketAddress, 'fd': String] }
>>
>>      Captures the address of a socket, which could also be a named file
>>      descriptor
>>
>>      Since: 1.3
>>
>> to
>>
>>  -- Object: SocketAddress
>>
>>      Captures the address of a socket, which could also be a named file
>>      descriptor
>>
>>      Members:
>>      'type'
>>           One of "inet", "unix", "vsock", "fd"
>>      'data: InetSocketAddress' when 'type' is "inet"
>>      'data: UnixSocketAddress' when 'type' is "unix"
>>      'data: VsockSocketAddress' when 'type' is "vsock"
>>      'data: String' when 'type' is "fd"
>>
>>      Since: 1.3
>>
>> In my opinion, the three lines of signature add nothing but noise to the
>> six lines of member table.
>>
>
> It is more natural and faster to read to me for commands and events for
> example.  The verbose description is mixing description and sometime even
> providing redundant information (ex: keys: array of KeyValue,  An array of
> 'KeyValue' elements...), slowing reading even more.

Doc comments that merely restate the type should be cleaned up.

>                                                     Often you don't need to
> read the documentation / description, you want to quickly check the return
> type, and remind you the arguments.

Point taken.

A formal description of unbounded (and often excessive) length can't
serve that purpose, though.

A sufficiently condensed summaries just might.  Perhaps names only, no
types.  Certainly no more than a few.

For instance, having

 -- Command: block-job-set-speed device speed

instead of just

 -- Command: block-job-set-speed

feels okay; the additional two words are technically redundant, but they
might occasionally serve someone as a reminder, and they're not
distracting.

But I feel

 -- Command: blockdev-mirror [job-id] device target [replaces] sync
          [speed] [granularity] [buf-size] [on-source-error]
          [on-target-error] [filter-node-name]

is pushing it.

So this begs the question which ones to omit when there are more than a
few.  I'm afraid asking a stupid computer program to pick out
"important" arguments is asking for too much.  For high-quality
summaries, we'd have to pick ourselves.

Moreover, what to do for truly complex commands like blockdev-add?
Simply omitting all variant members is one option:

 -- Command: blockdev-add driver [node-name] [discard] [cache]
          [read-only] [detect-zeroes] ...

But what may work for blockdev-add need not work for other complex
commands.

> struct/objects are more commonly declared with a line per member, so it
> doesn't bother me as much.
>
> I would appreciate if can have the declarative form for commands and events
> at least. Other types are usually more complex or long, so that may clear
> your concerns for the long declarations.

The worst offenders are actually commands such as blockdev-add and
block_set_io_throttle, unless we give up on the "reminder" mission for
them and merely add a reference to their (named) argument type.

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members Markus Armbruster
@ 2017-03-14 17:16   ` Eric Blake
  2017-03-15  7:12     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 17:16 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 771 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> qapi2texi.py already conjures up ArgSections for undocumented
> enumeration values, in texi_enum).  Drop that, and conjure them up for

Missing '('?

> all kinds of "arguments" (enumeration values, object and alternate
> type members) in qapi.py instead.
> 
> Take care to keep generated documentation exactly the same for now.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py      |  5 ++---
>  scripts/qapi2texi.py | 31 ++++++++++++++++---------------
>  2 files changed, 18 insertions(+), 18 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor Markus Armbruster
@ 2017-03-14 17:31   ` Eric Blake
  2017-03-15  7:14     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 17:31 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1625 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> qapi2texi works with schema expression trees.  Such a tight coupling
> to schema language syntax is not a good idea.  Convert it to the visitor
> interface the other generators use.
> 
> No change to generated documentation.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 228 ++++++++++++++++++++++++++-------------------------
>  1 file changed, 118 insertions(+), 110 deletions(-)
> 

> +    def visit_object_type(self, name, info, base, members, variants):
> +        doc = self.cur_doc
> +        if not variants:
> +            typ = 'Struct'
> +        elif variants._tag_name:        # TODO unclean member access
> +            typ = 'Flat Union'
> +        else:
> +            typ = 'Simple Union'

Do we even want to document this distinction to the end user?
Introspection managed to hide the difference by introducing the
appropriate generated wrapper types that demonstrate the additional {}
nesting in a way compatible with rewriting simple unions into flat
unions.  If we don't explain the difference here, we can get rid of the
unclean member access, but then again risk documentation that is not
clear whether {} nesting is needed.

I guess there's also the fact that for this patch, you intentionally
tried to make no difference to the generated docs (good); so any tweaks
to union output should be later patches anyways.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop Markus Armbruster
@ 2017-03-14 17:59   ` Eric Blake
  2017-03-15  7:22     ` Markus Armbruster
  2017-03-14 20:14   ` Eric Blake
  1 sibling, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 17:59 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 3806 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> We traditionally mark optional members #optional in the doc comment.
> Before commit 3313b61, this was entirely manual.
> 
> Commit 3313b61 added some automation because its qapi2texi.py relied
> on #optional to determine whether a member is optional.  This is no
> longer the case since the previous commit: the only thing qapi2texi.py
> still does with #optional is stripping it out.  We still reject bogus
> qapi-schema.json and six places for qga/qapi-schema.json.
> 
> Thus, you can't actually rely on #optional to see whether something is
> optional.  Yet we still make people add it manually.  That's just
> busy-work.

Yay! Let the computer do the work for us!

> 
> Drop the code to check, fix up and strip out #optional, along with all
> instances of #optional.  To keep it out, add code to reject it, to be
> dropped again once the dust settles.
> 
> No change to generated documentation.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

> @@ -150,10 +148,10 @@ For example:
>  #
>  # Statistics of a virtual block device or a block backing device.
>  #
> -# @device: #optional If the stats are for a virtual block device, the name
> -#          corresponding to the virtual block device.
> +# @device: If the stats are for a virtual block device, the name
> +# corresponding to the virtual block device.

This loses the hanging indentation in the example, but I don't see you
making that change in the actual .json files.  It shouldn't matter in
the long run, and is certainly easier if the way you generated this
patch was with sed scripts (where computing correct hanging indentation
after rewrapping is a lot harder than omitting it).  I don't have any
strong opinions about the change (less typing, but slightly harder to
visually see that the following lines belong to the same parameter doc,
if you don't have blank lines between distinct parameter docs).  I'm not
even sure if it you want to call it out in the commit message as an
intentional reformat, particularly since you didn't do it everywhere.

> +++ b/qapi-schema.json
> @@ -150,10 +150,10 @@
>  #
>  # @fdname: file descriptor name previously passed via 'getfd' command
>  #
> -# @skipauth: #optional whether to skip authentication. Only applies
> +# @skipauth: whether to skip authentication. Only applies
>  #            to "vnc" and "spice" protocols
>  #
> -# @tls: #optional whether to perform TLS. Only applies to the "spice"
> +# @tls: whether to perform TLS. Only applies to the "spice"
>  #       protocol

Again, whitespace changes shouldn't affect generated output, so
rewrapping lines like this would be more busy-work than necessary, even
though this particular example would now fit on one line.

> @@ -667,45 +667,45 @@
>  #
...
>  #
> -# @setup-time: #optional amount of setup time in milliseconds _before_ the
> +# @setup-time: amount of setup time in milliseconds _before_ the
>  #        iterations begin but _after_ the QMP command is issued. This is designed
>  #        to provide an accounting of any activities (such as RDMA pinning) which
>  #        may be expensive, but do not actually occur during the iterative
>  #        migration rounds themselves. (since 1.6)

Here's another place where wrapping now looks odd (short, followed by
multiple longer lines).  Again, the effort of rewrapping lines is not
worth the churn (and it's actually easier to read diffs that _don't_
reflow text).  So I'll just overlook wrapping oddities in the rest of
the patch, as inconsequential to the end result.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 18/47] qapi: Use raw strings for regular expressions consistently
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 18/47] qapi: Use raw strings for regular expressions consistently Markus Armbruster
@ 2017-03-14 18:00   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 18:00 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 360 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 19/47] qapi: Prefer single-quoted strings more consistently
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 19/47] qapi: Prefer single-quoted strings more consistently Markus Armbruster
@ 2017-03-14 18:05   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 18:05 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1253 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> PEP 8 advises:
> 
>     In Python, single-quoted strings and double-quoted strings are the
>     same.  This PEP does not make a recommendation for this.  Pick a
>     rule and stick to it.  When a string contains single or double
>     quote characters, however, use the other one to avoid backslashes
>     in the string.  It improves readability.
> 
> The QAPI generators succeed at picking a rule, but fail at sticking to
> it.  Convert a bunch of double-quoted strings to single-quoted ones.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi-event.py      |  2 +-
>  scripts/qapi-introspect.py |  4 +-
>  scripts/qapi-types.py      |  4 +-
>  scripts/qapi-visit.py      |  4 +-
>  scripts/qapi.py            | 96 +++++++++++++++++++++++-----------------------
>  scripts/qapi2texi.py       | 46 +++++++++++-----------
>  6 files changed, 78 insertions(+), 78 deletions(-)
> 

Purely stylistic, so I wouldn't do it as a lone patch. But as part of a
larger series, I think you're fine.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 20/47] qapi2texi: Plainer enum value and member name formatting
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 20/47] qapi2texi: Plainer enum value and member name formatting Markus Armbruster
@ 2017-03-14 18:06   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 18:06 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 755 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Use @code{%s} instead of @code{'%s'}.  Impact, using @id as example:
> 
> * Texinfo
>   -@item @code{'id'}
>   +@item @code{id}
> 
> * HTML
>   -<dt><code>'id'</code></dt>
>   +<dt><code>id</code></dt>
> 
> * POD (for manual pages):
>   -=item C<'id'>
>   +=item C<id>
> 
> * Formatted manual pages:
>   -'id'
>   +"id"
> 
> * Plain text:
>   -     ''id''
>   +     'id'
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 21/47] qapi2texi: Present the table of members more clearly
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 21/47] qapi2texi: Present the table of members more clearly Markus Armbruster
@ 2017-03-14 18:08   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 18:08 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1073 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> The table of members follows the main descriptive text immediately.
> Makes it hard to see what it is about.  Start a new paragraph, and
> lead with a line "Members:" for object and alternate types, "Values:"
> for enumeration types, and "Arguments:" for commands and events.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Command: set_link
> 
>       Sets the link status of a virtual network adapter.
> +
> +     Arguments:
>       'name'
>            the device name of the virtual network adapter
>       'up'
>            true to set the link status to be up
> 
>       Returns: Nothing on success If 'name' is not a valid network
>       device, DeviceNotFound
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 19 ++++++++++---------
>  1 file changed, 10 insertions(+), 9 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 22/47] qapi2texi: Explain enum value undocumentedness more clearly
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 22/47] qapi2texi: Explain enum value undocumentedness " Markus Armbruster
@ 2017-03-14 19:00   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:00 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 769 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Instead of not saying anything when we have no documentation, say "Not
> documented".
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Enum: GuestPanicAction
> 
>       An enumeration of the actions taken when guest OS panic is detected
> 
>       Values:
>       'pause'
>            system pauses
>       'poweroff'
> +          Not documented
> 
>       Since: 2.1 (poweroff since 2.8)
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 23/47] qapi2texi: Don't hide undocumented members and arguments
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 23/47] qapi2texi: Don't hide undocumented members and arguments Markus Armbruster
@ 2017-03-14 19:02   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:02 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 745 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Show undocumented object, alternate type members and command, event
> arguments exactly like undocumented enumeration type values.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Command: query-rocker
> 
>       Return rocker switch information.
> 
> +     Arguments:
> +     'name'
> +          Not documented
> +
>       Returns: 'Rocker' information
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 12 ++++--------
>  1 file changed, 4 insertions(+), 8 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation Markus Armbruster
@ 2017-03-14 19:12   ` Eric Blake
  2017-03-15  7:23     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:12 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 729 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> This replaces manual references like "For the arguments, see the
> documentation of ..." by a generated reference "Arguments: the members
> of ...".
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  qapi-schema.json     |  2 +-
>  qapi/block-core.json | 10 ----------
>  scripts/qapi2texi.py |  8 +++++++-
>  3 files changed, 8 insertions(+), 12 deletions(-)

Should be even more handy when you add html links to the type
documentation from the command documentation, later in the series.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation Markus Armbruster
  2017-03-14 12:42   ` Marc-André Lureau
@ 2017-03-14 19:16   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:16 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 948 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> The recent merge of docs/qmp-commands.txt and docs/qmp-events.txt into
> the schema lost type information.  Fix this documentation regression.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Struct: InputKeyEvent
> 
>       Keyboard input event.
> 
>       Members:
> -     'button'
> +     'button: InputButton'
>            Which button this event is for.
> -     'down'
> +     'down: boolean'
>            True for key-down and false for key-up events.
> 
>       Since: 2.0

Definitely worth having.

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py      | 14 ++++++++++++++
>  scripts/qapi2texi.py |  8 ++++++--
>  2 files changed, 20 insertions(+), 2 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members Markus Armbruster
@ 2017-03-14 19:29   ` Eric Blake
  2017-03-15  7:30     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:29 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 2291 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> The generated documentation doesn't mention object type members
> inherited from a base type.  Fix that.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Struct: VncServerInfo
> 
>       The network connection information for server
> 
>       Members:
>       'auth' (optional)
> 	   authentication method used for the plain (non-websocket) VNC
> 	   server
> +     The members of 'VncBasicInfo'
> 

Again, will be more useful later in the series when you add hyperlinking.

>       Since: 2.1
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> index 993b652..7083d0c 100755
> --- a/scripts/qapi2texi.py
> +++ b/scripts/qapi2texi.py
> @@ -143,7 +143,7 @@ def texi_member(member):
>          ' (optional)' if member.optional else '')
>  
>  
> -def texi_members(doc, what, member_func):
> +def texi_members(doc, what, base, member_func):
>      """Format the table of members"""
>      items = ''
>      for section in doc.args.itervalues():
> @@ -152,6 +152,8 @@ def texi_members(doc, what, member_func):
>          else:
>              desc = 'Not documented'
>          items += member_func(section.member) + texi_format(desc) + '\n'
> +    if base:
> +        items += '@item The members of @code{%s}\n' % base.doc_type()

Will this still work for implicit bases?

>  
> @@ -205,11 +207,13 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>              typ = 'Flat Union'
>          else:
>              typ = 'Simple Union'
> +        if base and base.is_implicit():
> +            base = None

Hmm - you just ignore those, such as the anonymous base in CpuInfo.  On
the other hand, CpuInfo documents its base fields explicitly.  Are we at
risk of double-documenting a base member, both explicitly and via its
named base type?

At any rate, this patch is an incremental improvement, so:
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members Markus Armbruster
@ 2017-03-14 19:36   ` Eric Blake
  2017-03-15  7:36     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:36 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 2221 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> A flat union's branch brings in the members of another type.  Generate
> a suitable reference to that type.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Flat Union: QCryptoBlockOpenOptions
> 
>       The options that are available for all encryption formats when
>       opening an existing volume
> 
>       Members:
>       The members of 'QCryptoBlockOptionsBase'
> +     The members of 'QCryptoBlockOptionsQCow' when 'format' is "qcow"

Relies on the implied knowledge that 'format' is a member of
'QCryptoBlockOptionsBase'. Does that mean references to another type
might usefully want to do a list of member names, to avoid having to
follow the hyperlink, while still leaving the hyperlink when searching
for full details on that member?  As in:

Members:
The members of 'QCryptoBlockOptionsBase' ('format')
The members of 'QCryptoBlockOptionsQCow' when 'format' is "qcow"
('key-secret')

But it could get noisy (the example here only adds one member; other
unions add lots of members), and I'm also okay if you don't like the
idea or would rather do it as a followup.

> +     The members of 'QCryptoBlockOptionsLUKS' when 'format' is "luks"
> 
>       Since: 2.6
> 
> A simple union's branch adds a member 'data' of some other type.
> Generate documentation for that member.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Simple Union: SocketAddress
> 
>       Captures the address of a socket, which could also be a named file
>       descriptor
> 
>       Members:
>       'type'
> 	   Not documented
> +     'data: InetSocketAddress' when 'type' is "inet"
> +     'data: UnixSocketAddress' when 'type' is "unix"
> +     'data: VsockSocketAddress' when 'type' is "vsock"
> +     'data: String' when 'type' is "fd"

Looks reasonable.

> 
>       Since: 1.3
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 27 ++++++++++++++++++++-------
>  1 file changed, 20 insertions(+), 7 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 28/47] qapi2texi: Generate descriptions for simple union tags
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 28/47] qapi2texi: Generate descriptions for simple union tags Markus Armbruster
@ 2017-03-14 19:54   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:54 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1052 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Simple union tags carry no type information, because their type is
> implicit.  Their description should make up for it, but many have
> none.  Generate one automatically then.
> 
> Example change (qemu-qmp-ref.txt):
> 
>   -- Simple Union: ImageInfoSpecific
> 
>       A discriminated record of image format specific information
>       structures.
> 
>       Members:
>       'type'
> -          Not documented
> +          One of "qcow2", "vmdk", "luks"

Yes, that's nicer.

>       'data: ImageInfoSpecificQCow2' when 'type' is "qcow2"
>       'data: ImageInfoSpecificVmdk' when 'type' is "vmdk"
>       'data: QCryptoBlockInfoLUKS' when 'type' is "luks"
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 29/47] qapi2texi: Use category "Object" for all object types
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 29/47] qapi2texi: Use category "Object" for all object types Markus Armbruster
@ 2017-03-14 19:56   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 19:56 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1132 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> At the protocol level, the distinction between struct, flat union and
> simple union is meaningless, they are all JSON objects.  Document them
> that way.
> 
> Example change (qemu-qmp-ref.txt):
> 
> - -- Simple Union: InputEvent
> + -- Object: InputEvent
> 
>       Input event union.

Yay - and even addresses one of my comments earlier in the series about
a needless distinction between simple and flat unions.

> 
> This also fixes the completely broken headings for flat and simple
> unions in qemu-qmp-ref.7 and qemu-ga-ref.7, by sidestepping a bug in
> texi2pod.pl.  For instance, it mistranslates "@deftp {Simple Union}
> InputEvent" to "B<Union> (Simple)", but translates "@deftp Object
> InputEvent" to "B<SocketAddress> (Object)".
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi2texi.py | 8 +-------
>  1 file changed, 1 insertion(+), 7 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage Markus Armbruster
@ 2017-03-14 20:02   ` Eric Blake
  2017-03-14 20:36   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:02 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 809 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> New test doc-bad-expr.json shows we fail to reject a misplaced
> expression comment.
> 
> New test doc-no-symbol.json shows a bad error message.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

> +++ b/tests/qapi-schema/doc-no-symbol.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/doc-no-symbol.json:4: Definition of 'foo' follows documentation for 'None'

Yep, that's python implementation leaking through.

> +++ b/tests/qapi-schema/doc-no-symbol.json
> @@ -0,0 +1,7 @@
> +# Documentation for expression lacks symbol
> +# BUG: Error message claims it has symbol 'None'

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop Markus Armbruster
  2017-03-14 17:59   ` Eric Blake
@ 2017-03-14 20:14   ` Eric Blake
  2017-03-15  7:15     ` Markus Armbruster
  1 sibling, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:14 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1906 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> We traditionally mark optional members #optional in the doc comment.
> Before commit 3313b61, this was entirely manual.
> 
> Commit 3313b61 added some automation because its qapi2texi.py relied
> on #optional to determine whether a member is optional.  This is no
> longer the case since the previous commit: the only thing qapi2texi.py
> still does with #optional is stripping it out.  We still reject bogus
> qapi-schema.json and six places for qga/qapi-schema.json.
> 
> Thus, you can't actually rely on #optional to see whether something is
> optional.  Yet we still make people add it manually.  That's just
> busy-work.
> 
> Drop the code to check, fix up and strip out #optional, along with all
> instances of #optional.  To keep it out, add code to reject it, to be
> dropped again once the dust settles.
> 
> No change to generated documentation.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  docs/qapi-code-gen.txt              |  16 +-
>  docs/writing-qmp-commands.txt       |   4 +-
>  qapi-schema.json                    | 378 ++++++++++++++++----------------
>  qapi/block-core.json                | 418 ++++++++++++++++++------------------

You'll have to rebase this on master, due to ...


> @@ -2349,17 +2349,17 @@
>  #
>  # @volume:              Name of the Archipelago volume image
>  #
> -# @mport:               #optional The port number on which mapperd is
> +# @mport:               The port number on which mapperd is
>  #                       listening. This is optional
>  #                       and if not specified, QEMU will make Archipelago
>  #                       use the default port (1001).
>  #

...commit e32ccbc killing broken archipelago

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch Markus Armbruster
@ 2017-03-14 20:35   ` Eric Blake
  2017-03-15  7:39     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:35 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 931 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> This fixes the errors uncovered by the previous commit.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

>  
>              expr = self.get_expr(False)
>              if 'include' in expr:
> +                self.reject_expr_doc()
>                  if len(expr) != 1:

Do you also need to handle 'pragma' expressions added earlier in the series?

/me goes and experiments:

diff --git i/tests/qapi-schema/doc-bad-expr.json
w/tests/qapi-schema/doc-bad-expr.json
index 0caa0ae..6c1204d 100644
--- i/tests/qapi-schema/doc-bad-expr.json
+++ w/tests/qapi-schema/doc-bad-expr.json
@@ -4,4 +4,5 @@
 # @foo:
 ##
 { 'include': 'empty.json' }
+{ 'pragma': {} }
 { 'struct': 'foo', 'data': {} }

Oops - back to accepting the program.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage Markus Armbruster
  2017-03-14 20:02   ` Eric Blake
@ 2017-03-14 20:36   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:36 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 752 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> New test doc-bad-expr.json shows we fail to reject a misplaced
> expression comment.
> 
> New test doc-no-symbol.json shows a bad error message.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

> +++ b/tests/qapi-schema/doc-bad-expr.json
> @@ -0,0 +1,8 @@
> +# Doc comment separated from defining expression by non-defining expression
> +# BUG: not rejected
> +
> +##
> +# @foo:
> +##
> +{ 'include': 'empty.json' }
> +{ 'struct': 'foo', 'data': {} }

See my comments on 31/47 for an enhancement to this test that also
sticks a { 'pragma': {} } there.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch Markus Armbruster
@ 2017-03-14 20:43   ` Eric Blake
  2017-03-15  7:39     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:43 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 842 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Move the check whether the doc matches the expression name from
> check_definition_doc() to check_exprs().  This changes the error
> location from the comment to the expression.  Makes sense as the
> message talks about the expresion: "Definition of '%s' follows

s/expresion/expression/

> documentation for '%s'".  It's also a step towards getting rid of
> check_docs().
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py                      | 28 ++++++++++++++++++----------
>  tests/qapi-schema/doc-bad-symbol.err |  2 +-
>  2 files changed, 19 insertions(+), 11 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 33/47] qapi: Improve error message on @NAME: in free-form doc
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 33/47] qapi: Improve error message on @NAME: in free-form doc Markus Armbruster
@ 2017-03-14 20:46   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:46 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 452 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py                           | 17 ++++++-----------
>  tests/qapi-schema/doc-invalid-section.err |  2 +-
>  2 files changed, 7 insertions(+), 12 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 35/47] tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 35/47] tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg Markus Armbruster
@ 2017-03-14 20:47   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:47 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1152 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  tests/Makefile.include                                            | 2 +-
>  tests/qapi-schema/doc-bad-args.err                                | 1 -
>  tests/qapi-schema/doc-bad-command-arg.err                         | 1 +
>  tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit} | 0
>  tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json} | 0
>  tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out}   | 0
>  6 files changed, 2 insertions(+), 2 deletions(-)
>  delete mode 100644 tests/qapi-schema/doc-bad-args.err
>  create mode 100644 tests/qapi-schema/doc-bad-command-arg.err
>  rename tests/qapi-schema/{doc-bad-args.exit => doc-bad-command-arg.exit} (100%)
>  rename tests/qapi-schema/{doc-bad-args.json => doc-bad-command-arg.json} (100%)
>  rename tests/qapi-schema/{doc-bad-args.out => doc-bad-command-arg.out} (100%)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 36/47] tests/qapi-schema: Improve coverage of bogus member docs
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 36/47] tests/qapi-schema: Improve coverage of bogus member docs Markus Armbruster
@ 2017-03-14 20:55   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:55 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 383 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> New test doc-bad-union-member.json shows we can fail to reject
> documentation for nonexistent members.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation Markus Armbruster
@ 2017-03-14 20:58   ` Eric Blake
  2017-03-15  7:46     ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-14 20:58 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1334 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> check_definition_doc() checks for member documentation without a
> matching member.  It laboriously second-guesses what members
> QAPISchema._def_exprs() will create.  That's a stupid game.
> 
> Move the check into QAPISchema.check(), where the members are known.
> Delegate the actual checking to new QAPIDoc.check().
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py                             | 38 ++++++++++-------------------
>  tests/qapi-schema/doc-bad-union-member.err  |  1 +
>  tests/qapi-schema/doc-bad-union-member.exit |  2 +-
>  tests/qapi-schema/doc-bad-union-member.out  | 11 ---------
>  4 files changed, 15 insertions(+), 37 deletions(-)

Nice diffstat.


> +++ b/tests/qapi-schema/doc-bad-union-member.err
> @@ -0,0 +1 @@
> +tests/qapi-schema/doc-bad-union-member.json:3: The following documented members are not in the declaration: a, b

Nice that you're able to report all problems within the doc, rather than
stopping at the first.  (Wish we could do the same about the overall
.json file, but that's harder, and out of scope for this series)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 38/47] qapi: Eliminate check_docs() and drop QAPIDoc.expr
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 38/47] qapi: Eliminate check_docs() and drop QAPIDoc.expr Markus Armbruster
@ 2017-03-14 21:00   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 21:00 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 545 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Move what's left in check_docs() to check_expr().  Delegate the actual
> checking to new QAPIDoc.check_expr().
> 
> QAPIDoc.expr is now unused; drop it.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 27 ++++++++++-----------------
>  1 file changed, 10 insertions(+), 17 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 39/47] qapi: Drop unused variable events
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 39/47] qapi: Drop unused variable events Markus Armbruster
@ 2017-03-14 21:02   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-14 21:02 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 647 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Missed in commit e98859a
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 3 ---
>  1 file changed, 3 deletions(-)
> 
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 0da426a..12b1bda 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -49,7 +49,6 @@ name_case_whitelist = []
>  enum_types = []
>  struct_types = []
>  union_types = []
> -events = []
>  all_names = {}

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 40/47] qapi: Simplify what gets stored in enum_types
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 40/47] qapi: Simplify what gets stored in enum_types Markus Armbruster
@ 2017-03-15  0:34   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  0:34 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 541 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Don't invent a new dictionary structure just for enum_types, simply
> store the defining expression, like we do for struct_types and
> union_types.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 29 +++++++++++++++--------------
>  1 file changed, 15 insertions(+), 14 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 41/47] qapi: Factor add_name() calls out of the meta conditional
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 41/47] qapi: Factor add_name() calls out of the meta conditional Markus Armbruster
@ 2017-03-15  0:39   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  0:39 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1300 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 24 +++++++++---------------
>  1 file changed, 9 insertions(+), 15 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

>  def add_enum(definition, info):
>      global enum_types
> -    name = definition['enum']
> -    add_name(name, info, 'enum', 'data' not in definition)

Here, we were passing a potential True for the 'implicit' parameter...


> +        name = expr[meta]
> +        add_name(name, info, meta)

...here, we always pass False, but that's okay (an explicit enum always
has 'data'),

>          if doc and doc.symbol != name:
>              raise QAPISemError(info, "Definition of '%s' follows documentation"
>                                 " for '%s'" % (name, doc.symbol))
> @@ -974,6 +967,7 @@ def check_exprs(exprs):
>          else:
>              continue
>          add_enum({ 'enum': name }, expr_elem['info'])
> +        add_name(name, info, 'enum', implicit=True)

...and here is the only place that was getting implicit=True.  Took me a
while to see it, but the refactoring is sane.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 42/47] qapi: enum_types is a list used like a dict, make it one
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 42/47] qapi: enum_types is a list used like a dict, make it one Markus Armbruster
@ 2017-03-15  0:47   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  0:47 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1438 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 29 ++++++-----------------------
>  1 file changed, 6 insertions(+), 23 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

No idea if python actually behaves more efficiently, but this is a nice
algorithmic change:

> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index f06e3c4..5a3a606 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -46,7 +46,7 @@ returns_whitelist = []
>  # Whitelist of entities allowed to violate case conventions
>  name_case_whitelist = []
>  
> -enum_types = []
> +enum_types = {}
>  struct_types = []
>  union_types = []
>  all_names = {}
> @@ -562,7 +562,7 @@ def find_alternate_member_qtype(qapi_type):
>          return builtin_types[qapi_type]
>      elif find_struct(qapi_type):
>          return 'QTYPE_QDICT'
> -    elif find_enum(qapi_type):
> +    elif qapi_type in enum_types:

A good dictionary uses a tree structure for O(log n), or even hash
lookup for amortized O(1) behavior here,

> -def find_enum(name):
> -    global enum_types
> -    for enum in enum_types:
> -        if enum['enum'] == name:
> -            return enum
> -    return None
> -

while our lookup was O(n) on paper.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 43/47] qapi: struct_types is a list used like a dict, make it one
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 43/47] qapi: struct_types " Markus Armbruster
@ 2017-03-15  1:31   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:31 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 375 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 21 ++++-----------------
>  1 file changed, 4 insertions(+), 17 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 44/47] qapi: union_types is a list used like a dict, make it one
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 44/47] qapi: union_types " Markus Armbruster
@ 2017-03-15  1:34   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:34 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 373 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 19 +++----------------
>  1 file changed, 3 insertions(+), 16 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser Markus Armbruster
  2017-03-13  6:23   ` Markus Armbruster
@ 2017-03-15  1:37   ` Eric Blake
  1 sibling, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:37 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 562 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Results in a more precise error location, but the real reason is
> emptying out check_docs() step by step.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py                         | 20 ++++++++++++++------
>  tests/qapi-schema/doc-empty-section.err |  2 +-
>  2 files changed, 15 insertions(+), 7 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser
  2017-03-13  6:23   ` Markus Armbruster
@ 2017-03-15  1:40     ` Eric Blake
  2017-03-15  7:44       ` Markus Armbruster
  0 siblings, 1 reply; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:40 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1043 bytes --]

On 03/13/2017 01:23 AM, Markus Armbruster wrote:
> Markus Armbruster <armbru@redhat.com> writes:
> 
>> Results in a more precise error location, but the real reason is
>> emptying out check_docs() step by step.
>>
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> 
> Perhaps we should simply drop this error condition.  Are empty sections
> this a mistake users make accidentally?

Parse error; did you mean "empty sections _like_ this"?

I'm okay with keeping the error; especially if we can't guarantee that
the generator copes gracefully with an empty section (different than an
omitted section).  On the other hand, even if we remove the error,
you're probably right that anyone proposing a patch for incorporation
that adds an empty section will have to explain themselves, whether or
not the parser flagged it, and if the error is cheap to maintain in the
parser, then it saves some review cycles.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 45/47] qapi: Drop unused .check_clash() parameter schema
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 45/47] qapi: Drop unused .check_clash() parameter schema Markus Armbruster
@ 2017-03-15  1:46   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:46 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 779 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)

I'm not sure now why the 'schema' parameter was introduced; looks like
it was in commit b807a1e and unused there. I think at one point in my
multitude of refactoring patches that I was using schema for a name
lookup for nicer error reporting, but that idea fell by the wayside over
several revisions, and the 'schema' parameter became unused without
either of us realizing it.

At any rate, the cleanup is sane.
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 46/47] qapi: Make pylint a bit happier
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 46/47] qapi: Make pylint a bit happier Markus Armbruster
@ 2017-03-15  1:47   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:47 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 445 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi-commands.py | 6 +++---
>  scripts/qapi-visit.py    | 1 -
>  scripts/qapi.py          | 8 ++++----
>  3 files changed, 7 insertions(+), 8 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 47/47] qapi: Fix a misleading parser error message
  2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 47/47] qapi: Fix a misleading parser error message Markus Armbruster
@ 2017-03-15  1:48   ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15  1:48 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 790 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> When choking on a token where an expression is expected, we report
> 'Expected "{", "[" or string'.  Close, but no cigar.  Fix it to
> Expected '"{", "[", string, boolean or "null"'.
> 
> Missed in commit e53188a.

Will need adjustment again if we ever start parsing numbers to provide
default values. Maybe we'll remember that time around :)

> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  scripts/qapi.py                           | 3 ++-
>  tests/qapi-schema/trailing-comma-list.err | 2 +-
>  2 files changed, 3 insertions(+), 2 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation
  2017-03-14 15:55   ` Eric Blake
@ 2017-03-15  7:08     ` Markus Armbruster
  2017-03-15 11:53       ` Eric Blake
  0 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:08 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> Rename intermediate qemu-qapi.texi to qemu-qmp-qapi.texi to match its
>> user qemu-qmp-ref.texi, just like qemu-ga-qapi.texi matches
>> qemu-ga-ref.texi.
>> 
>> Build the intermediate .texi next to the sources and the final output
>> in docs/ instead of dumping them into the build root.
>> 
>> Fix version.texi dependencies so that only the targets that actually
>> need it depend on it.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  .gitignore             | 10 +++++-----
>>  Makefile               | 27 +++++++++++++++------------
>>  docs/qemu-qmp-ref.texi |  2 +-
>>  rules.mak              |  2 +-
>>  4 files changed, 22 insertions(+), 19 deletions(-)
>> 
>> diff --git a/.gitignore b/.gitignore
>> index 2849d75..0e99e6a 100644
>> --- a/.gitignore
>> +++ b/.gitignore
>> @@ -103,11 +103,11 @@
>>  /docs/qemu-ga-ref.txt
>
> [1]
>
>>  /docs/qemu-qmp-ref.html
>>  /docs/qemu-qmp-ref.txt
>> -docs/qemu-ga-ref.info*
>> -docs/qemu-qmp-ref.info*
>> -/qemu-ga-qapi.texi
>> -/qemu-qapi.texi
>> -/version.texi
>> +/docs/qemu-ga-ref.info*
>
> worth sorting this line up by [1]?

Fine with me, except I think we should either not mess with the order,
or go all the way, i.e. ...

>> +/docs/qemu-qmp-ref.info*
>> +/docs/qemu-ga-qapi.texi

... move this one, too.  Feeding to sort leads to this incremental
patch:

@@ -99,14 +99,14 @@
 /pc-bios/optionrom/kvmvapic.img
 /pc-bios/s390-ccw/s390-ccw.elf
 /pc-bios/s390-ccw/s390-ccw.img
+/docs/qemu-ga-qapi.texi
 /docs/qemu-ga-ref.html
+/docs/qemu-ga-ref.info*
 /docs/qemu-ga-ref.txt
+/docs/qemu-qmp-qapi.texi
 /docs/qemu-qmp-ref.html
-/docs/qemu-qmp-ref.txt
-/docs/qemu-ga-ref.info*
 /docs/qemu-qmp-ref.info*
-/docs/qemu-ga-qapi.texi
-/docs/qemu-qmp-qapi.texi
+/docs/qemu-qmp-ref.txt
 /docs/version.texi
 *.tps
 .stgit-*

>> +/docs/qemu-qmp-qapi.texi
>> +/docs/version.texi
>>  *.tps
>>  .stgit-*
>>  cscope.*
>> @@ -663,25 +663,28 @@ ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
>>  
>>  # documentation
>>  MAKEINFO=makeinfo
>> -MAKEINFOFLAGS=--no-split --number-sections
>> +MAKEINFOFLAGS=--no-split --number-sections -I docs
>
> Will this cause grief on any older makinfo versions (such as RHEL 6)?  I
> didn't test myself on those setups.  I guess if a buildbot doesn't flag
> you, it's okay.

RHEL-6 has texinfo 4.13, and its manual page documents -I.  No mention
in NEWS, which goes back to 2.2.

> The sorting issue is worth fixing, but trivial, so you can add:
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base
  2017-03-14 15:56   ` Eric Blake
@ 2017-03-15  7:11     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:11 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> The new test case shows off qapi.py choking on an empty union base.
>
> We're still finding ways to choke the parser ;)

At least we're not finding dozens of ways without having to look hard
anymore :)

>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members
  2017-03-14 17:16   ` Eric Blake
@ 2017-03-15  7:12     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:12 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> qapi2texi.py already conjures up ArgSections for undocumented
>> enumeration values, in texi_enum).  Drop that, and conjure them up for
>
> Missing '('?

Or extra ')'.  I'll clean it up.

>> all kinds of "arguments" (enumeration values, object and alternate
>> type members) in qapi.py instead.
>> 
>> Take care to keep generated documentation exactly the same for now.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi.py      |  5 ++---
>>  scripts/qapi2texi.py | 31 ++++++++++++++++---------------
>>  2 files changed, 18 insertions(+), 18 deletions(-)
>> 
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor
  2017-03-14 17:31   ` Eric Blake
@ 2017-03-15  7:14     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:14 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> qapi2texi works with schema expression trees.  Such a tight coupling
>> to schema language syntax is not a good idea.  Convert it to the visitor
>> interface the other generators use.
>> 
>> No change to generated documentation.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi2texi.py | 228 ++++++++++++++++++++++++++-------------------------
>>  1 file changed, 118 insertions(+), 110 deletions(-)
>> 
>
>> +    def visit_object_type(self, name, info, base, members, variants):
>> +        doc = self.cur_doc
>> +        if not variants:
>> +            typ = 'Struct'
>> +        elif variants._tag_name:        # TODO unclean member access
>> +            typ = 'Flat Union'
>> +        else:
>> +            typ = 'Simple Union'
>
> Do we even want to document this distinction to the end user?

No, we don't.  '[PATCH for-2.9 29/47] qapi2texi: Use category "Object"
for all object types' takes care of it.

> Introspection managed to hide the difference by introducing the
> appropriate generated wrapper types that demonstrate the additional {}
> nesting in a way compatible with rewriting simple unions into flat
> unions.  If we don't explain the difference here, we can get rid of the
> unclean member access, but then again risk documentation that is not
> clear whether {} nesting is needed.
>
> I guess there's also the fact that for this patch, you intentionally
> tried to make no difference to the generated docs (good); so any tweaks
> to union output should be later patches anyways.
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop
  2017-03-14 20:14   ` Eric Blake
@ 2017-03-15  7:15     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:15 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> We traditionally mark optional members #optional in the doc comment.
>> Before commit 3313b61, this was entirely manual.
>> 
>> Commit 3313b61 added some automation because its qapi2texi.py relied
>> on #optional to determine whether a member is optional.  This is no
>> longer the case since the previous commit: the only thing qapi2texi.py
>> still does with #optional is stripping it out.  We still reject bogus
>> qapi-schema.json and six places for qga/qapi-schema.json.
>> 
>> Thus, you can't actually rely on #optional to see whether something is
>> optional.  Yet we still make people add it manually.  That's just
>> busy-work.
>> 
>> Drop the code to check, fix up and strip out #optional, along with all
>> instances of #optional.  To keep it out, add code to reject it, to be
>> dropped again once the dust settles.
>> 
>> No change to generated documentation.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  docs/qapi-code-gen.txt              |  16 +-
>>  docs/writing-qmp-commands.txt       |   4 +-
>>  qapi-schema.json                    | 378 ++++++++++++++++----------------
>>  qapi/block-core.json                | 418 ++++++++++++++++++------------------
>
> You'll have to rebase this on master, due to ...
>
>
>> @@ -2349,17 +2349,17 @@
>>  #
>>  # @volume:              Name of the Archipelago volume image
>>  #
>> -# @mport:               #optional The port number on which mapperd is
>> +# @mport:               The port number on which mapperd is
>>  #                       listening. This is optional
>>  #                       and if not specified, QEMU will make Archipelago
>>  #                       use the default port (1001).
>>  #
>
> ...commit e32ccbc killing broken archipelago

Yes.  Thanks for the heads-up.

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop
  2017-03-14 17:59   ` Eric Blake
@ 2017-03-15  7:22     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:22 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> We traditionally mark optional members #optional in the doc comment.
>> Before commit 3313b61, this was entirely manual.
>> 
>> Commit 3313b61 added some automation because its qapi2texi.py relied
>> on #optional to determine whether a member is optional.  This is no
>> longer the case since the previous commit: the only thing qapi2texi.py
>> still does with #optional is stripping it out.  We still reject bogus
>> qapi-schema.json and six places for qga/qapi-schema.json.
>> 
>> Thus, you can't actually rely on #optional to see whether something is
>> optional.  Yet we still make people add it manually.  That's just
>> busy-work.
>
> Yay! Let the computer do the work for us!
>
>> 
>> Drop the code to check, fix up and strip out #optional, along with all
>> instances of #optional.  To keep it out, add code to reject it, to be
>> dropped again once the dust settles.
>> 
>> No change to generated documentation.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
>> @@ -150,10 +148,10 @@ For example:
>>  #
>>  # Statistics of a virtual block device or a block backing device.
>>  #
>> -# @device: #optional If the stats are for a virtual block device, the name
>> -#          corresponding to the virtual block device.
>> +# @device: If the stats are for a virtual block device, the name
>> +# corresponding to the virtual block device.
>
> This loses the hanging indentation in the example, but I don't see you
> making that change in the actual .json files.  It shouldn't matter in
> the long run, and is certainly easier if the way you generated this
> patch was with sed scripts (where computing correct hanging indentation
> after rewrapping is a lot harder than omitting it).

Obvious sed job.

>                                                      I don't have any
> strong opinions about the change (less typing, but slightly harder to
> visually see that the following lines belong to the same parameter doc,
> if you don't have blank lines between distinct parameter docs).  I'm not
> even sure if it you want to call it out in the commit message as an
> intentional reformat, particularly since you didn't do it everywhere.

I'll touch up this patch to change qapi-code-gen.txt exactly like the
schema.

>> +++ b/qapi-schema.json
>> @@ -150,10 +150,10 @@
>>  #
>>  # @fdname: file descriptor name previously passed via 'getfd' command
>>  #
>> -# @skipauth: #optional whether to skip authentication. Only applies
>> +# @skipauth: whether to skip authentication. Only applies
>>  #            to "vnc" and "spice" protocols
>>  #
>> -# @tls: #optional whether to perform TLS. Only applies to the "spice"
>> +# @tls: whether to perform TLS. Only applies to the "spice"
>>  #       protocol
>
> Again, whitespace changes shouldn't affect generated output, so
> rewrapping lines like this would be more busy-work than necessary, even
> though this particular example would now fit on one line.
>
>> @@ -667,45 +667,45 @@
>>  #
> ...
>>  #
>> -# @setup-time: #optional amount of setup time in milliseconds _before_ the
>> +# @setup-time: amount of setup time in milliseconds _before_ the
>>  #        iterations begin but _after_ the QMP command is issued. This is designed
>>  #        to provide an accounting of any activities (such as RDMA pinning) which
>>  #        may be expensive, but do not actually occur during the iterative
>>  #        migration rounds themselves. (since 1.6)
>
> Here's another place where wrapping now looks odd (short, followed by
> multiple longer lines).  Again, the effort of rewrapping lines is not
> worth the churn (and it's actually easier to read diffs that _don't_
> reflow text).  So I'll just overlook wrapping oddities in the rest of
> the patch, as inconsequential to the end result.

A sufficiently clever Emacs macro could give us more pleasantly wrapped
lines, at the cost of a messier diff.  I'll experiment if time permits.

> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation
  2017-03-14 19:12   ` Eric Blake
@ 2017-03-15  7:23     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:23 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> This replaces manual references like "For the arguments, see the
>> documentation of ..." by a generated reference "Arguments: the members
>> of ...".
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  qapi-schema.json     |  2 +-
>>  qapi/block-core.json | 10 ----------
>>  scripts/qapi2texi.py |  8 +++++++-
>>  3 files changed, 8 insertions(+), 12 deletions(-)
>
> Should be even more handy when you add html links to the type
> documentation from the command documentation, later in the series.

Yes, but actual links are left to a later series.

> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members
  2017-03-14 19:29   ` Eric Blake
@ 2017-03-15  7:30     ` Markus Armbruster
  2017-03-15 12:13       ` Eric Blake
  0 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:30 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> The generated documentation doesn't mention object type members
>> inherited from a base type.  Fix that.
>> 
>> Example change (qemu-qmp-ref.txt):
>> 
>>   -- Struct: VncServerInfo
>> 
>>       The network connection information for server
>> 
>>       Members:
>>       'auth' (optional)
>> 	   authentication method used for the plain (non-websocket) VNC
>> 	   server
>> +     The members of 'VncBasicInfo'
>> 
>
> Again, will be more useful later in the series when you add hyperlinking.
>
>>       Since: 2.1
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi2texi.py | 12 ++++++++----
>>  1 file changed, 8 insertions(+), 4 deletions(-)
>> 
>
> Reviewed-by: Eric Blake <eblake@redhat.com>
>
>> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
>> index 993b652..7083d0c 100755
>> --- a/scripts/qapi2texi.py
>> +++ b/scripts/qapi2texi.py
>> @@ -143,7 +143,7 @@ def texi_member(member):
>>          ' (optional)' if member.optional else '')
>>  
>>  
>> -def texi_members(doc, what, member_func):
>> +def texi_members(doc, what, base, member_func):
>>      """Format the table of members"""
>>      items = ''
>>      for section in doc.args.itervalues():
>> @@ -152,6 +152,8 @@ def texi_members(doc, what, member_func):
>>          else:
>>              desc = 'Not documented'
>>          items += member_func(section.member) + texi_format(desc) + '\n'
>> +    if base:
>> +        items += '@item The members of @code{%s}\n' % base.doc_type()
>
> Will this still work for implicit bases?
>
>>  
>> @@ -205,11 +207,13 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>>              typ = 'Flat Union'
>>          else:
>>              typ = 'Simple Union'
>> +        if base and base.is_implicit():
>> +            base = None
>
> Hmm - you just ignore those, such as the anonymous base in CpuInfo.  On
> the other hand, CpuInfo documents its base fields explicitly.  Are we at
> risk of double-documenting a base member, both explicitly and via its
> named base type?

Actually no.

Doc comments should document exactly the members defined locally.  This
includes members of anonymous bases, but not members of named bases.  If
you try to document members of named basses, you get your wrist slapped.
For example, if I do

    diff --git a/qapi-schema.json b/qapi-schema.json
    index 1d7b1cd..4214e97 100644
    --- a/qapi-schema.json
    +++ b/qapi-schema.json
    @@ -1549,6 +1549,7 @@
     #
     # @auth: authentication method used for
     #        the plain (non-websocket) VNC server
    +# @family: address family
     #
     # Since: 2.1
     ##

I get

    qemu/qapi-schema.json:1545: The following documented members are not in the declaration: family

> At any rate, this patch is an incremental improvement, so:
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members
  2017-03-14 19:36   ` Eric Blake
@ 2017-03-15  7:36     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:36 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> A flat union's branch brings in the members of another type.  Generate
>> a suitable reference to that type.
>> 
>> Example change (qemu-qmp-ref.txt):
>> 
>>   -- Flat Union: QCryptoBlockOpenOptions
>> 
>>       The options that are available for all encryption formats when
>>       opening an existing volume
>> 
>>       Members:
>>       The members of 'QCryptoBlockOptionsBase'
>> +     The members of 'QCryptoBlockOptionsQCow' when 'format' is "qcow"
>
> Relies on the implied knowledge that 'format' is a member of
> 'QCryptoBlockOptionsBase'. Does that mean references to another type
> might usefully want to do a list of member names, to avoid having to
> follow the hyperlink, while still leaving the hyperlink when searching

Apropos link: 'format' in 'format is "qcow" could be made one.

> for full details on that member?  As in:
>
> Members:
> The members of 'QCryptoBlockOptionsBase' ('format')
> The members of 'QCryptoBlockOptionsQCow' when 'format' is "qcow"
> ('key-secret')
>
> But it could get noisy (the example here only adds one member; other
> unions add lots of members), and I'm also okay if you don't like the
> idea or would rather do it as a followup.

I figure more than a few members would be too noisy.  Which ones to omit
then?  I'm open to ideas, but it needs to be done as a follow-up, to
give us a chance to fix the QMP documentation regression in time for
2.9.

>> +     The members of 'QCryptoBlockOptionsLUKS' when 'format' is "luks"
>> 
>>       Since: 2.6
>> 
>> A simple union's branch adds a member 'data' of some other type.
>> Generate documentation for that member.
>> 
>> Example change (qemu-qmp-ref.txt):
>> 
>>   -- Simple Union: SocketAddress
>> 
>>       Captures the address of a socket, which could also be a named file
>>       descriptor
>> 
>>       Members:
>>       'type'
>> 	   Not documented
>> +     'data: InetSocketAddress' when 'type' is "inet"
>> +     'data: UnixSocketAddress' when 'type' is "unix"
>> +     'data: VsockSocketAddress' when 'type' is "vsock"
>> +     'data: String' when 'type' is "fd"
>
> Looks reasonable.
>
>> 
>>       Since: 1.3
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi2texi.py | 27 ++++++++++++++++++++-------
>>  1 file changed, 20 insertions(+), 7 deletions(-)
>> 
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch
  2017-03-14 20:35   ` Eric Blake
@ 2017-03-15  7:39     ` Markus Armbruster
  2017-03-15 12:14       ` Eric Blake
  0 siblings, 1 reply; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:39 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> This fixes the errors uncovered by the previous commit.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>
>>  
>>              expr = self.get_expr(False)
>>              if 'include' in expr:
>> +                self.reject_expr_doc()
>>                  if len(expr) != 1:
>
> Do you also need to handle 'pragma' expressions added earlier in the series?

Yes.

> /me goes and experiments:
>
> diff --git i/tests/qapi-schema/doc-bad-expr.json
> w/tests/qapi-schema/doc-bad-expr.json
> index 0caa0ae..6c1204d 100644
> --- i/tests/qapi-schema/doc-bad-expr.json
> +++ w/tests/qapi-schema/doc-bad-expr.json
> @@ -4,4 +4,5 @@
>  # @foo:
>  ##
>  { 'include': 'empty.json' }
> +{ 'pragma': {} }
>  { 'struct': 'foo', 'data': {} }
>
> Oops - back to accepting the program.

Need to squash in

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 1dc33c9..8d55ff4 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -301,6 +301,7 @@ class QAPISchemaParser(object):
                 self._include(include, info, os.path.dirname(abs_fname),
                               previously_included)
             elif "pragma" in expr:
+                self.reject_expr_doc()
                 if len(expr) != 1:
                     raise QAPISemError(info, "Invalid 'pragma' directive")
                 for name, value in expr['pragma'].iteritems():

^ permalink raw reply related	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch
  2017-03-14 20:43   ` Eric Blake
@ 2017-03-15  7:39     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:39 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> Move the check whether the doc matches the expression name from
>> check_definition_doc() to check_exprs().  This changes the error
>> location from the comment to the expression.  Makes sense as the
>> message talks about the expresion: "Definition of '%s' follows
>
> s/expresion/expression/

Will fix.

>> documentation for '%s'".  It's also a step towards getting rid of
>> check_docs().
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi.py                      | 28 ++++++++++++++++++----------
>>  tests/qapi-schema/doc-bad-symbol.err |  2 +-
>>  2 files changed, 19 insertions(+), 11 deletions(-)
>> 
>
> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser
  2017-03-15  1:40     ` Eric Blake
@ 2017-03-15  7:44       ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:44 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:23 AM, Markus Armbruster wrote:
>> Markus Armbruster <armbru@redhat.com> writes:
>> 
>>> Results in a more precise error location, but the real reason is
>>> emptying out check_docs() step by step.
>>>
>>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> 
>> Perhaps we should simply drop this error condition.  Are empty sections
>> this a mistake users make accidentally?
>
> Parse error; did you mean "empty sections _like_ this"?

Yes.

> I'm okay with keeping the error; especially if we can't guarantee that
> the generator copes gracefully with an empty section (different than an
> omitted section).

We'd have to verify it does.

>                    On the other hand, even if we remove the error,
> you're probably right that anyone proposing a patch for incorporation
> that adds an empty section will have to explain themselves, whether or
> not the parser flagged it, and if the error is cheap to maintain in the
> parser, then it saves some review cycles.

The patch adds two methods and changes three existing ones just to catch
empty sections.  I can't help to ask: why bother?

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation
  2017-03-14 20:58   ` Eric Blake
@ 2017-03-15  7:46     ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15  7:46 UTC (permalink / raw)
  To: Eric Blake; +Cc: qemu-devel, marcandre.lureau, mdroth

Eric Blake <eblake@redhat.com> writes:

> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>> check_definition_doc() checks for member documentation without a
>> matching member.  It laboriously second-guesses what members
>> QAPISchema._def_exprs() will create.  That's a stupid game.
>> 
>> Move the check into QAPISchema.check(), where the members are known.
>> Delegate the actual checking to new QAPIDoc.check().
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  scripts/qapi.py                             | 38 ++++++++++-------------------
>>  tests/qapi-schema/doc-bad-union-member.err  |  1 +
>>  tests/qapi-schema/doc-bad-union-member.exit |  2 +-
>>  tests/qapi-schema/doc-bad-union-member.out  | 11 ---------
>>  4 files changed, 15 insertions(+), 37 deletions(-)
>
> Nice diffstat.
>
>
>> +++ b/tests/qapi-schema/doc-bad-union-member.err
>> @@ -0,0 +1 @@
>> +tests/qapi-schema/doc-bad-union-member.json:3: The following documented members are not in the declaration: a, b
>
> Nice that you're able to report all problems within the doc, rather than
> stopping at the first.  (Wish we could do the same about the overall
> .json file, but that's harder, and out of scope for this series)

Nice to have, but whether it would be worth the error recovery
complications is doubtful.

> Reviewed-by: Eric Blake <eblake@redhat.com>

Thanks!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation
  2017-03-15  7:08     ` Markus Armbruster
@ 2017-03-15 11:53       ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15 11:53 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 2028 bytes --]

On 03/15/2017 02:08 AM, Markus Armbruster wrote:

>>> +++ b/.gitignore
>>> @@ -103,11 +103,11 @@
>>>  /docs/qemu-ga-ref.txt
>>
>> [1]
>>
>>>  /docs/qemu-qmp-ref.html
>>>  /docs/qemu-qmp-ref.txt
>>> -docs/qemu-ga-ref.info*
>>> -docs/qemu-qmp-ref.info*
>>> -/qemu-ga-qapi.texi
>>> -/qemu-qapi.texi
>>> -/version.texi
>>> +/docs/qemu-ga-ref.info*
>>
>> worth sorting this line up by [1]?
> 
> Fine with me, except I think we should either not mess with the order,
> or go all the way, i.e. ...
> 
>>> +/docs/qemu-qmp-ref.info*
>>> +/docs/qemu-ga-qapi.texi
> 
> ... move this one, too.  Feeding to sort leads to this incremental
> patch:
> 
> @@ -99,14 +99,14 @@
>  /pc-bios/optionrom/kvmvapic.img
>  /pc-bios/s390-ccw/s390-ccw.elf
>  /pc-bios/s390-ccw/s390-ccw.img
> +/docs/qemu-ga-qapi.texi
>  /docs/qemu-ga-ref.html
> +/docs/qemu-ga-ref.info*
>  /docs/qemu-ga-ref.txt
> +/docs/qemu-qmp-qapi.texi
>  /docs/qemu-qmp-ref.html
> -/docs/qemu-qmp-ref.txt
> -/docs/qemu-ga-ref.info*
>  /docs/qemu-qmp-ref.info*
> -/docs/qemu-ga-qapi.texi
> -/docs/qemu-qmp-qapi.texi
> +/docs/qemu-qmp-ref.txt
>  /docs/version.texi
>  *.tps
>  .stgit-*

Works for me (I always find fully-sorted lists easier to modify, because
I don't have to guess whether inserting new stuff is grouped sanely).


>>>  MAKEINFO=makeinfo
>>> -MAKEINFOFLAGS=--no-split --number-sections
>>> +MAKEINFOFLAGS=--no-split --number-sections -I docs
>>
>> Will this cause grief on any older makinfo versions (such as RHEL 6)?  I
>> didn't test myself on those setups.  I guess if a buildbot doesn't flag
>> you, it's okay.
> 
> RHEL-6 has texinfo 4.13, and its manual page documents -I.  No mention
> in NEWS, which goes back to 2.2.

Phew, we're safe then.

> 
>> The sorting issue is worth fixing, but trivial, so you can add:
>>
>> Reviewed-by: Eric Blake <eblake@redhat.com>
> 
> Thanks!
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members
  2017-03-15  7:30     ` Markus Armbruster
@ 2017-03-15 12:13       ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15 12:13 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1590 bytes --]

On 03/15/2017 02:30 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 

>>> @@ -152,6 +152,8 @@ def texi_members(doc, what, member_func):
>>>          else:
>>>              desc = 'Not documented'
>>>          items += member_func(section.member) + texi_format(desc) + '\n'
>>> +    if base:
>>> +        items += '@item The members of @code{%s}\n' % base.doc_type()
>>
>> Will this still work for implicit bases?
>>
>>>  
>>> @@ -205,11 +207,13 @@ class QAPISchemaGenDocVisitor(qapi.QAPISchemaVisitor):
>>>              typ = 'Flat Union'
>>>          else:
>>>              typ = 'Simple Union'
>>> +        if base and base.is_implicit():
>>> +            base = None
>>
>> Hmm - you just ignore those, such as the anonymous base in CpuInfo.  On
>> the other hand, CpuInfo documents its base fields explicitly.  Are we at
>> risk of double-documenting a base member, both explicitly and via its
>> named base type?
> 
> Actually no.
> 
> Doc comments should document exactly the members defined locally.  This
> includes members of anonymous bases, but not members of named bases.  If
> you try to document members of named basses, you get your wrist slapped.

Cool, we enforce a uniform style.  That's what I was missing.

>> At any rate, this patch is an incremental improvement, so:
>> Reviewed-by: Eric Blake <eblake@redhat.com>

And you've shown me that we don't even need a followup for my original
concern.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch
  2017-03-15  7:39     ` Markus Armbruster
@ 2017-03-15 12:14       ` Eric Blake
  0 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-03-15 12:14 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 1451 bytes --]

On 03/15/2017 02:39 AM, Markus Armbruster wrote:
> Eric Blake <eblake@redhat.com> writes:
> 
>> On 03/13/2017 01:18 AM, Markus Armbruster wrote:
>>> This fixes the errors uncovered by the previous commit.
>>>
>>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>>> ---
>>
>>>  
>>>              expr = self.get_expr(False)
>>>              if 'include' in expr:
>>> +                self.reject_expr_doc()
>>>                  if len(expr) != 1:
>>
>> Do you also need to handle 'pragma' expressions added earlier in the series?
> 
> Yes.
> 

> 
> Need to squash in
> 
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 1dc33c9..8d55ff4 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -301,6 +301,7 @@ class QAPISchemaParser(object):
>                  self._include(include, info, os.path.dirname(abs_fname),
>                                previously_included)
>              elif "pragma" in expr:
> +                self.reject_expr_doc()
>                  if len(expr) != 1:
>                      raise QAPISemError(info, "Invalid 'pragma' directive")
>                  for name, value in expr['pragma'].iteritems():
> 

Yep, that looks like it. So with the test updated in 30/47, and this
squashed into 31/47, you can add:
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-14 13:24 ` Marc-André Lureau
@ 2017-03-15 13:06   ` Markus Armbruster
  0 siblings, 0 replies; 137+ messages in thread
From: Markus Armbruster @ 2017-03-15 13:06 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel, mdroth

Marc-André Lureau <marcandre.lureau@gmail.com> writes:

> Hi
>
> On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <armbru@redhat.com>
> wrote:
>
>> I'm proposing this is 2.9 because it fixes a documentation regression.
>> It affects only documentation; generated C code is unchanged except
>> for the removal of trailing space in PATCH 46.
[...]
> Except the few comments and questions I left, the series looks good to me.
> I don't think we need to rush it in the 2.9 release though, but I will let
> the maintainers decide how to deal with the planning and rules.

Letting documentation quality regress in 2.9 wouldn't be the end of the
world, but this series is as safe as they get, despite its size.

Thanks for your review!

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-14 16:14           ` Markus Armbruster
@ 2017-03-15 14:00             ` Marc-André Lureau
  0 siblings, 0 replies; 137+ messages in thread
From: Marc-André Lureau @ 2017-03-15 14:00 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel, mdroth

Hi

On Tue, Mar 14, 2017 at 8:14 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
>
> > Hi
> >
> > On Mon, Mar 13, 2017 at 5:12 PM Markus Armbruster <armbru@redhat.com>
> wrote:
> >
> >> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
> >>
> >> > Hi
> >> >
> >> > On Mon, Mar 13, 2017 at 4:14 PM Markus Armbruster <armbru@redhat.com>
> wrote:
> >> >
> >> >> Marc-André Lureau <marcandre.lureau@gmail.com> writes:
> >> >>
> >> >> > Hi
> >> >> >
> >> >> > On Mon, Mar 13, 2017 at 10:23 AM Markus Armbruster <
> armbru@redhat.com
> >> >
> >> >> > wrote:
> >> >> >
> >> >> >> I'm proposing this is 2.9 because it fixes a documentation
> regression.
> >> >> >> It affects only documentation; generated C code is unchanged
> except
> >> >> >> for the removal of trailing space in PATCH 46.
> >> >> >>
> >> >> >> Based on my qapi-next branch, which contains Marc-André's PATCH
> 1/2.
> >> >> >>
> >> >> >> Marc-André's work to merge qmp-commands.txt and qmp-events.txt
> into
> >> >> >> the QAPI schema and generate their replacements from the schema
> >> >> >> (commit b6af8ea..56e8bdd) was a big step forward.  As committed,
> it
> >> >> >> also was a step back: the documentation lost information on JSON
> >> >> >> types, because I didn't like Marc-André's patch to add it.  He
> >> >> >> reposted it for further review afterwards:
> >> >> >>
> >> >> >>     Subject: [PATCH 0/2] qapi2texi: add type information
> >> >> >>     Message-Id: <
> 20170125130308.16104-1-marcandre.lureau@redhat.com>
> >> >> >>
> https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg05432.html
> >> >> >>
> >> >> >> His PATCH 1/2 is a straightforward cleanup.  His PATCH 2/2 adds
> type
> >> >> >> descriptions in a new formal language to the generated
> documentation.
> >> >> >> Quoting the commit message:
> >> >> >>
> >> >> >>     Array types have the following syntax: type[]. Ex: str[].
> >> >> >>
> >> >> >>     - Struct, commands and events use the following members
> syntax:
> >> >> >>
> >> >> >>       { 'member': type, ('foo': str), ... }
> >> >> >>
> >> >> >>     Optional members are under parentheses.
> >> >> >>
> >> >> >>     A structure with a base type will have 'BaseStruct +'
> prepended.
> >> >> >>
> >> >> >>     - Alternates use the following syntax:
> >> >> >>
> >> >> >>       [ 'foo': type, 'bar': type, ... ]
> >> >> >>
> >> >> >>     - Simple unions use the following syntax:
> >> >> >>
> >> >> >>       { 'type': str, 'data': 'type' = [ 'foo': type, 'bar':
> type... ] }
> >> >> >>
> >> >> >>     - Flat unions use the following syntax:
> >> >> >>
> >> >> >>       BaseStruct + 'discriminator' = [ 'foo': type, 'bar':
> type... ]
> >> >> >>
> >> >> >> End quote.  Looks like this in generated documentation:
> >> >> >>
> >> >> >>  -- Event: VNC_CONNECTED {'server': VncServerInfo, 'client':
> >> >> >>           VncBasicInfo}
> >> >> >>
> >> >> >>      Emitted when a VNC client establishes a connection
> >> >> >>      ''server''
> >> >> >>           server information
> >> >> >>      ''client''
> >> >> >>           client information
> >> >> >>
> >> >> >>      Note: This event is emitted before any authentication takes
> place,
> >> >> >>      thus the authentication ID is not provided
> >> >> >> [...]
> >> >> >>
> >> >> >>  -- Struct: VncServerInfo VncBasicInfo + {('auth': str)}
> >> >> >>
> >> >> >>      The network connection information for server
> >> >> >>      ''auth'' (optional)
> >> >> >>           authentication method used for the plain
> (non-websocket) VNC
> >> >> >>           server
> >> >> >>
> >> >> >>      Since: 2.1
> >> >> >>
> >> >> >>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' =
> ['inet':
> >> >> >>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
> >> >> >>           VsockSocketAddress, 'fd': String] }
> >> >> >>
> >> >> >>      Captures the address of a socket, which could also be a
> named file
> >> >> >>      descriptor
> >> >> >>
> >> >> >>      Since: 1.3
> >> >> >>
> >> >> >> Here's my counter-proposal: instead of inventing a formal
> language,
> >> >> >> fix the natural language documentation to actually mention *all*
> >> >> >> members, and add type information in a plain, easy-to-understand
> way.
> >> >> >> Looks like this:
> >> >> >>
> >> >> >>  -- Event: VNC_CONNECTED
> >> >> >>
> >> >> >>      Emitted when a VNC client establishes a connection
> >> >> >>
> >> >> >>      Arguments:
> >> >> >>      'server: VncServerInfo'
> >> >> >>           server information
> >> >> >>      'client: VncBasicInfo'
> >> >> >>           client information
> >> >> >>
> >> >> >>      Note: This event is emitted before any authentication takes
> place,
> >> >> >>      thus the authentication ID is not provided
> >> >> >> [...]
> >> >> >>
> >> >> >>  -- Object: VncServerInfo
> >> >> >>
> >> >> >>      The network connection information for server
> >> >> >>
> >> >> >>      Members:
> >> >> >>      'auth: string' (optional)
> >> >> >>           authentication method used for the plain
> (non-websocket) VNC
> >> >> >>           server
> >> >> >>      The members of 'VncBasicInfo'
> >> >> >>
> >> >> >>      Since: 2.1
> >> >> >>
> >> >> >>  -- Object: SocketAddress
> >> >> >>
> >> >> >>      Captures the address of a socket, which could also be a
> named file
> >> >> >>      descriptor
> >> >> >>
> >> >> >>      Members:
> >> >> >>      'type'
> >> >> >>           One of "inet", "unix", "vsock", "fd"
> >> >> >>      'data: InetSocketAddress' when 'type' is "inet"
> >> >> >>      'data: UnixSocketAddress' when 'type' is "unix"
> >> >> >>      'data: VsockSocketAddress' when 'type' is "vsock"
> >> >> >>      'data: String' when 'type' is "fd"
> >> >> >>
> >> >> >>      Since: 1.3
> >> >> >>
> >> >> >>
> >> >> > I like both, to me they serve different purposes. I like to have a
> short
> >> >> > overview / signature and then a more detailed documentation for
> each
> >> >> field.
> >> >>
> >> >> I sympathize with the argument.  Unfortunately, the "short"
> signatures
> >> >> are anything but for real-world QAPI:
> >> >>
> >> >
> >> > That's a worse case, a regular case is more readable.
> >>
> >> There are readable cases, but there are plenty of cases that plainly
> >> aren't.
> >>
> >> 102 out of 472 signatures don't count because they're empty.
> >>
> >> Roughly half the non-empty signatures fit on a single line.  That's
> short.
> >>
> >> A bit under a third take two lines.  I guess that's still short enough.
> >>
> >> More than one in six signatures is three lines or more.
> >>
> >> >                                                       And it is still
> >> > useful anyway since the common members would be listed first.
> >>
> >> Whatever comes first in signatures comes first in the table of members,
> >> too.  The names are easier to spot there, because they're all on the
> >> left.
> >>
> >> Compare
> >>
> >>  -- Simple Union: SocketAddress { 'type': str, 'data': 'type' = ['inet':
> >>           InetSocketAddress, 'unix': UnixSocketAddress, 'vsock':
> >>           VsockSocketAddress, 'fd': String] }
> >>
> >>      Captures the address of a socket, which could also be a named file
> >>      descriptor
> >>
> >>      Since: 1.3
> >>
> >> to
> >>
> >>  -- Object: SocketAddress
> >>
> >>      Captures the address of a socket, which could also be a named file
> >>      descriptor
> >>
> >>      Members:
> >>      'type'
> >>           One of "inet", "unix", "vsock", "fd"
> >>      'data: InetSocketAddress' when 'type' is "inet"
> >>      'data: UnixSocketAddress' when 'type' is "unix"
> >>      'data: VsockSocketAddress' when 'type' is "vsock"
> >>      'data: String' when 'type' is "fd"
> >>
> >>      Since: 1.3
> >>
> >> In my opinion, the three lines of signature add nothing but noise to the
> >> six lines of member table.
> >>
> >
> > It is more natural and faster to read to me for commands and events for
> > example.  The verbose description is mixing description and sometime even
> > providing redundant information (ex: keys: array of KeyValue,  An array
> of
> > 'KeyValue' elements...), slowing reading even more.
>
> Doc comments that merely restate the type should be cleaned up.
>
>
It's not just that, it's also the verbosity of the description that
clutters the information you need.

>                                                     Often you don't need
> to
> > read the documentation / description, you want to quickly check the
> return
> > type, and remind you the arguments.
>
> Point taken.
>
> A formal description of unbounded (and often excessive) length can't
> serve that purpose, though.
>

In which case we are screwed anyway in any form


>
> A sufficiently condensed summaries just might.  Perhaps names only, no
> types.  Certainly no more than a few.
>
> For instance, having
>
>  -- Command: block-job-set-speed device speed
>
> instead of just
>
>  -- Command: block-job-set-speed
>
> feels okay; the additional two words are technically redundant, but they
> might occasionally serve someone as a reminder, and they're not
> distracting.
>

In my generated pdf, using my type proposal (I use it daily), I have:

block-job-set-speed (’device’: str , ’speed’: int )

Which I find useful. I am going to lack it, and in fact I'll probably
maintain my own version of the document if we don't have that declaration
form. At least for a while, until I get used to your type version
eventually).

It feels like bikeshedding at this point, and you are the maintainer, so
I'll probably stop arguing, but it doesn't mean I am satisfied with your
proposal.


> But I feel
>
>  -- Command: blockdev-mirror [job-id] device target [replaces] sync
>           [speed] [granularity] [buf-size] [on-source-error]
>           [on-target-error] [filter-node-name]
>
> is pushing it.
>
> So this begs the question which ones to omit when there are more than a
> few.  I'm afraid asking a stupid computer program to pick out
> "important" arguments is asking for too much.  For high-quality
> summaries, we'd have to pick ourselves.
>
> Moreover, what to do for truly complex commands like blockdev-add?
> Simply omitting all variant members is one option:
>
>  -- Command: blockdev-add driver [node-name] [discard] [cache]
>           [read-only] [detect-zeroes] ...
>
> But what may work for blockdev-add need not work for other complex
> commands.
>
> > struct/objects are more commonly declared with a line per member, so it
> > doesn't bother me as much.
> >
> > I would appreciate if can have the declarative form for commands and
> events
> > at least. Other types are usually more complex or long, so that may clear
> > your concerns for the long declarations.
>
> The worst offenders are actually commands such as blockdev-add and
> block_set_io_throttle, unless we give up on the "reminder" mission for
> them and merely add a reference to their (named) argument type.
>
-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 137+ messages in thread

* Re: [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation
  2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
                   ` (48 preceding siblings ...)
  2017-03-14 13:24 ` Marc-André Lureau
@ 2017-04-27 18:16 ` Eric Blake
  49 siblings, 0 replies; 137+ messages in thread
From: Eric Blake @ 2017-04-27 18:16 UTC (permalink / raw)
  To: Markus Armbruster, qemu-devel; +Cc: marcandre.lureau, mdroth

[-- Attachment #1: Type: text/plain, Size: 2535 bytes --]

On 03/13/2017 01:18 AM, Markus Armbruster wrote:
> I'm proposing this is 2.9 because it fixes a documentation regression.
> It affects only documentation; generated C code is unchanged except
> for the removal of trailing space in PATCH 46.
> 

> Additionally, my series fixes a number of bugs and cleans up along the
> way.  In particular, it converts qapi2texi.py from parse trees to the
> visitor interface the other generators use.
> 
> Future generated documentation work includes eliding types that aren't
> visible in QMP (like introspection does), and making uses of type
> names links in HTML.

Reporting here, so it doesn't get lost in IRC.  Other potential future
work: fix this poor error message:

  GEN     docs/qemu-qmp-qapi.texi
Traceback (most recent call last):
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 300, in <module>
    main(sys.argv)
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 296, in main
    print texi_schema(schema)
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 279, in texi_schema
    gen.symbol(doc, schema.lookup_entity(doc.symbol))
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 263, in symbol
    entity.visit(self)
  File "/home/eblake/qemu/scripts/qapi.py", line 1448, in visit
    visitor.visit_event(self.name, self.info, self.arg_type, self.boxed)
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 259, in visit_event
    body=texi_entity(doc, 'Arguments'))
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 200, in texi_entity
    + texi_sections(doc))
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 160, in texi_members
    items += member_func(section.member) + desc + '\n'
  File "/home/eblake/qemu/scripts/qapi2texi.py", line 138, in texi_member
    typ = member.type.doc_type()
AttributeError: 'NoneType' object has no attribute 'type'
Makefile:706: recipe for target 'docs/qemu-qmp-qapi.texi' failed
make: *** [docs/qemu-qmp-qapi.texi] Error 1
make: *** Deleting file 'docs/qemu-qmp-qapi.texi'

caused by this small change (documenting an event member, but omitting
'data' for the event itself):

diff --git i/qapi/event.json w/qapi/event.json
index 6d22b02..8978b33 100644
--- i/qapi/event.json
+++ w/qapi/event.json
@@ -68,6 +68,8 @@
 #
 # Emitted when the virtual machine is stopped
 #
+# @bogus: new field
+#
 # Since: 0.12.0
 #
 # Example:


-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply related	[flat|nested] 137+ messages in thread

end of thread, other threads:[~2017-04-27 18:16 UTC | newest]

Thread overview: 137+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-13  6:18 [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 01/47] qapi: Factor QAPISchemaParser._include() out of .__init__() Markus Armbruster
2017-03-13 19:34   ` Eric Blake
2017-03-14  8:28   ` Marc-André Lureau
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 02/47] qapi: Make doc comments optional where we don't need them Markus Armbruster
2017-03-13 21:00   ` Eric Blake
2017-03-14  7:21     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 03/47] qapi: Back out doc comments added just to please qapi.py Markus Armbruster
2017-03-13 21:13   ` Eric Blake
2017-03-14  7:26     ` Markus Armbruster
2017-03-14  8:28   ` Marc-André Lureau
2017-03-14  9:45     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 04/47] docs/qapi-code-gen.txt: Drop confusing reference to 'gen' Markus Armbruster
2017-03-13 22:17   ` Eric Blake
2017-03-14  8:30   ` Marc-André Lureau
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 05/47] qapi: Have each QAPI schema declare its returns white-list Markus Armbruster
2017-03-13 22:41   ` Eric Blake
2017-03-14  7:40     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 06/47] qapi: Have each QAPI schema declare its name rule violations Markus Armbruster
2017-03-13 22:46   ` Eric Blake
2017-03-14  7:51     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 07/47] qapi: Clean up build of generated documentation Markus Armbruster
2017-03-14 15:55   ` Eric Blake
2017-03-15  7:08     ` Markus Armbruster
2017-03-15 11:53       ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 08/47] tests/qapi-schema: Cover empty union base Markus Armbruster
2017-03-14  8:41   ` Marc-André Lureau
2017-03-14 15:56   ` Eric Blake
2017-03-15  7:11     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 09/47] qapi: Fix to reject empty union base gracefully Markus Armbruster
2017-03-14  8:40   ` Marc-André Lureau
2017-03-14 15:58   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 10/47] qapi2texi: Fix up output around #optional Markus Armbruster
2017-03-14  8:37   ` Marc-André Lureau
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 11/47] qapi: Avoid unwanted blank lines in QAPIDoc Markus Armbruster
2017-03-14  8:46   ` Marc-André Lureau
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 12/47] qapi/rocker: Fix up doc comment notes on optional members Markus Armbruster
2017-03-14  8:49   ` Marc-André Lureau
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 13/47] qapi: Fix QAPISchemaEnumType.is_implicit() for 'QType' Markus Armbruster
2017-03-14 16:03   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 14/47] qapi: Prepare for requiring more complete documentation Markus Armbruster
2017-03-14 16:08   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 15/47] qapi: Conjure up QAPIDoc.ArgSection for undocumented members Markus Armbruster
2017-03-14 17:16   ` Eric Blake
2017-03-15  7:12     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 16/47] qapi2texi: Convert to QAPISchemaVisitor Markus Armbruster
2017-03-14 17:31   ` Eric Blake
2017-03-15  7:14     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 17/47] qapi: The #optional tag is redundant, drop Markus Armbruster
2017-03-14 17:59   ` Eric Blake
2017-03-15  7:22     ` Markus Armbruster
2017-03-14 20:14   ` Eric Blake
2017-03-15  7:15     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 18/47] qapi: Use raw strings for regular expressions consistently Markus Armbruster
2017-03-14 18:00   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 19/47] qapi: Prefer single-quoted strings more consistently Markus Armbruster
2017-03-14 18:05   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 20/47] qapi2texi: Plainer enum value and member name formatting Markus Armbruster
2017-03-14 18:06   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 21/47] qapi2texi: Present the table of members more clearly Markus Armbruster
2017-03-14 18:08   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 22/47] qapi2texi: Explain enum value undocumentedness " Markus Armbruster
2017-03-14 19:00   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 23/47] qapi2texi: Don't hide undocumented members and arguments Markus Armbruster
2017-03-14 19:02   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 24/47] qapi2texi: Implement boxed argument documentation Markus Armbruster
2017-03-14 19:12   ` Eric Blake
2017-03-15  7:23     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 25/47] qapi2texi: Include member type in generated documentation Markus Armbruster
2017-03-14 12:42   ` Marc-André Lureau
2017-03-14 15:16     ` Markus Armbruster
2017-03-14 19:16   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 26/47] qapi2texi: Generate reference to base type members Markus Armbruster
2017-03-14 19:29   ` Eric Blake
2017-03-15  7:30     ` Markus Armbruster
2017-03-15 12:13       ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 27/47] qapi2texi: Generate documentation for variant members Markus Armbruster
2017-03-14 19:36   ` Eric Blake
2017-03-15  7:36     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 28/47] qapi2texi: Generate descriptions for simple union tags Markus Armbruster
2017-03-14 19:54   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 29/47] qapi2texi: Use category "Object" for all object types Markus Armbruster
2017-03-14 19:56   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 30/47] tests/qapi-schema: Improve doc / expression mismatch coverage Markus Armbruster
2017-03-14 20:02   ` Eric Blake
2017-03-14 20:36   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 31/47] qapi: Fix detection of doc / expression mismatch Markus Armbruster
2017-03-14 20:35   ` Eric Blake
2017-03-15  7:39     ` Markus Armbruster
2017-03-15 12:14       ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 32/47] qapi: Move detection of doc / expression name mismatch Markus Armbruster
2017-03-14 20:43   ` Eric Blake
2017-03-15  7:39     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 33/47] qapi: Improve error message on @NAME: in free-form doc Markus Armbruster
2017-03-14 20:46   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 34/47] qapi: Move empty doc section checking to doc parser Markus Armbruster
2017-03-13  6:23   ` Markus Armbruster
2017-03-15  1:40     ` Eric Blake
2017-03-15  7:44       ` Markus Armbruster
2017-03-15  1:37   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 35/47] tests/qapi-schema: Rename doc-bad-args to doc-bad-command-arg Markus Armbruster
2017-03-14 20:47   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 36/47] tests/qapi-schema: Improve coverage of bogus member docs Markus Armbruster
2017-03-14 20:55   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 37/47] qapi: Fix detection of bogus member documentation Markus Armbruster
2017-03-14 20:58   ` Eric Blake
2017-03-15  7:46     ` Markus Armbruster
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 38/47] qapi: Eliminate check_docs() and drop QAPIDoc.expr Markus Armbruster
2017-03-14 21:00   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 39/47] qapi: Drop unused variable events Markus Armbruster
2017-03-14 21:02   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 40/47] qapi: Simplify what gets stored in enum_types Markus Armbruster
2017-03-15  0:34   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 41/47] qapi: Factor add_name() calls out of the meta conditional Markus Armbruster
2017-03-15  0:39   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 42/47] qapi: enum_types is a list used like a dict, make it one Markus Armbruster
2017-03-15  0:47   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 43/47] qapi: struct_types " Markus Armbruster
2017-03-15  1:31   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 44/47] qapi: union_types " Markus Armbruster
2017-03-15  1:34   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 45/47] qapi: Drop unused .check_clash() parameter schema Markus Armbruster
2017-03-15  1:46   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 46/47] qapi: Make pylint a bit happier Markus Armbruster
2017-03-15  1:47   ` Eric Blake
2017-03-13  6:18 ` [Qemu-devel] [PATCH for-2.9 47/47] qapi: Fix a misleading parser error message Markus Armbruster
2017-03-15  1:48   ` Eric Blake
2017-03-13 10:32 ` [Qemu-devel] [PATCH for-2.9 00/47] qapi: Put type information back into QMP documentation Marc-André Lureau
2017-03-13 12:14   ` Markus Armbruster
2017-03-13 12:21     ` Marc-André Lureau
2017-03-13 13:12       ` Markus Armbruster
2017-03-14 13:22         ` Marc-André Lureau
2017-03-14 16:14           ` Markus Armbruster
2017-03-15 14:00             ` Marc-André Lureau
2017-03-14 13:24 ` Marc-André Lureau
2017-03-15 13:06   ` Markus Armbruster
2017-04-27 18:16 ` Eric Blake

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.