qapi: Another round of fixes and cleanups

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJV6aFGAAoJEDhwtADrkYZT8o8P/R7CZzKv6JE85xQYKtIEdgK7
 zP+GiNY+ysXL/4uRzXk/Ksh3TYuRe/ptMdeXINayOoC3qG8WYuiIjIB6VTtscWGF
 NKj/iKUxk6APLHunLBCf/ubW1uqsOHCgmuxZJEB7aZhUpWfpYL+0pvF+n8qm67f/
 RaaN2FCppTTzKrGFWjmTP1iwm2GF/ETOdlyNQ79AEjEb3n6IvjpVPuHU9ZcZhqLP
 CF0efVX172sbZqOlIBiDlvyCmPHsCpoRRUw4D/E5ctAxj/JkhKtv5pwsIAhKQVNj
 +plsYFYujhkUBT8QRZQF1oH3CQXoDD03qimCRptBSOWHTKsCPYWpSZSaE6BIzOyJ
 NaFcAr4x+/NCxkZ0Ef/qQZfwIH2NLb5gPpaSUpsVrJQUsx4ImKSpa8t1x+iTLqO4
 QnU+pkQ6PdkFNlhj1tOvKcaOWV5wlPTtEfpEflYg0Cx173Ao3nIOPIIYTqdelcn5
 1sopuADvFB61/EiMail9NS9aPPuPrnrrOtzVNyFtDZorO+sot7pWOJ24xAzylG6G
 jOZxMVJteq+XF0DLTdCKJiCxCdwMSrg/wNKnFMmKFGlqJIpRrd7XYPfzVX+pX/s7
 gpuCc3r73WPReP1b/sjn8vQ4PBRpaQb8uK8hkh+GQjnr99cSyTZgI/M1anTh5YEC
 mXPB0mw60g8YA61gJSX0
 =CGzi
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-09-04' into staging

qapi: Another round of fixes and cleanups

# gpg: Signature made Fri 04 Sep 2015 14:48:54 BST using RSA key ID EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"

* remotes/armbru/tags/pull-qapi-2015-09-04: (33 commits)
  qapi: Generators crash when --output-dir isn't given, fix
  docs/qapi-code-gen.txt: Fix QAPI schema examples
  qapi: Simplify error reporting for array types
  qapi: Fix errors for non-string, non-dictionary members
  tests/qapi-schema: Cover non-string, non-dictionary members
  tests/qapi-schema: Cover two more syntax errors
  qapi: Drop one of two "simple union must not have base" checks
  qapi: Generated code cleanup
  qapi-commands: Drop useless initialization
  qapi-commands: Don't feed output of mcgen() to mcgen() again
  qapi-commands: Inline gen_marshal_output_call()
  qapi-commands: Fix gen_err_check(e) for e and e != 'local_err'
  qapi: Command returning anonymous type doesn't work, outlaw
  qapi: Fix to reject union command and event arguments
  qapi-tests: New tests for union, alternate command arguments
  tests/qapi-schema: Rename tests from data- to args-
  tests/qapi-schema: Restore test case for flat union base bug
  qapi: Document flaws in checking of names
  qapi: Document shortcoming with union 'data' branch
  qapi: Document that input visitor semantics are prone to leaks
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-09-04 15:53:48 +01:00
commit b5bff7518d
82 changed files with 317 additions and 268 deletions

View File

