mirror of
https://github.com/qemu/qemu.git
synced 2024-12-14 06:53:43 +08:00
QAPI patches patches for 2021-03-23
-----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmBaX7ESHGFybWJydUBy ZWRoYXQuY29tAAoJEDhwtADrkYZTJtcP/jk3JNg4+rFQJ3BnxQFSpy7TnmuJ91yo V8AcrPBhLm/HFhoUN2nPkz1I5QcifPGnO8KUFeOupOi6DCEy1fVgUeti3IynPV0M TbsHUIDhpyxxK3Ppy13TpLXnGdsFNyD+j03uS2kXpHUn/jQIVQ/DYVwguo1hAVwv RoPFHJ1qh8bTPytWBelaXDxiuHDhjApIcjzuNpcSWKkupP6CalrBWIHlFG5Xzc1S +/XpsroIbGIvV9Ed5BvRzZGLeBxHy+aOdeL//gbgC89I4CFTgUDBvo3uWYT/3whN j0spF/QSQM/6pDbnG6KUmQglg9FWaO0MgjTXjJHVg8iRr7ohJavVb5H+mot2ML5O KbT8ASUrQ2uk3AWXwjAHjxk+ZKnd+NegjrwSvsP9XUbNt7lW+g1ZsYEA2HuUWu2/ UnD7JhcTKwebJfBGmwGUhgGpFA3nsOnOk+feOxW7wX2y2ZXG4NZEX094ZOrb+atW ZsJLBz/ZIBB41+6hJTlQEgaLH+WnEdUWRBZEGj/To2R7g4t3RY7QTQW4VIyMNdxv j74qw8QgyWHH8tMYXxAwFoLS/GXLhMXQUgYVD3f/+Cqwv1flSEAGMDqW3PD6eR5/ 4kVq4pR7tu64c69kQVFwpTORskbw4KVfLxQRqjhASNH+Q4LBtnoJ/MnWJ87puUzz BMPLykjETa1K =pQZf -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-03-23' into staging QAPI patches patches for 2021-03-23 # gpg: Signature made Tue 23 Mar 2021 21:37:53 GMT # 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-2021-03-23: (29 commits) block: Remove monitor command block_passwd qapi: Enforce union and alternate branch naming rules qapi: Enforce enum member naming rules qapi: Enforce struct member naming rules tests/qapi-schema: Switch member name clash test to struct qapi: Enforce command naming rules qapi: Enforce feature naming rules qapi: Prepare for rejecting underscore in command and member names tests-qmp-cmds: Drop unused and incorrect qmp_TestIfCmd() qapi/pragma: Streamline comments on member-name-exceptions qapi: Rename pragma *-whitelist to *-exceptions tests/qapi-schema: Rename returns-whitelist to returns-bad-type tests/qapi-schema: Rename pragma-*-crap to pragma-value-not-* qapi: Factor out QAPISchemaParser._check_pragma_list_of_str() tests/qapi-schema: Rename redefined-builtin to redefined-predefined qapi: Enforce type naming rules qapi: Enforce event naming rules qapi: Consistently permit any case in downstream prefixes qapi: Move uppercase rejection to check_name_lower() qapi: Rework name checking in preparation of stricter checking ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
2664699471
@ -515,16 +515,6 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
|
||||
hmp_handle_error(mon, error);
|
||||
}
|
||||
|
||||
void hmp_block_passwd(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
const char *password = qdict_get_str(qdict, "password");
|
||||
Error *err = NULL;
|
||||
|
||||
qmp_block_passwd(true, device, false, NULL, password, &err);
|
||||
hmp_handle_error(mon, err);
|
||||
}
|
||||
|
||||
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
@ -2407,14 +2407,6 @@ exit:
|
||||
job_txn_unref(block_job_txn);
|
||||
}
|
||||
|
||||
void qmp_block_passwd(bool has_device, const char *device,
|
||||
bool has_node_name, const char *node_name,
|
||||
const char *password, Error **errp)
|
||||
{
|
||||
error_setg(errp,
|
||||
"Setting block passwords directly is no longer supported");
|
||||
}
|
||||
|
||||
BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
|
||||
const char *name,
|
||||
Error **errp)
|
||||
|
@ -147,9 +147,11 @@ prevent incomplete include files.
|
||||
=== Pragma directives ===
|
||||
|
||||
Syntax:
|
||||
PRAGMA = { 'pragma': { '*doc-required': BOOL,
|
||||
'*returns-whitelist': [ STRING, ... ],
|
||||
'*name-case-whitelist': [ STRING, ... ] } }
|
||||
PRAGMA = { 'pragma': {
|
||||
'*doc-required': BOOL,
|
||||
'*command-name-exceptions': [ STRING, ... ],
|
||||
'*command-returns-exceptions': [ STRING, ... ],
|
||||
'*member-name-exceptions': [ STRING, ... ] } }
|
||||
|
||||
The pragma directive lets you control optional generator behavior.
|
||||
|
||||
@ -159,11 +161,15 @@ pragma to different values in parts of the schema doesn't work.
|
||||
Pragma 'doc-required' takes a boolean value. If true, documentation
|
||||
is required. Default is false.
|
||||
|
||||
Pragma 'returns-whitelist' takes a list of command names that may
|
||||
Pragma 'command-name-exceptions' takes a list of commands whose names
|
||||
may contain '_' instead of '-'. Default is none.
|
||||
|
||||
Pragma 'command-returns-exceptions' takes a list of commands that may
|
||||
violate the rules on permitted return types. Default is none.
|
||||
|
||||
Pragma 'name-case-whitelist' takes a list of names that may violate
|
||||
rules on use of upper- vs. lower-case letters. Default is none.
|
||||
Pragma 'member-name-exceptions' takes a list of types whose member
|
||||
names may contain uppercase letters, and '_' instead of '-'. Default
|
||||
is none.
|
||||
|
||||
|
||||
=== Enumeration types ===
|
||||
@ -490,9 +496,9 @@ are the arguments. A union type requires 'boxed': true.
|
||||
Member 'returns' defines the command's return type. It defaults to an
|
||||
empty struct type. It must normally be a complex type or an array of
|
||||
a complex type. To return anything else, the command must be listed
|
||||
in pragma 'returns-whitelist'. If you do this, extending the command
|
||||
to return additional information will be harder. Use of
|
||||
'returns-whitelist' for new commands is strongly discouraged.
|
||||
in pragma 'commands-returns-exceptions'. If you do this, extending
|
||||
the command to return additional information will be harder. Use of
|
||||
the pragma for new commands is strongly discouraged.
|
||||
|
||||
A command's error responses are not specified in the QAPI schema.
|
||||
Error conditions should be documented in comments.
|
||||
@ -755,8 +761,8 @@ Any name (command, event, type, member, or enum value) beginning with
|
||||
"x-" is marked experimental, and may be withdrawn or changed
|
||||
incompatibly in a future release.
|
||||
|
||||
Pragma 'name-case-whitelist' lets you violate the rules on use of
|
||||
upper and lower case. Use for new code is strongly discouraged.
|
||||
Pragmas 'command-name-exceptions' and 'member-name-exceptions' let you
|
||||
violate naming rules. Use for new code is strongly discouraged.
|
||||
|
||||
|
||||
=== Downstream extensions ===
|
||||
|
@ -1493,21 +1493,6 @@ SRST
|
||||
used by another monitor command.
|
||||
ERST
|
||||
|
||||
{
|
||||
.name = "block_passwd",
|
||||
.args_type = "device:B,password:s",
|
||||
.params = "block_passwd device password",
|
||||
.help = "set the password of encrypted block devices",
|
||||
.cmd = hmp_block_passwd,
|
||||
},
|
||||
|
||||
SRST
|
||||
``block_passwd`` *device* *password*
|
||||
Set the encrypted device *device* password to *password*
|
||||
|
||||
This command is now obsolete and will always return an error since 2.10
|
||||
ERST
|
||||
|
||||
{
|
||||
.name = "block_set_io_throttle",
|
||||
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
|
||||
|
@ -1207,20 +1207,6 @@
|
||||
##
|
||||
{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
|
||||
|
||||
##
|
||||
# @block_passwd:
|
||||
#
|
||||
# This command sets the password of a block device that has not been open
|
||||
# with a password and requires one.
|
||||
#
|
||||
# This command is now obsolete and will always return an error since 2.10
|
||||
#
|
||||
##
|
||||
{ 'command': 'block_passwd',
|
||||
'data': { '*device': 'str',
|
||||
'*node-name': 'str',
|
||||
'password': 'str' } }
|
||||
|
||||
##
|
||||
# @block_resize:
|
||||
#
|
||||
|
@ -4,21 +4,61 @@
|
||||
# add to them!
|
||||
{ 'pragma': {
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
'command-name-exceptions': [
|
||||
'add_client',
|
||||
'block_resize',
|
||||
'block_set_io_throttle',
|
||||
'client_migrate_info',
|
||||
'device_add',
|
||||
'device_del',
|
||||
'expire_password',
|
||||
'migrate_cancel',
|
||||
'netdev_add',
|
||||
'netdev_del',
|
||||
'qmp_capabilities',
|
||||
'set_link',
|
||||
'set_password',
|
||||
'system_powerdown',
|
||||
'system_reset',
|
||||
'system_wakeup' ],
|
||||
'command-returns-exceptions': [
|
||||
'human-monitor-command',
|
||||
'qom-get',
|
||||
'query-migrate-cache-size',
|
||||
'query-tpm-models',
|
||||
'query-tpm-types',
|
||||
'ringbuf-read' ],
|
||||
'name-case-whitelist': [
|
||||
'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
|
||||
'CpuInfoMIPS', # PC, visible through query-cpu
|
||||
'CpuInfoTricore', # PC, visible through query-cpu
|
||||
'BlockdevVmdkSubformat', # all members, to match VMDK spec spellings
|
||||
'BlockdevVmdkAdapterType', # legacyESX, to match VMDK spec spellings
|
||||
'QapiErrorClass', # all members, visible through errors
|
||||
'UuidInfo', # UUID, visible through query-uuid
|
||||
'X86CPURegister32', # all members, visible indirectly through qom-get
|
||||
'CpuInfo' # CPU, visible through query-cpu
|
||||
# Externally visible types whose member names may use uppercase
|
||||
'member-name-exceptions': [ # visible in:
|
||||
'ACPISlotType', # query-acpi-ospm-status
|
||||
'AcpiTableOptions', # -acpitable
|
||||
'BlkdebugEvent', # blockdev-add, -blockdev
|
||||
'BlkdebugSetStateOptions', # blockdev-add, -blockdev
|
||||
'BlockDeviceInfo', # query-block
|
||||
'BlockDeviceStats', # query-blockstats
|
||||
'BlockDeviceTimedStats', # query-blockstats
|
||||
'BlockIOThrottle', # block_set_io_throttle
|
||||
'BlockInfo', # query-block
|
||||
'BlockdevAioOptions', # blockdev-add, -blockdev
|
||||
'BlockdevDriver', # blockdev-add, query-blockstats, ...
|
||||
'BlockdevVmdkAdapterType', # blockdev-create (to match VMDK spec)
|
||||
'BlockdevVmdkSubformat', # blockdev-create (to match VMDK spec)
|
||||
'ColoCompareProperties', # object_add, -object
|
||||
'FilterMirrorProperties', # object_add, -object
|
||||
'FilterRedirectorProperties', # object_add, -object
|
||||
'FilterRewriterProperties', # object_add, -object
|
||||
'InputLinuxProperties', # object_add, -object
|
||||
'NetdevTapOptions', # netdev_add, query-netdev, -netdev
|
||||
'ObjectType', # object-add, -object
|
||||
'PCIELinkSpeed', # internal only
|
||||
'PciBusInfo', # query-pci
|
||||
'PciDeviceInfo', # query-pci
|
||||
'PciMemoryRegion', # query-pci
|
||||
'QKeyCode', # send-key, input-sent-event
|
||||
'QapiErrorClass', # QMP error replies
|
||||
'SshHostKeyCheckMode', # blockdev-add, -blockdev
|
||||
'SysEmuTarget', # query-cpu-fast, query-target
|
||||
'UuidInfo', # query-uuid
|
||||
'VncClientInfo', # query-vnc, query-vnc-servers, ...
|
||||
'X86CPURegister32' # qom-get of x86 CPU properties
|
||||
# feature-words, filtered-features
|
||||
] } }
|
||||
|
@ -19,8 +19,12 @@
|
||||
# Whitelists to permit QAPI rule violations; think twice before you
|
||||
# add to them!
|
||||
{ 'pragma': {
|
||||
# Types whose member names may use '_'
|
||||
'member-name-exceptions': [
|
||||
'GuestAgentInfo'
|
||||
],
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
'command-returns-exceptions': [
|
||||
'guest-file-open',
|
||||
'guest-fsfreeze-freeze',
|
||||
'guest-fsfreeze-freeze-list',
|
||||
|
@ -18,7 +18,6 @@ from typing import Optional, Sequence
|
||||
#: Magic string that gets removed along with all space to its right.
|
||||
EATSPACE = '\033EATSPACE.'
|
||||
POINTER_SUFFIX = ' *' + EATSPACE
|
||||
_C_NAME_TRANS = str.maketrans('.-', '__')
|
||||
|
||||
|
||||
def camel_to_upper(value: str) -> str:
|
||||
@ -109,9 +108,10 @@ def c_name(name: str, protect: bool = True) -> str:
|
||||
'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
|
||||
# namespace pollution:
|
||||
polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386'])
|
||||
name = name.translate(_C_NAME_TRANS)
|
||||
if protect and (name in c89_words | c99_words | c11_words | gcc_words
|
||||
| cpp_words | polluted_words):
|
||||
name = re.sub(r'[^A-Za-z0-9_]', '_', name)
|
||||
if protect and (name in (c89_words | c99_words | c11_words | gcc_words
|
||||
| cpp_words | polluted_words)
|
||||
or name[0].isdigit()):
|
||||
return 'q_' + name
|
||||
return name
|
||||
|
||||
|
@ -21,11 +21,12 @@ from .common import c_name
|
||||
from .error import QAPISemError
|
||||
|
||||
|
||||
# Names must be letters, numbers, -, and _. They must start with letter,
|
||||
# except for downstream extensions which must start with __RFQDN_.
|
||||
# Dots are only valid in the downstream extension prefix.
|
||||
valid_name = re.compile(r'^(__[a-zA-Z0-9.-]+_)?'
|
||||
'[a-zA-Z][a-zA-Z0-9_-]*$')
|
||||
# Names consist of letters, digits, -, and _, starting with a letter.
|
||||
# An experimental name is prefixed with x-. A name of a downstream
|
||||
# extension is prefixed with __RFQDN_. The latter prefix goes first.
|
||||
valid_name = re.compile(r'(__[a-z0-9.-]+_)?'
|
||||
r'(x-)?'
|
||||
r'([a-z][a-z0-9_-]*)$', re.IGNORECASE)
|
||||
|
||||
|
||||
def check_name_is_str(name, info, source):
|
||||
@ -33,30 +34,47 @@ def check_name_is_str(name, info, source):
|
||||
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):
|
||||
membername = name
|
||||
|
||||
if allow_optional and name.startswith('*'):
|
||||
membername = name[1:]
|
||||
# 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():
|
||||
membername = 'D' + membername
|
||||
def check_name_str(name, info, source):
|
||||
# Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
|
||||
# and 'q_obj_*' implicit type names.
|
||||
if not valid_name.match(membername) or \
|
||||
c_name(membername, False).startswith('q_'):
|
||||
match = valid_name.match(name)
|
||||
if not match or c_name(name, False).startswith('q_'):
|
||||
raise QAPISemError(info, "%s has an invalid name" % source)
|
||||
if not permit_upper and name.lower() != name:
|
||||
return match.group(3)
|
||||
|
||||
|
||||
def check_name_upper(name, info, source):
|
||||
stem = check_name_str(name, info, source)
|
||||
if re.search(r'[a-z-]', stem):
|
||||
raise QAPISemError(
|
||||
info, "%s uses uppercase in name" % source)
|
||||
assert not membername.startswith('*')
|
||||
info, "name of %s must not use lowercase or '-'" % source)
|
||||
|
||||
|
||||
def check_name_lower(name, info, source,
|
||||
permit_upper=False,
|
||||
permit_underscore=False):
|
||||
stem = check_name_str(name, info, source)
|
||||
if ((not permit_upper and re.search(r'[A-Z]', stem))
|
||||
or (not permit_underscore and '_' in stem)):
|
||||
raise QAPISemError(
|
||||
info, "name of %s must not use uppercase or '_'" % source)
|
||||
|
||||
|
||||
def check_name_camel(name, info, source):
|
||||
stem = check_name_str(name, info, source)
|
||||
if not re.match(r'[A-Z][A-Za-z0-9]*[a-z][A-Za-z0-9]*$', stem):
|
||||
raise QAPISemError(info, "name of %s must use CamelCase" % source)
|
||||
|
||||
|
||||
def check_defn_name_str(name, info, meta):
|
||||
check_name_str(name, info, meta, permit_upper=True)
|
||||
if meta == 'event':
|
||||
check_name_upper(name, info, meta)
|
||||
elif meta == 'command':
|
||||
check_name_lower(
|
||||
name, info, meta,
|
||||
permit_underscore=name in info.pragma.command_name_exceptions)
|
||||
else:
|
||||
check_name_camel(name, info, meta)
|
||||
if name.endswith('Kind') or name.endswith('List'):
|
||||
raise QAPISemError(
|
||||
info, "%s name should not end in '%s'" % (meta, name[-4:]))
|
||||
@ -166,13 +184,16 @@ def check_type(value, info, source,
|
||||
raise QAPISemError(info,
|
||||
"%s should be an object or type name" % source)
|
||||
|
||||
permit_upper = allow_dict in info.pragma.name_case_whitelist
|
||||
permissive = allow_dict in info.pragma.member_name_exceptions
|
||||
|
||||
# value is a dictionary, check that each member is okay
|
||||
for (key, arg) in value.items():
|
||||
key_source = "%s member '%s'" % (source, key)
|
||||
check_name_str(key, info, key_source,
|
||||
allow_optional=True, permit_upper=permit_upper)
|
||||
if key.startswith('*'):
|
||||
key = key[1:]
|
||||
check_name_lower(key, info, key_source,
|
||||
permit_upper=permissive,
|
||||
permit_underscore=permissive)
|
||||
if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
|
||||
raise QAPISemError(info, "%s uses reserved name" % key_source)
|
||||
check_keys(arg, info, key_source, ['type'], ['if', 'features'])
|
||||
@ -194,7 +215,7 @@ def check_features(features, 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_name_lower(f['name'], info, source)
|
||||
check_if(f, info, source)
|
||||
|
||||
|
||||
@ -208,17 +229,22 @@ def check_enum(expr, info):
|
||||
if prefix is not None and not isinstance(prefix, str):
|
||||
raise QAPISemError(info, "'prefix' must be a string")
|
||||
|
||||
permit_upper = name in info.pragma.name_case_whitelist
|
||||
permissive = name in info.pragma.member_name_exceptions
|
||||
|
||||
members[:] = [m if isinstance(m, dict) else {'name': m}
|
||||
for m in members]
|
||||
for member in members:
|
||||
source = "'data' member"
|
||||
member_name = member['name']
|
||||
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_name_is_str(member_name, info, source)
|
||||
source = "%s '%s'" % (source, member_name)
|
||||
# Enum members may start with a digit
|
||||
if member_name[0].isdigit():
|
||||
member_name = 'd' + member_name # Hack: hide the digit
|
||||
check_name_lower(member_name, info, source,
|
||||
permit_upper=permissive,
|
||||
permit_underscore=permissive)
|
||||
check_if(member, info, source)
|
||||
|
||||
|
||||
@ -247,7 +273,9 @@ def check_union(expr, info):
|
||||
|
||||
for (key, value) in members.items():
|
||||
source = "'data' member '%s'" % key
|
||||
check_name_str(key, info, source)
|
||||
if discriminator is None:
|
||||
check_name_lower(key, info, source)
|
||||
# else: name is in discriminator enum, which gets checked
|
||||
check_keys(value, info, source, ['type'], ['if'])
|
||||
check_if(value, info, source)
|
||||
check_type(value['type'], info, source, allow_array=not base)
|
||||
@ -260,7 +288,7 @@ def check_alternate(expr, info):
|
||||
raise QAPISemError(info, "'data' must not be empty")
|
||||
for (key, value) in members.items():
|
||||
source = "'data' member '%s'" % key
|
||||
check_name_str(key, info, source)
|
||||
check_name_lower(key, info, source)
|
||||
check_keys(value, info, source, ['type'], ['if'])
|
||||
check_if(value, info, source)
|
||||
check_type(value['type'], info, source)
|
||||
|
@ -119,26 +119,28 @@ class QAPISchemaParser:
|
||||
|
||||
return QAPISchemaParser(incl_fname, previously_included, info)
|
||||
|
||||
def _check_pragma_list_of_str(self, name, value, info):
|
||||
if (not isinstance(value, list)
|
||||
or any([not isinstance(elt, str) for elt in value])):
|
||||
raise QAPISemError(
|
||||
info,
|
||||
"pragma %s must be a list of strings" % name)
|
||||
|
||||
def _pragma(self, name, value, info):
|
||||
if name == 'doc-required':
|
||||
if not isinstance(value, bool):
|
||||
raise QAPISemError(info,
|
||||
"pragma 'doc-required' must be boolean")
|
||||
info.pragma.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")
|
||||
info.pragma.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")
|
||||
info.pragma.name_case_whitelist = value
|
||||
elif name == 'command-name-exceptions':
|
||||
self._check_pragma_list_of_str(name, value, info)
|
||||
info.pragma.command_name_exceptions = value
|
||||
elif name == 'command-returns-exceptions':
|
||||
self._check_pragma_list_of_str(name, value, info)
|
||||
info.pragma.command_returns_exceptions = value
|
||||
elif name == 'member-name-exceptions':
|
||||
self._check_pragma_list_of_str(name, value, info)
|
||||
info.pragma.member_name_exceptions = value
|
||||
else:
|
||||
raise QAPISemError(info, "unknown pragma '%s'" % name)
|
||||
|
||||
|
@ -779,7 +779,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
if self._ret_type_name:
|
||||
self.ret_type = schema.resolve_type(
|
||||
self._ret_type_name, self.info, "command's 'returns'")
|
||||
if self.name not in self.info.pragma.returns_whitelist:
|
||||
if self.name not in self.info.pragma.command_returns_exceptions:
|
||||
typ = self.ret_type
|
||||
if isinstance(typ, QAPISchemaArrayType):
|
||||
typ = self.ret_type.element_type
|
||||
|
@ -21,10 +21,12 @@ class QAPISchemaPragma:
|
||||
def __init__(self) -> None:
|
||||
# Are documentation comments required?
|
||||
self.doc_required = False
|
||||
# Whitelist of commands allowed to return a non-dictionary
|
||||
self.returns_whitelist: List[str] = []
|
||||
# Whitelist of entities allowed to violate case conventions
|
||||
self.name_case_whitelist: List[str] = []
|
||||
# Commands whose names may use '_'
|
||||
self.command_name_exceptions: List[str] = []
|
||||
# Commands allowed to return a non-dictionary
|
||||
self.command_returns_exceptions: List[str] = []
|
||||
# Types whose member names may violate case conventions
|
||||
self.member_name_exceptions: List[str] = []
|
||||
|
||||
|
||||
class QAPISourceInfo:
|
||||
|
@ -1,2 +1,2 @@
|
||||
alternate-clash.json: In alternate 'Alt1':
|
||||
alternate-clash.json:7: branch 'a_b' collides with branch 'a-b'
|
||||
alternate-clash.json:6: name of 'data' member 'a_b' must not use uppercase or '_'
|
||||
|
@ -1,8 +1,7 @@
|
||||
# Alternate branch name collision
|
||||
# Reject an alternate that would result in a collision in generated C
|
||||
# names (this would try to generate two enum values 'ALT1_KIND_A_B').
|
||||
# TODO: In the future, if alternates are simplified to not generate
|
||||
# the implicit Alt1Kind enum, we would still have a collision with the
|
||||
# resulting C union trying to have two members named 'a_b'.
|
||||
# Naming rules make collision impossible (even with the pragma). If
|
||||
# that wasn't the case, then we'd get a collision in generated C: two
|
||||
# union members a_b.
|
||||
{ 'pragma': { 'member-name-exceptions': [ 'Alt1' ] } }
|
||||
{ 'alternate': 'Alt1',
|
||||
'data': { 'a-b': 'bool', 'a_b': 'int' } }
|
||||
|
@ -1,2 +1,2 @@
|
||||
args-member-case.json: In command 'no-way-this-will-get-whitelisted':
|
||||
args-member-case.json:2: 'data' member 'Arg' uses uppercase in name
|
||||
args-member-case.json:2: name of 'data' member 'Arg' must not use uppercase or '_'
|
||||
|
@ -1,2 +0,0 @@
|
||||
args-name-clash.json: In command 'oops':
|
||||
args-name-clash.json:4: parameter 'a_b' collides with parameter 'a-b'
|
@ -1,4 +0,0 @@
|
||||
# C member name collision
|
||||
# Reject members that clash when mapped to C names (we would have two 'a_b'
|
||||
# members).
|
||||
{ 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }
|
@ -11,9 +11,9 @@
|
||||
'data': { 'nothing': 'Empty' } }
|
||||
|
||||
{ 'struct': 'Base',
|
||||
'data': { 'type': 'T' } }
|
||||
'data': { 'type': 'FrobType' } }
|
||||
|
||||
{ 'struct': 'Empty',
|
||||
'data': { } }
|
||||
|
||||
{ 'enum': 'T', 'data': ['nothing'] }
|
||||
{ 'enum': 'FrobType', 'data': ['nothing'] }
|
||||
|
@ -179,10 +179,10 @@
|
||||
'features': [ 'cmd-feat1', 'cmd-feat2' ] }
|
||||
|
||||
##
|
||||
# @EVT-BOXED:
|
||||
# @EVT_BOXED:
|
||||
# Features:
|
||||
# @feat3: a feature
|
||||
##
|
||||
{ 'event': 'EVT-BOXED', 'boxed': true,
|
||||
{ 'event': 'EVT_BOXED', 'boxed': true,
|
||||
'features': [ 'feat3' ],
|
||||
'data': 'Object' }
|
||||
|
@ -63,7 +63,7 @@ command cmd-boxed Object -> None
|
||||
gen=True success_response=True boxed=True oob=False preconfig=False
|
||||
feature cmd-feat1
|
||||
feature cmd-feat2
|
||||
event EVT-BOXED Object
|
||||
event EVT_BOXED Object
|
||||
boxed=True
|
||||
feature feat3
|
||||
doc freeform
|
||||
@ -211,7 +211,7 @@ another feature
|
||||
-> in
|
||||
|
||||
<- out
|
||||
doc symbol=EVT-BOXED
|
||||
doc symbol=EVT_BOXED
|
||||
body=
|
||||
|
||||
feature=feat3
|
||||
|
@ -272,7 +272,7 @@ Example
|
||||
<- out
|
||||
|
||||
|
||||
"EVT-BOXED" (Event)
|
||||
"EVT_BOXED" (Event)
|
||||
-------------------
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Events can't have 'Returns' section
|
||||
|
||||
##
|
||||
# @foo:
|
||||
# @FOO:
|
||||
# Returns: blah
|
||||
##
|
||||
{ 'event': 'foo' }
|
||||
{ 'event': 'FOO' }
|
||||
|
@ -1,3 +1,3 @@
|
||||
double-type.json: In struct 'bar':
|
||||
double-type.json: In struct 'Bar':
|
||||
double-type.json:2: struct has unknown key 'command'
|
||||
Valid keys are 'base', 'data', 'features', 'if', 'struct'.
|
||||
|
@ -1,2 +1,2 @@
|
||||
# we reject an expression with ambiguous metatype
|
||||
{ 'command': 'foo', 'struct': 'bar', 'data': { } }
|
||||
{ 'command': 'foo', 'struct': 'Bar', 'data': { } }
|
||||
|
@ -1,2 +1,2 @@
|
||||
enum-clash-member.json: In enum 'MyEnum':
|
||||
enum-clash-member.json:2: value 'one_two' collides with value 'one-two'
|
||||
enum-clash-member.json:3: value 'one_two' collides with value 'one-two'
|
||||
|
@ -1,2 +1,3 @@
|
||||
# we reject enums where members will clash when mapped to C enum
|
||||
{ 'pragma': { 'member-name-exceptions': [ 'MyEnum' ] } }
|
||||
{ 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] }
|
||||
|
@ -1,2 +1,2 @@
|
||||
enum-member-case.json: In enum 'NoWayThisWillGetWhitelisted':
|
||||
enum-member-case.json:4: 'data' member 'Value' uses uppercase in name
|
||||
enum-member-case.json:4: name of 'data' member 'Value' must not use uppercase or '_'
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Member names should be 'lower-case' unless the enum is whitelisted
|
||||
{ 'pragma': { 'name-case-whitelist': [ 'UuidInfo' ] } }
|
||||
{ 'pragma': { 'member-name-exceptions': [ 'UuidInfo' ] } }
|
||||
{ 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted
|
||||
{ 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] }
|
||||
|
@ -0,0 +1,2 @@
|
||||
event-case.json: In event 'oops':
|
||||
event-case.json:1: name of event must not use lowercase or '-'
|
@ -1,3 +1 @@
|
||||
# TODO: might be nice to enforce naming conventions; but until then this works
|
||||
# even though events should usually be ALL_CAPS
|
||||
{ 'event': 'oops' }
|
||||
|
@ -1,14 +0,0 @@
|
||||
module ./builtin
|
||||
object q_empty
|
||||
enum QType
|
||||
prefix QTYPE
|
||||
member none
|
||||
member qnull
|
||||
member qnum
|
||||
member qstring
|
||||
member qdict
|
||||
member qlist
|
||||
member qbool
|
||||
module event-case.json
|
||||
event oops None
|
||||
boxed=False
|
@ -1,2 +1,2 @@
|
||||
event-member-invalid-dict.json: In event 'EVENT_A':
|
||||
event-member-invalid-dict.json:1: 'data' member 'a' misses key 'type'
|
||||
event-member-invalid-dict.json:3: 'data' member 'a' misses key 'type'
|
||||
|
@ -1,2 +1,4 @@
|
||||
# event 'data' member with dict value is (longhand) argument
|
||||
# definition, not inline complex type
|
||||
{ 'event': 'EVENT_A',
|
||||
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
|
||||
|
@ -1,2 +1,2 @@
|
||||
features-deprecated-type.json: In struct 'S':
|
||||
features-deprecated-type.json: In struct 'Foo':
|
||||
features-deprecated-type.json:2: feature 'deprecated' is not supported for types
|
||||
|
@ -1,3 +1,3 @@
|
||||
# Feature 'deprecated' is not supported for types
|
||||
{ 'struct': 'S', 'data': {},
|
||||
{ 'struct': 'Foo', 'data': {},
|
||||
'features': [ 'deprecated' ] }
|
||||
|
@ -1,5 +1,5 @@
|
||||
# we require branches to be a struct name
|
||||
# TODO: should we allow anonymous inline branch types?
|
||||
# union 'data' member with dict value is (longhand) branch
|
||||
# definition, not inline complex type
|
||||
{ 'enum': 'TestEnum',
|
||||
'data': [ 'value1', 'value2' ] }
|
||||
{ 'struct': 'Base',
|
||||
|
@ -1,2 +0,0 @@
|
||||
flat-union-inline.json: In union 'TestUnion':
|
||||
flat-union-inline.json:7: 'data' member 'value1' should be a type name
|
@ -1,11 +0,0 @@
|
||||
# we require branches to be a struct name
|
||||
# TODO: should we allow anonymous inline branch types?
|
||||
{ 'enum': 'TestEnum',
|
||||
'data': [ 'value1', 'value2' ] }
|
||||
{ 'struct': 'Base',
|
||||
'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
|
||||
{ 'union': 'TestUnion',
|
||||
'base': 'Base',
|
||||
'discriminator': 'enum1',
|
||||
'data': { 'value1': { 'type': {} },
|
||||
'value2': { 'integer': 'int' } } }
|
@ -1,2 +1,2 @@
|
||||
flat-union-no-base.json: In union 'TestUnion':
|
||||
flat-union-no-base.json:9: 'discriminator' requires 'base'
|
||||
flat-union-no-base.json:8: 'discriminator' requires 'base'
|
||||
|
@ -1,5 +1,4 @@
|
||||
# flat unions require a base
|
||||
# TODO: simple unions should be able to use an enum discriminator
|
||||
{ 'struct': 'TestTypeA',
|
||||
'data': { 'string': 'str' } }
|
||||
{ 'struct': 'TestTypeB',
|
||||
|
@ -30,7 +30,6 @@ schemas = [
|
||||
'args-member-array-bad.json',
|
||||
'args-member-case.json',
|
||||
'args-member-unknown.json',
|
||||
'args-name-clash.json',
|
||||
'args-union.json',
|
||||
'args-unknown.json',
|
||||
'bad-base.json',
|
||||
@ -111,7 +110,6 @@ schemas = [
|
||||
'flat-union-clash-member.json',
|
||||
'flat-union-discriminator-bad-name.json',
|
||||
'flat-union-empty.json',
|
||||
'flat-union-inline.json',
|
||||
'flat-union-inline-invalid-dict.json',
|
||||
'flat-union-int-branch.json',
|
||||
'flat-union-invalid-branch-key.json',
|
||||
@ -145,17 +143,17 @@ schemas = [
|
||||
'oob-coroutine.json',
|
||||
'oob-test.json',
|
||||
'allow-preconfig-test.json',
|
||||
'pragma-doc-required-crap.json',
|
||||
'pragma-extra-junk.json',
|
||||
'pragma-name-case-whitelist-crap.json',
|
||||
'pragma-non-dict.json',
|
||||
'pragma-unknown.json',
|
||||
'pragma-returns-whitelist-crap.json',
|
||||
'pragma-value-not-bool.json',
|
||||
'pragma-value-not-list-of-str.json',
|
||||
'pragma-value-not-list.json',
|
||||
'qapi-schema-test.json',
|
||||
'quoted-structural-chars.json',
|
||||
'redefined-builtin.json',
|
||||
'redefined-command.json',
|
||||
'redefined-event.json',
|
||||
'redefined-predefined.json',
|
||||
'redefined-type.json',
|
||||
'reserved-command-q.json',
|
||||
'reserved-enum-q.json',
|
||||
@ -167,9 +165,9 @@ schemas = [
|
||||
'reserved-type-list.json',
|
||||
'returns-alternate.json',
|
||||
'returns-array-bad.json',
|
||||
'returns-bad-type.json',
|
||||
'returns-dict.json',
|
||||
'returns-unknown.json',
|
||||
'returns-whitelist.json',
|
||||
'string-code-point-31.json',
|
||||
'string-code-point-127.json',
|
||||
'struct-base-clash-deep.json',
|
||||
@ -178,9 +176,11 @@ schemas = [
|
||||
'struct-member-if-invalid.json',
|
||||
'struct-member-invalid-dict.json',
|
||||
'struct-member-invalid.json',
|
||||
'struct-member-name-clash.json',
|
||||
'trailing-comma-list.json',
|
||||
'trailing-comma-object.json',
|
||||
'type-bypass-bad-gen.json',
|
||||
'type-case.json',
|
||||
'unclosed-list.json',
|
||||
'unclosed-object.json',
|
||||
'unclosed-string.json',
|
||||
|
@ -1,2 +1,2 @@
|
||||
nested-struct-data-invalid-dict.json: In command 'foo':
|
||||
nested-struct-data-invalid-dict.json:2: 'data' member 'a' misses key 'type'
|
||||
nested-struct-data-invalid-dict.json:3: 'data' member 'a' misses key 'type'
|
||||
|
@ -1,3 +1,4 @@
|
||||
# inline subtypes collide with our desired future use of defaults
|
||||
# command 'data' member with dict value is (longhand) argument
|
||||
# definition, not inline complex type
|
||||
{ 'command': 'foo',
|
||||
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }
|
||||
|
@ -1,3 +1,3 @@
|
||||
# inline subtypes collide with our desired future use of defaults
|
||||
# {} is not a valid type reference
|
||||
{ 'command': 'foo',
|
||||
'data': { 'a' : { 'type': {} }, 'b' : 'str' } }
|
||||
|
@ -1 +0,0 @@
|
||||
pragma-doc-required-crap.json:3: pragma 'doc-required' must be boolean
|
@ -1 +0,0 @@
|
||||
pragma-name-case-whitelist-crap.json:3: pragma name-case-whitelist must be a list of strings
|
@ -1,3 +0,0 @@
|
||||
# 'name-case-whitelist' must be list of strings
|
||||
|
||||
{ 'pragma': { 'name-case-whitelist': false } }
|
@ -1 +0,0 @@
|
||||
pragma-returns-whitelist-crap.json:3: pragma returns-whitelist must be a list of strings
|
@ -1,3 +0,0 @@
|
||||
# 'returns-whitelist' must be list of strings
|
||||
|
||||
{ 'pragma': { 'returns-whitelist': [ 'good', [ 'bad' ] ] } }
|
1
tests/qapi-schema/pragma-value-not-bool.err
Normal file
1
tests/qapi-schema/pragma-value-not-bool.err
Normal file
@ -0,0 +1 @@
|
||||
pragma-value-not-bool.json:3: pragma 'doc-required' must be boolean
|
@ -1,3 +1,3 @@
|
||||
# 'doc-required' must be bool
|
||||
# pragma value must be bool
|
||||
|
||||
{ 'pragma': { 'doc-required': {} } }
|
1
tests/qapi-schema/pragma-value-not-list-of-str.err
Normal file
1
tests/qapi-schema/pragma-value-not-list-of-str.err
Normal file
@ -0,0 +1 @@
|
||||
pragma-value-not-list-of-str.json:3: pragma command-returns-exceptions must be a list of strings
|
3
tests/qapi-schema/pragma-value-not-list-of-str.json
Normal file
3
tests/qapi-schema/pragma-value-not-list-of-str.json
Normal file
@ -0,0 +1,3 @@
|
||||
# pragma value must be list of strings
|
||||
|
||||
{ 'pragma': { 'command-returns-exceptions': [ 'good', [ 'bad' ] ] } }
|
1
tests/qapi-schema/pragma-value-not-list.err
Normal file
1
tests/qapi-schema/pragma-value-not-list.err
Normal file
@ -0,0 +1 @@
|
||||
pragma-value-not-list.json:2: pragma member-name-exceptions must be a list of strings
|
2
tests/qapi-schema/pragma-value-not-list.json
Normal file
2
tests/qapi-schema/pragma-value-not-list.json
Normal file
@ -0,0 +1,2 @@
|
||||
# pragma value must be list
|
||||
{ 'pragma': { 'member-name-exceptions': false } }
|
@ -6,8 +6,12 @@
|
||||
|
||||
# Whitelists to permit QAPI rule violations
|
||||
{ 'pragma': {
|
||||
# Types whose member names may use '_'
|
||||
'member-name-exceptions': [
|
||||
'UserDefA'
|
||||
],
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
'command-returns-exceptions': [
|
||||
'guest-get-time',
|
||||
'guest-sync' ] } }
|
||||
|
||||
@ -31,7 +35,7 @@
|
||||
'base': { 'type': 'EnumOne' }, 'discriminator': 'type',
|
||||
'data': { } }
|
||||
|
||||
{ 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
|
||||
{ 'command': 'user-def-cmd0', 'data': 'Empty2', 'returns': 'Empty2' }
|
||||
|
||||
# for testing override of default naming heuristic
|
||||
{ 'enum': 'QEnumTwo',
|
||||
@ -141,9 +145,9 @@
|
||||
{ 'include': 'include/sub-module.json' }
|
||||
|
||||
# testing commands
|
||||
{ 'command': 'user_def_cmd', 'data': {} }
|
||||
{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
|
||||
{ 'command': 'user_def_cmd2',
|
||||
{ 'command': 'user-def-cmd', 'data': {} }
|
||||
{ 'command': 'user-def-cmd1', 'data': {'ud1a': 'UserDefOne'} }
|
||||
{ 'command': 'user-def-cmd2',
|
||||
'data': {'ud1a': {'type': 'UserDefOne'}, '*ud1b': 'UserDefOne'},
|
||||
'returns': 'UserDefTwo' }
|
||||
|
||||
@ -227,10 +231,11 @@
|
||||
|
||||
{ 'union': 'TestIfUnion', 'data':
|
||||
{ 'foo': 'TestStruct',
|
||||
'union_bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
|
||||
'bar': { 'type': 'str', 'if': 'defined(TEST_IF_UNION_BAR)'} },
|
||||
'if': 'defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)' }
|
||||
|
||||
{ 'command': 'TestIfUnionCmd', 'data': { 'union_cmd_arg': 'TestIfUnion' },
|
||||
{ 'command': 'test-if-union-cmd',
|
||||
'data': { 'union-cmd-arg': 'TestIfUnion' },
|
||||
'if': 'defined(TEST_IF_UNION)' }
|
||||
|
||||
{ 'alternate': 'TestIfAlternate', 'data':
|
||||
@ -238,18 +243,20 @@
|
||||
'bar': { 'type': 'TestStruct', 'if': 'defined(TEST_IF_ALT_BAR)'} },
|
||||
'if': 'defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)' }
|
||||
|
||||
{ 'command': 'TestIfAlternateCmd', 'data': { 'alt_cmd_arg': 'TestIfAlternate' },
|
||||
{ 'command': 'test-if-alternate-cmd',
|
||||
'data': { 'alt-cmd-arg': 'TestIfAlternate' },
|
||||
'if': 'defined(TEST_IF_ALT)' }
|
||||
|
||||
{ 'command': 'TestIfCmd', 'data':
|
||||
{ 'foo': 'TestIfStruct',
|
||||
{ 'command': 'test-if-cmd',
|
||||
'data': {
|
||||
'foo': 'TestIfStruct',
|
||||
'bar': { 'type': 'TestIfEnum', 'if': 'defined(TEST_IF_CMD_BAR)' } },
|
||||
'returns': 'UserDefThree',
|
||||
'if': ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)'] }
|
||||
|
||||
{ 'command': 'TestCmdReturnDefThree', 'returns': 'UserDefThree' }
|
||||
{ 'command': 'test-cmd-return-def-three', 'returns': 'UserDefThree' }
|
||||
|
||||
{ 'event': 'TestIfEvent', 'data':
|
||||
{ 'event': 'TEST_IF_EVENT', 'data':
|
||||
{ 'foo': 'TestIfStruct',
|
||||
'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } },
|
||||
'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
|
||||
@ -324,8 +331,8 @@
|
||||
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
|
||||
'defined(TEST_IF_COND_2)'] } ] }
|
||||
|
||||
{ 'event': 'TEST-EVENT-FEATURES0',
|
||||
{ 'event': 'TEST_EVENT_FEATURES0',
|
||||
'data': 'FeatureStruct1' }
|
||||
|
||||
{ 'event': 'TEST-EVENT-FEATURES1',
|
||||
{ 'event': 'TEST_EVENT_FEATURES1',
|
||||
'features': [ 'deprecated' ] }
|
||||
|
@ -32,7 +32,7 @@ object Union
|
||||
case value2: q_empty
|
||||
case value3: q_empty
|
||||
case value4: q_empty
|
||||
command user_def_cmd0 Empty2 -> Empty2
|
||||
command user-def-cmd0 Empty2 -> Empty2
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
enum QEnumTwo
|
||||
prefix QENUM_TWO
|
||||
@ -190,16 +190,16 @@ object UserDefListUnion
|
||||
case any: q_obj_anyList-wrapper
|
||||
case user: q_obj_StatusList-wrapper
|
||||
include include/sub-module.json
|
||||
command user_def_cmd None -> None
|
||||
command user-def-cmd None -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
object q_obj_user_def_cmd1-arg
|
||||
object q_obj_user-def-cmd1-arg
|
||||
member ud1a: UserDefOne optional=False
|
||||
command user_def_cmd1 q_obj_user_def_cmd1-arg -> None
|
||||
command user-def-cmd1 q_obj_user-def-cmd1-arg -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
object q_obj_user_def_cmd2-arg
|
||||
object q_obj_user-def-cmd2-arg
|
||||
member ud1a: UserDefOne optional=False
|
||||
member ud1b: UserDefOne optional=True
|
||||
command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo
|
||||
command user-def-cmd2 q_obj_user-def-cmd2-arg -> UserDefTwo
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
command cmd-success-response None -> None
|
||||
gen=True success_response=False boxed=False oob=False preconfig=False
|
||||
@ -309,20 +309,20 @@ object q_obj_TestStruct-wrapper
|
||||
member data: TestStruct optional=False
|
||||
enum TestIfUnionKind
|
||||
member foo
|
||||
member union_bar
|
||||
member bar
|
||||
if ['defined(TEST_IF_UNION_BAR)']
|
||||
if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
|
||||
object TestIfUnion
|
||||
member type: TestIfUnionKind optional=False
|
||||
tag type
|
||||
case foo: q_obj_TestStruct-wrapper
|
||||
case union_bar: q_obj_str-wrapper
|
||||
case bar: q_obj_str-wrapper
|
||||
if ['defined(TEST_IF_UNION_BAR)']
|
||||
if ['defined(TEST_IF_UNION) && defined(TEST_IF_STRUCT)']
|
||||
object q_obj_TestIfUnionCmd-arg
|
||||
member union_cmd_arg: TestIfUnion optional=False
|
||||
object q_obj_test-if-union-cmd-arg
|
||||
member union-cmd-arg: TestIfUnion optional=False
|
||||
if ['defined(TEST_IF_UNION)']
|
||||
command TestIfUnionCmd q_obj_TestIfUnionCmd-arg -> None
|
||||
command test-if-union-cmd q_obj_test-if-union-cmd-arg -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
if ['defined(TEST_IF_UNION)']
|
||||
alternate TestIfAlternate
|
||||
@ -331,30 +331,30 @@ alternate TestIfAlternate
|
||||
case bar: TestStruct
|
||||
if ['defined(TEST_IF_ALT_BAR)']
|
||||
if ['defined(TEST_IF_ALT) && defined(TEST_IF_STRUCT)']
|
||||
object q_obj_TestIfAlternateCmd-arg
|
||||
member alt_cmd_arg: TestIfAlternate optional=False
|
||||
object q_obj_test-if-alternate-cmd-arg
|
||||
member alt-cmd-arg: TestIfAlternate optional=False
|
||||
if ['defined(TEST_IF_ALT)']
|
||||
command TestIfAlternateCmd q_obj_TestIfAlternateCmd-arg -> None
|
||||
command test-if-alternate-cmd q_obj_test-if-alternate-cmd-arg -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
if ['defined(TEST_IF_ALT)']
|
||||
object q_obj_TestIfCmd-arg
|
||||
object q_obj_test-if-cmd-arg
|
||||
member foo: TestIfStruct optional=False
|
||||
member bar: TestIfEnum optional=False
|
||||
if ['defined(TEST_IF_CMD_BAR)']
|
||||
if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
|
||||
command TestIfCmd q_obj_TestIfCmd-arg -> UserDefThree
|
||||
command test-if-cmd q_obj_test-if-cmd-arg -> UserDefThree
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
if ['defined(TEST_IF_CMD)', 'defined(TEST_IF_STRUCT)']
|
||||
command TestCmdReturnDefThree None -> UserDefThree
|
||||
command test-cmd-return-def-three None -> UserDefThree
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
array TestIfEnumList TestIfEnum
|
||||
if ['defined(TEST_IF_ENUM)']
|
||||
object q_obj_TestIfEvent-arg
|
||||
object q_obj_TEST_IF_EVENT-arg
|
||||
member foo: TestIfStruct optional=False
|
||||
member bar: TestIfEnumList optional=False
|
||||
if ['defined(TEST_IF_EVT_BAR)']
|
||||
if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
|
||||
event TestIfEvent q_obj_TestIfEvent-arg
|
||||
event TEST_IF_EVENT q_obj_TEST_IF_EVENT-arg
|
||||
boxed=False
|
||||
if ['defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)']
|
||||
object FeatureStruct0
|
||||
@ -440,9 +440,9 @@ command test-command-cond-features3 None -> None
|
||||
gen=True success_response=True boxed=False oob=False preconfig=False
|
||||
feature feature1
|
||||
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
|
||||
event TEST-EVENT-FEATURES0 FeatureStruct1
|
||||
event TEST_EVENT_FEATURES0 FeatureStruct1
|
||||
boxed=False
|
||||
event TEST-EVENT-FEATURES1 None
|
||||
event TEST_EVENT_FEATURES1 None
|
||||
boxed=False
|
||||
feature deprecated
|
||||
module include/sub-module.json
|
||||
|
@ -1,2 +0,0 @@
|
||||
redefined-builtin.json: In struct 'size':
|
||||
redefined-builtin.json:2: built-in type 'size' is already defined
|
@ -1,2 +0,0 @@
|
||||
# we reject types that duplicate builtin names
|
||||
{ 'struct': 'size', 'data': { 'myint': 'size' } }
|
2
tests/qapi-schema/redefined-predefined.err
Normal file
2
tests/qapi-schema/redefined-predefined.err
Normal file
@ -0,0 +1,2 @@
|
||||
redefined-predefined.json: In struct 'QType':
|
||||
redefined-predefined.json:2: enum type 'QType' is already defined
|
2
tests/qapi-schema/redefined-predefined.json
Normal file
2
tests/qapi-schema/redefined-predefined.json
Normal file
@ -0,0 +1,2 @@
|
||||
# we reject types that clash with predefined types
|
||||
{ 'struct': 'QType', 'data': { 'myint': 'size' } }
|
@ -1,4 +1,4 @@
|
||||
redefined-type.json: In enum 'foo':
|
||||
redefined-type.json:3: 'foo' is already defined
|
||||
redefined-type.json: In struct 'foo':
|
||||
redefined-type.json: In enum 'Foo':
|
||||
redefined-type.json:3: 'Foo' is already defined
|
||||
redefined-type.json: In struct 'Foo':
|
||||
redefined-type.json:2: previous definition
|
||||
|
@ -1,3 +1,3 @@
|
||||
# we reject types defined more than once
|
||||
{ 'struct': 'foo', 'data': { 'one': 'str' } }
|
||||
{ 'enum': 'foo', 'data': [ 'two' ] }
|
||||
{ 'struct': 'Foo', 'data': { 'one': 'str' } }
|
||||
{ 'enum': 'Foo', 'data': [ 'two' ] }
|
||||
|
@ -1,2 +1,2 @@
|
||||
reserved-member-u.json: In struct 'Oops':
|
||||
reserved-member-u.json:7: 'data' member 'u' uses reserved name
|
||||
reserved-member-u.json:7: 'data' member '*u' uses reserved name
|
||||
|
@ -4,4 +4,4 @@
|
||||
# This is true even for non-unions, because it is possible to convert a
|
||||
# struct to flat union while remaining backwards compatible in QMP.
|
||||
# TODO - we could munge the member name to 'q_u' to avoid the collision
|
||||
{ 'struct': 'Oops', 'data': { 'u': 'str' } }
|
||||
{ 'struct': 'Oops', 'data': { '*u': 'str' } }
|
||||
|
2
tests/qapi-schema/returns-bad-type.err
Normal file
2
tests/qapi-schema/returns-bad-type.err
Normal file
@ -0,0 +1,2 @@
|
||||
returns-bad-type.json: In command 'no-way-this-will-get-whitelisted':
|
||||
returns-bad-type.json:14: command's 'returns' cannot take array type ['int']
|
@ -1,6 +1,6 @@
|
||||
# we enforce that 'returns' be a dict or array of dict unless whitelisted
|
||||
|
||||
{ 'pragma': { 'returns-whitelist': [
|
||||
{ 'pragma': { 'command-returns-exceptions': [
|
||||
'human-monitor-command', 'query-tpm-models', 'guest-get-time' ] } }
|
||||
|
||||
{ 'command': 'human-monitor-command',
|
@ -1,2 +0,0 @@
|
||||
returns-whitelist.json: In command 'no-way-this-will-get-whitelisted':
|
||||
returns-whitelist.json:14: command's 'returns' cannot take array type ['int']
|
@ -1,2 +1,2 @@
|
||||
struct-data-invalid.json: In struct 'foo':
|
||||
struct-data-invalid.json: In struct 'Foo':
|
||||
struct-data-invalid.json:1: 'data' should be an object or type name
|
||||
|
@ -1,2 +1,2 @@
|
||||
{ 'struct': 'foo',
|
||||
{ 'struct': 'Foo',
|
||||
'data': false }
|
||||
|
@ -1,2 +1,2 @@
|
||||
struct-member-invalid-dict.json: In struct 'foo':
|
||||
struct-member-invalid-dict.json:2: 'data' member '*a' misses key 'type'
|
||||
struct-member-invalid-dict.json: In struct 'Foo':
|
||||
struct-member-invalid-dict.json:3: 'data' member '*a' misses key 'type'
|
||||
|
@ -1,3 +1,4 @@
|
||||
# Long form of member must have a value member 'type'
|
||||
{ 'struct': 'foo',
|
||||
# struct 'data' member with dict value is (longhand) member
|
||||
# definition, not inline complex type
|
||||
{ 'struct': 'Foo',
|
||||
'data': { '*a': { 'case': 'foo' } } }
|
||||
|
@ -1,2 +1,2 @@
|
||||
struct-member-invalid.json: In struct 'foo':
|
||||
struct-member-invalid.json: In struct 'Foo':
|
||||
struct-member-invalid.json:1: 'data' member 'a' should be a type name
|
||||
|
@ -1,2 +1,2 @@
|
||||
{ 'struct': 'foo',
|
||||
{ 'struct': 'Foo',
|
||||
'data': { 'a': false } }
|
||||
|
2
tests/qapi-schema/struct-member-name-clash.err
Normal file
2
tests/qapi-schema/struct-member-name-clash.err
Normal file
@ -0,0 +1,2 @@
|
||||
struct-member-name-clash.json: In struct 'Oops':
|
||||
struct-member-name-clash.json:5: member 'a_b' collides with member 'a-b'
|
5
tests/qapi-schema/struct-member-name-clash.json
Normal file
5
tests/qapi-schema/struct-member-name-clash.json
Normal file
@ -0,0 +1,5 @@
|
||||
# C member name collision
|
||||
# Reject members that clash when mapped to C names (we would have two 'a_b'
|
||||
# members).
|
||||
{ 'pragma': { 'member-name-exceptions': [ 'Oops' ] } }
|
||||
{ 'struct': 'Oops', 'data': { 'a-b': 'str', 'a_b': 'str' } }
|
2
tests/qapi-schema/type-case.err
Normal file
2
tests/qapi-schema/type-case.err
Normal file
@ -0,0 +1,2 @@
|
||||
type-case.json: In struct 'not-a-camel':
|
||||
type-case.json:2: name of struct must use CamelCase
|
2
tests/qapi-schema/type-case.json
Normal file
2
tests/qapi-schema/type-case.json
Normal file
@ -0,0 +1,2 @@
|
||||
# Type names should use CamelCase
|
||||
{ 'struct': 'not-a-camel', 'data': {} }
|
@ -1,2 +1,2 @@
|
||||
union-branch-case.json: In union 'Uni':
|
||||
union-branch-case.json:2: 'data' member 'Branch' uses uppercase in name
|
||||
union-branch-case.json:2: name of 'data' member 'Branch' must not use uppercase or '_'
|
||||
|
@ -1,2 +1,2 @@
|
||||
union-clash-branches.json: In union 'TestUnion':
|
||||
union-clash-branches.json:4: branch 'a_b' collides with branch 'a-b'
|
||||
union-clash-branches.json:6: name of 'data' member 'a_b' must not use uppercase or '_'
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Union branch name collision
|
||||
# Reject a union that would result in a collision in generated C names (this
|
||||
# would try to generate two members 'a_b').
|
||||
# Naming rules make collision impossible (even with the pragma). If
|
||||
# that wasn't the case, then we'd get collisions in generated C: two
|
||||
# union members a_b, and two enum members TEST_UNION_A_B.
|
||||
{ 'pragma': { 'member-name-exceptions': [ 'TestUnion' ] } }
|
||||
{ 'union': 'TestUnion',
|
||||
'data': { 'a-b': 'int', 'a_b': 'str' } }
|
||||
|
@ -1,3 +1,3 @@
|
||||
unknown-expr-key.json: In struct 'bar':
|
||||
unknown-expr-key.json: In struct 'Bar':
|
||||
unknown-expr-key.json:2: struct has unknown keys 'bogus', 'phony'
|
||||
Valid keys are 'base', 'data', 'features', 'if', 'struct'.
|
||||
|
@ -1,2 +1,2 @@
|
||||
# we reject an expression with unknown top-level keys
|
||||
{ 'struct': 'bar', 'data': { 'string': 'str'}, 'bogus': { }, 'phony': { } }
|
||||
{ 'struct': 'Bar', 'data': { 'string': 'str'}, 'bogus': { }, 'phony': { } }
|
||||
|
@ -13,14 +13,7 @@
|
||||
|
||||
static QmpCommandList qmp_commands;
|
||||
|
||||
#if defined(TEST_IF_STRUCT) && defined(TEST_IF_CMD)
|
||||
UserDefThree *qmp_TestIfCmd(TestIfStruct *foo, Error **errp)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
UserDefThree *qmp_TestCmdReturnDefThree(Error **errp)
|
||||
UserDefThree *qmp_test_cmd_return_def_three(Error **errp)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -206,7 +199,7 @@ static void test_dispatch_cmd(void)
|
||||
|
||||
ret = qobject_to(QDict,
|
||||
do_qmp_dispatch(false,
|
||||
"{ 'execute': 'user_def_cmd' }"));
|
||||
"{ 'execute': 'user-def-cmd' }"));
|
||||
assert(ret && qdict_size(ret) == 0);
|
||||
qobject_unref(ret);
|
||||
}
|
||||
@ -227,11 +220,11 @@ static void test_dispatch_cmd_failure(void)
|
||||
{
|
||||
/* missing arguments */
|
||||
do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
|
||||
"{ 'execute': 'user_def_cmd2' }");
|
||||
"{ 'execute': 'user-def-cmd2' }");
|
||||
|
||||
/* extra arguments */
|
||||
do_qmp_dispatch_error(false, ERROR_CLASS_GENERIC_ERROR,
|
||||
"{ 'execute': 'user_def_cmd',"
|
||||
"{ 'execute': 'user-def-cmd',"
|
||||
" 'arguments': { 'a': 66 } }");
|
||||
}
|
||||
|
||||
@ -255,7 +248,7 @@ static void test_dispatch_cmd_io(void)
|
||||
int64_t val;
|
||||
|
||||
ret = qobject_to(QDict, do_qmp_dispatch(false,
|
||||
"{ 'execute': 'user_def_cmd2', 'arguments': {"
|
||||
"{ 'execute': 'user-def-cmd2', 'arguments': {"
|
||||
" 'ud1a': { 'integer': 42, 'string': 'hello' },"
|
||||
" 'ud1b': { 'integer': 422, 'string': 'hello2' } } }"));
|
||||
|
||||
|
@ -143,7 +143,7 @@ static void test_event_d(TestEventData *data,
|
||||
|
||||
static void test_event_deprecated(TestEventData *data, const void *unused)
|
||||
{
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES1' }");
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST_EVENT_FEATURES1' }");
|
||||
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
@ -163,7 +163,7 @@ static void test_event_deprecated_data(TestEventData *data, const void *unused)
|
||||
{
|
||||
memset(&compat_policy, 0, sizeof(compat_policy));
|
||||
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0',"
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST_EVENT_FEATURES0',"
|
||||
" 'data': { 'foo': 42 } }");
|
||||
qapi_event_send_test_event_features0(42);
|
||||
g_assert(data->emitted);
|
||||
@ -172,7 +172,7 @@ static void test_event_deprecated_data(TestEventData *data, const void *unused)
|
||||
|
||||
compat_policy.has_deprecated_output = true;
|
||||
compat_policy.deprecated_output = COMPAT_POLICY_OUTPUT_HIDE;
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST-EVENT-FEATURES0' }");
|
||||
data->expect = qdict_from_jsonf_nofail("{ 'event': 'TEST_EVENT_FEATURES0' }");
|
||||
qapi_event_send_test_event_features0(42);
|
||||
g_assert(data->emitted);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user