aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-10-01 11:40:15 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-10-01 11:40:15 +0100
commit2094695689f74ff6d6fb273ccecde45a1de88cc2 (patch)
tree27e3593a34499c79244d8b492fdb803baedb793f
parent95e9d74fe4281f7ad79a5a7511400541729aa44a (diff)
parentc615550df306a7b16e75d21f65ee38898c756bac (diff)
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2019-09-28' into staging
QAPI patches for 2019-09-28 # gpg: Signature made Sat 28 Sep 2019 16:18:13 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qapi-2019-09-28: (27 commits) qapi: Improve source file read error handling qapi: Improve reporting of redefinition qapi: Improve reporting of missing documentation comment qapi: Eliminate check_keys(), rename check_known_keys() qapi: Improve reporting of invalid 'if' further qapi: Avoid redundant definition references in error messages qapi: Improve reporting of missing / unknown definition keys qapi: Improve reporting of invalid flags qapi: Improve reporting of invalid 'if' errors qapi: Move context-free checking to the proper place qapi: Move context-sensitive checking to the proper place qapi: Inline check_name() into check_union() qapi: Plumb info to the QAPISchemaMember qapi: Make check_type()'s array case a bit more obvious qapi: Move check for reserved names out of add_name() qapi: Report invalid '*' prefix like any other invalid name qapi: Use check_name_str() where it suffices qapi: Improve reporting of invalid name errors qapi: Reorder check_FOO() parameters for consistency qapi: Improve reporting of member name clashes ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--qapi/qapi-schema.json2
-rw-r--r--qapi/qmp-dispatch.c5
-rw-r--r--scripts/qapi/common.py1052
-rw-r--r--scripts/qapi/events.py2
-rw-r--r--tests/qapi-schema/allow-preconfig-test.err3
-rw-r--r--tests/qapi-schema/alternate-any.err3
-rw-r--r--tests/qapi-schema/alternate-array.err3
-rw-r--r--tests/qapi-schema/alternate-base.err3
-rw-r--r--tests/qapi-schema/alternate-branch-if-invalid.err3
-rw-r--r--tests/qapi-schema/alternate-clash.err3
-rw-r--r--tests/qapi-schema/alternate-conflict-bool-string.err3
-rw-r--r--tests/qapi-schema/alternate-conflict-dict.err3
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-bool.err3
-rw-r--r--tests/qapi-schema/alternate-conflict-enum-int.err3
-rw-r--r--tests/qapi-schema/alternate-conflict-num-string.err3
-rw-r--r--tests/qapi-schema/alternate-conflict-string.err3
-rw-r--r--tests/qapi-schema/alternate-empty.err3
-rw-r--r--tests/qapi-schema/alternate-invalid-dict.err3
-rw-r--r--tests/qapi-schema/alternate-nested.err3
-rw-r--r--tests/qapi-schema/alternate-unknown.err3
-rw-r--r--tests/qapi-schema/args-alternate.err3
-rw-r--r--tests/qapi-schema/args-any.err3
-rw-r--r--tests/qapi-schema/args-array-empty.err3
-rw-r--r--tests/qapi-schema/args-array-unknown.err3
-rw-r--r--tests/qapi-schema/args-bad-boxed.err3
-rw-r--r--tests/qapi-schema/args-boxed-anon.err3
-rw-r--r--tests/qapi-schema/args-boxed-string.err3
-rw-r--r--tests/qapi-schema/args-int.err3
-rw-r--r--tests/qapi-schema/args-invalid.err3
-rw-r--r--tests/qapi-schema/args-member-array-bad.err3
-rw-r--r--tests/qapi-schema/args-member-case.err3
-rw-r--r--tests/qapi-schema/args-member-case.json2
-rw-r--r--tests/qapi-schema/args-member-unknown.err3
-rw-r--r--tests/qapi-schema/args-name-clash.err3
-rw-r--r--tests/qapi-schema/args-union.err3
-rw-r--r--tests/qapi-schema/args-unknown.err3
-rw-r--r--tests/qapi-schema/bad-base.err3
-rw-r--r--tests/qapi-schema/bad-data.err3
-rw-r--r--tests/qapi-schema/bad-ident.err3
-rw-r--r--tests/qapi-schema/bad-if-empty-list.err3
-rw-r--r--tests/qapi-schema/bad-if-empty.err3
-rw-r--r--tests/qapi-schema/bad-if-list.err3
-rw-r--r--tests/qapi-schema/bad-if.err3
-rw-r--r--tests/qapi-schema/bad-type-bool.err2
-rw-r--r--tests/qapi-schema/bad-type-dict.err2
-rw-r--r--tests/qapi-schema/bad-type-int.err2
-rw-r--r--tests/qapi-schema/base-cycle-direct.err3
-rw-r--r--tests/qapi-schema/base-cycle-indirect.err3
-rw-r--r--tests/qapi-schema/command-int.err3
-rw-r--r--tests/qapi-schema/doc-bad-alternate-member.err2
-rw-r--r--tests/qapi-schema/doc-bad-command-arg.err2
-rw-r--r--tests/qapi-schema/doc-bad-symbol.err3
-rw-r--r--tests/qapi-schema/doc-bad-union-member.err2
-rw-r--r--tests/qapi-schema/doc-before-include.err2
-rw-r--r--tests/qapi-schema/doc-before-pragma.err2
-rw-r--r--tests/qapi-schema/doc-duplicated-return.err2
-rw-r--r--tests/qapi-schema/doc-duplicated-since.err2
-rw-r--r--tests/qapi-schema/doc-empty-arg.err2
-rw-r--r--tests/qapi-schema/doc-empty-section.err2
-rw-r--r--tests/qapi-schema/doc-empty-symbol.err2
-rw-r--r--tests/qapi-schema/doc-invalid-end.err2
-rw-r--r--tests/qapi-schema/doc-invalid-end2.err2
-rw-r--r--tests/qapi-schema/doc-invalid-start.err2
-rw-r--r--tests/qapi-schema/doc-missing-colon.err2
-rw-r--r--tests/qapi-schema/doc-missing-expr.err2
-rw-r--r--tests/qapi-schema/doc-missing-space.err2
-rw-r--r--tests/qapi-schema/doc-missing.err3
-rw-r--r--tests/qapi-schema/doc-no-symbol.err2
-rw-r--r--tests/qapi-schema/double-type.err3
-rw-r--r--tests/qapi-schema/duplicate-key.err2
-rw-r--r--tests/qapi-schema/enum-bad-member.err3
-rw-r--r--tests/qapi-schema/enum-bad-name.err3
-rw-r--r--tests/qapi-schema/enum-bad-prefix.err3
-rw-r--r--tests/qapi-schema/enum-clash-member.err3
-rw-r--r--tests/qapi-schema/enum-dict-member-unknown.err3
-rw-r--r--tests/qapi-schema/enum-if-invalid.err3
-rw-r--r--tests/qapi-schema/enum-int-member.err2
-rw-r--r--tests/qapi-schema/enum-member-case.err3
-rw-r--r--tests/qapi-schema/enum-missing-data.err3
-rw-r--r--tests/qapi-schema/enum-wrong-data.err3
-rw-r--r--tests/qapi-schema/escape-outside-string.err2
-rw-r--r--tests/qapi-schema/event-boxed-empty.err3
-rw-r--r--tests/qapi-schema/event-member-invalid-dict.err3
-rw-r--r--tests/qapi-schema/event-nest-struct.err3
-rw-r--r--tests/qapi-schema/features-bad-type.err3
-rw-r--r--tests/qapi-schema/features-duplicate-name.err3
-rw-r--r--tests/qapi-schema/features-if-invalid.err3
-rw-r--r--tests/qapi-schema/features-missing-name.err3
-rw-r--r--tests/qapi-schema/features-name-bad-type.err3
-rw-r--r--tests/qapi-schema/features-no-list.err3
-rw-r--r--tests/qapi-schema/features-unknown-key.err3
-rw-r--r--tests/qapi-schema/flat-union-array-branch.err3
-rw-r--r--tests/qapi-schema/flat-union-bad-base.err3
-rw-r--r--tests/qapi-schema/flat-union-bad-discriminator.err3
-rw-r--r--tests/qapi-schema/flat-union-base-any.err3
-rw-r--r--tests/qapi-schema/flat-union-base-union.err3
-rw-r--r--tests/qapi-schema/flat-union-clash-member.err3
-rw-r--r--tests/qapi-schema/flat-union-discriminator-bad-name.err3
-rw-r--r--tests/qapi-schema/flat-union-discriminator-bad-name.json1
-rw-r--r--tests/qapi-schema/flat-union-empty.err3
-rw-r--r--tests/qapi-schema/flat-union-inline-invalid-dict.err3
-rw-r--r--tests/qapi-schema/flat-union-inline.err3
-rw-r--r--tests/qapi-schema/flat-union-int-branch.err3
-rw-r--r--tests/qapi-schema/flat-union-invalid-branch-key.err3
-rw-r--r--tests/qapi-schema/flat-union-invalid-discriminator.err3
-rw-r--r--tests/qapi-schema/flat-union-invalid-if-discriminator.err3
-rw-r--r--tests/qapi-schema/flat-union-no-base.err3
-rw-r--r--tests/qapi-schema/flat-union-optional-discriminator.err3
-rw-r--r--tests/qapi-schema/flat-union-optional-discriminator.json1
-rw-r--r--tests/qapi-schema/flat-union-string-discriminator.err3
-rw-r--r--tests/qapi-schema/funny-char.err2
-rw-r--r--tests/qapi-schema/funny-word.err2
-rw-r--r--tests/qapi-schema/ident-with-escape.err2
-rw-r--r--tests/qapi-schema/include-before-err.err2
-rw-r--r--tests/qapi-schema/include-cycle.err2
-rw-r--r--tests/qapi-schema/include-extra-junk.err2
-rw-r--r--tests/qapi-schema/include-nested-err.err2
-rw-r--r--tests/qapi-schema/include-no-file.err2
-rw-r--r--tests/qapi-schema/include-non-file.err2
-rw-r--r--tests/qapi-schema/include-self-cycle.err2
-rw-r--r--tests/qapi-schema/leading-comma-list.err2
-rw-r--r--tests/qapi-schema/leading-comma-object.err2
-rw-r--r--tests/qapi-schema/missing-colon.err2
-rw-r--r--tests/qapi-schema/missing-comma-list.err2
-rw-r--r--tests/qapi-schema/missing-comma-object.err2
-rw-r--r--tests/qapi-schema/missing-type.err2
-rw-r--r--tests/qapi-schema/nested-struct-data-invalid-dict.err3
-rw-r--r--tests/qapi-schema/nested-struct-data.err3
-rw-r--r--tests/qapi-schema/non-objects.err2
-rw-r--r--tests/qapi-schema/oob-test.err3
-rw-r--r--tests/qapi-schema/pragma-doc-required-crap.err2
-rw-r--r--tests/qapi-schema/pragma-extra-junk.err2
-rw-r--r--tests/qapi-schema/pragma-name-case-whitelist-crap.err2
-rw-r--r--tests/qapi-schema/pragma-non-dict.err2
-rw-r--r--tests/qapi-schema/pragma-returns-whitelist-crap.err2
-rw-r--r--tests/qapi-schema/pragma-unknown.err2
-rw-r--r--tests/qapi-schema/quoted-structural-chars.err2
-rw-r--r--tests/qapi-schema/redefined-builtin.err3
-rw-r--r--tests/qapi-schema/redefined-command.err5
-rw-r--r--tests/qapi-schema/redefined-event.err5
-rw-r--r--tests/qapi-schema/redefined-type.err5
-rw-r--r--tests/qapi-schema/reserved-command-q.err3
-rw-r--r--tests/qapi-schema/reserved-enum-q.err3
-rw-r--r--tests/qapi-schema/reserved-member-has.err3
-rw-r--r--tests/qapi-schema/reserved-member-q.err3
-rw-r--r--tests/qapi-schema/reserved-member-u.err3
-rw-r--r--tests/qapi-schema/reserved-member-underscore.err3
-rw-r--r--tests/qapi-schema/reserved-type-kind.err3
-rw-r--r--tests/qapi-schema/reserved-type-list.err3
-rw-r--r--tests/qapi-schema/returns-alternate.err3
-rw-r--r--tests/qapi-schema/returns-array-bad.err3
-rw-r--r--tests/qapi-schema/returns-dict.err3
-rw-r--r--tests/qapi-schema/returns-unknown.err3
-rw-r--r--tests/qapi-schema/returns-whitelist.err3
-rw-r--r--tests/qapi-schema/string-code-point-127.err2
-rw-r--r--tests/qapi-schema/string-code-point-31.err2
-rw-r--r--tests/qapi-schema/struct-base-clash-deep.err3
-rw-r--r--tests/qapi-schema/struct-base-clash.err3
-rw-r--r--tests/qapi-schema/struct-data-invalid.err3
-rw-r--r--tests/qapi-schema/struct-member-if-invalid.err3
-rw-r--r--tests/qapi-schema/struct-member-invalid-dict.err3
-rw-r--r--tests/qapi-schema/struct-member-invalid.err3
-rw-r--r--tests/qapi-schema/trailing-comma-list.err2
-rw-r--r--tests/qapi-schema/trailing-comma-object.err2
-rw-r--r--tests/qapi-schema/type-bypass-bad-gen.err3
-rw-r--r--tests/qapi-schema/unclosed-list.err2
-rw-r--r--tests/qapi-schema/unclosed-object.err2
-rw-r--r--tests/qapi-schema/unclosed-string.err2
-rw-r--r--tests/qapi-schema/union-base-empty.err3
-rw-r--r--tests/qapi-schema/union-base-no-discriminator.err3
-rw-r--r--tests/qapi-schema/union-branch-case.err3
-rw-r--r--tests/qapi-schema/union-branch-case.json4
-rw-r--r--tests/qapi-schema/union-branch-if-invalid.err3
-rw-r--r--tests/qapi-schema/union-branch-invalid-dict.err3
-rw-r--r--tests/qapi-schema/union-clash-branches.err3
-rw-r--r--tests/qapi-schema/union-empty.err3
-rw-r--r--tests/qapi-schema/union-invalid-base.err3
-rw-r--r--tests/qapi-schema/union-optional-branch.err3
-rw-r--r--tests/qapi-schema/union-unknown.err3
-rw-r--r--tests/qapi-schema/union-unknown.json2
-rw-r--r--tests/qapi-schema/unknown-escape.err2
-rw-r--r--tests/qapi-schema/unknown-expr-key.err3
-rw-r--r--tests/test-qga.c4
183 files changed, 847 insertions, 698 deletions
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 920b03b0aa..9751b11f8f 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -71,7 +71,7 @@
'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
+ 'CpuInfo' # CPU, visible through query-cpu
] } }
# Documentation generated with qapi-gen.py is in source order, with
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 3037d353a4..bc264b3c9b 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -104,8 +104,9 @@ static QObject *do_qmp_dispatch(QmpCommandList *cmds, QObject *request,
return NULL;
}
if (!cmd->enabled) {
- error_setg(errp, "The command %s has been disabled for this instance",
- command);
+ error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND,
+ "The command %s has been disabled for this instance",
+ command);
return NULL;
}
if (oob && !(cmd->options & QCO_ALLOW_OOB)) {
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index b00caacca3..d6e00c80ea 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -13,6 +13,7 @@
from __future__ import print_function
from contextlib import contextmanager
+import copy
import errno
import os
import re
@@ -20,25 +21,6 @@ import string
import sys
from collections import OrderedDict
-builtin_types = {
- 'null': 'QTYPE_QNULL',
- 'str': 'QTYPE_QSTRING',
- 'int': 'QTYPE_QNUM',
- 'number': 'QTYPE_QNUM',
- 'bool': 'QTYPE_QBOOL',
- 'int8': 'QTYPE_QNUM',
- 'int16': 'QTYPE_QNUM',
- 'int32': 'QTYPE_QNUM',
- 'int64': 'QTYPE_QNUM',
- 'uint8': 'QTYPE_QNUM',
- 'uint16': 'QTYPE_QNUM',
- 'uint32': 'QTYPE_QNUM',
- 'uint64': 'QTYPE_QNUM',
- 'size': 'QTYPE_QNUM',
- 'any': None, # any QType possible, actually
- 'QType': 'QTYPE_QSTRING',
-}
-
# Are documentation comments required?
doc_required = False
@@ -48,39 +30,67 @@ returns_whitelist = []
# Whitelist of entities allowed to violate case conventions
name_case_whitelist = []
-enum_types = {}
-struct_types = {}
-union_types = {}
-all_names = {}
#
# Parsing the schema into expressions
#
+class QAPISourceInfo(object):
+ def __init__(self, fname, line, parent):
+ self.fname = fname
+ self.line = line
+ self.parent = parent
+ self.defn_meta = None
+ self.defn_name = None
+
+ def set_defn(self, meta, name):
+ self.defn_meta = meta
+ self.defn_name = name
+
+ def next_line(self):
+ info = copy.copy(self)
+ info.line += 1
+ return info
+
+ def loc(self):
+ if self.fname is None:
+ return sys.argv[0]
+ ret = self.fname
+ if self.line is not None:
+ ret += ':%d' % self.line
+ return ret
+
+ def in_defn(self):
+ if self.defn_name:
+ return "%s: In %s '%s':\n" % (self.fname,
+ self.defn_meta, self.defn_name)
+ return ''
-def error_path(parent):
- res = ''
- while parent:
- res = ('In file included from %s:%d:\n' % (parent['file'],
- parent['line'])) + res
- parent = parent['parent']
- return res
+ def include_path(self):
+ ret = ''
+ parent = self.parent
+ while parent:
+ ret = 'In file included from %s:\n' % parent.loc() + ret
+ parent = parent.parent
+ return ret
+
+ def __str__(self):
+ return self.include_path() + self.in_defn() + self.loc()
class QAPIError(Exception):
- def __init__(self, fname, line, col, incl_info, msg):
+ def __init__(self, info, col, msg):
Exception.__init__(self)
- self.fname = fname
- self.line = line
+ self.info = info
self.col = col
- self.info = incl_info
self.msg = msg
def __str__(self):
- loc = '%s:%d' % (self.fname, self.line)
+ loc = str(self.info)
if self.col is not None:
+ assert self.info.line is not None
loc += ':%s' % self.col
- return error_path(self.info) + '%s: %s' % (loc, self.msg)
+ return loc + ': ' + self.msg
class QAPIParseError(QAPIError):
@@ -91,14 +101,12 @@ class QAPIParseError(QAPIError):
col = (col + 7) % 8 + 1
else:
col += 1
- QAPIError.__init__(self, parser.fname, parser.line, col,
- parser.incl_info, msg)
+ QAPIError.__init__(self, parser.info, col, msg)
class QAPISemError(QAPIError):
def __init__(self, info, msg):
- QAPIError.__init__(self, info['file'], info['line'], None,
- info['parent'], msg)
+ QAPIError.__init__(self, info, None, msg)
class QAPIDoc(object):
@@ -180,7 +188,7 @@ class QAPIDoc(object):
return
if line[0] != ' ':
- raise QAPIParseError(self._parser, "Missing space after #")
+ raise QAPIParseError(self._parser, "missing space after #")
line = line[1:]
self._append_line(line)
@@ -214,11 +222,11 @@ class QAPIDoc(object):
# recognized, and get silently treated as ordinary text
if not self.symbol and not self.body.text and line.startswith('@'):
if not line.endswith(':'):
- raise QAPIParseError(self._parser, "Line should end with ':'")
+ raise QAPIParseError(self._parser, "line should end with ':'")
self.symbol = line[1:-1]
# FIXME invalid names other than the empty string aren't flagged
if not self.symbol:
- raise QAPIParseError(self._parser, "Invalid name")
+ raise QAPIParseError(self._parser, "invalid name")
elif self.symbol:
# This is a definition documentation block
if name.startswith('@') and name.endswith(':'):
@@ -317,7 +325,7 @@ class QAPIDoc(object):
def _start_symbol_section(self, symbols_dict, name):
# FIXME invalid names other than the empty string aren't flagged
if not name:
- raise QAPIParseError(self._parser, "Invalid parameter name")
+ raise QAPIParseError(self._parser, "invalid parameter name")
if name in symbols_dict:
raise QAPIParseError(self._parser,
"'%s' parameter name duplicated" % name)
@@ -335,7 +343,7 @@ class QAPIDoc(object):
def _start_section(self, name=None):
if name in ('Returns', 'Since') and self.has_section(name):
raise QAPIParseError(self._parser,
- "Duplicated '%s' section" % name)
+ "duplicated '%s' section" % name)
self._end_section()
self._section = QAPIDoc.Section(name)
self.sections.append(self._section)
@@ -344,8 +352,9 @@ class QAPIDoc(object):
if self._section:
text = self._section.text = self._section.text.strip()
if self._section.name and (not text or text.isspace()):
- raise QAPIParseError(self._parser, "Empty doc section '%s'"
- % self._section.name)
+ raise QAPIParseError(
+ self._parser,
+ "empty doc section '%s'" % self._section.name)
self._section = None
def _append_freeform(self, line):
@@ -373,21 +382,32 @@ class QAPIDoc(object):
if bogus:
raise QAPISemError(
self.info,
- "The following documented members are not in "
+ "the following documented members are not in "
"the declaration: %s" % ", ".join(bogus))
class QAPISchemaParser(object):
- def __init__(self, fp, previously_included=[], incl_info=None):
- self.fname = fp.name
- previously_included.append(os.path.abspath(fp.name))
- self.incl_info = incl_info
- self.src = fp.read()
+ def __init__(self, fname, previously_included=[], incl_info=None):
+ previously_included.append(os.path.abspath(fname))
+
+ try:
+ if sys.version_info[0] >= 3:
+ fp = open(fname, 'r', encoding='utf-8')
+ else:
+ fp = open(fname, 'r')
+ self.src = fp.read()
+ except IOError as e:
+ raise QAPISemError(incl_info or QAPISourceInfo(None, None, None),
+ "can't read %s file '%s': %s"
+ % ("include" if incl_info else "schema",
+ fname,
+ e.strerror))
+
if self.src == '' or self.src[-1] != '\n':
self.src += '\n'
self.cursor = 0
- self.line = 1
+ self.info = QAPISourceInfo(fname, 1, incl_info)
self.line_pos = 0
self.exprs = []
self.docs = []
@@ -395,8 +415,7 @@ class QAPISchemaParser(object):
cur_doc = None
while self.tok is not None:
- info = {'file': self.fname, 'line': self.line,
- 'parent': self.incl_info}
+ info = self.info
if self.tok == '#':
self.reject_expr_doc(cur_doc)
cur_doc = self.get_doc(info)
@@ -407,12 +426,12 @@ class QAPISchemaParser(object):
if 'include' in expr:
self.reject_expr_doc(cur_doc)
if len(expr) != 1:
- raise QAPISemError(info, "Invalid 'include' directive")
+ 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_fname = os.path.join(os.path.dirname(self.fname),
+ "value of 'include' must be a string")
+ incl_fname = os.path.join(os.path.dirname(fname),
include)
self.exprs.append({'expr': {'include': incl_fname},
'info': info})
@@ -424,11 +443,11 @@ class QAPISchemaParser(object):
elif "pragma" in expr:
self.reject_expr_doc(cur_doc)
if len(expr) != 1:
- raise QAPISemError(info, "Invalid 'pragma' directive")
+ raise QAPISemError(info, "invalid 'pragma' directive")
pragma = expr['pragma']
if not isinstance(pragma, dict):
raise QAPISemError(
- info, "Value of 'pragma' must be an object")
+ info, "value of 'pragma' must be an object")
for name, value in pragma.items():
self._pragma(name, value, info)
else:
@@ -437,7 +456,7 @@ class QAPISchemaParser(object):
if cur_doc:
if not cur_doc.symbol:
raise QAPISemError(
- cur_doc.info, "Definition documentation required")
+ cur_doc.info, "definition documentation required")
expr_elem['doc'] = cur_doc
self.exprs.append(expr_elem)
cur_doc = None
@@ -448,7 +467,7 @@ class QAPISchemaParser(object):
if doc and doc.symbol:
raise QAPISemError(
doc.info,
- "Documentation for '%s' is not followed by the definition"
+ "documentation for '%s' is not followed by the definition"
% doc.symbol)
def _include(self, include, info, incl_fname, previously_included):
@@ -456,46 +475,39 @@ class QAPISchemaParser(object):
# 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']
+ if incl_abs_fname == os.path.abspath(inf.fname):
+ 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 None
- try:
- if sys.version_info[0] >= 3:
- fobj = open(incl_fname, 'r', encoding='utf-8')
- else:
- fobj = open(incl_fname, 'r')
- except IOError as e:
- raise QAPISemError(info, "%s: %s" % (e.strerror, incl_fname))
- return QAPISchemaParser(fobj, previously_included, info)
+ return QAPISchemaParser(incl_fname, previously_included, info)
def _pragma(self, name, value, info):
global doc_required, returns_whitelist, name_case_whitelist
if name == 'doc-required':
if not isinstance(value, bool):
raise QAPISemError(info,
- "Pragma 'doc-required' must be boolean")
+ "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")
+ raise QAPISemError(
+ info,
+ "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")
+ 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)
+ raise QAPISemError(info, "unknown pragma '%s'" % name)
def accept(self, skip_comment=True):
while True:
@@ -522,13 +534,13 @@ class QAPISchemaParser(object):
ch = self.src[self.cursor]
self.cursor += 1
if ch == '\n':
- raise QAPIParseError(self, "Missing terminating \"'\"")
+ raise QAPIParseError(self, "missing terminating \"'\"")
if esc:
# Note: we recognize only \\ because we have
# no use for funny characters in strings
if ch != '\\':
raise QAPIParseError(self,
- "Unknown escape \\%s" % ch)
+ "unknown escape \\%s" % ch)
esc = False
elif ch == '\\':
esc = True
@@ -538,7 +550,7 @@ class QAPISchemaParser(object):
return
if ord(ch) < 32 or ord(ch) >= 127:
raise QAPIParseError(
- self, "Funny character in string")
+ self, "funny character in string")
string += ch
elif self.src.startswith('true', self.pos):
self.val = True
@@ -552,14 +564,14 @@ class QAPISchemaParser(object):
if self.cursor == len(self.src):
self.tok = None
return
- self.line += 1
+ self.info = self.info.next_line()
self.line_pos = self.cursor
elif not self.tok.isspace():
# Show up to next structural, whitespace or quote
# character
match = re.match('[^[\\]{}:,\\s\'"]+',
self.src[self.cursor-1:])
- raise QAPIParseError(self, "Stray '%s'" % match.group(0))
+ raise QAPIParseError(self, "stray '%s'" % match.group(0))
def get_members(self):
expr = OrderedDict()
@@ -567,24 +579,24 @@ class QAPISchemaParser(object):
self.accept()
return expr
if self.tok != "'":
- raise QAPIParseError(self, "Expected string or '}'")
+ raise QAPIParseError(self, "expected string or '}'")
while True:
key = self.val
self.accept()
if self.tok != ':':
- raise QAPIParseError(self, "Expected ':'")
+ raise QAPIParseError(self, "expected ':'")
self.accept()
if key in expr:
- raise QAPIParseError(self, "Duplicate key '%s'" % key)
+ raise QAPIParseError(self, "duplicate key '%s'" % key)
expr[key] = self.get_expr(True)
if self.tok == '}':
self.accept()
return expr
if self.tok != ',':
- raise QAPIParseError(self, "Expected ',' or '}'")
+ raise QAPIParseError(self, "expected ',' or '}'")
self.accept()
if self.tok != "'":
- raise QAPIParseError(self, "Expected string")
+ raise QAPIParseError(self, "expected string")
def get_values(self):
expr = []
@@ -593,19 +605,19 @@ class QAPISchemaParser(object):
return expr
if self.tok not in "{['tfn":
raise QAPIParseError(
- self, "Expected '{', '[', ']', string, boolean or 'null'")
+ self, "expected '{', '[', ']', string, boolean or 'null'")
while True:
expr.append(self.get_expr(True))
if self.tok == ']':
self.accept()
return expr
if self.tok != ',':
- raise QAPIParseError(self, "Expected ',' or ']'")
+ raise QAPIParseError(self, "expected ',' or ']'")
self.accept()
def get_expr(self, nested):
if self.tok != '{' and not nested:
- raise QAPIParseError(self, "Expected '{'")
+ raise QAPIParseError(self, "expected '{'")
if self.tok == '{':
self.accept()
expr = self.get_members()
@@ -617,13 +629,13 @@ class QAPISchemaParser(object):
self.accept()
else:
raise QAPIParseError(
- self, "Expected '{', '[', string, boolean or 'null'")
+ self, "expected '{', '[', string, boolean or 'null'")
return expr
def get_doc(self, info):
if self.val != '##':
- raise QAPIParseError(self, "Junk after '##' at start of "
- "documentation comment")
+ raise QAPIParseError(
+ self, "junk after '##' at start of documentation comment")
doc = QAPIDoc(self, info)
self.accept(False)
@@ -631,8 +643,9 @@ class QAPISchemaParser(object):
if self.val.startswith('##'):
# End of doc comment
if self.val != '##':
- raise QAPIParseError(self, "Junk after '##' at end of "
- "documentation comment")
+ raise QAPIParseError(
+ self,
+ "junk after '##' at end of documentation comment")
doc.end_comment()
self.accept()
return doc
@@ -640,38 +653,13 @@ class QAPISchemaParser(object):
doc.append(self.val)
self.accept(False)
- raise QAPIParseError(self, "Documentation comment must end with '##'")
+ raise QAPIParseError(self, "documentation comment must end with '##'")
#
-# Semantic analysis of schema expressions
-# TODO fold into QAPISchema
-# TODO catching name collisions in generated code would be nice
+# Check (context-free) schema expression structure
#
-
-def find_base_members(base):
- if isinstance(base, dict):
- return base
- base_struct_define = struct_types.get(base)
- if not base_struct_define:
- return None
- return base_struct_define['data']
-
-
-# Return the qtype of an alternate branch, or None on error.
-def find_alternate_member_qtype(qapi_type):
- if qapi_type in builtin_types:
- return builtin_types[qapi_type]
- elif qapi_type in struct_types:
- return 'QTYPE_QDICT'
- elif qapi_type in enum_types:
- return 'QTYPE_QSTRING'
- elif qapi_type in union_types:
- return 'QTYPE_QDICT'
- return None
-
-
# 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.
@@ -679,18 +667,19 @@ valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
'[a-zA-Z][a-zA-Z0-9_-]*$')
-def check_name(info, source, name, allow_optional=False,
- enum_member=False):
+def check_name_is_str(name, info, source):
+ if not isinstance(name, str):
+ raise QAPISemError(info, "%s requires a string name" % source)
+
+
+def check_name_str(name, info, source,
+ allow_optional=False, enum_member=False,
+ permit_upper=False):
global valid_name
membername = name
- if not isinstance(name, str):
- raise QAPISemError(info, "%s requires a string name" % source)
- if name.startswith('*'):
+ if allow_optional and name.startswith('*'):
membername = name[1:]
- if not allow_optional:
- raise QAPISemError(info, "%s does not allow optional name '%s'"
- % (source, name))
# Enum members can start with a digit, because the generated C
# code always prefixes it with the enum name
if enum_member and membername[0].isdigit():
@@ -699,53 +688,53 @@ def check_name(info, source, name, allow_optional=False,
# and 'q_obj_*' implicit type names.
if not valid_name.match(membername) or \
c_name(membername, False).startswith('q_'):
- raise QAPISemError(info, "%s uses invalid name '%s'" % (source, name))
+ raise QAPISemError(info, "%s has an invalid name" % source)
+ if not permit_upper and name.lower() != name:
+ raise QAPISemError(
+ info, "%s uses uppercase in name" % source)
+ assert not membername.startswith('*')
-def add_name(name, info, meta):
- global all_names
- check_name(info, "'%s'" % meta, name)
- # FIXME should reject names that differ only in '_' vs. '.'
- # vs. '-', because they're liable to clash in generated C.
- if name in all_names:
- raise QAPISemError(info, "%s '%s' is already defined"
- % (all_names[name], name))
+def check_defn_name_str(name, info, meta):
+ check_name_str(name, info, meta, permit_upper=True)
if name.endswith('Kind') or name.endswith('List'):
- raise QAPISemError(info, "%s '%s' should not end in '%s'"
- % (meta, name, name[-4:]))
- all_names[name] = meta
+ raise QAPISemError(
+ info, "%s name should not end in '%s'" % (meta, name[-4:]))
-def check_if(expr, info):
+def check_if(expr, info, source):
def check_if_str(ifcond, info):
if not isinstance(ifcond, str):
raise QAPISemError(
- info, "'if' condition must be a string or a list of strings")
+ info,
+ "'if' condition of %s must be a string or a list of strings"
+ % source)
if ifcond.strip() == '':
- raise QAPISemError(info, "'if' condition '%s' makes no sense"
- % ifcond)
+ raise QAPISemError(
+ info,
+ "'if' condition '%s' of %s makes no sense"
+ % (ifcond, source))
ifcond = expr.get('if')
if ifcond is None:
return
if isinstance(ifcond, list):
if ifcond == []:
- raise QAPISemError(info, "'if' condition [] is useless")
+ raise QAPISemError(
+ info, "'if' condition [] of %s is useless" % source)
for elt in ifcond:
check_if_str(elt, info)
else:
check_if_str(ifcond, info)
-def check_type(info, source, value,
- allow_array=False, allow_dict=False, allow_metas=[]):
- global all_names
-
+def check_type(value, info, source,
+ allow_array=False, allow_dict=False):
if value is None:
return
- # Check if array type for value is okay
+ # Array type
if isinstance(value, list):
if not allow_array:
raise QAPISemError(info, "%s cannot be an array" % source)
@@ -753,18 +742,14 @@ def check_type(info, source, value,
raise QAPISemError(info,
"%s: array type must contain single type name" %
source)
- value = value[0]
+ return
- # Check if type name for value is okay
+ # Type name
if isinstance(value, str):
- if value not in all_names:
- raise QAPISemError(info, "%s uses unknown type '%s'"
- % (source, value))
- if not all_names[value] in allow_metas:
- raise QAPISemError(info, "%s cannot use %s type '%s'" %
- (source, all_names[value], value))
return
+ # Anonymous type
+
if not allow_dict:
raise QAPISemError(info, "%s should be a type name" % source)
@@ -772,57 +757,39 @@ def check_type(info, source, value,
raise QAPISemError(info,
"%s should be an object or type name" % source)
+ permit_upper = allow_dict in name_case_whitelist
+
# value is a dictionary, check that each member is okay
for (key, arg) in value.items():
- check_name(info, "Member of %s" % source, key,
- allow_optional=True)
+ key_source = "%s member '%s'" % (source, key)
+ check_name_str(key, info, key_source,
+ allow_optional=True, permit_upper=permit_upper)
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
- raise QAPISemError(info, "Member of %s uses reserved name '%s'"
- % (source, key))
- # Todo: allow dictionaries to represent default values of
- # an optional argument.
- check_known_keys(info, "member '%s' of %s" % (key, source),
- arg, ['type'], ['if'])
- check_if(arg, info)
+ raise QAPISemError(info, "%s uses reserved name" % key_source)
+ check_keys(arg, info, key_source, ['type'], ['if'])
+ check_if(arg, info, key_source)
normalize_if(arg)
- check_type(info, "Member '%s' of %s" % (key, source),
- arg['type'], allow_array=True,
- allow_metas=['built-in', 'union', 'alternate', 'struct',
- 'enum'])
+ check_type(arg['type'], info, key_source, allow_array=True)
def check_command(expr, info):
- name = expr['command']
+ args = expr.get('data')
+ rets = expr.get('returns')
boxed = expr.get('boxed', False)
- args_meta = ['struct']
- if boxed:
- args_meta += ['union']
- check_type(info, "'data' for command '%s'" % name,
- expr.get('data'), allow_dict=not boxed,
- allow_metas=args_meta)
- returns_meta = ['union', 'struct']
- if name in returns_whitelist:
- returns_meta += ['built-in', 'alternate', 'enum']
- check_type(info, "'returns' for command '%s'" % name,
- expr.get('returns'), allow_array=True,
- allow_metas=returns_meta)
+ if boxed and args is None:
+ raise QAPISemError(info, "'boxed': true requires 'data'")
+ check_type(args, info, "'data'", allow_dict=not boxed)
+ check_type(rets, info, "'returns'", allow_array=True)
def check_event(expr, info):
- name = expr['event']
+ args = expr.get('data')
boxed = expr.get('boxed', False)
- meta = ['struct']
- if boxed:
- meta += ['union']
- check_type(info, "'data' for event '%s'" % name,
- expr.get('data'), allow_dict=not boxed,
- allow_metas=meta)
-
-
-def enum_get_names(expr):
- return [e['name'] for e in expr['data']]
+ if boxed and args is None:
+ raise QAPISemError(info, "'boxed': true requires 'data'")
+ check_type(args, info, "'data'", allow_dict=not boxed)
def check_union(expr, info):
@@ -831,118 +798,36 @@ def check_union(expr, info):
discriminator = expr.get('discriminator')
members = expr['data']
- # Two types of unions, determined by discriminator.
-
- # With no discriminator it is a simple union.
- if discriminator is None:
- enum_values = members.keys()
- allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
+ if discriminator is None: # simple union
if base is not None:
- raise QAPISemError(info, "Simple union '%s' must not have a base" %
- name)
-
- # Else, it's a flat union.
- else:
- # The object must have a string or dictionary 'base'.
- check_type(info, "'base' for union '%s'" % name,
- base, allow_dict=True,
- allow_metas=['struct'])
+ raise QAPISemError(info, "'base' requires 'discriminator'")
+ else: # flat union
+ check_type(base, info, "'base'", allow_dict=name)
if not base:
- raise QAPISemError(info, "Flat union '%s' must have a base"
- % name)
- base_members = find_base_members(base)
- assert base_members is not None
-
- # The value of member 'discriminator' must name a non-optional
- # member of the base struct.
- check_name(info, "Discriminator of flat union '%s'" % name,
- discriminator)
- discriminator_value = base_members.get(discriminator)
- if not discriminator_value:
- raise QAPISemError(info,
- "Discriminator '%s' is not a member of 'base'"
- % discriminator)
- if discriminator_value.get('if'):
- raise QAPISemError(
- info,
- "The discriminator '%s' for union %s must not be conditional"
- % (discriminator, name))
- enum_define = enum_types.get(discriminator_value['type'])
- # Do not allow string discriminator
- if not enum_define:
- raise QAPISemError(info,
- "Discriminator '%s' must be of enumeration "
- "type" % discriminator)
- enum_values = enum_get_names(enum_define)
- allow_metas = ['struct']
-
- if (len(enum_values) == 0):
- raise QAPISemError(info, "Union '%s' has no branches" % name)
+ raise QAPISemError(info, "'discriminator' requires 'base'")
+ check_name_is_str(discriminator, info, "'discriminator'")
for (key, value) in members.items():
- check_name(info, "Member of union '%s'" % name, key)
-
- check_known_keys(info, "member '%s' of union '%s'" % (key, name),
- value, ['type'], ['if'])
- check_if(value, info)
+ source = "'data' member '%s'" % key
+ check_name_str(key, info, source)
+ check_keys(value, info, source, ['type'], ['if'])
+ check_if(value, info, source)
normalize_if(value)
- # Each value must name a known type
- check_type(info, "Member '%s' of union '%s'" % (key, name),
- value['type'],
- allow_array=not base, allow_metas=allow_metas)
-
- # If the discriminator names an enum type, then all members
- # of 'data' must also be members of the enum type.
- if discriminator is not None:
- if key not in enum_values:
- raise QAPISemError(info,
- "Discriminator value '%s' is not found in "
- "enum '%s'"
- % (key, enum_define['enum']))
+ check_type(value['type'], info, source, allow_array=not base)
def check_alternate(expr, info):
- name = expr['alternate']
members = expr['data']
- types_seen = {}
if len(members) == 0:
- raise QAPISemError(info,
- "Alternate '%s' cannot have empty 'data'" % name)
+ raise QAPISemError(info, "'data' must not be empty")
for (key, value) in members.items():
- check_name(info, "Member of alternate '%s'" % name, key)
- check_known_keys(info,
- "member '%s' of alternate '%s'" % (key, name),
- value, ['type'], ['if'])
- check_if(value, info)
+ source = "'data' member '%s'" % key
+ check_name_str(key, info, source)
+ check_keys(value, info, source, ['type'], ['if'])
+ check_if(value, info, source)
normalize_if(value)
- typ = value['type']
-
- # Ensure alternates have no type conflicts.
- check_type(info, "Member '%s' of alternate '%s'" % (key, name), typ,
- allow_metas=['built-in', 'union', 'struct', 'enum'])
- qtype = find_alternate_member_qtype(typ)
- if not qtype:
- raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
- "type '%s'" % (name, key, typ))
- conflicting = set([qtype])
- if qtype == 'QTYPE_QSTRING':
- enum_expr = enum_types.get(typ)
- if enum_expr:
- for v in enum_get_names(enum_expr):
- if v in ['on', 'off']:
- conflicting.add('QTYPE_QBOOL')
- if re.match(r'[-+0-9.]', v): # lazy, could be tightened
- conflicting.add('QTYPE_QNUM')
- else:
- conflicting.add('QTYPE_QNUM')
- conflicting.add('QTYPE_QBOOL')
- for qt in conflicting:
- if qt in types_seen:
- raise QAPISemError(info, "Alternate '%s' member '%s' can't "
- "be distinguished from member '%s'"
- % (name, key, types_seen[qt]))
- types_seen[qt] = key
+ check_type(value['type'], info, source)
def check_enum(expr, info):
@@ -951,19 +836,21 @@ def check_enum(expr, info):
prefix = expr.get('prefix')
if not isinstance(members, list):
- raise QAPISemError(info,
- "Enum '%s' requires an array for 'data'" % name)
+ raise QAPISemError(info, "'data' must be an array")
if prefix is not None and not isinstance(prefix, str):
- raise QAPISemError(info,
- "Enum '%s' requires a string for 'prefix'" % name)
+ raise QAPISemError(info, "'prefix' must be a string")
+
+ permit_upper = name in name_case_whitelist
for member in members:
- check_known_keys(info, "member of enum '%s'" % name, member,
- ['name'], ['if'])
- check_if(member, info)
+ source = "'data' member"
+ check_keys(member, info, source, ['name'], ['if'])
+ check_name_is_str(member['name'], info, source)
+ source = "%s '%s'" % (source, member['name'])
+ check_name_str(member['name'], info, source,
+ enum_member=True, permit_upper=permit_upper)
+ check_if(member, info, source)
normalize_if(member)
- check_name(info, "Member of enum '%s'" % name, member['name'],
- enum_member=True)
def check_struct(expr, info):
@@ -971,63 +858,54 @@ def check_struct(expr, info):
members = expr['data']
features = expr.get('features')
- check_type(info, "'data' for struct '%s'" % name, members,
- allow_dict=True)
- check_type(info, "'base' for struct '%s'" % name, expr.get('base'),
- allow_metas=['struct'])
+ check_type(members, info, "'data'", allow_dict=name)
+ check_type(expr.get('base'), info, "'base'")
if features:
if not isinstance(features, list):
- raise QAPISemError(info,
- "Struct '%s' requires an array for 'features'" %
- name)
+ raise QAPISemError(info, "'features' must be an array")
for f in features:
+ source = "'features' member"
assert isinstance(f, dict)
- check_known_keys(info, "feature of struct %s" % name, f,
- ['name'], ['if'])
-
- check_if(f, info)
+ check_keys(f, info, source, ['name'], ['if'])
+ check_name_is_str(f['name'], info, source)
+ source = "%s '%s'" % (source, f['name'])
+ check_name_str(f['name'], info, source)
+ check_if(f, info, source)
normalize_if(f)
- check_name(info, "Feature of struct %s" % name, f['name'])
-def check_known_keys(info, source, value, required, optional):
+def check_keys(value, info, source, required, optional):
def pprint(elems):
return ', '.join("'" + e + "'" for e in sorted(elems))
missing = set(required) - set(value)
if missing:
- raise QAPISemError(info, "Key%s %s %s missing from %s"
- % ('s' if len(missing) > 1 else '', pprint(missing),
- 'are' if len(missing) > 1 else 'is', source))
+ raise QAPISemError(
+ info,
+ "%s misses key%s %s"
+ % (source, 's' if len(missing) > 1 else '',
+ pprint(missing)))
allowed = set(required + optional)
unknown = set(value) - allowed
if unknown:
- raise QAPISemError(info, "Unknown key%s %s in %s\nValid keys are %s."
- % ('s' if len(unknown) > 1 else '', pprint(unknown),
- source, pprint(allowed)))
+ raise QAPISemError(
+ info,
+ "%s has unknown key%s %s\nValid keys are %s."
+ % (source, 's' if len(unknown) > 1 else '',
+ pprint(unknown), pprint(allowed)))
-def check_keys(expr, info, meta, required, optional=[]):
- name = expr[meta]
- if not isinstance(name, str):
- raise QAPISemError(info, "'%s' key must have a string value" % meta)
- required = required + [meta]
- source = "%s '%s'" % (meta, name)
- check_known_keys(info, source, expr, required, optional)
- for (key, value) in expr.items():
- if key in ['gen', 'success-response'] and value is not False:
- raise QAPISemError(info,
- "'%s' of %s '%s' should only use false value"
- % (key, meta, name))
- if (key in ['boxed', 'allow-oob', 'allow-preconfig']
- and value is not True):
- raise QAPISemError(info,
- "'%s' of %s '%s' should only use true value"
- % (key, meta, name))
- if key == 'if':
- check_if(expr, info)
+def check_flags(expr, info):
+ for key in ['gen', 'success-response']:
+ if key in expr and expr[key] is not False:
+ raise QAPISemError(
+ info, "flag '%s' may only use false value" % key)
+ for key in ['boxed', 'allow-oob', 'allow-preconfig']:
+ if key in expr and expr[key] is not True:
+ raise QAPISemError(
+ info, "flag '%s' may only use true value" % key)
def normalize_enum(expr):
@@ -1057,13 +935,6 @@ def normalize_if(expr):
def check_exprs(exprs):
- global all_names
-
- # 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']
@@ -1072,86 +943,89 @@ def check_exprs(exprs):
if 'include' in expr:
continue
- if not doc and doc_required:
- raise QAPISemError(info,
- "Definition missing documentation comment")
-
if 'enum' in expr:
meta = 'enum'
- check_keys(expr, info, 'enum', ['data'], ['if', 'prefix'])
- normalize_enum(expr)
- enum_types[expr[meta]] = expr
elif 'union' in expr:
meta = 'union'
- check_keys(expr, info, 'union', ['data'],
- ['base', 'discriminator', 'if'])
- normalize_members(expr.get('base'))
- normalize_members(expr['data'])
- union_types[expr[meta]] = expr
elif 'alternate' in expr:
meta = 'alternate'
- check_keys(expr, info, 'alternate', ['data'], ['if'])
- normalize_members(expr['data'])
elif 'struct' in expr:
meta = 'struct'
- check_keys(expr, info, 'struct', ['data'],
- ['base', 'if', 'features'])
- normalize_members(expr['data'])
- normalize_features(expr.get('features'))
- struct_types[expr[meta]] = expr
elif 'command' in expr:
meta = 'command'
- check_keys(expr, info, 'command', [],
- ['data', 'returns', 'gen', 'success-response',
- 'boxed', 'allow-oob', 'allow-preconfig', 'if'])
- normalize_members(expr.get('data'))
elif 'event' in expr:
meta = 'event'
- check_keys(expr, info, 'event', [], ['data', 'boxed', 'if'])
- normalize_members(expr.get('data'))
else:
- raise QAPISemError(info, "Expression is missing metatype")
- normalize_if(expr)
+ raise QAPISemError(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))
+ check_name_is_str(name, info, "'%s'" % meta)
+ info.set_defn(meta, name)
+ check_defn_name_str(name, info, meta)
- # Validate that exprs make sense
- for expr_elem in exprs:
- expr = expr_elem['expr']
- info = expr_elem['info']
- doc = expr_elem.get('doc')
+ if doc:
+ if doc.symbol != name:
+ raise QAPISemError(
+ info, "documentation comment is for '%s'" % doc.symbol)
+ doc.check_expr(expr)
+ elif doc_required:
+ raise QAPISemError(info,
+ "documentation comment required")
- if 'include' in expr:
- continue
- if 'enum' in expr:
+ if meta == 'enum':
+ check_keys(expr, info, meta,
+ ['enum', 'data'], ['if', 'prefix'])
+ normalize_enum(expr)
check_enum(expr, info)
- elif 'union' in expr:
+ elif meta == 'union':
+ check_keys(expr, info, meta,
+ ['union', 'data'],
+ ['base', 'discriminator', 'if'])
+ normalize_members(expr.get('base'))
+ normalize_members(expr['data'])
check_union(expr, info)
- elif 'alternate' in expr:
+ elif meta == 'alternate':
+ check_keys(expr, info, meta,
+ ['alternate', 'data'], ['if'])
+ normalize_members(expr['data'])
check_alternate(expr, info)
- elif 'struct' in expr:
+ elif meta == 'struct':
+ check_keys(expr, info, meta,
+ ['struct', 'data'], ['base', 'if', 'features'])
+ normalize_members(expr['data'])
+ normalize_features(expr.get('features'))
check_struct(expr, info)
- elif 'command' in expr:
+ elif meta == 'command':
+ check_keys(expr, info, meta,
+ ['command'],
+ ['data', 'returns', 'boxed', 'if',
+ 'gen', 'success-response', 'allow-oob',
+ 'allow-preconfig'])
+ normalize_members(expr.get('data'))
check_command(expr, info)
- elif 'event' in expr:
+ elif meta == 'event':
+ check_keys(expr, info, meta,
+ ['event'], ['data', 'boxed', 'if'])
+ normalize_members(expr.get('data'))
check_event(expr, info)
else:
assert False, 'unexpected meta type'
- if doc:
- doc.check_expr(expr)
+ normalize_if(expr)
+ check_if(expr, info, meta)
+ check_flags(expr, info)
return exprs
#
# Schema compiler frontend
+# TODO catching name collisions in generated code would be nice
#
class QAPISchemaEntity(object):
+ meta = None
+
def __init__(self, name, info, doc, ifcond=None):
assert name is None or isinstance(name, str)
self.name = name
@@ -1172,7 +1046,7 @@ class QAPISchemaEntity(object):
def check(self, schema):
assert not self._checked
if self.info:
- self._module = os.path.relpath(self.info['file'],
+ self._module = os.path.relpath(self.info.fname,
os.path.dirname(schema.fname))
self._checked = True
@@ -1192,6 +1066,10 @@ class QAPISchemaEntity(object):
def visit(self, visitor):
assert self._checked
+ def describe(self):
+ assert self.meta
+ return "%s '%s'" % (self.meta, self.name)
+
class QAPISchemaVisitor(object):
def visit_begin(self, schema):
@@ -1282,8 +1160,14 @@ class QAPISchemaType(QAPISchemaEntity):
return None
return self.name
+ def describe(self):
+ assert self.meta
+ return "%s type '%s'" % (self.meta, self.name)
+
class QAPISchemaBuiltinType(QAPISchemaType):
+ meta = 'built-in'
+
def __init__(self, name, json_type, c_type):
QAPISchemaType.__init__(self, name, None, None)
assert not c_type or isinstance(c_type, str)
@@ -1315,11 +1199,13 @@ class QAPISchemaBuiltinType(QAPISchemaType):
class QAPISchemaEnumType(QAPISchemaType):
+ meta = 'enum'
+
def __init__(self, name, info, doc, ifcond, members, prefix):
QAPISchemaType.__init__(self, name, info, doc, ifcond)
for m in members:
assert isinstance(m, QAPISchemaEnumMember)
- m.set_owner(name)
+ m.set_defined_in(name)
assert prefix is None or isinstance(prefix, str)
self.members = members
self.prefix = prefix
@@ -1352,6 +1238,8 @@ class QAPISchemaEnumType(QAPISchemaType):
class QAPISchemaArrayType(QAPISchemaType):
+ meta = 'array'
+
def __init__(self, name, info, element_type):
QAPISchemaType.__init__(self, name, info, None, None)
assert isinstance(element_type, str)
@@ -1360,8 +1248,10 @@ class QAPISchemaArrayType(QAPISchemaType):
def check(self, schema):
QAPISchemaType.check(self, schema)
- self.element_type = schema.lookup_type(self._element_type_name)
- assert self.element_type
+ self.element_type = schema.resolve_type(
+ self._element_type_name, self.info,
+ self.info and self.info.defn_meta)
+ assert not isinstance(self.element_type, QAPISchemaArrayType)
@property
def ifcond(self):
@@ -1393,6 +1283,10 @@ class QAPISchemaArrayType(QAPISchemaType):
visitor.visit_array_type(self.name, self.info, self.ifcond,
self.element_type)
+ def describe(self):
+ assert self.meta
+ return "%s type ['%s']" % (self.meta, self._element_type_name)
+
class QAPISchemaObjectType(QAPISchemaType):
def __init__(self, name, info, doc, ifcond,
@@ -1401,16 +1295,17 @@ class QAPISchemaObjectType(QAPISchemaType):
# flat union has base, variants, and no local_members
# simple union has local_members, variants, and no base
QAPISchemaType.__init__(self, name, info, doc, ifcond)
+ self.meta = 'union' if variants else 'struct'
assert base is None or isinstance(base, str)
for m in local_members:
assert isinstance(m, QAPISchemaObjectTypeMember)
- m.set_owner(name)
+ m.set_defined_in(name)
if variants is not None:
assert isinstance(variants, QAPISchemaObjectTypeVariants)
- variants.set_owner(name)
+ variants.set_defined_in(name)
for f in features:
assert isinstance(f, QAPISchemaFeature)
- f.set_owner(name)
+ f.set_defined_in(name)
self._base_name = base
self.base = None
self.local_members = local_members
@@ -1428,15 +1323,21 @@ class QAPISchemaObjectType(QAPISchemaType):
if self._checked:
# Recursed: C struct contains itself
raise QAPISemError(self.info,
- "Object %s contains itself" % self.name)
+ "object %s contains itself" % self.name)
QAPISchemaType.check(self, schema)
assert self._checked and self.members is None
seen = OrderedDict()
if self._base_name:
- self.base = schema.lookup_type(self._base_name)
- assert isinstance(self.base, QAPISchemaObjectType)
+ self.base = schema.resolve_type(self._base_name, self.info,
+ "'base'")
+ if (not isinstance(self.base, QAPISchemaObjectType)
+ or self.base.variants):
+ raise QAPISemError(
+ self.info,
+ "'base' requires a struct type, %s isn't"
+ % self.base.describe())
self.base.check(schema)
self.base.check_clash(self.info, seen)
for m in self.local_members:
@@ -1448,7 +1349,6 @@ class QAPISchemaObjectType(QAPISchemaType):
if self.variants:
self.variants.check(schema, seen)
- assert self.variants.tag_member in members
self.variants.check_clash(self.info, seen)
# Features are in a name space separate from members
@@ -1516,47 +1416,55 @@ class QAPISchemaMember(object):
""" Represents object members, enum members and features """
role = 'member'
- def __init__(self, name, ifcond=None):
+ def __init__(self, name, info, ifcond=None):
assert isinstance(name, str)
self.name = name
+ self.info = info
self.ifcond = ifcond or []
- self.owner = None
+ self.defined_in = None
- def set_owner(self, name):
- assert not self.owner
- self.owner = name
+ def set_defined_in(self, name):
+ assert not self.defined_in
+ self.defined_in = name
def check_clash(self, info, seen):
cname = c_name(self.name)
- 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:
- raise QAPISemError(info, "%s collides with %s" %
- (self.describe(), seen[cname].describe()))
+ raise QAPISemError(
+ info,
+ "%s collides with %s"
+ % (self.describe(info), seen[cname].describe(info)))
seen[cname] = self
- def _pretty_owner(self):
- owner = self.owner
- if owner.startswith('q_obj_'):
+ def describe(self, info):
+ role = self.role
+ defined_in = self.defined_in
+ assert defined_in
+
+ if defined_in.startswith('q_obj_'):
# See QAPISchema._make_implicit_object_type() - reverse the
# mapping there to create a nice human-readable description
- owner = owner[6:]
- if owner.endswith('-arg'):
- return '(parameter of %s)' % owner[:-4]
- elif owner.endswith('-base'):
- return '(base of %s)' % owner[:-5]
+ defined_in = defined_in[6:]
+ if defined_in.endswith('-arg'):
+ # Implicit type created for a command's dict 'data'
+ assert role == 'member'
+ role = 'parameter'
+ elif defined_in.endswith('-base'):
+ # Implicit type created for a flat union's dict 'base'
+ role = 'base ' + role
else:
- assert owner.endswith('-wrapper')
+ # Implicit type created for a simple union's branch
+ assert defined_in.endswith('-wrapper')
# Unreachable and not implemented
assert False
- if owner.endswith('Kind'):
+ elif defined_in.endswith('Kind'):
# See QAPISchema._make_implicit_enum_type()
- return '(branch of %s)' % owner[:-4]
- return '(%s of %s)' % (self.role, owner)
-
- def describe(self):
- return "'%s' %s" % (self.name, self._pretty_owner())
+ # Implicit enum created for simple union's branches
+ assert role == 'value'
+ role = 'branch'
+ elif defined_in != info.defn_name:
+ return "%s '%s' of type '%s'" % (role, self.name, defined_in)
+ return "%s '%s'" % (role, self.name)
class QAPISchemaEnumMember(QAPISchemaMember):
@@ -1568,8 +1476,8 @@ class QAPISchemaFeature(QAPISchemaMember):
class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, typ, optional, ifcond=None):
- QAPISchemaMember.__init__(self, name, ifcond)
+ def __init__(self, name, info, typ, optional, ifcond=None):
+ QAPISchemaMember.__init__(self, name, info, ifcond)
assert isinstance(typ, str)
assert isinstance(optional, bool)
self._type_name = typ
@@ -1577,13 +1485,13 @@ class QAPISchemaObjectTypeMember(QAPISchemaMember):
self.optional = optional
def check(self, schema):
- assert self.owner
- self.type = schema.lookup_type(self._type_name)
- assert self.type
+ assert self.defined_in
+ self.type = schema.resolve_type(self._type_name, self.info,
+ self.describe)
class QAPISchemaObjectTypeVariants(object):
- def __init__(self, tag_name, tag_member, variants):
+ def __init__(self, tag_name, info, tag_member, variants):
# Flat unions pass tag_name but not tag_member.
# Simple unions and alternates pass tag_member but not tag_name.
# After check(), tag_member is always set, and tag_name remains
@@ -1594,58 +1502,102 @@ class QAPISchemaObjectTypeVariants(object):
for v in variants:
assert isinstance(v, QAPISchemaObjectTypeVariant)
self._tag_name = tag_name
+ self.info = info
self.tag_member = tag_member
self.variants = variants
- def set_owner(self, name):
+ def set_defined_in(self, name):
for v in self.variants:
- v.set_owner(name)
+ v.set_defined_in(name)
def check(self, schema, seen):
- if not self.tag_member: # flat union
- self.tag_member = seen[c_name(self._tag_name)]
- assert self._tag_name == self.tag_member.name
- assert isinstance(self.tag_member.type, QAPISchemaEnumType)
+ if not self.tag_member: # flat union
+ self.tag_member = seen.get(c_name(self._tag_name))
+ base = "'base'"
+ # Pointing to the base type when not implicit would be
+ # nice, but we don't know it here
+ if not self.tag_member or self._tag_name != self.tag_member.name:
+ raise QAPISemError(
+ self.info,
+ "discriminator '%s' is not a member of %s"
+ % (self._tag_name, base))
+ # Here we do:
+ base_type = schema.lookup_type(self.tag_member.defined_in)
+ assert base_type
+ if not base_type.is_implicit():
+ base = "base type '%s'" % self.tag_member.defined_in
+ if not isinstance(self.tag_member.type, QAPISchemaEnumType):
+ raise QAPISemError(
+ self.info,
+ "discriminator member '%s' of %s must be of enum type"
+ % (self._tag_name, base))
+ if self.tag_member.optional:
+ raise QAPISemError(
+ self.info,
+ "discriminator member '%s' of %s must not be optional"
+ % (self._tag_name, base))
+ if self.tag_member.ifcond:
+ raise QAPISemError(
+ self.info,
+ "discriminator member '%s' of %s must not be conditional"
+ % (self._tag_name, base))
+ else: # simple union
+ assert isinstance(self.tag_member.type, QAPISchemaEnumType)
+ assert not self.tag_member.optional
+ assert self.tag_member.ifcond == []
if self._tag_name: # flat union
# branches that are not explicitly covered get an empty type
cases = set([v.name for v in self.variants])
for m in self.tag_member.type.members:
if m.name not in cases:
- v = QAPISchemaObjectTypeVariant(m.name, 'q_empty',
- m.ifcond)
- v.set_owner(self.tag_member.owner)
+ v = QAPISchemaObjectTypeVariant(m.name, self.info,
+ 'q_empty', m.ifcond)
+ v.set_defined_in(self.tag_member.defined_in)
self.variants.append(v)
+ if not self.variants:
+ raise QAPISemError(self.info, "union has no branches")
for v in self.variants:
v.check(schema)
# Union names must match enum values; alternate names are
# checked separately. Use 'seen' to tell the two apart.
if seen:
- assert v.name in self.tag_member.type.member_names()
- assert isinstance(v.type, QAPISchemaObjectType)
+ if v.name not in self.tag_member.type.member_names():
+ raise QAPISemError(
+ self.info,
+ "branch '%s' is not a value of %s"
+ % (v.name, self.tag_member.type.describe()))
+ if (not isinstance(v.type, QAPISchemaObjectType)
+ or v.type.variants):
+ raise QAPISemError(
+ self.info,
+ "%s cannot use %s"
+ % (v.describe(self.info), v.type.describe()))
v.type.check(schema)
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(info, dict(seen))
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
role = 'branch'
- def __init__(self, name, typ, ifcond=None):
- QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
+ def __init__(self, name, info, typ, ifcond=None):
+ QAPISchemaObjectTypeMember.__init__(self, name, info, typ,
+ False, ifcond)
class QAPISchemaAlternateType(QAPISchemaType):
+ meta = 'alternate'
+
def __init__(self, name, info, doc, ifcond, variants):
QAPISchemaType.__init__(self, name, info, doc, ifcond)
assert isinstance(variants, QAPISchemaObjectTypeVariants)
assert variants.tag_member
- variants.set_owner(name)
- variants.tag_member.set_owner(self.name)
+ variants.set_defined_in(name)
+ variants.tag_member.set_defined_in(self.name)
self.variants = variants
def check(self, schema):
@@ -1657,8 +1609,34 @@ class QAPISchemaAlternateType(QAPISchemaType):
# Alternate branch names have no relation to the tag enum values;
# so we have to check for potential name collisions ourselves.
seen = {}
+ types_seen = {}
for v in self.variants.variants:
v.check_clash(self.info, seen)
+ qtype = v.type.alternate_qtype()
+ if not qtype:
+ raise QAPISemError(
+ self.info,
+ "%s cannot use %s"
+ % (v.describe(self.info), v.type.describe()))
+ conflicting = set([qtype])
+ if qtype == 'QTYPE_QSTRING':
+ if isinstance(v.type, QAPISchemaEnumType):
+ for m in v.type.members:
+ if m.name in ['on', 'off']:
+ conflicting.add('QTYPE_QBOOL')
+ if re.match(r'[-+0-9.]', m.name):
+ # lazy, could be tightened
+ conflicting.add('QTYPE_QNUM')
+ else:
+ conflicting.add('QTYPE_QNUM')
+ conflicting.add('QTYPE_QBOOL')
+ for qt in conflicting:
+ if qt in types_seen:
+ raise QAPISemError(
+ self.info,
+ "%s can't be distinguished from '%s'"
+ % (v.describe(self.info), types_seen[qt]))
+ types_seen[qt] = v.name
if self.doc:
self.doc.connect_member(v)
if self.doc:
@@ -1677,6 +1655,8 @@ class QAPISchemaAlternateType(QAPISchemaType):
class QAPISchemaCommand(QAPISchemaEntity):
+ meta = 'command'
+
def __init__(self, name, info, doc, ifcond, arg_type, ret_type,
gen, success_response, boxed, allow_oob, allow_preconfig):
QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
@@ -1695,14 +1675,30 @@ class QAPISchemaCommand(QAPISchemaEntity):
def check(self, schema):
QAPISchemaEntity.check(self, schema)
if self._arg_type_name:
- self.arg_type = schema.lookup_type(self._arg_type_name)
- assert isinstance(self.arg_type, QAPISchemaObjectType)
- assert not self.arg_type.variants or self.boxed
- elif self.boxed:
- raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
+ self.arg_type = schema.resolve_type(
+ self._arg_type_name, self.info, "command's 'data'")
+ if not isinstance(self.arg_type, QAPISchemaObjectType):
+ raise QAPISemError(
+ self.info,
+ "command's 'data' cannot take %s"
+ % self.arg_type.describe())
+ if self.arg_type.variants and not self.boxed:
+ raise QAPISemError(
+ self.info,
+ "command's 'data' can take %s only with 'boxed': true"
+ % self.arg_type.describe())
if self._ret_type_name:
- self.ret_type = schema.lookup_type(self._ret_type_name)
- assert isinstance(self.ret_type, QAPISchemaType)
+ self.ret_type = schema.resolve_type(
+ self._ret_type_name, self.info, "command's 'returns'")
+ if self.name not in returns_whitelist:
+ if not (isinstance(self.ret_type, QAPISchemaObjectType)
+ or (isinstance(self.ret_type, QAPISchemaArrayType)
+ and isinstance(self.ret_type.element_type,
+ QAPISchemaObjectType))):
+ raise QAPISemError(
+ self.info,
+ "command's 'returns' cannot take %s"
+ % self.ret_type.describe())
def visit(self, visitor):
QAPISchemaEntity.visit(self, visitor)
@@ -1714,6 +1710,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
class QAPISchemaEvent(QAPISchemaEntity):
+ meta = 'event'
+
def __init__(self, name, info, doc, ifcond, arg_type, boxed):
QAPISchemaEntity.__init__(self, name, info, doc, ifcond)
assert not arg_type or isinstance(arg_type, str)
@@ -1724,11 +1722,18 @@ class QAPISchemaEvent(QAPISchemaEntity):
def check(self, schema):
QAPISchemaEntity.check(self, schema)
if self._arg_type_name:
- self.arg_type = schema.lookup_type(self._arg_type_name)
- assert isinstance(self.arg_type, QAPISchemaObjectType)
- assert not self.arg_type.variants or self.boxed
- elif self.boxed:
- raise QAPISemError(self.info, "Use of 'boxed' requires 'data'")
+ self.arg_type = schema.resolve_type(
+ self._arg_type_name, self.info, "event's 'data'")
+ if not isinstance(self.arg_type, QAPISchemaObjectType):
+ raise QAPISemError(
+ self.info,
+ "event's 'data' cannot take %s"
+ % self.arg_type.describe())
+ if self.arg_type.variants and not self.boxed:
+ raise QAPISemError(
+ self.info,
+ "event's 'data' can take %s only with 'boxed': true"
+ % self.arg_type.describe())
def visit(self, visitor):
QAPISchemaEntity.visit(self, visitor)
@@ -1739,11 +1744,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
class QAPISchema(object):
def __init__(self, fname):
self.fname = fname
- if sys.version_info[0] >= 3:
- f = open(fname, 'r', encoding='utf-8')
- else:
- f = open(fname, 'r')
- parser = QAPISchemaParser(f)
+ parser = QAPISchemaParser(fname)
exprs = check_exprs(parser.exprs)
self.docs = parser.docs
self._entity_list = []
@@ -1757,10 +1758,21 @@ class QAPISchema(object):
def _def_entity(self, ent):
# Only the predefined types are allowed to not have info
assert ent.info or self._predefining
- assert ent.name is None or ent.name not in self._entity_dict
self._entity_list.append(ent)
- if ent.name is not None:
- self._entity_dict[ent.name] = ent
+ if ent.name is None:
+ return
+ # TODO reject names that differ only in '_' vs. '.' vs. '-',
+ # because they're liable to clash in generated C.
+ other_ent = self._entity_dict.get(ent.name)
+ if other_ent:
+ if other_ent.info:
+ where = QAPIError(other_ent.info, None, "previous definition")
+ raise QAPISemError(
+ ent.info,
+ "'%s' is already defined\n%s" % (ent.name, where))
+ raise QAPISemError(
+ ent.info, "%s is already defined" % other_ent.describe())
+ self._entity_dict[ent.name] = ent
def lookup_entity(self, name, typ=None):
ent = self._entity_dict.get(name)
@@ -1771,13 +1783,22 @@ class QAPISchema(object):
def lookup_type(self, name):
return self.lookup_entity(name, QAPISchemaType)
+ def resolve_type(self, name, info, what):
+ typ = self.lookup_type(name)
+ if not typ:
+ if callable(what):
+ what = what(info)
+ raise QAPISemError(
+ info, "%s uses unknown type '%s'" % (what, name))
+ return typ
+
def _def_include(self, expr, info, doc):
include = expr['include']
assert doc is None
main_info = info
- while main_info['parent']:
- main_info = main_info['parent']
- fname = os.path.relpath(include, os.path.dirname(main_info['file']))
+ while main_info.parent:
+ main_info = main_info.parent
+ fname = os.path.relpath(include, os.path.dirname(main_info.fname))
self._def_entity(QAPISchemaInclude(fname, info))
def _def_builtin_type(self, name, json_type, c_type):
@@ -1811,27 +1832,30 @@ class QAPISchema(object):
qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
'qbool']
- qtype_values = self._make_enum_members([{'name': n} for n in qtypes])
+ qtype_values = self._make_enum_members(
+ [{'name': n} for n in qtypes], None)
self._def_entity(QAPISchemaEnumType('QType', None, None, None,
qtype_values, 'QTYPE'))
- def _make_features(self, features):
- return [QAPISchemaFeature(f['name'], f.get('if')) for f in features]
+ def _make_features(self, features, info):
+ return [QAPISchemaFeature(f['name'], info, f.get('if'))
+ for f in features]
- def _make_enum_members(self, values):
- return [QAPISchemaEnumMember(v['name'], v.get('if'))
+ def _make_enum_members(self, values, info):
+ return [QAPISchemaEnumMember(v['name'], info, v.get('if'))
for v in values]
def _make_implicit_enum_type(self, name, info, ifcond, values):
- # See also QAPISchemaObjectTypeMember._pretty_owner()
- name = name + 'Kind' # Use namespace reserved by add_name()
+ # See also QAPISchemaObjectTypeMember.describe()
+ name = name + 'Kind' # reserved by check_defn_name_str()
self._def_entity(QAPISchemaEnumType(
- name, info, None, ifcond, self._make_enum_members(values), None))
+ name, info, None, ifcond, self._make_enum_members(values, info),
+ None))
return name
def _make_array_type(self, element_type, info):
- name = element_type + 'List' # Use namespace reserved by add_name()
+ name = element_type + 'List' # reserved by check_defn_name_str()
if not self.lookup_type(name):
self._def_entity(QAPISchemaArrayType(name, info, element_type))
return name
@@ -1840,7 +1864,7 @@ class QAPISchema(object):
role, members):
if not members:
return None
- # See also QAPISchemaObjectTypeMember._pretty_owner()
+ # See also QAPISchemaObjectTypeMember.describe()
name = 'q_obj_%s-%s' % (name, role)
typ = self.lookup_entity(name, QAPISchemaObjectType)
if typ:
@@ -1853,7 +1877,7 @@ class QAPISchema(object):
# But it's not tight: the disjunction need not imply it. We
# may end up compiling useless wrapper types.
# TODO kill simple unions or implement the disjunction
- assert ifcond == typ._ifcond # pylint: disable=protected-access
+ assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access
else:
self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
None, members, None, []))
@@ -1866,7 +1890,7 @@ class QAPISchema(object):
ifcond = expr.get('if')
self._def_entity(QAPISchemaEnumType(
name, info, doc, ifcond,
- self._make_enum_members(data), prefix))
+ self._make_enum_members(data, info), prefix))
def _make_member(self, name, typ, ifcond, info):
optional = False
@@ -1876,7 +1900,7 @@ class QAPISchema(object):
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
- return QAPISchemaObjectTypeMember(name, typ, optional, ifcond)
+ return QAPISchemaObjectTypeMember(name, info, typ, optional, ifcond)
def _make_members(self, data, info):
return [self._make_member(key, value['type'], value.get('if'), info)
@@ -1888,13 +1912,14 @@ class QAPISchema(object):
data = expr['data']
ifcond = expr.get('if')
features = expr.get('features', [])
- self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, base,
- self._make_members(data, info),
- None,
- self._make_features(features)))
+ self._def_entity(QAPISchemaObjectType(
+ name, info, doc, ifcond, base,
+ self._make_members(data, info),
+ None,
+ self._make_features(features, info)))
- def _make_variant(self, case, typ, ifcond):
- return QAPISchemaObjectTypeVariant(case, typ, ifcond)
+ def _make_variant(self, case, typ, ifcond, info):
+ return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
def _make_simple_variant(self, case, typ, ifcond, info):
if isinstance(typ, list):
@@ -1903,7 +1928,7 @@ class QAPISchema(object):
typ = self._make_implicit_object_type(
typ, info, None, self.lookup_type(typ),
'wrapper', [self._make_member('data', typ, None, info)])
- return QAPISchemaObjectTypeVariant(case, typ, ifcond)
+ return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
def _def_union_type(self, expr, info, doc):
name = expr['union']
@@ -1917,7 +1942,8 @@ class QAPISchema(object):
name, info, doc, ifcond,
'base', self._make_members(base, info))
if tag_name:
- variants = [self._make_variant(key, value['type'], value.get('if'))
+ variants = [self._make_variant(key, value['type'],
+ value.get('if'), info)
for (key, value) in data.items()]
members = []
else:
@@ -1926,26 +1952,26 @@ class QAPISchema(object):
for (key, value) in data.items()]
enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
typ = self._make_implicit_enum_type(name, info, ifcond, enum)
- tag_member = QAPISchemaObjectTypeMember('type', typ, False)
+ tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
members = [tag_member]
self._def_entity(
QAPISchemaObjectType(name, info, doc, ifcond, base, members,
- QAPISchemaObjectTypeVariants(tag_name,
- tag_member,
- variants), []))
+ QAPISchemaObjectTypeVariants(
+ tag_name, info, tag_member, variants),
+ []))
def _def_alternate_type(self, expr, info, doc):
name = expr['alternate']
data = expr['data']
ifcond = expr.get('if')
- variants = [self._make_variant(key, value['type'], value.get('if'))
+ variants = [self._make_variant(key, value['type'], value.get('if'),
+ info)
for (key, value) in data.items()]
- tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
+ tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
self._def_entity(
QAPISchemaAlternateType(name, info, doc, ifcond,
- QAPISchemaObjectTypeVariants(None,
- tag_member,
- variants)))
+ QAPISchemaObjectTypeVariants(
+ None, info, tag_member, variants)))
def _def_command(self, expr, info, doc):
name = expr['command']
@@ -2237,7 +2263,7 @@ const QEnumLookup %(c_name)s_lookup = {
def gen_enum(name, members, prefix=None):
# append automatically generated _MAX value
- enum_members = members + [QAPISchemaEnumMember('_MAX')]
+ enum_members = members + [QAPISchemaEnumMember('_MAX', None)]
ret = mcgen('''
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index 7062553cf3..7308e8e589 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -194,7 +194,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
self._event_emit_name))
# Note: we generate the enum member regardless of @ifcond, to
# keep the enumeration usable in target-independent code.
- self._event_enum_members.append(QAPISchemaEnumMember(name))
+ self._event_enum_members.append(QAPISchemaEnumMember(name, None))
def gen_events(schema, output_dir, prefix):
diff --git a/tests/qapi-schema/allow-preconfig-test.err b/tests/qapi-schema/allow-preconfig-test.err
index 700d583306..2a4e6ce663 100644
--- a/tests/qapi-schema/allow-preconfig-test.err
+++ b/tests/qapi-schema/allow-preconfig-test.err
@@ -1 +1,2 @@
-tests/qapi-schema/allow-preconfig-test.json:2: 'allow-preconfig' of command 'allow-preconfig-test' should only use true value
+tests/qapi-schema/allow-preconfig-test.json: In command 'allow-preconfig-test':
+tests/qapi-schema/allow-preconfig-test.json:2: flag 'allow-preconfig' may only use true value
diff --git a/tests/qapi-schema/alternate-any.err b/tests/qapi-schema/alternate-any.err
index aaa0154731..03aaf29506 100644
--- a/tests/qapi-schema/alternate-any.err
+++ b/tests/qapi-schema/alternate-any.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any'
+tests/qapi-schema/alternate-any.json: In alternate 'Alt':
+tests/qapi-schema/alternate-any.json:2: branch 'one' cannot use built-in type 'any'
diff --git a/tests/qapi-schema/alternate-array.err b/tests/qapi-schema/alternate-array.err
index 7b930c64ab..dfbe3ee998 100644
--- a/tests/qapi-schema/alternate-array.err
+++ b/tests/qapi-schema/alternate-array.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-array.json:5: Member 'two' of alternate 'Alt' cannot be an array
+tests/qapi-schema/alternate-array.json: In alternate 'Alt':
+tests/qapi-schema/alternate-array.json:5: 'data' member 'two' cannot be an array
diff --git a/tests/qapi-schema/alternate-base.err b/tests/qapi-schema/alternate-base.err
index ebe05bc898..04cea97e5c 100644
--- a/tests/qapi-schema/alternate-base.err
+++ b/tests/qapi-schema/alternate-base.err
@@ -1,2 +1,3 @@
-tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'
+tests/qapi-schema/alternate-base.json: In alternate 'Alt':
+tests/qapi-schema/alternate-base.json:4: alternate has unknown key 'base'
Valid keys are 'alternate', 'data', 'if'.
diff --git a/tests/qapi-schema/alternate-branch-if-invalid.err b/tests/qapi-schema/alternate-branch-if-invalid.err
index f1d6c10e00..6c68e5a922 100644
--- a/tests/qapi-schema/alternate-branch-if-invalid.err
+++ b/tests/qapi-schema/alternate-branch-if-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-branch-if-invalid.json:2: 'if' condition ' ' makes no sense
+tests/qapi-schema/alternate-branch-if-invalid.json: In alternate 'Alt':
+tests/qapi-schema/alternate-branch-if-invalid.json:2: 'if' condition ' ' of 'data' member 'branch' makes no sense
diff --git a/tests/qapi-schema/alternate-clash.err b/tests/qapi-schema/alternate-clash.err
index 604d8495eb..73a52d69d1 100644
--- a/tests/qapi-schema/alternate-clash.err
+++ b/tests/qapi-schema/alternate-clash.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1)
+tests/qapi-schema/alternate-clash.json: In alternate 'Alt1':
+tests/qapi-schema/alternate-clash.json:7: branch 'a_b' collides with branch 'a-b'
diff --git a/tests/qapi-schema/alternate-conflict-bool-string.err b/tests/qapi-schema/alternate-conflict-bool-string.err
index e52fee7620..f7513b9cbe 100644
--- a/tests/qapi-schema/alternate-conflict-bool-string.err
+++ b/tests/qapi-schema/alternate-conflict-bool-string.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-conflict-bool-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-bool-string.json: In alternate 'Alt':
+tests/qapi-schema/alternate-conflict-bool-string.json:2: branch 'two' can't be distinguished from 'one'
diff --git a/tests/qapi-schema/alternate-conflict-dict.err b/tests/qapi-schema/alternate-conflict-dict.err
index 0f411f4faf..e5b42d04c9 100644
--- a/tests/qapi-schema/alternate-conflict-dict.err
+++ b/tests/qapi-schema/alternate-conflict-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-conflict-dict.json:6: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-dict.json: In alternate 'Alt':
+tests/qapi-schema/alternate-conflict-dict.json:6: branch 'two' can't be distinguished from 'one'
diff --git a/tests/qapi-schema/alternate-conflict-enum-bool.err b/tests/qapi-schema/alternate-conflict-enum-bool.err
index 0dfc00242d..3d23aeba51 100644
--- a/tests/qapi-schema/alternate-conflict-enum-bool.err
+++ b/tests/qapi-schema/alternate-conflict-enum-bool.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-conflict-enum-bool.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-enum-bool.json: In alternate 'Alt':
+tests/qapi-schema/alternate-conflict-enum-bool.json:4: branch 'two' can't be distinguished from 'one'
diff --git a/tests/qapi-schema/alternate-conflict-enum-int.err b/tests/qapi-schema/alternate-conflict-enum-int.err
index 2cc8e7b9aa..b72768caa4 100644
--- a/tests/qapi-schema/alternate-conflict-enum-int.err
+++ b/tests/qapi-schema/alternate-conflict-enum-int.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-conflict-enum-int.json:4: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-enum-int.json: In alternate 'Alt':
+tests/qapi-schema/alternate-conflict-enum-int.json:4: branch 'two' can't be distinguished from 'one'
diff --git a/tests/qapi-schema/alternate-conflict-num-string.err b/tests/qapi-schema/alternate-conflict-num-string.err
index 5ba3827dd1..b8a2bb1829 100644
--- a/tests/qapi-schema/alternate-conflict-num-string.err
+++ b/tests/qapi-schema/alternate-conflict-num-string.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-conflict-num-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-num-string.json: In alternate 'Alt':
+tests/qapi-schema/alternate-conflict-num-string.json:2: branch 'two' can't be distinguished from 'one'
diff --git a/tests/qapi-schema/alternate-conflict-string.err b/tests/qapi-schema/alternate-conflict-string.err
index fe2f188295..3edec51911 100644
--- a/tests/qapi-schema/alternate-conflict-string.err
+++ b/tests/qapi-schema/alternate-conflict-string.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-conflict-string.json:2: Alternate 'Alt' member 'two' can't be distinguished from member 'one'
+tests/qapi-schema/alternate-conflict-string.json: In alternate 'Alt':
+tests/qapi-schema/alternate-conflict-string.json:2: branch 'two' can't be distinguished from 'one'
diff --git a/tests/qapi-schema/alternate-empty.err b/tests/qapi-schema/alternate-empty.err
index 86dbc666eb..908c309518 100644
--- a/tests/qapi-schema/alternate-empty.err
+++ b/tests/qapi-schema/alternate-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' cannot have empty 'data'
+tests/qapi-schema/alternate-empty.json: In alternate 'Alt':
+tests/qapi-schema/alternate-empty.json:2: 'data' must not be empty
diff --git a/tests/qapi-schema/alternate-invalid-dict.err b/tests/qapi-schema/alternate-invalid-dict.err
index 631d46628e..d6a18a294b 100644
--- a/tests/qapi-schema/alternate-invalid-dict.err
+++ b/tests/qapi-schema/alternate-invalid-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-invalid-dict.json:2: Key 'type' is missing from member 'two' of alternate 'Alt'
+tests/qapi-schema/alternate-invalid-dict.json: In alternate 'Alt':
+tests/qapi-schema/alternate-invalid-dict.json:2: 'data' member 'two' misses key 'type'
diff --git a/tests/qapi-schema/alternate-nested.err b/tests/qapi-schema/alternate-nested.err
index 4d1187e60e..cd7a076ce5 100644
--- a/tests/qapi-schema/alternate-nested.err
+++ b/tests/qapi-schema/alternate-nested.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-nested.json:4: Member 'nested' of alternate 'Alt2' cannot use alternate type 'Alt1'
+tests/qapi-schema/alternate-nested.json: In alternate 'Alt2':
+tests/qapi-schema/alternate-nested.json:4: branch 'nested' cannot use alternate type 'Alt1'
diff --git a/tests/qapi-schema/alternate-unknown.err b/tests/qapi-schema/alternate-unknown.err
index dea45dc730..df05860bba 100644
--- a/tests/qapi-schema/alternate-unknown.err
+++ b/tests/qapi-schema/alternate-unknown.err
@@ -1 +1,2 @@
-tests/qapi-schema/alternate-unknown.json:2: Member 'unknown' of alternate 'Alt' uses unknown type 'MissingType'
+tests/qapi-schema/alternate-unknown.json: In alternate 'Alt':
+tests/qapi-schema/alternate-unknown.json:2: branch 'unknown' uses unknown type 'MissingType'
diff --git a/tests/qapi-schema/args-alternate.err b/tests/qapi-schema/args-alternate.err
index 3086eae56b..852b81b89c 100644
--- a/tests/qapi-schema/args-alternate.err
+++ b/tests/qapi-schema/args-alternate.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt'
+tests/qapi-schema/args-alternate.json: In command 'oops':
+tests/qapi-schema/args-alternate.json:3: command's 'data' cannot take alternate type 'Alt'
diff --git a/tests/qapi-schema/args-any.err b/tests/qapi-schema/args-any.err
index bf9b5e0730..04e11df29f 100644
--- a/tests/qapi-schema/args-any.err
+++ b/tests/qapi-schema/args-any.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any'
+tests/qapi-schema/args-any.json: In command 'oops':
+tests/qapi-schema/args-any.json:2: command's 'data' cannot take built-in type 'any'
diff --git a/tests/qapi-schema/args-array-empty.err b/tests/qapi-schema/args-array-empty.err
index cb7ed33b3f..c7d367730e 100644
--- a/tests/qapi-schema/args-array-empty.err
+++ b/tests/qapi-schema/args-array-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name
+tests/qapi-schema/args-array-empty.json: In command 'oops':
+tests/qapi-schema/args-array-empty.json:2: 'data' member 'empty': array type must contain single type name
diff --git a/tests/qapi-schema/args-array-unknown.err b/tests/qapi-schema/args-array-unknown.err
index cd7a0f98d7..218fc4bf9a 100644
--- a/tests/qapi-schema/args-array-unknown.err
+++ b/tests/qapi-schema/args-array-unknown.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/args-array-unknown.json: In command 'oops':
+tests/qapi-schema/args-array-unknown.json:2: command uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/args-bad-boxed.err b/tests/qapi-schema/args-bad-boxed.err
index ad0d417321..31d39038fc 100644
--- a/tests/qapi-schema/args-bad-boxed.err
+++ b/tests/qapi-schema/args-bad-boxed.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-bad-boxed.json:2: 'boxed' of command 'foo' should only use true value
+tests/qapi-schema/args-bad-boxed.json: In command 'foo':
+tests/qapi-schema/args-bad-boxed.json:2: flag 'boxed' may only use true value
diff --git a/tests/qapi-schema/args-boxed-anon.err b/tests/qapi-schema/args-boxed-anon.err
index f24f345218..5e0c2979b7 100644
--- a/tests/qapi-schema/args-boxed-anon.err
+++ b/tests/qapi-schema/args-boxed-anon.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-boxed-anon.json:2: 'data' for command 'foo' should be a type name
+tests/qapi-schema/args-boxed-anon.json: In command 'foo':
+tests/qapi-schema/args-boxed-anon.json:2: 'data' should be a type name
diff --git a/tests/qapi-schema/args-boxed-string.err b/tests/qapi-schema/args-boxed-string.err
index d326b48aef..dc2b00f217 100644
--- a/tests/qapi-schema/args-boxed-string.err
+++ b/tests/qapi-schema/args-boxed-string.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-boxed-string.json:2: 'data' for command 'foo' cannot use built-in type 'str'
+tests/qapi-schema/args-boxed-string.json: In command 'foo':
+tests/qapi-schema/args-boxed-string.json:2: command's 'data' cannot take built-in type 'str'
diff --git a/tests/qapi-schema/args-int.err b/tests/qapi-schema/args-int.err
index dc1d2504ff..81b6f86b66 100644
--- a/tests/qapi-schema/args-int.err
+++ b/tests/qapi-schema/args-int.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'
+tests/qapi-schema/args-int.json: In command 'oops':
+tests/qapi-schema/args-int.json:2: command's 'data' cannot take built-in type 'int'
diff --git a/tests/qapi-schema/args-invalid.err b/tests/qapi-schema/args-invalid.err
index bfb2e4133e..c4971e1399 100644
--- a/tests/qapi-schema/args-invalid.err
+++ b/tests/qapi-schema/args-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be an object or type name
+tests/qapi-schema/args-invalid.json: In command 'foo':
+tests/qapi-schema/args-invalid.json:1: 'data' should be an object or type name
diff --git a/tests/qapi-schema/args-member-array-bad.err b/tests/qapi-schema/args-member-array-bad.err
index 881b4d954f..f95ac01372 100644
--- a/tests/qapi-schema/args-member-array-bad.err
+++ b/tests/qapi-schema/args-member-array-bad.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name
+tests/qapi-schema/args-member-array-bad.json: In command 'oops':
+tests/qapi-schema/args-member-array-bad.json:2: 'data' member 'member': array type must contain single type name
diff --git a/tests/qapi-schema/args-member-case.err b/tests/qapi-schema/args-member-case.err
index 19c4426601..3ecd276040 100644
--- a/tests/qapi-schema/args-member-case.err
+++ b/tests/qapi-schema/args-member-case.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase
+tests/qapi-schema/args-member-case.json: In command 'no-way-this-will-get-whitelisted':
+tests/qapi-schema/args-member-case.json:2: 'data' member 'Arg' uses uppercase in name
diff --git a/tests/qapi-schema/args-member-case.json b/tests/qapi-schema/args-member-case.json
index 93439bee8b..e27c603548 100644
--- a/tests/qapi-schema/args-member-case.json
+++ b/tests/qapi-schema/args-member-case.json
@@ -1,2 +1,2 @@
-# Member names should be 'lower-case' unless the struct/command is whitelisted
+# Member names should be 'lower-case' unless the struct is 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 f6f82828ce..0626e1209d 100644
--- a/tests/qapi-schema/args-member-unknown.err
+++ b/tests/qapi-schema/args-member-unknown.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/args-member-unknown.json: In command 'oops':
+tests/qapi-schema/args-member-unknown.json:2: parameter 'member' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/args-name-clash.err b/tests/qapi-schema/args-name-clash.err
index d953e8d241..c5916a80fb 100644
--- a/tests/qapi-schema/args-name-clash.err
+++ b/tests/qapi-schema/args-name-clash.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops)
+tests/qapi-schema/args-name-clash.json: In command 'oops':
+tests/qapi-schema/args-name-clash.json:4: parameter 'a_b' collides with parameter 'a-b'
diff --git a/tests/qapi-schema/args-union.err b/tests/qapi-schema/args-union.err
index f8ad223dde..3a77b2863f 100644
--- a/tests/qapi-schema/args-union.err
+++ b/tests/qapi-schema/args-union.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-union.json:3: 'data' for command 'oops' cannot use union type 'Uni'
+tests/qapi-schema/args-union.json: In command 'oops':
+tests/qapi-schema/args-union.json:3: command's 'data' can take union type 'Uni' only with 'boxed': true
diff --git a/tests/qapi-schema/args-unknown.err b/tests/qapi-schema/args-unknown.err
index 4d91ec869f..6857d6bf48 100644
--- a/tests/qapi-schema/args-unknown.err
+++ b/tests/qapi-schema/args-unknown.err
@@ -1 +1,2 @@
-tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/args-unknown.json: In command 'oops':
+tests/qapi-schema/args-unknown.json:2: command's 'data' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/bad-base.err b/tests/qapi-schema/bad-base.err
index 154274bdd3..039678a364 100644
--- a/tests/qapi-schema/bad-base.err
+++ b/tests/qapi-schema/bad-base.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-base.json:3: 'base' for struct 'MyType' cannot use union type 'Union'
+tests/qapi-schema/bad-base.json: In struct 'MyType':
+tests/qapi-schema/bad-base.json:3: 'base' requires a struct type, union type 'Union' isn't
diff --git a/tests/qapi-schema/bad-data.err b/tests/qapi-schema/bad-data.err
index 8523ac4f46..5227bdce7e 100644
--- a/tests/qapi-schema/bad-data.err
+++ b/tests/qapi-schema/bad-data.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-data.json:2: 'data' for command 'oops' cannot be an array
+tests/qapi-schema/bad-data.json: In command 'oops':
+tests/qapi-schema/bad-data.json:2: 'data' cannot be an array
diff --git a/tests/qapi-schema/bad-ident.err b/tests/qapi-schema/bad-ident.err
index c4190602b5..ad38a679c7 100644
--- a/tests/qapi-schema/bad-ident.err
+++ b/tests/qapi-schema/bad-ident.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-ident.json:2: 'struct' does not allow optional name '*oops'
+tests/qapi-schema/bad-ident.json: In struct '*oops':
+tests/qapi-schema/bad-ident.json:2: struct has an invalid name
diff --git a/tests/qapi-schema/bad-if-empty-list.err b/tests/qapi-schema/bad-if-empty-list.err
index 75fe6497bc..517519f500 100644
--- a/tests/qapi-schema/bad-if-empty-list.err
+++ b/tests/qapi-schema/bad-if-empty-list.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] is useless
+tests/qapi-schema/bad-if-empty-list.json: In struct 'TestIfStruct':
+tests/qapi-schema/bad-if-empty-list.json:2: 'if' condition [] of struct is useless
diff --git a/tests/qapi-schema/bad-if-empty.err b/tests/qapi-schema/bad-if-empty.err
index 358bdc3e51..5f1767388e 100644
--- a/tests/qapi-schema/bad-if-empty.err
+++ b/tests/qapi-schema/bad-if-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' makes no sense
+tests/qapi-schema/bad-if-empty.json: In struct 'TestIfStruct':
+tests/qapi-schema/bad-if-empty.json:2: 'if' condition '' of struct makes no sense
diff --git a/tests/qapi-schema/bad-if-list.err b/tests/qapi-schema/bad-if-list.err
index 53af099083..e5d72b2f39 100644
--- a/tests/qapi-schema/bad-if-list.err
+++ b/tests/qapi-schema/bad-if-list.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-if-list.json:2: 'if' condition ' ' makes no sense
+tests/qapi-schema/bad-if-list.json: In struct 'TestIfStruct':
+tests/qapi-schema/bad-if-list.json:2: 'if' condition ' ' of struct makes no sense
diff --git a/tests/qapi-schema/bad-if.err b/tests/qapi-schema/bad-if.err
index c2e3f5f44c..65d8efd7e4 100644
--- a/tests/qapi-schema/bad-if.err
+++ b/tests/qapi-schema/bad-if.err
@@ -1 +1,2 @@
-tests/qapi-schema/bad-if.json:2: 'if' condition must be a string or a list of strings
+tests/qapi-schema/bad-if.json: In struct 'TestIfStruct':
+tests/qapi-schema/bad-if.json:2: 'if' condition of struct must be a string or a list of strings
diff --git a/tests/qapi-schema/bad-type-bool.err b/tests/qapi-schema/bad-type-bool.err
index 62fd70baaf..984a77c4e3 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:2: 'struct' key must have a string value
+tests/qapi-schema/bad-type-bool.json:2: 'struct' requires a string name
diff --git a/tests/qapi-schema/bad-type-dict.err b/tests/qapi-schema/bad-type-dict.err
index 0b2a2aeac4..e83b8cfb41 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:2: 'command' key must have a string value
+tests/qapi-schema/bad-type-dict.json:2: 'command' requires a string name
diff --git a/tests/qapi-schema/bad-type-int.err b/tests/qapi-schema/bad-type-int.err
index 9b2c12c1eb..7f5916ea29 100644
--- a/tests/qapi-schema/bad-type-int.err
+++ b/tests/qapi-schema/bad-type-int.err
@@ -1 +1 @@
-tests/qapi-schema/bad-type-int.json:3:13: Stray '123'
+tests/qapi-schema/bad-type-int.json:3:13: stray '123'
diff --git a/tests/qapi-schema/base-cycle-direct.err b/tests/qapi-schema/base-cycle-direct.err
index 9c68f6543d..233e4b8952 100644
--- a/tests/qapi-schema/base-cycle-direct.err
+++ b/tests/qapi-schema/base-cycle-direct.err
@@ -1 +1,2 @@
-tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself
+tests/qapi-schema/base-cycle-direct.json: In struct 'Loopy':
+tests/qapi-schema/base-cycle-direct.json:2: object Loopy contains itself
diff --git a/tests/qapi-schema/base-cycle-indirect.err b/tests/qapi-schema/base-cycle-indirect.err
index fc92fe47f8..4472f30ba1 100644
--- a/tests/qapi-schema/base-cycle-indirect.err
+++ b/tests/qapi-schema/base-cycle-indirect.err
@@ -1 +1,2 @@
-tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself
+tests/qapi-schema/base-cycle-indirect.json: In struct 'Base1':
+tests/qapi-schema/base-cycle-indirect.json:2: object Base1 contains itself
diff --git a/tests/qapi-schema/command-int.err b/tests/qapi-schema/command-int.err
index 0f9300679b..3523d50a79 100644
--- a/tests/qapi-schema/command-int.err
+++ b/tests/qapi-schema/command-int.err
@@ -1 +1,2 @@
-tests/qapi-schema/command-int.json:2: built-in 'int' is already defined
+tests/qapi-schema/command-int.json: In command 'int':
+tests/qapi-schema/command-int.json:2: built-in type 'int' is already defined
diff --git a/tests/qapi-schema/doc-bad-alternate-member.err b/tests/qapi-schema/doc-bad-alternate-member.err
index 387f7824da..19a1ffd76e 100644
--- a/tests/qapi-schema/doc-bad-alternate-member.err
+++ b/tests/qapi-schema/doc-bad-alternate-member.err
@@ -1 +1 @@
-tests/qapi-schema/doc-bad-alternate-member.json:3: The following documented members are not in the declaration: aa, bb
+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-command-arg.err b/tests/qapi-schema/doc-bad-command-arg.err
index 8075b146ae..6962ebed69 100644
--- a/tests/qapi-schema/doc-bad-command-arg.err
+++ b/tests/qapi-schema/doc-bad-command-arg.err
@@ -1 +1 @@
-tests/qapi-schema/doc-bad-command-arg.json:3: The following documented members are not in the declaration: b
+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-symbol.err b/tests/qapi-schema/doc-bad-symbol.err
index 8472030c79..b23e99d160 100644
--- a/tests/qapi-schema/doc-bad-symbol.err
+++ b/tests/qapi-schema/doc-bad-symbol.err
@@ -1 +1,2 @@
-tests/qapi-schema/doc-bad-symbol.json:6: Definition of 'foo' follows documentation for 'food'
+tests/qapi-schema/doc-bad-symbol.json: In command 'foo':
+tests/qapi-schema/doc-bad-symbol.json:6: documentation comment is for 'food'
diff --git a/tests/qapi-schema/doc-bad-union-member.err b/tests/qapi-schema/doc-bad-union-member.err
index 4b016df7ff..da3cd806e3 100644
--- a/tests/qapi-schema/doc-bad-union-member.err
+++ b/tests/qapi-schema/doc-bad-union-member.err
@@ -1 +1 @@
-tests/qapi-schema/doc-bad-union-member.json:3: The following documented members are not in the declaration: a, b
+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-before-include.err b/tests/qapi-schema/doc-before-include.err
index a649d38a63..e5566f11e9 100644
--- a/tests/qapi-schema/doc-before-include.err
+++ b/tests/qapi-schema/doc-before-include.err
@@ -1 +1 @@
-tests/qapi-schema/doc-before-include.json:3: Documentation for 'foo' is not followed by the definition
+tests/qapi-schema/doc-before-include.json:3: documentation for 'foo' is not followed by the definition
diff --git a/tests/qapi-schema/doc-before-pragma.err b/tests/qapi-schema/doc-before-pragma.err
index c0fb0660d1..8a97ebb578 100644
--- a/tests/qapi-schema/doc-before-pragma.err
+++ b/tests/qapi-schema/doc-before-pragma.err
@@ -1 +1 @@
-tests/qapi-schema/doc-before-pragma.json:3: Documentation for 'foo' is not followed by the definition
+tests/qapi-schema/doc-before-pragma.json:3: documentation for 'foo' is not followed by the definition
diff --git a/tests/qapi-schema/doc-duplicated-return.err b/tests/qapi-schema/doc-duplicated-return.err
index e48039f8e5..7631933093 100644
--- a/tests/qapi-schema/doc-duplicated-return.err
+++ b/tests/qapi-schema/doc-duplicated-return.err
@@ -1 +1 @@
-tests/qapi-schema/doc-duplicated-return.json:7:1: Duplicated 'Returns' section
+tests/qapi-schema/doc-duplicated-return.json:7:1: duplicated 'Returns' section
diff --git a/tests/qapi-schema/doc-duplicated-since.err b/tests/qapi-schema/doc-duplicated-since.err
index 3fb890744a..5ee15ae2a1 100644
--- a/tests/qapi-schema/doc-duplicated-since.err
+++ b/tests/qapi-schema/doc-duplicated-since.err
@@ -1 +1 @@
-tests/qapi-schema/doc-duplicated-since.json:7:1: Duplicated 'Since' section
+tests/qapi-schema/doc-duplicated-since.json:7:1: duplicated 'Since' section
diff --git a/tests/qapi-schema/doc-empty-arg.err b/tests/qapi-schema/doc-empty-arg.err
index 2895518fa7..3c78a37ae1 100644
--- a/tests/qapi-schema/doc-empty-arg.err
+++ b/tests/qapi-schema/doc-empty-arg.err
@@ -1 +1 @@
-tests/qapi-schema/doc-empty-arg.json:5:1: Invalid parameter name
+tests/qapi-schema/doc-empty-arg.json:5:1: invalid parameter name
diff --git a/tests/qapi-schema/doc-empty-section.err b/tests/qapi-schema/doc-empty-section.err
index b61e4a7886..f6586c566f 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:7:1: Empty doc section 'Note'
+tests/qapi-schema/doc-empty-section.json:7:1: empty doc section 'Note'
diff --git a/tests/qapi-schema/doc-empty-symbol.err b/tests/qapi-schema/doc-empty-symbol.err
index 1936ad094f..2dcddca7f6 100644
--- a/tests/qapi-schema/doc-empty-symbol.err
+++ b/tests/qapi-schema/doc-empty-symbol.err
@@ -1 +1 @@
-tests/qapi-schema/doc-empty-symbol.json:4:1: Invalid name
+tests/qapi-schema/doc-empty-symbol.json:4:1: invalid name
diff --git a/tests/qapi-schema/doc-invalid-end.err b/tests/qapi-schema/doc-invalid-end.err
index 2bda28cb54..6345aa6a0f 100644
--- a/tests/qapi-schema/doc-invalid-end.err
+++ b/tests/qapi-schema/doc-invalid-end.err
@@ -1 +1 @@
-tests/qapi-schema/doc-invalid-end.json:5:2: Documentation comment must end with '##'
+tests/qapi-schema/doc-invalid-end.json:5:2: documentation comment must end with '##'
diff --git a/tests/qapi-schema/doc-invalid-end2.err b/tests/qapi-schema/doc-invalid-end2.err
index 6fad9c789e..13ead36fd2 100644
--- a/tests/qapi-schema/doc-invalid-end2.err
+++ b/tests/qapi-schema/doc-invalid-end2.err
@@ -1 +1 @@
-tests/qapi-schema/doc-invalid-end2.json:5:1: Junk after '##' at end of documentation comment
+tests/qapi-schema/doc-invalid-end2.json:5:1: junk after '##' at end of documentation comment
diff --git a/tests/qapi-schema/doc-invalid-start.err b/tests/qapi-schema/doc-invalid-start.err
index 149af2bfac..dcaa9699d6 100644
--- a/tests/qapi-schema/doc-invalid-start.err
+++ b/tests/qapi-schema/doc-invalid-start.err
@@ -1 +1 @@
-tests/qapi-schema/doc-invalid-start.json:3:1: Junk after '##' at start of documentation comment
+tests/qapi-schema/doc-invalid-start.json:3:1: junk after '##' at start of documentation comment
diff --git a/tests/qapi-schema/doc-missing-colon.err b/tests/qapi-schema/doc-missing-colon.err
index b41d5078b0..6fb5a380bd 100644
--- a/tests/qapi-schema/doc-missing-colon.err
+++ b/tests/qapi-schema/doc-missing-colon.err
@@ -1 +1 @@
-tests/qapi-schema/doc-missing-colon.json:4:1: Line should end with ':'
+tests/qapi-schema/doc-missing-colon.json:4:1: line should end with ':'
diff --git a/tests/qapi-schema/doc-missing-expr.err b/tests/qapi-schema/doc-missing-expr.err
index c909e26eca..622a37cc6c 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: Documentation 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-missing-space.err b/tests/qapi-schema/doc-missing-space.err
index d6b46ffd77..1187ba12c4 100644
--- a/tests/qapi-schema/doc-missing-space.err
+++ b/tests/qapi-schema/doc-missing-space.err
@@ -1 +1 @@
-tests/qapi-schema/doc-missing-space.json:5:1: Missing space after #
+tests/qapi-schema/doc-missing-space.json:5:1: missing space after #
diff --git a/tests/qapi-schema/doc-missing.err b/tests/qapi-schema/doc-missing.err
index 3a377ddc57..7fbf54ff65 100644
--- a/tests/qapi-schema/doc-missing.err
+++ b/tests/qapi-schema/doc-missing.err
@@ -1 +1,2 @@
-tests/qapi-schema/doc-missing.json:5: Definition missing documentation comment
+tests/qapi-schema/doc-missing.json: In command 'undocumented':
+tests/qapi-schema/doc-missing.json:5: documentation comment required
diff --git a/tests/qapi-schema/doc-no-symbol.err b/tests/qapi-schema/doc-no-symbol.err
index 212984ff20..9a3057730c 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:3: Definition documentation required
+tests/qapi-schema/doc-no-symbol.json:3: definition documentation required
diff --git a/tests/qapi-schema/double-type.err b/tests/qapi-schema/double-type.err
index 69457173a7..23f88aae99 100644
--- a/tests/qapi-schema/double-type.err
+++ b/tests/qapi-schema/double-type.err
@@ -1,2 +1,3 @@
-tests/qapi-schema/double-type.json:2: Unknown key 'command' in struct 'bar'
+tests/qapi-schema/double-type.json: In struct 'bar':
+tests/qapi-schema/double-type.json:2: struct has unknown key 'command'
Valid keys are 'base', 'data', 'features', 'if', 'struct'.
diff --git a/tests/qapi-schema/duplicate-key.err b/tests/qapi-schema/duplicate-key.err
index 3af2f55174..7f34a34eb6 100644
--- a/tests/qapi-schema/duplicate-key.err
+++ b/tests/qapi-schema/duplicate-key.err
@@ -1 +1 @@
-tests/qapi-schema/duplicate-key.json:3:10: Duplicate key 'key'
+tests/qapi-schema/duplicate-key.json:3:10: duplicate key 'key'
diff --git a/tests/qapi-schema/enum-bad-member.err b/tests/qapi-schema/enum-bad-member.err
index 211db9e6fc..2b1b4f98d0 100644
--- a/tests/qapi-schema/enum-bad-member.err
+++ b/tests/qapi-schema/enum-bad-member.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-bad-member.json:2: Member of enum 'MyEnum' requires a string name
+tests/qapi-schema/enum-bad-member.json: In enum 'MyEnum':
+tests/qapi-schema/enum-bad-member.json:2: 'data' member requires a string name
diff --git a/tests/qapi-schema/enum-bad-name.err b/tests/qapi-schema/enum-bad-name.err
index 26a09f84ad..3273a9808a 100644
--- a/tests/qapi-schema/enum-bad-name.err
+++ b/tests/qapi-schema/enum-bad-name.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-bad-name.json:3: Member of enum 'MyEnum' uses invalid name 'not\possible'
+tests/qapi-schema/enum-bad-name.json: In enum 'MyEnum':
+tests/qapi-schema/enum-bad-name.json:3: 'data' member 'not\possible' has an invalid name
diff --git a/tests/qapi-schema/enum-bad-prefix.err b/tests/qapi-schema/enum-bad-prefix.err
index 399f5f7af5..933e33aa18 100644
--- a/tests/qapi-schema/enum-bad-prefix.err
+++ b/tests/qapi-schema/enum-bad-prefix.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix'
+tests/qapi-schema/enum-bad-prefix.json: In enum 'MyEnum':
+tests/qapi-schema/enum-bad-prefix.json:2: 'prefix' must be a string
diff --git a/tests/qapi-schema/enum-clash-member.err b/tests/qapi-schema/enum-clash-member.err
index 8238d2e807..84e02db82c 100644
--- a/tests/qapi-schema/enum-clash-member.err
+++ b/tests/qapi-schema/enum-clash-member.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-clash-member.json:2: 'one_two' (value of MyEnum) collides with 'one-two' (value of MyEnum)
+tests/qapi-schema/enum-clash-member.json: In enum 'MyEnum':
+tests/qapi-schema/enum-clash-member.json:2: value 'one_two' collides with value 'one-two'
diff --git a/tests/qapi-schema/enum-dict-member-unknown.err b/tests/qapi-schema/enum-dict-member-unknown.err
index 7fd9c032bf..5df0236343 100644
--- a/tests/qapi-schema/enum-dict-member-unknown.err
+++ b/tests/qapi-schema/enum-dict-member-unknown.err
@@ -1,2 +1,3 @@
-tests/qapi-schema/enum-dict-member-unknown.json:2: Unknown key 'bad-key' in member of enum 'MyEnum'
+tests/qapi-schema/enum-dict-member-unknown.json: In enum 'MyEnum':
+tests/qapi-schema/enum-dict-member-unknown.json:2: 'data' member has unknown key 'bad-key'
Valid keys are 'if', 'name'.
diff --git a/tests/qapi-schema/enum-if-invalid.err b/tests/qapi-schema/enum-if-invalid.err
index 54c3cf887b..30c1f0e91c 100644
--- a/tests/qapi-schema/enum-if-invalid.err
+++ b/tests/qapi-schema/enum-if-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-if-invalid.json:2: 'if' condition must be a string or a list of strings
+tests/qapi-schema/enum-if-invalid.json: In enum 'TestIfEnum':
+tests/qapi-schema/enum-if-invalid.json:2: 'if' condition of 'data' member 'bar' must be a string or a list of strings
diff --git a/tests/qapi-schema/enum-int-member.err b/tests/qapi-schema/enum-int-member.err
index 3f8d7b5b71..27f06e334c 100644
--- a/tests/qapi-schema/enum-int-member.err
+++ b/tests/qapi-schema/enum-int-member.err
@@ -1 +1 @@
-tests/qapi-schema/enum-int-member.json:3:31: Stray '1'
+tests/qapi-schema/enum-int-member.json:3:31: stray '1'
diff --git a/tests/qapi-schema/enum-member-case.err b/tests/qapi-schema/enum-member-case.err
index 5d689e92d5..e6b080c6e5 100644
--- a/tests/qapi-schema/enum-member-case.err
+++ b/tests/qapi-schema/enum-member-case.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-member-case.json:4: 'Value' (value of NoWayThisWillGetWhitelisted) should not use uppercase
+tests/qapi-schema/enum-member-case.json: In enum 'NoWayThisWillGetWhitelisted':
+tests/qapi-schema/enum-member-case.json:4: 'data' member 'Value' uses uppercase in name
diff --git a/tests/qapi-schema/enum-missing-data.err b/tests/qapi-schema/enum-missing-data.err
index ba4873ae69..4809b01f34 100644
--- a/tests/qapi-schema/enum-missing-data.err
+++ b/tests/qapi-schema/enum-missing-data.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum'
+tests/qapi-schema/enum-missing-data.json: In enum 'MyEnum':
+tests/qapi-schema/enum-missing-data.json:2: enum misses key 'data'
diff --git a/tests/qapi-schema/enum-wrong-data.err b/tests/qapi-schema/enum-wrong-data.err
index 11b43471cf..ad5f0ce46f 100644
--- a/tests/qapi-schema/enum-wrong-data.err
+++ b/tests/qapi-schema/enum-wrong-data.err
@@ -1 +1,2 @@
-tests/qapi-schema/enum-wrong-data.json:2: Enum 'MyEnum' requires an array for 'data'
+tests/qapi-schema/enum-wrong-data.json: In enum 'MyEnum':
+tests/qapi-schema/enum-wrong-data.json:2: 'data' must be an array
diff --git a/tests/qapi-schema/escape-outside-string.err b/tests/qapi-schema/escape-outside-string.err
index efee335ba0..06f5f2ed55 100644
--- a/tests/qapi-schema/escape-outside-string.err
+++ b/tests/qapi-schema/escape-outside-string.err
@@ -1 +1 @@
-tests/qapi-schema/escape-outside-string.json:3:27: Stray '\'
+tests/qapi-schema/escape-outside-string.json:3:27: stray '\'
diff --git a/tests/qapi-schema/event-boxed-empty.err b/tests/qapi-schema/event-boxed-empty.err
index 68ec6f2d2b..931c10b036 100644
--- a/tests/qapi-schema/event-boxed-empty.err
+++ b/tests/qapi-schema/event-boxed-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/event-boxed-empty.json:2: Use of 'boxed' requires 'data'
+tests/qapi-schema/event-boxed-empty.json: In event 'FOO':
+tests/qapi-schema/event-boxed-empty.json:2: 'boxed': true requires 'data'
diff --git a/tests/qapi-schema/event-member-invalid-dict.err b/tests/qapi-schema/event-member-invalid-dict.err
index 1a57fa29b0..8406c43df7 100644
--- a/tests/qapi-schema/event-member-invalid-dict.err
+++ b/tests/qapi-schema/event-member-invalid-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/event-member-invalid-dict.json:1: Key 'type' is missing from member 'a' of 'data' for event 'EVENT_A'
+tests/qapi-schema/event-member-invalid-dict.json: In event 'EVENT_A':
+tests/qapi-schema/event-member-invalid-dict.json:1: 'data' member 'a' misses key 'type'
diff --git a/tests/qapi-schema/event-nest-struct.err b/tests/qapi-schema/event-nest-struct.err
index 5a42701b8f..1a3254a73c 100644
--- a/tests/qapi-schema/event-nest-struct.err
+++ b/tests/qapi-schema/event-nest-struct.err
@@ -1 +1,2 @@
-tests/qapi-schema/event-nest-struct.json:1: Member 'a' of 'data' for event 'EVENT_A' should be a type name
+tests/qapi-schema/event-nest-struct.json: In event 'EVENT_A':
+tests/qapi-schema/event-nest-struct.json:1: 'data' member 'a' should be a type name
diff --git a/tests/qapi-schema/features-bad-type.err b/tests/qapi-schema/features-bad-type.err
index 5fb95c2f90..30deb8b624 100644
--- a/tests/qapi-schema/features-bad-type.err
+++ b/tests/qapi-schema/features-bad-type.err
@@ -1 +1,2 @@
-tests/qapi-schema/features-bad-type.json:1: Feature of struct FeatureStruct0 requires a string name
+tests/qapi-schema/features-bad-type.json: In struct 'FeatureStruct0':
+tests/qapi-schema/features-bad-type.json:1: 'features' member requires a string name
diff --git a/tests/qapi-schema/features-duplicate-name.err b/tests/qapi-schema/features-duplicate-name.err
index c0a4cccae6..a99bbde737 100644
--- a/tests/qapi-schema/features-duplicate-name.err
+++ b/tests/qapi-schema/features-duplicate-name.err
@@ -1 +1,2 @@
-tests/qapi-schema/features-duplicate-name.json:1: 'foo' (feature of FeatureStruct0) collides with 'foo' (feature of FeatureStruct0)
+tests/qapi-schema/features-duplicate-name.json: In struct 'FeatureStruct0':
+tests/qapi-schema/features-duplicate-name.json:1: feature 'foo' collides with feature 'foo'
diff --git a/tests/qapi-schema/features-if-invalid.err b/tests/qapi-schema/features-if-invalid.err
index 295800b4fc..ffb39378af 100644
--- a/tests/qapi-schema/features-if-invalid.err
+++ b/tests/qapi-schema/features-if-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/features-if-invalid.json:2: 'if' condition must be a string or a list of strings
+tests/qapi-schema/features-if-invalid.json: In struct 'Stru':
+tests/qapi-schema/features-if-invalid.json:2: 'if' condition of 'features' member 'f' must be a string or a list of strings
diff --git a/tests/qapi-schema/features-missing-name.err b/tests/qapi-schema/features-missing-name.err
index 4f1d2715aa..b8db328acc 100644
--- a/tests/qapi-schema/features-missing-name.err
+++ b/tests/qapi-schema/features-missing-name.err
@@ -1 +1,2 @@
-tests/qapi-schema/features-missing-name.json:1: Key 'name' is missing from feature of struct FeatureStruct0
+tests/qapi-schema/features-missing-name.json: In struct 'FeatureStruct0':
+tests/qapi-schema/features-missing-name.json:1: 'features' member misses key 'name'
diff --git a/tests/qapi-schema/features-name-bad-type.err b/tests/qapi-schema/features-name-bad-type.err
index 8a3eecb972..86db2c0ea2 100644
--- a/tests/qapi-schema/features-name-bad-type.err
+++ b/tests/qapi-schema/features-name-bad-type.err
@@ -1 +1,2 @@
-tests/qapi-schema/features-name-bad-type.json:1: Feature of struct FeatureStruct0 requires a string name
+tests/qapi-schema/features-name-bad-type.json: In struct 'FeatureStruct0':
+tests/qapi-schema/features-name-bad-type.json:1: 'features' member requires a string name
diff --git a/tests/qapi-schema/features-no-list.err b/tests/qapi-schema/features-no-list.err
index 61ed68612b..e493f85057 100644
--- a/tests/qapi-schema/features-no-list.err
+++ b/tests/qapi-schema/features-no-list.err
@@ -1 +1,2 @@
-tests/qapi-schema/features-no-list.json:1: Struct 'FeatureStruct0' requires an array for 'features'
+tests/qapi-schema/features-no-list.json: In struct 'FeatureStruct0':
+tests/qapi-schema/features-no-list.json:1: 'features' must be an array
diff --git a/tests/qapi-schema/features-unknown-key.err b/tests/qapi-schema/features-unknown-key.err
index a1d693030d..22f5dcf4b0 100644
--- a/tests/qapi-schema/features-unknown-key.err
+++ b/tests/qapi-schema/features-unknown-key.err
@@ -1,2 +1,3 @@
-tests/qapi-schema/features-unknown-key.json:1: Unknown key 'colour' in feature of struct FeatureStruct0
+tests/qapi-schema/features-unknown-key.json: In struct 'FeatureStruct0':
+tests/qapi-schema/features-unknown-key.json:1: 'features' member has unknown key 'colour'
Valid keys are 'if', 'name'.
diff --git a/tests/qapi-schema/flat-union-array-branch.err b/tests/qapi-schema/flat-union-array-branch.err
index 8ea91eadb2..de07a7b32a 100644
--- a/tests/qapi-schema/flat-union-array-branch.err
+++ b/tests/qapi-schema/flat-union-array-branch.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-array-branch.json:8: Member 'value1' of union 'TestUnion' cannot be an array
+tests/qapi-schema/flat-union-array-branch.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-array-branch.json:8: 'data' member 'value1' cannot be an array
diff --git a/tests/qapi-schema/flat-union-bad-base.err b/tests/qapi-schema/flat-union-bad-base.err
index bee24a217a..5da7602c20 100644
--- a/tests/qapi-schema/flat-union-bad-base.err
+++ b/tests/qapi-schema/flat-union-bad-base.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion)
+tests/qapi-schema/flat-union-bad-base.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-bad-base.json:8: member 'string' of type 'TestTypeA' collides with base member 'string'
diff --git a/tests/qapi-schema/flat-union-bad-discriminator.err b/tests/qapi-schema/flat-union-bad-discriminator.err
index c38cc8e4df..c1b4209ffd 100644
--- a/tests/qapi-schema/flat-union-bad-discriminator.err
+++ b/tests/qapi-schema/flat-union-bad-discriminator.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-bad-discriminator.json:11: Discriminator of flat union 'TestUnion' requires a string name
+tests/qapi-schema/flat-union-bad-discriminator.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-bad-discriminator.json:11: 'discriminator' requires a string name
diff --git a/tests/qapi-schema/flat-union-base-any.err b/tests/qapi-schema/flat-union-base-any.err
index 646f1c9cd1..7ab3402396 100644
--- a/tests/qapi-schema/flat-union-base-any.err
+++ b/tests/qapi-schema/flat-union-base-any.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-base-any.json:8: 'base' for union 'TestUnion' cannot use built-in type 'any'
+tests/qapi-schema/flat-union-base-any.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-base-any.json:8: 'base' requires a struct type, built-in type 'any' isn't
diff --git a/tests/qapi-schema/flat-union-base-union.err b/tests/qapi-schema/flat-union-base-union.err
index f138395e45..5db7b1e404 100644
--- a/tests/qapi-schema/flat-union-base-union.err
+++ b/tests/qapi-schema/flat-union-base-union.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-base-union.json:14: 'base' for union 'TestUnion' cannot use union type 'UnionBase'
+tests/qapi-schema/flat-union-base-union.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-base-union.json:14: 'base' requires a struct type, union type 'UnionBase' isn't
diff --git a/tests/qapi-schema/flat-union-clash-member.err b/tests/qapi-schema/flat-union-clash-member.err
index 2adf69755a..40f10681f8 100644
--- a/tests/qapi-schema/flat-union-clash-member.err
+++ b/tests/qapi-schema/flat-union-clash-member.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base)
+tests/qapi-schema/flat-union-clash-member.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-clash-member.json:11: member 'name' of type 'Branch1' collides with member 'name' of type 'Base'
diff --git a/tests/qapi-schema/flat-union-discriminator-bad-name.err b/tests/qapi-schema/flat-union-discriminator-bad-name.err
index 7238d126ca..2a0deb6a0e 100644
--- a/tests/qapi-schema/flat-union-discriminator-bad-name.err
+++ b/tests/qapi-schema/flat-union-discriminator-bad-name.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-discriminator-bad-name.json:7: Discriminator of flat union 'MyUnion' does not allow optional name '*switch'
+tests/qapi-schema/flat-union-discriminator-bad-name.json: In union 'MyUnion':
+tests/qapi-schema/flat-union-discriminator-bad-name.json:6: discriminator '*switch' is not a member of 'base'
diff --git a/tests/qapi-schema/flat-union-discriminator-bad-name.json b/tests/qapi-schema/flat-union-discriminator-bad-name.json
index 66376084fc..3ae8c06a89 100644
--- a/tests/qapi-schema/flat-union-discriminator-bad-name.json
+++ b/tests/qapi-schema/flat-union-discriminator-bad-name.json
@@ -1,5 +1,4 @@
# discriminator '*switch' isn't a member of base, 'switch' is
-# reports "does not allow optional name", which is good enough
{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
{ 'struct': 'Base',
'data': { '*switch': 'Enum' } }
diff --git a/tests/qapi-schema/flat-union-empty.err b/tests/qapi-schema/flat-union-empty.err
index fedbc0d1cf..91a5b57f5d 100644
--- a/tests/qapi-schema/flat-union-empty.err
+++ b/tests/qapi-schema/flat-union-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-empty.json:4: Union 'Union' has no branches
+tests/qapi-schema/flat-union-empty.json: In union 'Union':
+tests/qapi-schema/flat-union-empty.json:4: union has no branches
diff --git a/tests/qapi-schema/flat-union-inline-invalid-dict.err b/tests/qapi-schema/flat-union-inline-invalid-dict.err
index 9c4c45b7f0..d353bdd338 100644
--- a/tests/qapi-schema/flat-union-inline-invalid-dict.err
+++ b/tests/qapi-schema/flat-union-inline-invalid-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-inline-invalid-dict.json:7: Key 'type' is missing from member 'value1' of union 'TestUnion'
+tests/qapi-schema/flat-union-inline-invalid-dict.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-inline-invalid-dict.json:7: 'data' member 'value1' misses key 'type'
diff --git a/tests/qapi-schema/flat-union-inline.err b/tests/qapi-schema/flat-union-inline.err
index 2333358d28..95b1e8c1b7 100644
--- a/tests/qapi-schema/flat-union-inline.err
+++ b/tests/qapi-schema/flat-union-inline.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name
+tests/qapi-schema/flat-union-inline.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-inline.json:7: 'data' member 'value1' should be a type name
diff --git a/tests/qapi-schema/flat-union-int-branch.err b/tests/qapi-schema/flat-union-int-branch.err
index faf01573b7..416b696c8f 100644
--- a/tests/qapi-schema/flat-union-int-branch.err
+++ b/tests/qapi-schema/flat-union-int-branch.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-int-branch.json:8: Member 'value1' of union 'TestUnion' cannot use built-in type 'int'
+tests/qapi-schema/flat-union-int-branch.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-int-branch.json:8: branch 'value1' cannot use built-in type 'int'
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err
index ccf72d2dfe..6997b3387d 100644
--- a/tests/qapi-schema/flat-union-invalid-branch-key.err
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-invalid-branch-key.json:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
+tests/qapi-schema/flat-union-invalid-branch-key.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-invalid-branch-key.json:13: branch 'value_wrong' is not a value of enum type 'TestEnum'
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err
index 495d5a520e..3f80de3044 100644
--- a/tests/qapi-schema/flat-union-invalid-discriminator.err
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-invalid-discriminator.json:10: Discriminator 'enum_wrong' is not a member of 'base'
+tests/qapi-schema/flat-union-invalid-discriminator.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-invalid-discriminator.json:10: discriminator 'enum_wrong' is not a member of 'base'
diff --git a/tests/qapi-schema/flat-union-invalid-if-discriminator.err b/tests/qapi-schema/flat-union-invalid-if-discriminator.err
index cc5c3fb80b..d2b35be9ae 100644
--- a/tests/qapi-schema/flat-union-invalid-if-discriminator.err
+++ b/tests/qapi-schema/flat-union-invalid-if-discriminator.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-invalid-if-discriminator.json:10: The discriminator 'enum1' for union TestUnion must not be conditional
+tests/qapi-schema/flat-union-invalid-if-discriminator.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-invalid-if-discriminator.json:10: discriminator member 'enum1' of 'base' must not be conditional
diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err
index 841c93b554..a16f3231f1 100644
--- a/tests/qapi-schema/flat-union-no-base.err
+++ b/tests/qapi-schema/flat-union-no-base.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a base
+tests/qapi-schema/flat-union-no-base.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-no-base.json:9: 'discriminator' requires 'base'
diff --git a/tests/qapi-schema/flat-union-optional-discriminator.err b/tests/qapi-schema/flat-union-optional-discriminator.err
index 45f5407c34..49fbf5b04d 100644
--- a/tests/qapi-schema/flat-union-optional-discriminator.err
+++ b/tests/qapi-schema/flat-union-optional-discriminator.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-optional-discriminator.json:7: Discriminator 'switch' is not a member of 'base'
+tests/qapi-schema/flat-union-optional-discriminator.json: In union 'MyUnion':
+tests/qapi-schema/flat-union-optional-discriminator.json:6: discriminator member 'switch' of base type 'Base' must not be optional
diff --git a/tests/qapi-schema/flat-union-optional-discriminator.json b/tests/qapi-schema/flat-union-optional-discriminator.json
index 143ab23a0d..2e7f766f60 100644
--- a/tests/qapi-schema/flat-union-optional-discriminator.json
+++ b/tests/qapi-schema/flat-union-optional-discriminator.json
@@ -1,5 +1,4 @@
# we require the discriminator to be non-optional
-# FIXME reports "discriminator 'switch' is not a member of base struct 'Base'"
{ 'enum': 'Enum', 'data': [ 'one', 'two' ] }
{ 'struct': 'Base',
'data': { '*switch': 'Enum' } }
diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err
index 200016bd5c..fb499188aa 100644
--- a/tests/qapi-schema/flat-union-string-discriminator.err
+++ b/tests/qapi-schema/flat-union-string-discriminator.err
@@ -1 +1,2 @@
-tests/qapi-schema/flat-union-string-discriminator.json:13: Discriminator 'kind' must be of enumeration type
+tests/qapi-schema/flat-union-string-discriminator.json: In union 'TestUnion':
+tests/qapi-schema/flat-union-string-discriminator.json:13: discriminator member 'kind' of base type 'TestBase' must be of enum type
diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err
index 139ecf4eb8..132fac93ea 100644
--- a/tests/qapi-schema/funny-char.err
+++ b/tests/qapi-schema/funny-char.err
@@ -1 +1 @@
-tests/qapi-schema/funny-char.json:2:36: Stray ';'
+tests/qapi-schema/funny-char.json:2:36: stray ';'
diff --git a/tests/qapi-schema/funny-word.err b/tests/qapi-schema/funny-word.err
index af92fe2551..d9286c8962 100644
--- a/tests/qapi-schema/funny-word.err
+++ b/tests/qapi-schema/funny-word.err
@@ -1 +1 @@
-tests/qapi-schema/funny-word.json:1:3: Stray 'command'
+tests/qapi-schema/funny-word.json:1:3: stray 'command'
diff --git a/tests/qapi-schema/ident-with-escape.err b/tests/qapi-schema/ident-with-escape.err
index 5517dcb4b1..1117283c81 100644
--- a/tests/qapi-schema/ident-with-escape.err
+++ b/tests/qapi-schema/ident-with-escape.err
@@ -1 +1 @@
-tests/qapi-schema/ident-with-escape.json:3:3: Unknown escape \u
+tests/qapi-schema/ident-with-escape.json:3:3: unknown escape \u
diff --git a/tests/qapi-schema/include-before-err.err b/tests/qapi-schema/include-before-err.err
index 2b26322170..098314bc49 100644
--- a/tests/qapi-schema/include-before-err.err
+++ b/tests/qapi-schema/include-before-err.err
@@ -1 +1 @@
-tests/qapi-schema/include-before-err.json:2:13: Expected ':'
+tests/qapi-schema/include-before-err.json:2:13: expected ':'
diff --git a/tests/qapi-schema/include-cycle.err b/tests/qapi-schema/include-cycle.err
index bdcd07dce2..52028669b5 100644
--- a/tests/qapi-schema/include-cycle.err
+++ b/tests/qapi-schema/include-cycle.err
@@ -1,3 +1,3 @@
In file included from tests/qapi-schema/include-cycle.json:1:
In file included from tests/qapi-schema/include-cycle-b.json:1:
-tests/qapi-schema/include-cycle-c.json:1: Inclusion loop for include-cycle.json
+tests/qapi-schema/include-cycle-c.json:1: inclusion loop for include-cycle.json
diff --git a/tests/qapi-schema/include-extra-junk.err b/tests/qapi-schema/include-extra-junk.err
index e6ef2a3720..854cec3ce3 100644
--- a/tests/qapi-schema/include-extra-junk.err
+++ b/tests/qapi-schema/include-extra-junk.err
@@ -1 +1 @@
-tests/qapi-schema/include-extra-junk.json:3: Invalid 'include' directive
+tests/qapi-schema/include-extra-junk.json:3: invalid 'include' directive
diff --git a/tests/qapi-schema/include-nested-err.err b/tests/qapi-schema/include-nested-err.err
index aec6207eb0..11928b4f7f 100644
--- a/tests/qapi-schema/include-nested-err.err
+++ b/tests/qapi-schema/include-nested-err.err
@@ -1,2 +1,2 @@
In file included from tests/qapi-schema/include-nested-err.json:1:
-tests/qapi-schema/missing-colon.json:1:10: Expected ':'
+tests/qapi-schema/missing-colon.json:1:10: expected ':'
diff --git a/tests/qapi-schema/include-no-file.err b/tests/qapi-schema/include-no-file.err
index e42bcf4bc1..0a6c6bb4a9 100644
--- a/tests/qapi-schema/include-no-file.err
+++ b/tests/qapi-schema/include-no-file.err
@@ -1 +1 @@
-tests/qapi-schema/include-no-file.json:1: No such file or directory: tests/qapi-schema/include-no-file-sub.json
+tests/qapi-schema/include-no-file.json:1: can't read include file 'tests/qapi-schema/include-no-file-sub.json': No such file or directory
diff --git a/tests/qapi-schema/include-non-file.err b/tests/qapi-schema/include-non-file.err
index faae1eacf1..65dd3c7c2c 100644
--- a/tests/qapi-schema/include-non-file.err
+++ b/tests/qapi-schema/include-non-file.err
@@ -1 +1 @@
-tests/qapi-schema/include-non-file.json:1: Value of 'include' must be a string
+tests/qapi-schema/include-non-file.json:1: value of 'include' must be a string
diff --git a/tests/qapi-schema/include-self-cycle.err b/tests/qapi-schema/include-self-cycle.err
index 981742ae5f..c84795d1dc 100644
--- a/tests/qapi-schema/include-self-cycle.err
+++ b/tests/qapi-schema/include-self-cycle.err
@@ -1 +1 @@
-tests/qapi-schema/include-self-cycle.json:1: Inclusion loop for include-self-cycle.json
+tests/qapi-schema/include-self-cycle.json:1: inclusion loop for include-self-cycle.json
diff --git a/tests/qapi-schema/leading-comma-list.err b/tests/qapi-schema/leading-comma-list.err
index e021e42ad9..cddf471f71 100644
--- a/tests/qapi-schema/leading-comma-list.err
+++ b/tests/qapi-schema/leading-comma-list.err
@@ -1 +1 @@
-tests/qapi-schema/leading-comma-list.json:2:13: Expected '{', '[', ']', string, boolean or 'null'
+tests/qapi-schema/leading-comma-list.json:2:13: expected '{', '[', ']', string, boolean or 'null'
diff --git a/tests/qapi-schema/leading-comma-object.err b/tests/qapi-schema/leading-comma-object.err
index 3852f123d2..2f3b193274 100644
--- a/tests/qapi-schema/leading-comma-object.err
+++ b/tests/qapi-schema/leading-comma-object.err
@@ -1 +1 @@
-tests/qapi-schema/leading-comma-object.json:1:3: Expected string or '}'
+tests/qapi-schema/leading-comma-object.json:1:3: expected string or '}'
diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err
index a255e51918..e642c7c549 100644
--- a/tests/qapi-schema/missing-colon.err
+++ b/tests/qapi-schema/missing-colon.err
@@ -1 +1 @@
-tests/qapi-schema/missing-colon.json:1:10: Expected ':'
+tests/qapi-schema/missing-colon.json:1:10: expected ':'
diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err
index df3f553f39..5359499430 100644
--- a/tests/qapi-schema/missing-comma-list.err
+++ b/tests/qapi-schema/missing-comma-list.err
@@ -1 +1 @@
-tests/qapi-schema/missing-comma-list.json:2:20: Expected ',' or ']'
+tests/qapi-schema/missing-comma-list.json:2:20: expected ',' or ']'
diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err
index 0f691b8ddd..c9b02b0760 100644
--- a/tests/qapi-schema/missing-comma-object.err
+++ b/tests/qapi-schema/missing-comma-object.err
@@ -1 +1 @@
-tests/qapi-schema/missing-comma-object.json:2:3: Expected ',' or '}'
+tests/qapi-schema/missing-comma-object.json:2:3: expected ',' or '}'
diff --git a/tests/qapi-schema/missing-type.err b/tests/qapi-schema/missing-type.err
index b3e7b14e42..19b7c495e7 100644
--- a/tests/qapi-schema/missing-type.err
+++ b/tests/qapi-schema/missing-type.err
@@ -1 +1 @@
-tests/qapi-schema/missing-type.json:2: Expression is missing metatype
+tests/qapi-schema/missing-type.json:2: expression is missing metatype
diff --git a/tests/qapi-schema/nested-struct-data-invalid-dict.err b/tests/qapi-schema/nested-struct-data-invalid-dict.err
index 5bd364e8d9..ed42d6323e 100644
--- a/tests/qapi-schema/nested-struct-data-invalid-dict.err
+++ b/tests/qapi-schema/nested-struct-data-invalid-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/nested-struct-data-invalid-dict.json:2: Key 'type' is missing from member 'a' of 'data' for command 'foo'
+tests/qapi-schema/nested-struct-data-invalid-dict.json: In command 'foo':
+tests/qapi-schema/nested-struct-data-invalid-dict.json:2: 'data' member 'a' misses key 'type'
diff --git a/tests/qapi-schema/nested-struct-data.err b/tests/qapi-schema/nested-struct-data.err
index da767bade2..b0ec410eb7 100644
--- a/tests/qapi-schema/nested-struct-data.err
+++ b/tests/qapi-schema/nested-struct-data.err
@@ -1 +1,2 @@
-tests/qapi-schema/nested-struct-data.json:2: Member 'a' of 'data' for command 'foo' should be a type name
+tests/qapi-schema/nested-struct-data.json: In command 'foo':
+tests/qapi-schema/nested-struct-data.json:2: 'data' member 'a' should be a type name
diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err
index a972abd937..9237af6939 100644
--- a/tests/qapi-schema/non-objects.err
+++ b/tests/qapi-schema/non-objects.err
@@ -1 +1 @@
-tests/qapi-schema/non-objects.json:1:1: Expected '{'
+tests/qapi-schema/non-objects.json:1:1: expected '{'
diff --git a/tests/qapi-schema/oob-test.err b/tests/qapi-schema/oob-test.err
index 35b60f7480..3c2ba6e0fd 100644
--- a/tests/qapi-schema/oob-test.err
+++ b/tests/qapi-schema/oob-test.err
@@ -1 +1,2 @@
-tests/qapi-schema/oob-test.json:2: 'allow-oob' of command 'oob-command-1' should only use true value
+tests/qapi-schema/oob-test.json: In command 'oob-command-1':
+tests/qapi-schema/oob-test.json:2: flag 'allow-oob' may only use true value
diff --git a/tests/qapi-schema/pragma-doc-required-crap.err b/tests/qapi-schema/pragma-doc-required-crap.err
index 39cd56cd48..bcd981ada8 100644
--- a/tests/qapi-schema/pragma-doc-required-crap.err
+++ b/tests/qapi-schema/pragma-doc-required-crap.err
@@ -1 +1 @@
-tests/qapi-schema/pragma-doc-required-crap.json:3: Pragma 'doc-required' must be boolean
+tests/qapi-schema/pragma-doc-required-crap.json:3: pragma 'doc-required' must be boolean
diff --git a/tests/qapi-schema/pragma-extra-junk.err b/tests/qapi-schema/pragma-extra-junk.err
index 4481688dbf..3ae48d3668 100644
--- a/tests/qapi-schema/pragma-extra-junk.err
+++ b/tests/qapi-schema/pragma-extra-junk.err
@@ -1 +1 @@
-tests/qapi-schema/pragma-extra-junk.json:3: Invalid 'pragma' directive
+tests/qapi-schema/pragma-extra-junk.json:3: invalid 'pragma' directive
diff --git a/tests/qapi-schema/pragma-name-case-whitelist-crap.err b/tests/qapi-schema/pragma-name-case-whitelist-crap.err
index f83b97e075..81f829ff36 100644
--- a/tests/qapi-schema/pragma-name-case-whitelist-crap.err
+++ b/tests/qapi-schema/pragma-name-case-whitelist-crap.err
@@ -1 +1 @@
-tests/qapi-schema/pragma-name-case-whitelist-crap.json:3: Pragma name-case-whitelist must be a list of strings
+tests/qapi-schema/pragma-name-case-whitelist-crap.json:3: pragma name-case-whitelist must be a list of strings
diff --git a/tests/qapi-schema/pragma-non-dict.err b/tests/qapi-schema/pragma-non-dict.err
index b358261050..8221724b0a 100644
--- a/tests/qapi-schema/pragma-non-dict.err
+++ b/tests/qapi-schema/pragma-non-dict.err
@@ -1 +1 @@
-tests/qapi-schema/pragma-non-dict.json:3: Value of 'pragma' must be an object
+tests/qapi-schema/pragma-non-dict.json:3: value of 'pragma' must be an object
diff --git a/tests/qapi-schema/pragma-returns-whitelist-crap.err b/tests/qapi-schema/pragma-returns-whitelist-crap.err
index 5d77021674..c0cae5de18 100644
--- a/tests/qapi-schema/pragma-returns-whitelist-crap.err
+++ b/tests/qapi-schema/pragma-returns-whitelist-crap.err
@@ -1 +1 @@
-tests/qapi-schema/pragma-returns-whitelist-crap.json:3: Pragma returns-whitelist must be a list of strings
+tests/qapi-schema/pragma-returns-whitelist-crap.json:3: pragma returns-whitelist must be a list of strings
diff --git a/tests/qapi-schema/pragma-unknown.err b/tests/qapi-schema/pragma-unknown.err
index 6ef2058316..f1335f0a0a 100644
--- a/tests/qapi-schema/pragma-unknown.err
+++ b/tests/qapi-schema/pragma-unknown.err
@@ -1 +1 @@
-tests/qapi-schema/pragma-unknown.json:1: Unknown pragma 'no-such-pragma'
+tests/qapi-schema/pragma-unknown.json:1: unknown pragma 'no-such-pragma'
diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err
index 6e036c8044..d8460a63a7 100644
--- a/tests/qapi-schema/quoted-structural-chars.err
+++ b/tests/qapi-schema/quoted-structural-chars.err
@@ -1 +1 @@
-tests/qapi-schema/quoted-structural-chars.json:1:1: Expected '{'
+tests/qapi-schema/quoted-structural-chars.json:1:1: expected '{'
diff --git a/tests/qapi-schema/redefined-builtin.err b/tests/qapi-schema/redefined-builtin.err
index b2757225c4..47c8933759 100644
--- a/tests/qapi-schema/redefined-builtin.err
+++ b/tests/qapi-schema/redefined-builtin.err
@@ -1 +1,2 @@
-tests/qapi-schema/redefined-builtin.json:2: built-in 'size' is already defined
+tests/qapi-schema/redefined-builtin.json: In struct 'size':
+tests/qapi-schema/redefined-builtin.json:2: built-in type 'size' is already defined
diff --git a/tests/qapi-schema/redefined-command.err b/tests/qapi-schema/redefined-command.err
index 82ae256e63..54e366bbf3 100644
--- a/tests/qapi-schema/redefined-command.err
+++ b/tests/qapi-schema/redefined-command.err
@@ -1 +1,4 @@
-tests/qapi-schema/redefined-command.json:3: command 'foo' is already defined
+tests/qapi-schema/redefined-command.json: In command 'foo':
+tests/qapi-schema/redefined-command.json:3: 'foo' is already defined
+tests/qapi-schema/redefined-command.json: In command 'foo':
+tests/qapi-schema/redefined-command.json:2: previous definition
diff --git a/tests/qapi-schema/redefined-event.err b/tests/qapi-schema/redefined-event.err
index 35429cb481..606c6e4497 100644
--- a/tests/qapi-schema/redefined-event.err
+++ b/tests/qapi-schema/redefined-event.err
@@ -1 +1,4 @@
-tests/qapi-schema/redefined-event.json:3: event 'EVENT_A' is already defined
+tests/qapi-schema/redefined-event.json: In event 'EVENT_A':
+tests/qapi-schema/redefined-event.json:3: 'EVENT_A' is already defined
+tests/qapi-schema/redefined-event.json: In event 'EVENT_A':
+tests/qapi-schema/redefined-event.json:2: previous definition
diff --git a/tests/qapi-schema/redefined-type.err b/tests/qapi-schema/redefined-type.err
index 06ea78c478..77786f98ae 100644
--- a/tests/qapi-schema/redefined-type.err
+++ b/tests/qapi-schema/redefined-type.err
@@ -1 +1,4 @@
-tests/qapi-schema/redefined-type.json:3: struct 'foo' is already defined
+tests/qapi-schema/redefined-type.json: In enum 'foo':
+tests/qapi-schema/redefined-type.json:3: 'foo' is already defined
+tests/qapi-schema/redefined-type.json: In struct 'foo':
+tests/qapi-schema/redefined-type.json:2: previous definition
diff --git a/tests/qapi-schema/reserved-command-q.err b/tests/qapi-schema/reserved-command-q.err
index f939e044eb..7f65cda02d 100644
--- a/tests/qapi-schema/reserved-command-q.err
+++ b/tests/qapi-schema/reserved-command-q.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix'
+tests/qapi-schema/reserved-command-q.json: In command 'q-unix':
+tests/qapi-schema/reserved-command-q.json:5: command has an invalid name
diff --git a/tests/qapi-schema/reserved-enum-q.err b/tests/qapi-schema/reserved-enum-q.err
index e1c3480ee2..e202f9ff7b 100644
--- a/tests/qapi-schema/reserved-enum-q.err
+++ b/tests/qapi-schema/reserved-enum-q.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-enum-q.json:4: Member of enum 'Foo' uses invalid name 'q-Unix'
+tests/qapi-schema/reserved-enum-q.json: In enum 'Foo':
+tests/qapi-schema/reserved-enum-q.json:4: 'data' member 'q-Unix' has an invalid name
diff --git a/tests/qapi-schema/reserved-member-has.err b/tests/qapi-schema/reserved-member-has.err
index e755771446..c7ad721ad1 100644
--- a/tests/qapi-schema/reserved-member-has.err
+++ b/tests/qapi-schema/reserved-member-has.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a'
+tests/qapi-schema/reserved-member-has.json: In command 'oops':
+tests/qapi-schema/reserved-member-has.json:5: 'data' member 'has-a' uses reserved name
diff --git a/tests/qapi-schema/reserved-member-q.err b/tests/qapi-schema/reserved-member-q.err
index f3d5dd7818..04078604fa 100644
--- a/tests/qapi-schema/reserved-member-q.err
+++ b/tests/qapi-schema/reserved-member-q.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
+tests/qapi-schema/reserved-member-q.json: In struct 'Foo':
+tests/qapi-schema/reserved-member-q.json:4: 'data' member 'q-unix' has an invalid name
diff --git a/tests/qapi-schema/reserved-member-u.err b/tests/qapi-schema/reserved-member-u.err
index 87d42296cc..2e92c11ba5 100644
--- a/tests/qapi-schema/reserved-member-u.err
+++ b/tests/qapi-schema/reserved-member-u.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u'
+tests/qapi-schema/reserved-member-u.json: In struct 'Oops':
+tests/qapi-schema/reserved-member-u.json:7: 'data' member 'u' uses reserved name
diff --git a/tests/qapi-schema/reserved-member-underscore.err b/tests/qapi-schema/reserved-member-underscore.err
index 65ff0da8ce..da62b48222 100644
--- a/tests/qapi-schema/reserved-member-underscore.err
+++ b/tests/qapi-schema/reserved-member-underscore.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-member-underscore.json:4: Member of 'data' for struct 'Oops' uses invalid name '_oops'
+tests/qapi-schema/reserved-member-underscore.json: In struct 'Oops':
+tests/qapi-schema/reserved-member-underscore.json:4: 'data' member '_oops' has an invalid name
diff --git a/tests/qapi-schema/reserved-type-kind.err b/tests/qapi-schema/reserved-type-kind.err
index 0a38efaad8..f8112cf92e 100644
--- a/tests/qapi-schema/reserved-type-kind.err
+++ b/tests/qapi-schema/reserved-type-kind.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-type-kind.json:2: enum 'UnionKind' should not end in 'Kind'
+tests/qapi-schema/reserved-type-kind.json: In enum 'UnionKind':
+tests/qapi-schema/reserved-type-kind.json:2: enum name should not end in 'Kind'
diff --git a/tests/qapi-schema/reserved-type-list.err b/tests/qapi-schema/reserved-type-list.err
index 4510fa6d90..c6eee0585c 100644
--- a/tests/qapi-schema/reserved-type-list.err
+++ b/tests/qapi-schema/reserved-type-list.err
@@ -1 +1,2 @@
-tests/qapi-schema/reserved-type-list.json:5: struct 'FooList' should not end in 'List'
+tests/qapi-schema/reserved-type-list.json: In struct 'FooList':
+tests/qapi-schema/reserved-type-list.json:5: struct name should not end in 'List'
diff --git a/tests/qapi-schema/returns-alternate.err b/tests/qapi-schema/returns-alternate.err
index dfbb419cac..c1caf98c47 100644
--- a/tests/qapi-schema/returns-alternate.err
+++ b/tests/qapi-schema/returns-alternate.err
@@ -1 +1,2 @@
-tests/qapi-schema/returns-alternate.json:3: 'returns' for command 'oops' cannot use alternate type 'Alt'
+tests/qapi-schema/returns-alternate.json: In command 'oops':
+tests/qapi-schema/returns-alternate.json:3: command's 'returns' cannot take alternate type 'Alt'
diff --git a/tests/qapi-schema/returns-array-bad.err b/tests/qapi-schema/returns-array-bad.err
index 138095ccde..1b86777d8f 100644
--- a/tests/qapi-schema/returns-array-bad.err
+++ b/tests/qapi-schema/returns-array-bad.err
@@ -1 +1,2 @@
-tests/qapi-schema/returns-array-bad.json:2: 'returns' for command 'oops': array type must contain single type name
+tests/qapi-schema/returns-array-bad.json: In command 'oops':
+tests/qapi-schema/returns-array-bad.json:2: 'returns': array type must contain single type name
diff --git a/tests/qapi-schema/returns-dict.err b/tests/qapi-schema/returns-dict.err
index eb2d0c4661..52e4f3ad71 100644
--- a/tests/qapi-schema/returns-dict.err
+++ b/tests/qapi-schema/returns-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name
+tests/qapi-schema/returns-dict.json: In command 'oops':
+tests/qapi-schema/returns-dict.json:2: 'returns' should be a type name
diff --git a/tests/qapi-schema/returns-unknown.err b/tests/qapi-schema/returns-unknown.err
index 1f43e3ac9f..f0a989a175 100644
--- a/tests/qapi-schema/returns-unknown.err
+++ b/tests/qapi-schema/returns-unknown.err
@@ -1 +1,2 @@
-tests/qapi-schema/returns-unknown.json:2: 'returns' for command 'oops' uses unknown type 'NoSuchType'
+tests/qapi-schema/returns-unknown.json: In command 'oops':
+tests/qapi-schema/returns-unknown.json:2: command's 'returns' uses unknown type 'NoSuchType'
diff --git a/tests/qapi-schema/returns-whitelist.err b/tests/qapi-schema/returns-whitelist.err
index b2ba7a9deb..5b0285220f 100644
--- a/tests/qapi-schema/returns-whitelist.err
+++ b/tests/qapi-schema/returns-whitelist.err
@@ -1 +1,2 @@
-tests/qapi-schema/returns-whitelist.json:14: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
+tests/qapi-schema/returns-whitelist.json: In command 'no-way-this-will-get-whitelisted':
+tests/qapi-schema/returns-whitelist.json:14: command's 'returns' cannot take array type ['int']
diff --git a/tests/qapi-schema/string-code-point-127.err b/tests/qapi-schema/string-code-point-127.err
index c310910c23..b4fa2610a9 100644
--- a/tests/qapi-schema/string-code-point-127.err
+++ b/tests/qapi-schema/string-code-point-127.err
@@ -1 +1 @@
-tests/qapi-schema/string-code-point-127.json:2:14: Funny character in string
+tests/qapi-schema/string-code-point-127.json:2:14: funny character in string
diff --git a/tests/qapi-schema/string-code-point-31.err b/tests/qapi-schema/string-code-point-31.err
index 45797928d9..0bb5ce37b8 100644
--- a/tests/qapi-schema/string-code-point-31.err
+++ b/tests/qapi-schema/string-code-point-31.err
@@ -1 +1 @@
-tests/qapi-schema/string-code-point-31.json:2:14: Funny character in string
+tests/qapi-schema/string-code-point-31.json:2:14: funny character in string
diff --git a/tests/qapi-schema/struct-base-clash-deep.err b/tests/qapi-schema/struct-base-clash-deep.err
index e2d7943f21..2b12b3c07f 100644
--- a/tests/qapi-schema/struct-base-clash-deep.err
+++ b/tests/qapi-schema/struct-base-clash-deep.err
@@ -1 +1,2 @@
-tests/qapi-schema/struct-base-clash-deep.json:10: 'name' (member of Sub) collides with 'name' (member of Base)
+tests/qapi-schema/struct-base-clash-deep.json: In struct 'Sub':
+tests/qapi-schema/struct-base-clash-deep.json:10: member 'name' collides with member 'name' of type 'Base'
diff --git a/tests/qapi-schema/struct-base-clash.err b/tests/qapi-schema/struct-base-clash.err
index c52f33d27b..8c3ee1c435 100644
--- a/tests/qapi-schema/struct-base-clash.err
+++ b/tests/qapi-schema/struct-base-clash.err
@@ -1 +1,2 @@
-tests/qapi-schema/struct-base-clash.json:5: 'name' (member of Sub) collides with 'name' (member of Base)
+tests/qapi-schema/struct-base-clash.json: In struct 'Sub':
+tests/qapi-schema/struct-base-clash.json:5: member 'name' collides with member 'name' of type 'Base'
diff --git a/tests/qapi-schema/struct-data-invalid.err b/tests/qapi-schema/struct-data-invalid.err
index 4bf5bcc255..aa868bf974 100644
--- a/tests/qapi-schema/struct-data-invalid.err
+++ b/tests/qapi-schema/struct-data-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be an object or type name
+tests/qapi-schema/struct-data-invalid.json: In struct 'foo':
+tests/qapi-schema/struct-data-invalid.json:1: 'data' should be an object or type name
diff --git a/tests/qapi-schema/struct-member-if-invalid.err b/tests/qapi-schema/struct-member-if-invalid.err
index bfd65db97b..4c5983674b 100644
--- a/tests/qapi-schema/struct-member-if-invalid.err
+++ b/tests/qapi-schema/struct-member-if-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/struct-member-if-invalid.json:2: 'if' condition must be a string or a list of strings
+tests/qapi-schema/struct-member-if-invalid.json: In struct 'Stru':
+tests/qapi-schema/struct-member-if-invalid.json:2: 'if' condition of 'data' member 'member' must be a string or a list of strings
diff --git a/tests/qapi-schema/struct-member-invalid-dict.err b/tests/qapi-schema/struct-member-invalid-dict.err
index 6a765bc668..46ec991c28 100644
--- a/tests/qapi-schema/struct-member-invalid-dict.err
+++ b/tests/qapi-schema/struct-member-invalid-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/struct-member-invalid-dict.json:2: Key 'type' is missing from member '*a' of 'data' for struct 'foo'
+tests/qapi-schema/struct-member-invalid-dict.json: In struct 'foo':
+tests/qapi-schema/struct-member-invalid-dict.json:2: 'data' member '*a' misses key 'type'
diff --git a/tests/qapi-schema/struct-member-invalid.err b/tests/qapi-schema/struct-member-invalid.err
index 69a326d450..92d4973832 100644
--- a/tests/qapi-schema/struct-member-invalid.err
+++ b/tests/qapi-schema/struct-member-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name
+tests/qapi-schema/struct-member-invalid.json: In struct 'foo':
+tests/qapi-schema/struct-member-invalid.json:1: 'data' member 'a' should be a type name
diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err
index 601c4537c3..167d688beb 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 '{', '[', string, boolean or 'null'
+tests/qapi-schema/trailing-comma-list.json:2:36: expected '{', '[', string, boolean or 'null'
diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err
index 30bce5e194..186df0fa45 100644
--- a/tests/qapi-schema/trailing-comma-object.err
+++ b/tests/qapi-schema/trailing-comma-object.err
@@ -1 +1 @@
-tests/qapi-schema/trailing-comma-object.json:2:38: Expected string
+tests/qapi-schema/trailing-comma-object.json:2:38: expected string
diff --git a/tests/qapi-schema/type-bypass-bad-gen.err b/tests/qapi-schema/type-bypass-bad-gen.err
index a83c3c655d..1077651896 100644
--- a/tests/qapi-schema/type-bypass-bad-gen.err
+++ b/tests/qapi-schema/type-bypass-bad-gen.err
@@ -1 +1,2 @@
-tests/qapi-schema/type-bypass-bad-gen.json:2: 'gen' of command 'foo' should only use false value
+tests/qapi-schema/type-bypass-bad-gen.json: In command 'foo':
+tests/qapi-schema/type-bypass-bad-gen.json:2: flag 'gen' may only use false value
diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err
index 1cc3a094fe..6648a8e30b 100644
--- a/tests/qapi-schema/unclosed-list.err
+++ b/tests/qapi-schema/unclosed-list.err
@@ -1 +1 @@
-tests/qapi-schema/unclosed-list.json:1:20: Expected ',' or ']'
+tests/qapi-schema/unclosed-list.json:1:20: expected ',' or ']'
diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err
index fd1a86b704..54d221e3a9 100644
--- a/tests/qapi-schema/unclosed-object.err
+++ b/tests/qapi-schema/unclosed-object.err
@@ -1 +1 @@
-tests/qapi-schema/unclosed-object.json:1:21: Expected ',' or '}'
+tests/qapi-schema/unclosed-object.json:1:21: expected ',' or '}'
diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err
index 12b187074e..9439698fe0 100644
--- a/tests/qapi-schema/unclosed-string.err
+++ b/tests/qapi-schema/unclosed-string.err
@@ -1 +1 @@
-tests/qapi-schema/unclosed-string.json:1:11: Missing terminating "'"
+tests/qapi-schema/unclosed-string.json:1:11: missing terminating "'"
diff --git a/tests/qapi-schema/union-base-empty.err b/tests/qapi-schema/union-base-empty.err
index 9453720ede..b76542d47a 100644
--- a/tests/qapi-schema/union-base-empty.err
+++ b/tests/qapi-schema/union-base-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-base-empty.json:5: Discriminator 'type' is not a member of 'base'
+tests/qapi-schema/union-base-empty.json: In union 'TestUnion':
+tests/qapi-schema/union-base-empty.json:5: discriminator 'type' is not a member of 'base'
diff --git a/tests/qapi-schema/union-base-no-discriminator.err b/tests/qapi-schema/union-base-no-discriminator.err
index 8b7a24260f..f4c16a2c14 100644
--- a/tests/qapi-schema/union-base-no-discriminator.err
+++ b/tests/qapi-schema/union-base-no-discriminator.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base
+tests/qapi-schema/union-base-no-discriminator.json: In union 'TestUnion':
+tests/qapi-schema/union-base-no-discriminator.json:11: 'base' requires 'discriminator'
diff --git a/tests/qapi-schema/union-branch-case.err b/tests/qapi-schema/union-branch-case.err
index 11521901d8..a0684ae637 100644
--- a/tests/qapi-schema/union-branch-case.err
+++ b/tests/qapi-schema/union-branch-case.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-branch-case.json:2: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase
+tests/qapi-schema/union-branch-case.json: In union 'Uni':
+tests/qapi-schema/union-branch-case.json:2: 'data' member 'Branch' uses uppercase in name
diff --git a/tests/qapi-schema/union-branch-case.json b/tests/qapi-schema/union-branch-case.json
index e6565dc3b3..b7894b75d6 100644
--- a/tests/qapi-schema/union-branch-case.json
+++ b/tests/qapi-schema/union-branch-case.json
@@ -1,2 +1,2 @@
-# Branch names should be 'lower-case' unless the union is whitelisted
-{ 'union': 'NoWayThisWillGetWhitelisted', 'data': { 'Branch': 'int' } }
+# Branch names should be 'lower-case'
+{ 'union': 'Uni', 'data': { 'Branch': 'int' } }
diff --git a/tests/qapi-schema/union-branch-if-invalid.err b/tests/qapi-schema/union-branch-if-invalid.err
index 607edee382..14819bf8b8 100644
--- a/tests/qapi-schema/union-branch-if-invalid.err
+++ b/tests/qapi-schema/union-branch-if-invalid.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-branch-if-invalid.json:4: 'if' condition '' makes no sense
+tests/qapi-schema/union-branch-if-invalid.json: In union 'Uni':
+tests/qapi-schema/union-branch-if-invalid.json:4: 'if' condition '' of 'data' member 'branch1' makes no sense
diff --git a/tests/qapi-schema/union-branch-invalid-dict.err b/tests/qapi-schema/union-branch-invalid-dict.err
index 89f9b36791..2967cd6260 100644
--- a/tests/qapi-schema/union-branch-invalid-dict.err
+++ b/tests/qapi-schema/union-branch-invalid-dict.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-branch-invalid-dict.json:2: Key 'type' is missing from member 'integer' of union 'UnionInvalidBranch'
+tests/qapi-schema/union-branch-invalid-dict.json: In union 'UnionInvalidBranch':
+tests/qapi-schema/union-branch-invalid-dict.json:2: 'data' member 'integer' misses key 'type'
diff --git a/tests/qapi-schema/union-clash-branches.err b/tests/qapi-schema/union-clash-branches.err
index e5b21135bb..931399f076 100644
--- a/tests/qapi-schema/union-clash-branches.err
+++ b/tests/qapi-schema/union-clash-branches.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-clash-branches.json:4: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion)
+tests/qapi-schema/union-clash-branches.json: In union 'TestUnion':
+tests/qapi-schema/union-clash-branches.json:4: branch 'a_b' collides with branch 'a-b'
diff --git a/tests/qapi-schema/union-empty.err b/tests/qapi-schema/union-empty.err
index d4241a38a2..35c0d62eb0 100644
--- a/tests/qapi-schema/union-empty.err
+++ b/tests/qapi-schema/union-empty.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-empty.json:2: Union 'Union' has no branches
+tests/qapi-schema/union-empty.json: In union 'Union':
+tests/qapi-schema/union-empty.json:2: union has no branches
diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err
index 03d7b97a93..10fecf0b56 100644
--- a/tests/qapi-schema/union-invalid-base.err
+++ b/tests/qapi-schema/union-invalid-base.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-invalid-base.json:8: 'base' for union 'TestUnion' cannot use built-in type 'int'
+tests/qapi-schema/union-invalid-base.json: In union 'TestUnion':
+tests/qapi-schema/union-invalid-base.json:8: 'base' requires a struct type, built-in type 'int' isn't
diff --git a/tests/qapi-schema/union-optional-branch.err b/tests/qapi-schema/union-optional-branch.err
index 3ada1334dc..9f24274923 100644
--- a/tests/qapi-schema/union-optional-branch.err
+++ b/tests/qapi-schema/union-optional-branch.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-optional-branch.json:2: Member of union 'Union' does not allow optional name '*a'
+tests/qapi-schema/union-optional-branch.json: In union 'Union':
+tests/qapi-schema/union-optional-branch.json:2: 'data' member '*a' has an invalid name
diff --git a/tests/qapi-schema/union-unknown.err b/tests/qapi-schema/union-unknown.err
index 54fe456f9c..a7f340ddca 100644
--- a/tests/qapi-schema/union-unknown.err
+++ b/tests/qapi-schema/union-unknown.err
@@ -1 +1,2 @@
-tests/qapi-schema/union-unknown.json:2: Member 'unknown' of union 'Union' uses unknown type 'MissingType'
+tests/qapi-schema/union-unknown.json: In union 'Union':
+tests/qapi-schema/union-unknown.json:2: union uses unknown type 'MissingType'
diff --git a/tests/qapi-schema/union-unknown.json b/tests/qapi-schema/union-unknown.json
index aa7e8143d8..64d3666176 100644
--- a/tests/qapi-schema/union-unknown.json
+++ b/tests/qapi-schema/union-unknown.json
@@ -1,3 +1,3 @@
# we reject a union with unknown type in branch
{ 'union': 'Union',
- 'data': { 'unknown': 'MissingType' } }
+ 'data': { 'unknown': ['MissingType'] } }
diff --git a/tests/qapi-schema/unknown-escape.err b/tests/qapi-schema/unknown-escape.err
index 000e30ddf3..e24bbaf046 100644
--- a/tests/qapi-schema/unknown-escape.err
+++ b/tests/qapi-schema/unknown-escape.err
@@ -1 +1 @@
-tests/qapi-schema/unknown-escape.json:3:21: Unknown escape \x
+tests/qapi-schema/unknown-escape.json:3:21: unknown escape \x
diff --git a/tests/qapi-schema/unknown-expr-key.err b/tests/qapi-schema/unknown-expr-key.err
index 4340eaf894..be9f99c4ef 100644
--- a/tests/qapi-schema/unknown-expr-key.err
+++ b/tests/qapi-schema/unknown-expr-key.err
@@ -1,2 +1,3 @@
-tests/qapi-schema/unknown-expr-key.json:2: Unknown keys 'bogus', 'phony' in struct 'bar'
+tests/qapi-schema/unknown-expr-key.json: In struct 'bar':
+tests/qapi-schema/unknown-expr-key.json:2: struct has unknown keys 'bogus', 'phony'
Valid keys are 'base', 'data', 'features', 'if', 'struct'.
diff --git a/tests/test-qga.c b/tests/test-qga.c
index 891aa3d322..1ca49bbced 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -668,7 +668,7 @@ static void test_qga_blacklist(gconstpointer data)
error = qdict_get_qdict(ret, "error");
class = qdict_get_try_str(error, "class");
desc = qdict_get_try_str(error, "desc");
- g_assert_cmpstr(class, ==, "GenericError");
+ g_assert_cmpstr(class, ==, "CommandNotFound");
g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
qobject_unref(ret);
@@ -677,7 +677,7 @@ static void test_qga_blacklist(gconstpointer data)
error = qdict_get_qdict(ret, "error");
class = qdict_get_try_str(error, "class");
desc = qdict_get_try_str(error, "desc");
- g_assert_cmpstr(class, ==, "GenericError");
+ g_assert_cmpstr(class, ==, "CommandNotFound");
g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled"));
qobject_unref(ret);