@ -163,7 +163,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
The directive is evaluated recursively, and include paths are relative to the
file using the directive. Multiple includes of the same file are
safe. No other keys should appear in the expression, and the include
idempotent. No other keys should appear in the expression, and the include
value should be a string.
As a matter of style, it is a good idea to have all files be
@ -300,7 +300,6 @@ an implicit C enum 'NameKind' is created, corresponding to the union
the union can be named 'max', as this would collide with the implicit
enum. The value for each branch can be of any type.
A flat union definition specifies a struct as its base, and
avoids nesting on the wire. All branches of the union must be
complex types, and the top-level fields of the union dictionary on
@ -314,7 +313,7 @@ adding a common field 'readonly', renaming the discriminator to
something more applicable, and reducing the number of {} required on
the wire:
{ 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] }
{ 'enum': 'BlockdevDriver', 'data': [ 'file', 'qcow2' ] }
{ 'struct': 'BlockdevCommonOptions',
'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
{ 'union': 'BlockdevOptions',
@ -350,7 +349,7 @@ is identical on the wire to:
{ 'struct': 'Base', 'data': { 'type': 'Enum' } }
{ 'struct': 'Branch1', 'data': { 'data': 'str' } }
{ 'struct': 'Branch2', 'data': { 'data': 'int' } }
{ 'union': 'Flat': 'base': 'Base', 'discriminator': 'type',
{ 'union': 'Flat', 'base': 'Base', 'discriminator': 'type',
'data': { 'one': 'Branch1', 'two': 'Branch2' } }
@ -394,7 +393,7 @@ following example objects:
=== Commands ===
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME-OR-DICT,
'*returns': TYPE-NAME,
'*gen': false, '*success-response': false }
Commands are defined by using a dictionary containing several members,
@ -405,10 +404,9 @@ Client JSON Protocol command exchange.
The 'data' argument maps to the "arguments" dictionary passed in as
part of a Client JSON Protocol command. The 'data' member is optional
and defaults to {} (an empty dictionary). If present, it must be the
string name of a complex type, a one-element array containing the name
of a complex type, or a dictionary that declares an anonymous type
with the same semantics as a 'struct' expression, with one exception
noted below when 'gen' is used.
string name of a complex type, or a dictionary that declares an
anonymous type with the same semantics as a 'struct' expression, with
one exception noted below when 'gen' is used.
The 'returns' member describes what will appear in the "return" field
of a Client JSON Protocol reply on successful completion of a command.
@ -416,14 +414,13 @@ The member is optional from the command declaration; if absent, the
"return" field will be an empty dictionary. If 'returns' is present,
it must be the string name of a complex or built-in type, a
one-element array containing the name of a complex or built-in type,
or a dictionary that declares an anonymous type with the same
semantics as a 'struct' expression, with one exception noted below
when 'gen' is used. Although it is permitted to have the 'returns'
member name a built-in type or an array of built-in types, any command
that does this cannot be extended to return additional information in
the future; thus, new commands should strongly consider returning a
dictionary-based type or an array of dictionaries, even if the
dictionary only contains one field at the present.
with one exception noted below when 'gen' is used. Although it is
permitted to have the 'returns' member name a built-in type or an
array of built-in types, any command that does this cannot be extended
to return additional information in the future; thus, new commands
should strongly consider returning a dictionary-based type or an array
of dictionaries, even if the dictionary only contains one field at the
present.
All commands in Client JSON Protocol use a dictionary to report
failure, with no way to specify that in QAPI. Where the error return
@ -555,6 +552,7 @@ Example:
qapi_dealloc_visitor_cleanup(md);
}
void qapi_free_UserDefOne(UserDefOne *obj)
{
QapiDeallocVisitor *md;
@ -569,7 +567,6 @@ Example:
visit_type_UserDefOne(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md);
}
$ cat qapi-generated/example-qapi-types.h
[Uninteresting stuff omitted...]
@ -580,8 +577,7 @@ Example:
typedef struct UserDefOne UserDefOne;
typedef struct UserDefOneList
{
typedef struct UserDefOneList {
union {
UserDefOne *value;
uint64_t padding;
@ -589,10 +585,10 @@ Example:
struct UserDefOneList *next;
} UserDefOneList;
[Functions on built-in types omitted...]
struct UserDefOne
{
struct UserDefOne {
int64_t integer;
char *string;
};
@ -630,6 +626,7 @@ Example:
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne **obj, Error **errp)
{
Error *err = NULL;
visit_type_int(m, &(*obj)->integer, "integer", &err);
if (err) {
goto out;
@ -743,7 +740,7 @@ Example:
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
{
Error *local_err = NULL;
UserDefOne *retval = NULL;
UserDefOne *retval;
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
Visitor *v;
@ -769,7 +766,6 @@ Example:
v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOne(v, &arg1, "arg1", NULL);
qapi_dealloc_visitor_cleanup(md);
return;
}
static void qmp_init_marshal(void)
@ -826,7 +822,7 @@ Example:
QDECREF(qmp);
}
const char *EXAMPLE_QAPIEvent_lookup[] = {
const char *example_QAPIEvent_lookup[] = {
"MY_EVENT",
NULL,
};
@ -843,11 +839,10 @@ Example:
void qapi_event_send_my_event(Error **errp);
extern const char *EXAMPLE_QAPIEvent_lookup[];
typedef enum EXAMPLE_QAPIEvent
{
extern const char *example_QAPIEvent_lookup[];
typedef enum example_QAPIEvent {
EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
EXAMPLE_QAPI_EVENT_MAX = 1,
} EXAMPLE_QAPIEvent;
} example_QAPIEvent;
#endif

View File

@ -27,18 +27,19 @@ def generate_command_decl(name, args, ret_type):
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
''',
ret_type=c_type(ret_type), name=c_name(name),
args=arglist).strip()
args=arglist)
def gen_err_check(errvar):
if errvar:
return mcgen('''
if (local_err) {
def gen_err_check(err):
if not err:
return ''
return mcgen('''
if (%(err)s) {
goto out;
}
''')
return ''
''',
err=err)
def gen_sync_call(name, args, ret_type, indent=0):
def gen_sync_call(name, args, ret_type):
ret = ""
arglist=""
retval=""
@ -48,41 +49,34 @@ def gen_sync_call(name, args, ret_type, indent=0):
if optional:
arglist += "has_%s, " % c_name(argname)
arglist += "%s, " % (c_name(argname))
push_indent(indent)
push_indent()
ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)s&local_err);
''',
name=c_name(name), args=arglist, retval=retval).rstrip()
name=c_name(name), args=arglist, retval=retval)
if ret_type:
ret += "\n" + gen_err_check('local_err')
ret += "\n" + mcgen(''''
%(marshal_output_call)s
ret += gen_err_check('local_err')
ret += mcgen('''
qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
''',
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
pop_indent(indent)
return ret.rstrip()
c_name=c_name(name))
pop_indent()
return ret
def gen_marshal_output_call(name, ret_type):
if not ret_type:
return ""
return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_name(name)
def gen_visitor_input_containers_decl(args, obj):
def gen_visitor_input_containers_decl(args):
ret = ""
push_indent()
if len(args) > 0:
ret += mcgen('''
QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s);
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
Visitor *v;
''',
obj=obj)
''')
pop_indent()
return ret.rstrip()
return ret
def gen_visitor_input_vars_decl(args):
ret = ""
@ -105,7 +99,7 @@ bool has_%(argname)s = false;
argname=c_name(argname), argtype=c_type(argtype))
pop_indent()
return ret.rstrip()
return ret
def gen_visitor_input_block(args, dealloc=False):
ret = ""
@ -159,9 +153,9 @@ visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
qapi_dealloc_visitor_cleanup(md);
''')
pop_indent()
return ret.rstrip()
return ret
def gen_marshal_output(name, args, ret_type, middle_mode):
def gen_marshal_output(name, ret_type):
if not ret_type:
return ""
@ -194,14 +188,14 @@ out:
return ret
def gen_marshal_input_decl(name, args, ret_type, middle_mode):
def gen_marshal_input_decl(name, middle_mode):
ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode:
ret = "static " + ret
return ret
def gen_marshal_input(name, args, ret_type, middle_mode):
hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
hdr = gen_marshal_input_decl(name, middle_mode)
ret = mcgen('''
%(header)s
@ -211,36 +205,24 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
header=hdr)
if ret_type:
if is_c_ptr(ret_type):
retval = " %s retval = NULL;" % c_type(ret_type)
else:
retval = " %s retval;" % c_type(ret_type)
ret += mcgen('''
%(retval)s
%(c_type)s retval;
''',
retval=retval)
c_type=c_type(ret_type))
if len(args) > 0:
ret += mcgen('''
%(visitor_input_containers_decl)s
%(visitor_input_vars_decl)s
%(visitor_input_block)s
''',
visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"),
visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
visitor_input_block=gen_visitor_input_block(args))
ret += gen_visitor_input_containers_decl(args)
ret += gen_visitor_input_vars_decl(args) + '\n'
ret += gen_visitor_input_block(args) + '\n'
else:
ret += mcgen('''
(void)args;
''')
ret += mcgen('''
%(sync_call)s
''',
sync_call=gen_sync_call(name, args, ret_type, indent=4))
ret += gen_sync_call(name, args, ret_type)
if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen('''
@ -248,11 +230,11 @@ out:
''')
ret += mcgen('''
error_propagate(errp, local_err);
%(visitor_input_block_cleanup)s
''')
ret += gen_visitor_input_block(args, dealloc=True)
ret += mcgen('''
}
''',
visitor_input_block_cleanup=gen_visitor_input_block(args,
dealloc=True))
''')
return ret
def gen_registry(commands):
@ -272,12 +254,13 @@ qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
ret = mcgen('''
static void qmp_init_marshal(void)
{
%(registry)s
''')
ret += registry
ret += mcgen('''
}
qapi_init(qmp_init_marshal);
''',
registry=registry.rstrip())
''')
return ret
middle_mode = False
@ -357,14 +340,14 @@ for cmd in commands:
arglist = cmd['data']
if cmd.has_key('returns'):
ret_type = cmd['returns']
ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
ret = generate_command_decl(cmd['command'], arglist, ret_type)
fdecl.write(ret)
if ret_type:
ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
ret = gen_marshal_output(cmd['command'], ret_type) + "\n"
fdef.write(ret)
if middle_mode:
fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], middle_mode))
ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
fdef.write(ret)

