qapi: Whitelist commands that don't return dictionary

...or an array of dictionaries. Although we have to cater to
existing commands, returning a non-dictionary means the command
is not extensible (no new name/value pairs can be added if more
information must be returned in parallel). By making the
whitelist explicit, any new command that falls foul of this
practice will have to be self-documenting, which will encourage
developers to either justify the action or rework the design to
use a dictionary after all.

It's a little bit sloppy that we share a single whitelist among
three clients (it's too permissive for each). If this is a
problem, a future patch could tighten things by having the
generator take the whitelist as an argument (as in
scripts/qapi-commands.py --legacy-returns=...), or by having
the generator output C code that requires explicit use of the
whitelist (as in:
then having the callers define appropriate macros). But until
we need such fine-grained separation (if ever), this patch does
the job just fine.

Backports commit 10d4d997f86cf2a4ce89145df5658952d5722e56 from qemu
This commit is contained in:
Eric Blake 2018-02-19 14:06:22 -05:00 committed by Lioncash
parent 68142c9df0
commit 0b9d15dd52
No known key found for this signature in database
GPG Key ID: 4E3C3CC1031BA9C7

View File

@ -32,6 +32,30 @@ builtin_types = {
'size': 'QTYPE_QINT', 'size': 'QTYPE_QINT',
} }
# Whitelist of commands allowed to return a non-dictionary
returns_whitelist = [
# From QMP:
'human-monitor-command',
'query-migrate-cache-size',
'query-tpm-models',
'query-tpm-types',
'ringbuf-read',
# From QGA:
'guest-file-open',
'guest-fsfreeze-freeze',
'guest-fsfreeze-freeze-list',
'guest-fsfreeze-status',
'guest-fsfreeze-thaw',
'guest-get-time',
'guest-set-vcpus',
'guest-sync',
'guest-sync-delimited',
# From qapi-schema-test:
'user_def_cmd3',
]
enum_types = [] enum_types = []
struct_types = [] struct_types = []
union_types = [] union_types = []
@ -354,11 +378,12 @@ def check_command(expr, expr_info):
check_type(expr_info, "'data' for command '%s'" % name, check_type(expr_info, "'data' for command '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True, expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct']) allow_metas=['union', 'struct'])
returns_meta = ['union', 'struct']
if name in returns_whitelist:
returns_meta += ['built-in', 'alternate', 'enum']
check_type(expr_info, "'returns' for command '%s'" % name, check_type(expr_info, "'returns' for command '%s'" % name,
expr.get('returns'), allow_array=True, allow_dict=True, expr.get('returns'), allow_array=True, allow_dict=True,
allow_optional=True, allow_optional=True, allow_metas=returns_meta)
allow_metas=['built-in', 'union', 'alternate', 'struct',
'enum'])
def check_event(expr, expr_info): def check_event(expr, expr_info):
global events global events