View File

@ -167,8 +167,7 @@ extern const char *%(event_enum_name)s_lookup[];
event_enum_name = event_enum_name)
enum_decl = mcgen('''
typedef enum %(event_enum_name)s
{
typedef enum %(event_enum_name)s {
''',
event_enum_name = event_enum_name)
@ -199,7 +198,6 @@ const char *%(event_enum_name)s_lookup[] = {
''',
event_enum_name = event_enum_name)
i = 0
for string in event_enum_strings:
ret += mcgen('''
"%(string)s",
@ -267,7 +265,7 @@ fdecl.write(mcgen('''
exprs = parse_schema(input_file)
event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
event_enum_values = []
event_enum_strings = []

View File

@ -15,8 +15,7 @@ from qapi import *
def generate_fwd_builtin(name):
return mcgen('''
typedef struct %(name)sList
{
typedef struct %(name)sList {
union {
%(type)s value;
uint64_t padding;
@ -32,8 +31,7 @@ def generate_fwd_struct(name):
typedef struct %(name)s %(name)s;
typedef struct %(name)sList
{
typedef struct %(name)sList {
union {
%(name)s *value;
uint64_t padding;
@ -45,8 +43,8 @@ typedef struct %(name)sList
def generate_fwd_enum_struct(name):
return mcgen('''
typedef struct %(name)sList
{
typedef struct %(name)sList {
union {
%(name)s value;
uint64_t padding;
@ -79,8 +77,8 @@ def generate_struct(expr):
base = expr.get('base')
ret = mcgen('''
struct %(name)s
{
struct %(name)s {
''',
name=c_name(structname))
@ -105,10 +103,10 @@ struct %(name)s
def generate_enum_lookup(name, values):
ret = mcgen('''
const char * const %(name)s_lookup[] = {
const char *const %(name)s_lookup[] = {
''',
name=c_name(name))
i = 0
for value in values:
index = c_enum_const(name, value)
ret += mcgen('''
@ -120,7 +118,6 @@ const char * const %(name)s_lookup[] = {
ret += mcgen('''
[%(max_index)s] = NULL,
};
''',
max_index=max_index)
return ret
@ -128,13 +125,14 @@ const char * const %(name)s_lookup[] = {
def generate_enum(name, values):
name = c_name(name)
lookup_decl = mcgen('''
extern const char * const %(name)s_lookup[];
extern const char *const %(name)s_lookup[];
''',
name=name)
enum_decl = mcgen('''
typedef enum %(name)s
{
typedef enum %(name)s {
''',
name=name)
@ -156,7 +154,7 @@ typedef enum %(name)s
''',
name=name)
return lookup_decl + enum_decl
return enum_decl + lookup_decl
def generate_alternate_qtypes(expr):
@ -164,6 +162,7 @@ def generate_alternate_qtypes(expr):
members = expr['data']
ret = mcgen('''
const int %(name)s_qtypes[QTYPE_MAX] = {
''',
name=c_name(name))
@ -199,14 +198,40 @@ def generate_union(expr, meta):
discriminator_type_name = '%sKind' % (name)
ret = mcgen('''
struct %(name)s
{
struct %(name)s {
''',
name=name)
if base:
ret += mcgen('''
/* Members inherited from %(c_name)s: */
''',
c_name=c_name(base))
base_fields = find_struct(base)['data']
ret += generate_struct_fields(base_fields)
ret += mcgen('''
/* Own members: */
''')
else:
assert not discriminator
ret += mcgen('''
%(discriminator_type_name)s kind;
union {
''',
discriminator_type_name=c_name(discriminator_type_name))
# FIXME: What purpose does data serve, besides preventing a union that
# has a branch named 'data'? We use it in qapi-visit.py to decide
# whether to bypass the switch statement if visiting the discriminator
# failed; but since we 0-initialize structs, and cannot tell what
# branch of the union is in use if the discriminator is invalid, there
# should not be any data leaks even without a data pointer. Or, if
# 'data' is merely added to guarantee we don't have an empty union,
# shouldn't we enforce that at .json parse time?
ret += mcgen('''
union { /* union tag is @%(c_name)s */
void *data;
''',
name=name,
discriminator_type_name=c_name(discriminator_type_name))
c_name=c_name(discriminator or 'kind'))
for key in typeinfo:
ret += mcgen('''
@ -217,17 +242,6 @@ struct %(name)s
ret += mcgen('''
};
''')
if base:
assert discriminator
base_fields = find_struct(base)['data'].copy()
del base_fields[discriminator]
ret += generate_struct_fields(base_fields)
else:
assert not discriminator
ret += mcgen('''
};
''')
if meta == 'alternate':
@ -314,14 +328,12 @@ fdef.write(mcgen('''
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"
''',
prefix=prefix))
fdecl.write(mcgen('''
#include <stdbool.h>
#include <stdint.h>
'''))
exprs = parse_schema(input_file)
@ -332,22 +344,22 @@ for typename in builtin_types.keys():
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for expr in exprs:
ret = "\n"
ret = ""
if expr.has_key('struct'):
ret += generate_fwd_struct(expr['struct'])
elif expr.has_key('enum'):
ret += generate_enum(expr['enum'], expr['data']) + "\n"
ret += generate_enum(expr['enum'], expr['data'])
ret += generate_fwd_enum_struct(expr['enum'])
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
elif expr.has_key('union'):
ret += generate_fwd_struct(expr['union']) + "\n"
ret += generate_fwd_struct(expr['union'])
enum_define = discriminator_find_enum_define(expr)
if not enum_define:
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
expr['data'].keys()))
elif expr.has_key('alternate'):
ret += generate_fwd_struct(expr['alternate']) + "\n"
ret += generate_fwd_struct(expr['alternate'])
ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
expr['data'].keys()))
@ -367,34 +379,32 @@ fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
# have the functions defined, so we use -b option to provide control
# over these cases
if do_builtins:
fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for typename in builtin_types.keys():
fdef.write(generate_type_cleanup(typename + "List"))
fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for expr in exprs:
ret = "\n"
ret = ""
if expr.has_key('struct'):
ret += generate_struct(expr) + "\n"
ret += generate_type_cleanup_decl(expr['struct'] + "List")
fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
fdef.write(generate_type_cleanup(expr['struct'] + "List"))
ret += generate_type_cleanup_decl(expr['struct'])
fdef.write(generate_type_cleanup(expr['struct']) + "\n")
fdef.write(generate_type_cleanup(expr['struct']))
elif expr.has_key('union'):
ret += generate_union(expr, 'union')
ret += generate_union(expr, 'union') + "\n"
ret += generate_type_cleanup_decl(expr['union'] + "List")
fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
fdef.write(generate_type_cleanup(expr['union'] + "List"))
ret += generate_type_cleanup_decl(expr['union'])
fdef.write(generate_type_cleanup(expr['union']) + "\n")
fdef.write(generate_type_cleanup(expr['union']))
elif expr.has_key('alternate'):
ret += generate_union(expr, 'alternate')
ret += generate_union(expr, 'alternate') + "\n"
ret += generate_type_cleanup_decl(expr['alternate'] + "List")
fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
fdef.write(generate_type_cleanup(expr['alternate'] + "List"))
ret += generate_type_cleanup_decl(expr['alternate'])
fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
fdef.write(generate_type_cleanup(expr['alternate']))
elif expr.has_key('enum'):
ret += generate_type_cleanup_decl(expr['enum'] + "List")
fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
ret += "\n" + generate_type_cleanup_decl(expr['enum'] + "List")
fdef.write(generate_type_cleanup(expr['enum'] + "List"))
else:
continue
fdecl.write(ret)

View File

@ -16,14 +16,23 @@ from ordereddict import OrderedDict
from qapi import *
import re
implicit_structs = []
implicit_structs_seen = set()
struct_fields_seen = set()
def generate_visit_implicit_struct(type):
global implicit_structs
if type in implicit_structs:
if type in implicit_structs_seen:
return ''
implicit_structs.append(type)
return mcgen('''
implicit_structs_seen.add(type)
ret = ''
if type not in struct_fields_seen:
# Need a forward declaration
ret += mcgen('''
static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
''',
c_type=type_name(type))
ret += mcgen('''
static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
{
@ -38,9 +47,11 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
}
''',
c_type=type_name(type))
return ret
def generate_visit_struct_fields(name, members, base = None):
substructs = []
struct_fields_seen.add(name)
ret = ''
if base:
@ -51,6 +62,7 @@ def generate_visit_struct_fields(name, members, base = None):
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
{
Error *err = NULL;
''',
name=c_name(name))
push_indent()
@ -103,7 +115,11 @@ out:
return ret
def generate_visit_struct_body(name, members):
def generate_visit_struct_body(name):
# FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
# *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
# rather than leaving it non-NULL. As currently written, the caller must
# call qapi_free_FOO() to avoid a memory leak of the partial FOO.
ret = mcgen('''
Error *err = NULL;
@ -135,14 +151,14 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''',
name=c_name(name))
ret += generate_visit_struct_body(name, members)
ret += generate_visit_struct_body(name)
ret += mcgen('''
}
''')
return ret
def generate_visit_list(name, members):
def generate_visit_list(name):
return mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
@ -171,15 +187,15 @@ out:
''',
name=type_name(name))
def generate_visit_enum(name, members):
def generate_visit_enum(name):
return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
{
visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
visit_type_enum(m, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
}
''',
name=c_name(name))
c_name=c_name(name), name=name)
def generate_visit_alternate(name, members):
ret = mcgen('''
@ -252,7 +268,7 @@ def generate_visit_union(expr):
else:
# There will always be a discriminator in the C switch code, by default
# it is an enum type generated silently
ret = generate_visit_enum(name + 'Kind', members.keys())
ret = generate_visit_enum(name + 'Kind')
disc_type = c_name(name) + 'Kind'
if base:
@ -267,17 +283,17 @@ def generate_visit_union(expr):
ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
if (err) {
goto out;
}
if (*obj) {
''',
name=c_name(name))
c_name=c_name(name), name=name)
if base:
ret += mcgen('''
@ -289,20 +305,23 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
name=c_name(name))
if not discriminator:
tag = 'kind'
disc_key = "type"
else:
tag = discriminator
disc_key = discriminator
ret += mcgen('''
visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
if (err) {
goto out_obj;
}
if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
goto out_obj;
}
switch ((*obj)->kind) {
switch ((*obj)->%(c_tag)s) {
''',
disc_type = disc_type,
c_tag=c_name(tag),
disc_key = disc_key)
for key in members:
@ -340,7 +359,7 @@ out:
return ret
def generate_declaration(name, members, builtin_type=False):
def generate_declaration(name, builtin_type=False):
ret = ""
if not builtin_type:
name = c_name(name)
@ -357,7 +376,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
return ret
def generate_enum_declaration(name, members):
def generate_enum_declaration(name):
ret = mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
''',
@ -365,7 +384,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
return ret
def generate_decl_enum(name, members):
def generate_decl_enum(name):
return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
@ -433,7 +452,7 @@ exprs = parse_schema(input_file)
# for built-in types in our header files and simply guard them
fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
for typename in builtin_types.keys():
fdecl.write(generate_declaration(typename, None, builtin_type=True))
fdecl.write(generate_declaration(typename, builtin_type=True))
fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# ...this doesn't work for cases where we link in multiple objects that
@ -441,44 +460,42 @@ fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# over these cases
if do_builtins:
for typename in builtin_types.keys():
fdef.write(generate_visit_list(typename, None))
fdef.write(generate_visit_list(typename))
for expr in exprs:
if expr.has_key('struct'):
ret = generate_visit_struct(expr)
ret += generate_visit_list(expr['struct'], expr['data'])
ret += generate_visit_list(expr['struct'])
fdef.write(ret)
ret = generate_declaration(expr['struct'], expr['data'])
ret = generate_declaration(expr['struct'])
fdecl.write(ret)
elif expr.has_key('union'):
ret = generate_visit_union(expr)
ret += generate_visit_list(expr['union'], expr['data'])
ret += generate_visit_list(expr['union'])
fdef.write(ret)
enum_define = discriminator_find_enum_define(expr)
ret = ""
if not enum_define:
ret = generate_decl_enum('%sKind' % expr['union'],
expr['data'].keys())
ret += generate_declaration(expr['union'], expr['data'])
ret = generate_decl_enum('%sKind' % expr['union'])
ret += generate_declaration(expr['union'])
fdecl.write(ret)
elif expr.has_key('alternate'):
ret = generate_visit_alternate(expr['alternate'], expr['data'])
ret += generate_visit_list(expr['alternate'], expr['data'])
ret += generate_visit_list(expr['alternate'])
fdef.write(ret)
ret = generate_decl_enum('%sKind' % expr['alternate'],
expr['data'].keys())
ret += generate_declaration(expr['alternate'], expr['data'])
ret = generate_decl_enum('%sKind' % expr['alternate'])
ret += generate_declaration(expr['alternate'])
fdecl.write(ret)
elif expr.has_key('enum'):
ret = generate_visit_list(expr['enum'], expr['data'])
ret += generate_visit_enum(expr['enum'], expr['data'])
ret = generate_visit_list(expr['enum'])
ret += generate_visit_enum(expr['enum'])
fdef.write(ret)
ret = generate_decl_enum(expr['enum'], expr['data'])
ret += generate_enum_declaration(expr['enum'], expr['data'])
ret = generate_decl_enum(expr['enum'])
ret += generate_enum_declaration(expr['enum'])
fdecl.write(ret)
close_output(fdef, fdecl)

View File

@ -341,6 +341,8 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type)
# FIXME should enforce "other than downstream extensions [...], all
# names should begin with a letter".
valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
def check_name(expr_info, source, name, allow_optional = False,
enum_member = False):
@ -367,6 +369,8 @@ def check_name(expr_info, source, name, allow_optional = False,
def add_name(name, info, meta, implicit = False):
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 QAPIExprError(info,
"%s '%s' is already defined"
@ -422,7 +426,6 @@ def check_type(expr_info, source, value, allow_array = False,
allow_dict = False, allow_optional = False,
allow_star = False, allow_metas = []):
global all_names
orig_value = value
if value is None:
return
@ -440,7 +443,6 @@ def check_type(expr_info, source, value, allow_array = False,
"%s: array type must contain single type name"
% source)
value = value[0]
orig_value = "array of %s" %value
# Check if type name for value is okay
if isinstance(value, str):
@ -451,20 +453,22 @@ def check_type(expr_info, source, value, allow_array = False,
if not value in all_names:
raise QAPIExprError(expr_info,
"%s uses unknown type '%s'"
% (source, orig_value))
% (source, value))
if not all_names[value] in allow_metas:
raise QAPIExprError(expr_info,
"%s cannot use %s type '%s'"
% (source, all_names[value], orig_value))
% (source, all_names[value], value))
return
# value is a dictionary, check that each member is okay
if not isinstance(value, OrderedDict):
raise QAPIExprError(expr_info,
"%s should be a dictionary" % source)
if not allow_dict:
raise QAPIExprError(expr_info,
"%s should be a type name" % source)
if not isinstance(value, OrderedDict):
raise QAPIExprError(expr_info,
"%s should be a dictionary or type name" % source)
# value is a dictionary, check that each member is okay
for (key, arg) in value.items():
check_name(expr_info, "Member of %s" % source, key,
allow_optional=allow_optional)
@ -495,26 +499,25 @@ def check_command(expr, expr_info):
check_type(expr_info, "'data' for command '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct'], allow_star=allow_star)
allow_metas=['struct'], allow_star=allow_star)
returns_meta = ['union', 'struct']
if name in returns_whitelist:
returns_meta += ['built-in', 'alternate', 'enum']
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_optional=True, allow_metas=returns_meta,
allow_star=allow_star)
def check_event(expr, expr_info):
global events
name = expr['event']
params = expr.get('data')
if name.upper() == 'MAX':
raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
events.append(name)
check_type(expr_info, "'data' for event '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
allow_metas=['union', 'struct'])
allow_metas=['struct'])
def check_union(expr, expr_info):
name = expr['union']
@ -523,14 +526,6 @@ def check_union(expr, expr_info):
members = expr['data']
values = { 'MAX': '(automatic)' }
# If the object has a member 'base', its value must name a struct,
# and there must be a discriminator.
if base is not None:
if discriminator is None:
raise QAPIExprError(expr_info,
"Union '%s' requires a discriminator to go "
"along with base" %name)
# Two types of unions, determined by discriminator.
# With no discriminator it is a simple union.
@ -943,24 +938,24 @@ def pop_indent(indent_amount=4):
global indent_level
indent_level -= indent_amount
# Generate @code with @kwds interpolated.
# Obey indent_level, and strip eatspace.
def cgen(code, **kwds):
indent = genindent(indent_level)
lines = code.split('\n')
lines = map(lambda x: indent + x, lines)
return '\n'.join(lines) % kwds + '\n'
def mcgen(code, **kwds):
raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
raw = code % kwds
if indent_level:
indent = genindent(indent_level)
raw = re.subn("^.", indent + r'\g<0>', raw, 0, re.MULTILINE)
raw = raw[0]
return re.sub(re.escape(eatspace) + ' *', '', raw)
def basename(filename):
return filename.split("/")[-1]
def mcgen(code, **kwds):
if code[0] == '\n':
code = code[1:]
return cgen(code, **kwds)
def guardname(filename):
guard = basename(filename).rsplit(".", 1)[0]
for substr in [".", " ", "-"]:
guard = guard.replace(substr, "_")
return guard.upper() + '_H'
return c_name(filename, protect=False).upper()
def guardstart(name):
return mcgen('''
@ -1003,6 +998,12 @@ def parse_command_line(extra_options = "", extra_long_options = []):
for oa in opts:
o, a = oa
if o in ("-p", "--prefix"):
match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
if match.end() != len(a):
print >>sys.stderr, \
"%s: 'funny character '%s' in argument of --prefix" \
% (sys.argv[0], a[match.end()])
sys.exit(1)
prefix = a
elif o in ("-o", "--output-dir"):
output_dir = a + "/"
@ -1030,14 +1031,16 @@ def parse_command_line(extra_options = "", extra_long_options = []):
def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
c_comment, h_comment):
guard = guardname(prefix + h_file)
c_file = output_dir + prefix + c_file
h_file = output_dir + prefix + h_file
try:
os.makedirs(output_dir)
except os.error, e:
if e.errno != errno.EEXIST:
raise
if output_dir:
try:
os.makedirs(output_dir)
except os.error, e:
if e.errno != errno.EEXIST:
raise
def maybe_open(really, name, opt):
if really:
@ -1062,7 +1065,7 @@ def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
#define %(guard)s
''',
comment = h_comment, guard = guardname(h_file)))
comment = h_comment, guard = guard))
return (fdef, fdecl)

View File

@ -229,13 +229,17 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
redefined-type.json redefined-command.json redefined-builtin.json \
redefined-event.json command-int.json bad-data.json event-max.json \
type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \
data-array-empty.json data-array-unknown.json data-int.json \
data-unknown.json data-member-unknown.json data-member-array.json \
data-member-array-bad.json returns-array-bad.json returns-int.json \
args-invalid.json \
args-array-empty.json args-array-unknown.json args-int.json \
args-unknown.json args-member-unknown.json args-member-array.json \
args-member-array-bad.json args-alternate.json args-union.json \
returns-array-bad.json returns-int.json returns-dict.json \
returns-unknown.json returns-alternate.json returns-whitelist.json \
missing-colon.json missing-comma-list.json missing-comma-object.json \
nested-struct-data.json nested-struct-returns.json non-objects.json \
struct-data-invalid.json struct-member-invalid.json \
nested-struct-data.json non-objects.json \
qapi-schema-test.json quoted-structural-chars.json \
leading-comma-list.json leading-comma-object.json \
trailing-comma-list.json trailing-comma-object.json \
unclosed-list.json unclosed-object.json unclosed-string.json \
duplicate-key.json union-invalid-base.json union-bad-branch.json \

View File

@ -0,0 +1 @@
tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt'

View File

@ -0,0 +1,3 @@
# we do not allow alternate arguments
{ 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } }
{ 'command': 'oops', 'data': 'Alt' }

View File

@ -1 +1 @@
tests/qapi-schema/data-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:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name

View File

@ -0,0 +1 @@
tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'

View File

@ -0,0 +1 @@
tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name

View File

@ -0,0 +1,2 @@
{ 'command': 'foo',
'data': false }

View File

@ -1 +1 @@
tests/qapi-schema/data-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:2: Member 'member' of 'data' for command 'oops': array type must contain single type name

View File

@ -0,0 +1 @@
tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
tests/qapi-schema/args-union.json:4: 'data' for command 'oops' cannot use union type 'Uni'

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
# we do not allow union arguments
# TODO should we support this?
{ 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } }
{ 'command': 'oops', 'data': 'Uni' }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
1

View File

View File

@ -1,3 +1,2 @@
# we reject collisions between commands and types
{ 'command': 'int', 'data': { 'character': 'str' },
'returns': { 'value': 'int' } }
{ 'command': 'int', 'data': { 'character': 'str' } }

View File

@ -1 +0,0 @@
tests/qapi-schema/data-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'array of NoSuchType'

View File

@ -1 +0,0 @@
tests/qapi-schema/data-int.json:2: 'data' for command 'oops' cannot use built-in type 'int'

View File

@ -1 +0,0 @@
tests/qapi-schema/data-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -1 +0,0 @@
tests/qapi-schema/data-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType'

View File

@ -0,0 +1 @@
tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null"

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'enum': 'Status',
'data': [ , 'good', 'bad', 'ugly' ] }

View File

View File

@ -0,0 +1 @@
tests/qapi-schema/leading-comma-object.json:1:3: Expected string or "}"

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ , 'enum': 'Status',
'data': [ 'good', 'bad', 'ugly' ] }

View File

@ -1,4 +1,3 @@
# inline subtypes collide with our desired future use of defaults
{ 'command': 'foo',
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' },
'returns': {} }
'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }

View File

@ -1 +0,0 @@
tests/qapi-schema/nested-struct-returns.json:2: Member 'a' of 'returns' for command 'foo' should be a type name

View File

@ -1,3 +0,0 @@
# inline subtypes collide with our desired future use of defaults
{ 'command': 'foo',
'returns': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } }

View File

@ -7,13 +7,13 @@
'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
# for testing nested structs
{ 'struct': 'UserDefOne',
'base': 'UserDefZero', # intentional forward reference
'data': { 'string': 'str', '*enum1': 'EnumOne' } }
{ 'struct': 'UserDefZero',
'data': { 'integer': 'int' } }
{ 'struct': 'UserDefOne',
'base': 'UserDefZero',
'data': { 'string': 'str', '*enum1': 'EnumOne' } }
{ 'struct': 'UserDefTwoDictDict',
'data': { 'userdef': 'UserDefOne', 'string': 'str' } }
@ -31,30 +31,36 @@
'data': { 'boolean': 'bool' } }
{ 'struct': 'UserDefB',
'data': { 'integer': 'int' } }
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
{ 'struct': 'UserDefUnionBase',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
'data': { 'intb': 'int' } }
{ 'union': 'UserDefFlatUnion',
'base': 'UserDefUnionBase',
'base': 'UserDefUnionBase', # intentional forward reference
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefA', 'value2' : 'UserDefB', 'value3' : 'UserDefB' } }
'data': { 'value1' : 'UserDefA',
'value2' : 'UserDefB',
'value3' : 'UserDefB' } }
# FIXME generated struct UserDefFlatUnion has members for direct base
# UserDefOne, but lacks members for indirect base UserDefZero
# UserDefUnionBase, but lacks members for indirect base UserDefZero
{ 'struct': 'UserDefUnionBase',
'base': 'UserDefZero',
'data': { 'string': 'str', 'enum1': 'EnumOne' } }
# this variant of UserDefFlatUnion defaults to a union that uses fields with
# allocated types to test corner cases in the cleanup/dealloc visitor
{ 'union': 'UserDefFlatUnion2',
'base': 'UserDefUnionBase',
'discriminator': 'enum1',
'data': { 'value1' : 'UserDefC', 'value2' : 'UserDefB', 'value3' : 'UserDefA' } }
'data': { 'value1' : 'UserDefC', # intentional forward reference
'value2' : 'UserDefB',
'value3' : 'UserDefA' } }
{ 'alternate': 'UserDefAlternate',
'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
# FIXME only a declaration of visit_type_UserDefAlternateKind() generated
{ 'struct': 'UserDefC',
'data': { 'string1': 'str', 'string2': 'str' } }
# for testing native lists
{ 'union': 'UserDefNativeListUnion',
@ -123,6 +129,9 @@
{ 'alternate': '__org.qemu_x-Alt',
'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
# FIXME generated qapi_event_send___org_qemu_x_event() has only a
# parameter for data's member __org_qemu_x_member2, none for its base
# __org.qemu_x-Base's member __org_qemu_x_member1
{ 'command': '__org.qemu_x-command',
'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },

View File

@ -1,17 +1,17 @@
[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]),
OrderedDict([('alternate', 'UserDefAlternate'), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]),
OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str']), ('sizes', ['size'])]))]),
OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]),
@ -39,15 +39,15 @@
{'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None},
{'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}]
[OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]),
OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]),

View File

@ -0,0 +1 @@
tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
# we reject inline struct return type
{ 'command': 'oops', 'returns': { 'a': 'str' } }

View File

View File

@ -1 +1 @@
tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'array of int'
tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'

View File

@ -0,0 +1 @@
tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'struct': 'foo',
'data': false }

View File

@ -0,0 +1 @@
tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,2 @@
{ 'struct': 'foo',
'data': { 'a': false } }

View File

@ -1 +1 @@
tests/qapi-schema/union-base-no-discriminator.json:11: Union 'TestUnion' requires a discriminator to go along with base
tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base

View File

@ -94,7 +94,7 @@ static bool qdict_cmp_simple(QDict *a, QDict *b)
/* This function is hooked as final emit function, which can verify the
correctness. */
static void event_test_emit(TEST_QAPIEvent event, QDict *d, Error **errp)
static void event_test_emit(test_QAPIEvent event, QDict *d, Error **errp)
{
QObject *obj;
QDict *t;

View File

@ -313,7 +313,7 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
g_assert(err == NULL);
g_assert_cmpint(tmp->kind, ==, ENUM_ONE_VALUE1);
g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
g_assert_cmpstr(tmp->string, ==, "str");
/* TODO g_assert_cmpint(tmp->integer, ==, 41); */
g_assert_cmpint(tmp->value1->boolean, ==, true);
@ -636,6 +636,8 @@ static void test_visitor_in_errors(TestInputVisitorData *data,
visit_type_TestStruct(v, &p, NULL, &err);
g_assert(err);
/* FIXME - a failed parse should not leave a partially-allocated p
* for us to clean up; this could cause callers to leak memory. */
g_assert(p->string == NULL);
error_free(err);

View File

@ -437,7 +437,7 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data,
Error *err = NULL;
UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
tmp->kind = ENUM_ONE_VALUE1;
tmp->enum1 = ENUM_ONE_VALUE1;
tmp->string = g_strdup("str");
tmp->value1 = g_malloc0(sizeof(UserDefA));
/* TODO when generator bug is fixed: tmp->integer = 41; */