qapi: Add feature flags to remaining definitions

In v4.1.0, we added feature flags just to struct types (commit
6a8c0b5102^..f3ed93d545), to satisfy an immediate need (commit
c9d4070991 "file-posix: Add dynamic-auto-read-only QAPI feature").  In
v4.2.0, we added them to commands (commit 23394b4c39 "qapi: Add
feature flags to commands") to satisfy another immediate need (commit
d76744e65e "qapi: Allow introspecting fix for savevm's cooperation
with blockdev").

Add them to the remaining definitions: enumeration types, union types,
alternate types, and events.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200317115459.31821-13-armbru@redhat.com>
This commit is contained in:
Markus Armbruster 2020-03-17 12:54:37 +01:00
parent e4405b3069
commit 013b4efc9b
17 changed files with 242 additions and 121 deletions

View File

@ -172,7 +172,8 @@ Syntax:
ENUM = { 'enum': STRING, ENUM = { 'enum': STRING,
'data': [ ENUM-VALUE, ... ], 'data': [ ENUM-VALUE, ... ],
'*prefix': STRING, '*prefix': STRING,
'*if': COND } '*if': COND,
'*features': FEATURES }
ENUM-VALUE = STRING ENUM-VALUE = STRING
| { 'name': STRING, '*if': COND } | { 'name': STRING, '*if': COND }
@ -207,6 +208,9 @@ the job satisfactorily.
The optional 'if' member specifies a conditional. See "Configuring The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this. the schema" below for more on this.
The optional 'features' member specifies features. See "Features"
below for more on this.
=== Type references and array types === === Type references and array types ===
@ -279,12 +283,14 @@ below for more on this.
Syntax: Syntax:
UNION = { 'union': STRING, UNION = { 'union': STRING,
'data': BRANCHES, 'data': BRANCHES,
'*if': COND } '*if': COND,
'*features': FEATURES }
| { 'union': STRING, | { 'union': STRING,
'data': BRANCHES, 'data': BRANCHES,
'base': ( MEMBERS | STRING ), 'base': ( MEMBERS | STRING ),
'discriminator': STRING, 'discriminator': STRING,
'*if': COND } '*if': COND,
'*features': FEATURES }
BRANCHES = { BRANCH, ... } BRANCHES = { BRANCH, ... }
BRANCH = STRING : TYPE-REF BRANCH = STRING : TYPE-REF
| STRING : { 'type': TYPE-REF, '*if': COND } | STRING : { 'type': TYPE-REF, '*if': COND }
@ -391,13 +397,17 @@ is identical on the wire to:
The optional 'if' member specifies a conditional. See "Configuring The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this. the schema" below for more on this.
The optional 'features' member specifies features. See "Features"
below for more on this.
=== Alternate types === === Alternate types ===
Syntax: Syntax:
ALTERNATE = { 'alternate': STRING, ALTERNATE = { 'alternate': STRING,
'data': ALTERNATIVES, 'data': ALTERNATIVES,
'*if': COND } '*if': COND,
'*features': FEATURES }
ALTERNATIVES = { ALTERNATIVE, ... } ALTERNATIVES = { ALTERNATIVE, ... }
ALTERNATIVE = STRING : STRING ALTERNATIVE = STRING : STRING
| STRING : { 'type': STRING, '*if': COND } | STRING : { 'type': STRING, '*if': COND }
@ -441,6 +451,9 @@ following example objects:
The optional 'if' member specifies a conditional. See "Configuring The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this. the schema" below for more on this.
The optional 'features' member specifies features. See "Features"
below for more on this.
=== Commands === === Commands ===
@ -584,6 +597,9 @@ started with --preconfig.
The optional 'if' member specifies a conditional. See "Configuring The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this. the schema" below for more on this.
The optional 'features' member specifies features. See "Features"
below for more on this.
=== Events === === Events ===
@ -595,7 +611,8 @@ Syntax:
'data': STRING, 'data': STRING,
'boxed': true, 'boxed': true,
) )
'*if': COND } '*if': COND,
'*features': FEATURES }
Member 'event' names the event. This is the event name used in the Member 'event' names the event. This is the event name used in the
Client JSON Protocol. Client JSON Protocol.
@ -628,6 +645,9 @@ complex type. See section "Code generated for events" for examples.
The optional 'if' member specifies a conditional. See "Configuring The optional 'if' member specifies a conditional. See "Configuring
the schema" below for more on this. the schema" below for more on this.
The optional 'features' member specifies features. See "Features"
below for more on this.
=== Features === === Features ===
@ -966,8 +986,9 @@ schema, along with the SchemaInfo type. This text attempts to give an
overview how things work. For details you need to consult the QAPI overview how things work. For details you need to consult the QAPI
schema. schema.
SchemaInfo objects have common members "name", "meta-type", and SchemaInfo objects have common members "name", "meta-type",
additional variant members depending on the value of meta-type. "features", and additional variant members depending on the value of
meta-type.
Each SchemaInfo object describes a wire ABI entity of a certain Each SchemaInfo object describes a wire ABI entity of a certain
meta-type: a command, event or one of several kinds of type. meta-type: a command, event or one of several kinds of type.
@ -980,19 +1001,21 @@ not. Therefore, the SchemaInfo for types have auto-generated
meaningless names. For readability, the examples in this section use meaningless names. For readability, the examples in this section use
meaningful type names instead. meaningful type names instead.
Optional member "features" exposes the entity's feature strings as a
JSON array of strings.
To examine a type, start with a command or event using it, then follow To examine a type, start with a command or event using it, then follow
references by name. references by name.
QAPI schema definitions not reachable that way are omitted. QAPI schema definitions not reachable that way are omitted.
The SchemaInfo for a command has meta-type "command", and variant The SchemaInfo for a command has meta-type "command", and variant
members "arg-type", "ret-type", "allow-oob", and "features". On the members "arg-type", "ret-type" and "allow-oob". On the wire, the
wire, the "arguments" member of a client's "execute" command must "arguments" member of a client's "execute" command must conform to the
conform to the object type named by "arg-type". The "return" member object type named by "arg-type". The "return" member that the server
that the server passes in a success response conforms to the type passes in a success response conforms to the type named by "ret-type".
named by "ret-type". When "allow-oob" is true, it means the command When "allow-oob" is true, it means the command supports out-of-band
supports out-of-band execution. It defaults to false. "features" execution. It defaults to false.
exposes the command's feature strings as a JSON array of strings.
If the command takes no arguments, "arg-type" names an object type If the command takes no arguments, "arg-type" names an object type
without members. Likewise, if the command returns nothing, "ret-type" without members. Likewise, if the command returns nothing, "ret-type"
@ -1027,8 +1050,7 @@ Example: the SchemaInfo for EVENT_C from section Events
The SchemaInfo for struct and union types has meta-type "object". The SchemaInfo for struct and union types has meta-type "object".
The SchemaInfo for a struct type has variant members "members" and The SchemaInfo for a struct type has variant member "members".
"features".
The SchemaInfo for a union type additionally has variant members "tag" The SchemaInfo for a union type additionally has variant members "tag"
and "variants". and "variants".

View File

@ -89,12 +89,18 @@
# #
# @meta-type: the entity's meta type, inherited from @base. # @meta-type: the entity's meta type, inherited from @base.
# #
# @features: names of features associated with the entity, in no
# particular order.
# (since 4.1 for object types, 4.2 for commands, 5.0 for
# the rest)
#
# Additional members depend on the value of @meta-type. # Additional members depend on the value of @meta-type.
# #
# Since: 2.5 # Since: 2.5
## ##
{ 'union': 'SchemaInfo', { 'union': 'SchemaInfo',
'base': { 'name': 'str', 'meta-type': 'SchemaMetaType' }, 'base': { 'name': 'str', 'meta-type': 'SchemaMetaType',
'*features': [ 'str' ] },
'discriminator': 'meta-type', 'discriminator': 'meta-type',
'data': { 'data': {
'builtin': 'SchemaInfoBuiltin', 'builtin': 'SchemaInfoBuiltin',
@ -174,9 +180,6 @@
# and may even differ from the order of the values of the # and may even differ from the order of the values of the
# enum type of the @tag. # enum type of the @tag.
# #
# @features: names of features associated with the type, in no particular
# order. (since: 4.1)
#
# Values of this type are JSON object on the wire. # Values of this type are JSON object on the wire.
# #
# Since: 2.5 # Since: 2.5
@ -184,8 +187,7 @@
{ 'struct': 'SchemaInfoObject', { 'struct': 'SchemaInfoObject',
'data': { 'members': [ 'SchemaInfoObjectMember' ], 'data': { 'members': [ 'SchemaInfoObjectMember' ],
'*tag': 'str', '*tag': 'str',
'*variants': [ 'SchemaInfoObjectVariant' ], '*variants': [ 'SchemaInfoObjectVariant' ] } }
'*features': [ 'str' ] } }
## ##
# @SchemaInfoObjectMember: # @SchemaInfoObjectMember:
@ -266,17 +268,13 @@
# @allow-oob: whether the command allows out-of-band execution, # @allow-oob: whether the command allows out-of-band execution,
# defaults to false (Since: 2.12) # defaults to false (Since: 2.12)
# #
# @features: names of features associated with the command, in no particular
# order. (since 4.2)
#
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP) # TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
# #
# Since: 2.5 # Since: 2.5
## ##
{ 'struct': 'SchemaInfoCommand', { 'struct': 'SchemaInfoCommand',
'data': { 'arg-type': 'str', 'ret-type': 'str', 'data': { 'arg-type': 'str', 'ret-type': 'str',
'*allow-oob': 'bool', '*allow-oob': 'bool' } }
'*features': [ 'str' ] } }
## ##
# @SchemaInfoEvent: # @SchemaInfoEvent:

View File

@ -243,7 +243,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
def write(self, output_dir): def write(self, output_dir):
self._gen.write(output_dir) self._gen.write(output_dir)
def visit_enum_type(self, name, info, ifcond, members, prefix): def visit_enum_type(self, name, info, ifcond, features, members, prefix):
doc = self.cur_doc doc = self.cur_doc
self._gen.add(texi_type('Enum', doc, ifcond, self._gen.add(texi_type('Enum', doc, ifcond,
texi_members(doc, 'Values', texi_members(doc, 'Values',
@ -257,7 +257,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
self._gen.add(texi_type('Object', doc, ifcond, self._gen.add(texi_type('Object', doc, ifcond,
texi_members(doc, 'Members', base, variants))) texi_members(doc, 'Members', base, variants)))
def visit_alternate_type(self, name, info, ifcond, variants): def visit_alternate_type(self, name, info, ifcond, features, variants):
doc = self.cur_doc doc = self.cur_doc
self._gen.add(texi_type('Alternate', doc, ifcond, self._gen.add(texi_type('Alternate', doc, ifcond,
texi_members(doc, 'Members'))) texi_members(doc, 'Members')))
@ -270,7 +270,7 @@ class QAPISchemaGenDocVisitor(QAPISchemaVisitor):
texi_arguments(doc, texi_arguments(doc,
arg_type if boxed else None))) arg_type if boxed else None)))
def visit_event(self, name, info, ifcond, arg_type, boxed): def visit_event(self, name, info, ifcond, features, arg_type, boxed):
doc = self.cur_doc doc = self.cur_doc
self._gen.add(texi_msg('Event', doc, ifcond, self._gen.add(texi_msg('Event', doc, ifcond,
texi_arguments(doc, texi_arguments(doc,

View File

@ -189,7 +189,7 @@ void %(event_emit)s(%(event_enum)s event, QDict *qdict);
event_emit=self._event_emit_name, event_emit=self._event_emit_name,
event_enum=self._event_enum_name)) event_enum=self._event_enum_name))
def visit_event(self, name, info, ifcond, arg_type, boxed): def visit_event(self, name, info, ifcond, features, arg_type, boxed):
with ifcontext(ifcond, self._genh, self._genc): with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed)) self._genh.add(gen_event_send_decl(name, arg_type, boxed))
self._genc.add(gen_event_send(name, arg_type, boxed, self._genc.add(gen_event_send(name, arg_type, boxed,

View File

@ -219,7 +219,6 @@ def check_struct(expr, info):
check_type(members, info, "'data'", allow_dict=name) check_type(members, info, "'data'", allow_dict=name)
check_type(expr.get('base'), info, "'base'") check_type(expr.get('base'), info, "'base'")
check_features(expr.get('features'), info)
def check_union(expr, info): def check_union(expr, info):
@ -267,7 +266,6 @@ def check_command(expr, info):
raise QAPISemError(info, "'boxed': true requires 'data'") raise QAPISemError(info, "'boxed': true requires 'data'")
check_type(args, info, "'data'", allow_dict=not boxed) check_type(args, info, "'data'", allow_dict=not boxed)
check_type(rets, info, "'returns'", allow_array=True) check_type(rets, info, "'returns'", allow_array=True)
check_features(expr.get('features'), info)
def check_event(expr, info): def check_event(expr, info):
@ -319,18 +317,18 @@ def check_exprs(exprs):
if meta == 'enum': if meta == 'enum':
check_keys(expr, info, meta, check_keys(expr, info, meta,
['enum', 'data'], ['if', 'prefix']) ['enum', 'data'], ['if', 'features', 'prefix'])
check_enum(expr, info) check_enum(expr, info)
elif meta == 'union': elif meta == 'union':
check_keys(expr, info, meta, check_keys(expr, info, meta,
['union', 'data'], ['union', 'data'],
['base', 'discriminator', 'if']) ['base', 'discriminator', 'if', 'features'])
normalize_members(expr.get('base')) normalize_members(expr.get('base'))
normalize_members(expr['data']) normalize_members(expr['data'])
check_union(expr, info) check_union(expr, info)
elif meta == 'alternate': elif meta == 'alternate':
check_keys(expr, info, meta, check_keys(expr, info, meta,
['alternate', 'data'], ['if']) ['alternate', 'data'], ['if', 'features'])
normalize_members(expr['data']) normalize_members(expr['data'])
check_alternate(expr, info) check_alternate(expr, info)
elif meta == 'struct': elif meta == 'struct':
@ -348,13 +346,14 @@ def check_exprs(exprs):
check_command(expr, info) check_command(expr, info)
elif meta == 'event': elif meta == 'event':
check_keys(expr, info, meta, check_keys(expr, info, meta,
['event'], ['data', 'boxed', 'if']) ['event'], ['data', 'boxed', 'if', 'features'])
normalize_members(expr.get('data')) normalize_members(expr.get('data'))
check_event(expr, info) check_event(expr, info)
else: else:
assert False, 'unexpected meta type' assert False, 'unexpected meta type'
check_if(expr, info, meta) check_if(expr, info, meta)
check_features(expr.get('features'), info)
check_flags(expr, info) check_flags(expr, info)
return exprs return exprs

View File

@ -144,7 +144,7 @@ const QLitObject %(c_name)s = %(c_string)s;
return '[' + self._use_type(typ.element_type) + ']' return '[' + self._use_type(typ.element_type) + ']'
return self._name(typ.name) return self._name(typ.name)
def _gen_qlit(self, name, mtype, obj, ifcond): def _gen_qlit(self, name, mtype, obj, ifcond, features):
extra = {} extra = {}
if mtype not in ('command', 'event', 'builtin', 'array'): if mtype not in ('command', 'event', 'builtin', 'array'):
if not self._unmask: if not self._unmask:
@ -154,6 +154,8 @@ const QLitObject %(c_name)s = %(c_string)s;
name = self._name(name) name = self._name(name)
obj['name'] = name obj['name'] = name
obj['meta-type'] = mtype obj['meta-type'] = mtype
if features:
obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
if ifcond: if ifcond:
extra['if'] = ifcond extra['if'] = ifcond
if extra: if extra:
@ -178,18 +180,18 @@ const QLitObject %(c_name)s = %(c_string)s;
{'if': variant.ifcond}) {'if': variant.ifcond})
def visit_builtin_type(self, name, info, json_type): def visit_builtin_type(self, name, info, json_type):
self._gen_qlit(name, 'builtin', {'json-type': json_type}, []) self._gen_qlit(name, 'builtin', {'json-type': json_type}, [], None)
def visit_enum_type(self, name, info, ifcond, members, prefix): def visit_enum_type(self, name, info, ifcond, features, members, prefix):
self._gen_qlit(name, 'enum', self._gen_qlit(name, 'enum',
{'values': {'values':
[(m.name, {'if': m.ifcond}) for m in members]}, [(m.name, {'if': m.ifcond}) for m in members]},
ifcond) ifcond, features)
def visit_array_type(self, name, info, ifcond, element_type): def visit_array_type(self, name, info, ifcond, element_type):
element = self._use_type(element_type) element = self._use_type(element_type)
self._gen_qlit('[' + element + ']', 'array', {'element-type': element}, self._gen_qlit('[' + element + ']', 'array', {'element-type': element},
ifcond) ifcond, None)
def visit_object_type_flat(self, name, info, ifcond, members, variants, def visit_object_type_flat(self, name, info, ifcond, members, variants,
features): features):
@ -197,16 +199,15 @@ const QLitObject %(c_name)s = %(c_string)s;
if variants: if variants:
obj.update(self._gen_variants(variants.tag_member.name, obj.update(self._gen_variants(variants.tag_member.name,
variants.variants)) variants.variants))
if features:
obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
self._gen_qlit(name, 'object', obj, ifcond) self._gen_qlit(name, 'object', obj, ifcond, features)
def visit_alternate_type(self, name, info, ifcond, variants): def visit_alternate_type(self, name, info, ifcond, features, variants):
self._gen_qlit(name, 'alternate', self._gen_qlit(name, 'alternate',
{'members': [ {'members': [
({'type': self._use_type(m.type)}, {'if': m.ifcond}) ({'type': self._use_type(m.type)}, {'if': m.ifcond})
for m in variants.variants]}, ifcond) for m in variants.variants]},
ifcond, features)
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig, success_response, boxed, allow_oob, allow_preconfig,
@ -217,16 +218,12 @@ const QLitObject %(c_name)s = %(c_string)s;
'ret-type': self._use_type(ret_type)} 'ret-type': self._use_type(ret_type)}
if allow_oob: if allow_oob:
obj['allow-oob'] = allow_oob obj['allow-oob'] = allow_oob
self._gen_qlit(name, 'command', obj, ifcond, features)
if features: def visit_event(self, name, info, ifcond, features, arg_type, boxed):
obj['features'] = [(f.name, {'if': f.ifcond}) for f in features]
self._gen_qlit(name, 'command', obj, ifcond)
def visit_event(self, name, info, ifcond, arg_type, boxed):
arg_type = arg_type or self._schema.the_empty_object_type arg_type = arg_type or self._schema.the_empty_object_type
self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)}, self._gen_qlit(name, 'event', {'arg-type': self._use_type(arg_type)},
ifcond) ifcond, features)
def gen_introspect(schema, output_dir, prefix, opt_unmask): def gen_introspect(schema, output_dir, prefix, opt_unmask):

View File

@ -109,7 +109,7 @@ class QAPISchemaVisitor:
def visit_builtin_type(self, name, info, json_type): def visit_builtin_type(self, name, info, json_type):
pass pass
def visit_enum_type(self, name, info, ifcond, members, prefix): def visit_enum_type(self, name, info, ifcond, features, members, prefix):
pass pass
def visit_array_type(self, name, info, ifcond, element_type): def visit_array_type(self, name, info, ifcond, element_type):
@ -123,7 +123,7 @@ class QAPISchemaVisitor:
features): features):
pass pass
def visit_alternate_type(self, name, info, ifcond, variants): def visit_alternate_type(self, name, info, ifcond, features, variants):
pass pass
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
@ -131,7 +131,7 @@ class QAPISchemaVisitor:
features): features):
pass pass
def visit_event(self, name, info, ifcond, arg_type, boxed): def visit_event(self, name, info, ifcond, features, arg_type, boxed):
pass pass
@ -234,8 +234,8 @@ class QAPISchemaBuiltinType(QAPISchemaType):
class QAPISchemaEnumType(QAPISchemaType): class QAPISchemaEnumType(QAPISchemaType):
meta = 'enum' meta = 'enum'
def __init__(self, name, info, doc, ifcond, members, prefix): def __init__(self, name, info, doc, ifcond, features, members, prefix):
super().__init__(name, info, doc, ifcond) super().__init__(name, info, doc, ifcond, features)
for m in members: for m in members:
assert isinstance(m, QAPISchemaEnumMember) assert isinstance(m, QAPISchemaEnumMember)
m.set_defined_in(name) m.set_defined_in(name)
@ -271,15 +271,16 @@ class QAPISchemaEnumType(QAPISchemaType):
def visit(self, visitor): def visit(self, visitor):
super().visit(visitor) super().visit(visitor)
visitor.visit_enum_type(self.name, self.info, self.ifcond, visitor.visit_enum_type(
self.members, self.prefix) self.name, self.info, self.ifcond, self.features,
self.members, self.prefix)
class QAPISchemaArrayType(QAPISchemaType): class QAPISchemaArrayType(QAPISchemaType):
meta = 'array' meta = 'array'
def __init__(self, name, info, element_type): def __init__(self, name, info, element_type):
super().__init__(name, info, None, None) super().__init__(name, info, None)
assert isinstance(element_type, str) assert isinstance(element_type, str)
self._element_type_name = element_type self._element_type_name = element_type
self.element_type = None self.element_type = None
@ -325,8 +326,8 @@ class QAPISchemaArrayType(QAPISchemaType):
class QAPISchemaObjectType(QAPISchemaType): class QAPISchemaObjectType(QAPISchemaType):
def __init__(self, name, info, doc, ifcond, def __init__(self, name, info, doc, ifcond, features,
base, local_members, variants, features): base, local_members, variants):
# struct has local_members, optional base, and no variants # struct has local_members, optional base, and no variants
# flat union has base, variants, and no local_members # flat union has base, variants, and no local_members
# simple union has local_members, variants, and no base # simple union has local_members, variants, and no base
@ -622,8 +623,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
class QAPISchemaAlternateType(QAPISchemaType): class QAPISchemaAlternateType(QAPISchemaType):
meta = 'alternate' meta = 'alternate'
def __init__(self, name, info, doc, ifcond, variants): def __init__(self, name, info, doc, ifcond, features, variants):
super().__init__(name, info, doc, ifcond) super().__init__(name, info, doc, ifcond, features)
assert isinstance(variants, QAPISchemaObjectTypeVariants) assert isinstance(variants, QAPISchemaObjectTypeVariants)
assert variants.tag_member assert variants.tag_member
variants.set_defined_in(name) variants.set_defined_in(name)
@ -683,16 +684,16 @@ class QAPISchemaAlternateType(QAPISchemaType):
def visit(self, visitor): def visit(self, visitor):
super().visit(visitor) super().visit(visitor)
visitor.visit_alternate_type(self.name, self.info, self.ifcond, visitor.visit_alternate_type(
self.variants) self.name, self.info, self.ifcond, self.features, self.variants)
class QAPISchemaCommand(QAPISchemaEntity): class QAPISchemaCommand(QAPISchemaEntity):
meta = 'command' meta = 'command'
def __init__(self, name, info, doc, ifcond, arg_type, ret_type, def __init__(self, name, info, doc, ifcond, features,
gen, success_response, boxed, allow_oob, allow_preconfig, arg_type, ret_type,
features): gen, success_response, boxed, allow_oob, allow_preconfig):
super().__init__(name, info, doc, ifcond, features) super().__init__(name, info, doc, ifcond, features)
assert not arg_type or isinstance(arg_type, str) assert not arg_type or isinstance(arg_type, str)
assert not ret_type or isinstance(ret_type, str) assert not ret_type or isinstance(ret_type, str)
@ -755,8 +756,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
class QAPISchemaEvent(QAPISchemaEntity): class QAPISchemaEvent(QAPISchemaEntity):
meta = 'event' meta = 'event'
def __init__(self, name, info, doc, ifcond, arg_type, boxed): def __init__(self, name, info, doc, ifcond, features, arg_type, boxed):
super().__init__(name, info, doc, ifcond) super().__init__(name, info, doc, ifcond, features)
assert not arg_type or isinstance(arg_type, str) assert not arg_type or isinstance(arg_type, str)
self._arg_type_name = arg_type self._arg_type_name = arg_type
self.arg_type = None self.arg_type = None
@ -787,8 +788,9 @@ class QAPISchemaEvent(QAPISchemaEntity):
def visit(self, visitor): def visit(self, visitor):
super().visit(visitor) super().visit(visitor)
visitor.visit_event(self.name, self.info, self.ifcond, visitor.visit_event(
self.arg_type, self.boxed) self.name, self.info, self.ifcond, self.features,
self.arg_type, self.boxed)
class QAPISchema: class QAPISchema:
@ -893,7 +895,7 @@ class QAPISchema:
('null', 'null', 'QNull' + pointer_suffix)]: ('null', 'null', 'QNull' + pointer_suffix)]:
self._def_builtin_type(*t) self._def_builtin_type(*t)
self.the_empty_object_type = QAPISchemaObjectType( self.the_empty_object_type = QAPISchemaObjectType(
'q_empty', None, None, None, None, [], None, []) 'q_empty', None, None, None, None, None, [], None)
self._def_entity(self.the_empty_object_type) self._def_entity(self.the_empty_object_type)
qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist', qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
@ -901,10 +903,11 @@ class QAPISchema:
qtype_values = self._make_enum_members( qtype_values = self._make_enum_members(
[{'name': n} for n in qtypes], None) [{'name': n} for n in qtypes], None)
self._def_entity(QAPISchemaEnumType('QType', None, None, None, self._def_entity(QAPISchemaEnumType('QType', None, None, None, None,
qtype_values, 'QTYPE')) qtype_values, 'QTYPE'))
def _make_features(self, features, info): def _make_features(self, expr, info):
features = expr.get('features', [])
return [QAPISchemaFeature(f['name'], info, f.get('if')) return [QAPISchemaFeature(f['name'], info, f.get('if'))
for f in features] for f in features]
@ -916,7 +919,8 @@ class QAPISchema:
# See also QAPISchemaObjectTypeMember.describe() # See also QAPISchemaObjectTypeMember.describe()
name = name + 'Kind' # reserved by check_defn_name_str() name = name + 'Kind' # reserved by check_defn_name_str()
self._def_entity(QAPISchemaEnumType( self._def_entity(QAPISchemaEnumType(
name, info, None, ifcond, self._make_enum_members(values, info), name, info, None, ifcond, None,
self._make_enum_members(values, info),
None)) None))
return name return name
@ -944,8 +948,8 @@ class QAPISchema:
# TODO kill simple unions or implement the disjunction # TODO kill simple unions or implement the disjunction
assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access
else: else:
self._def_entity(QAPISchemaObjectType(name, info, None, ifcond, self._def_entity(QAPISchemaObjectType(
None, members, None, [])) name, info, None, ifcond, None, None, members, None))
return name return name
def _def_enum_type(self, expr, info, doc): def _def_enum_type(self, expr, info, doc):
@ -953,8 +957,9 @@ class QAPISchema:
data = expr['data'] data = expr['data']
prefix = expr.get('prefix') prefix = expr.get('prefix')
ifcond = expr.get('if') ifcond = expr.get('if')
features = self._make_features(expr, info)
self._def_entity(QAPISchemaEnumType( self._def_entity(QAPISchemaEnumType(
name, info, doc, ifcond, name, info, doc, ifcond, features,
self._make_enum_members(data, info), prefix)) self._make_enum_members(data, info), prefix))
def _make_member(self, name, typ, ifcond, info): def _make_member(self, name, typ, ifcond, info):
@ -976,12 +981,11 @@ class QAPISchema:
base = expr.get('base') base = expr.get('base')
data = expr['data'] data = expr['data']
ifcond = expr.get('if') ifcond = expr.get('if')
features = expr.get('features', []) features = self._make_features(expr, info)
self._def_entity(QAPISchemaObjectType( self._def_entity(QAPISchemaObjectType(
name, info, doc, ifcond, base, name, info, doc, ifcond, features, base,
self._make_members(data, info), self._make_members(data, info),
None, None))
self._make_features(features, info)))
def _make_variant(self, case, typ, ifcond, info): def _make_variant(self, case, typ, ifcond, info):
return QAPISchemaObjectTypeVariant(case, info, typ, ifcond) return QAPISchemaObjectTypeVariant(case, info, typ, ifcond)
@ -1000,6 +1004,7 @@ class QAPISchema:
data = expr['data'] data = expr['data']
base = expr.get('base') base = expr.get('base')
ifcond = expr.get('if') ifcond = expr.get('if')
features = self._make_features(expr, info)
tag_name = expr.get('discriminator') tag_name = expr.get('discriminator')
tag_member = None tag_member = None
if isinstance(base, dict): if isinstance(base, dict):
@ -1020,21 +1025,22 @@ class QAPISchema:
tag_member = QAPISchemaObjectTypeMember('type', info, typ, False) tag_member = QAPISchemaObjectTypeMember('type', info, typ, False)
members = [tag_member] members = [tag_member]
self._def_entity( self._def_entity(
QAPISchemaObjectType(name, info, doc, ifcond, base, members, QAPISchemaObjectType(name, info, doc, ifcond, features,
base, members,
QAPISchemaObjectTypeVariants( QAPISchemaObjectTypeVariants(
tag_name, info, tag_member, variants), tag_name, info, tag_member, variants)))
[]))
def _def_alternate_type(self, expr, info, doc): def _def_alternate_type(self, expr, info, doc):
name = expr['alternate'] name = expr['alternate']
data = expr['data'] data = expr['data']
ifcond = expr.get('if') ifcond = expr.get('if')
features = self._make_features(expr, info)
variants = [self._make_variant(key, value['type'], value.get('if'), variants = [self._make_variant(key, value['type'], value.get('if'),
info) info)
for (key, value) in data.items()] for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False) tag_member = QAPISchemaObjectTypeMember('type', info, 'QType', False)
self._def_entity( self._def_entity(
QAPISchemaAlternateType(name, info, doc, ifcond, QAPISchemaAlternateType(name, info, doc, ifcond, features,
QAPISchemaObjectTypeVariants( QAPISchemaObjectTypeVariants(
None, info, tag_member, variants))) None, info, tag_member, variants)))
@ -1048,27 +1054,31 @@ class QAPISchema:
allow_oob = expr.get('allow-oob', False) allow_oob = expr.get('allow-oob', False)
allow_preconfig = expr.get('allow-preconfig', False) allow_preconfig = expr.get('allow-preconfig', False)
ifcond = expr.get('if') ifcond = expr.get('if')
features = expr.get('features', []) features = self._make_features(expr, info)
if isinstance(data, OrderedDict): if isinstance(data, OrderedDict):
data = self._make_implicit_object_type( data = self._make_implicit_object_type(
name, info, ifcond, 'arg', self._make_members(data, info)) name, info, ifcond,
'arg', self._make_members(data, info))
if isinstance(rets, list): if isinstance(rets, list):
assert len(rets) == 1 assert len(rets) == 1
rets = self._make_array_type(rets[0], info) rets = self._make_array_type(rets[0], info)
self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, data, rets, self._def_entity(QAPISchemaCommand(name, info, doc, ifcond, features,
data, rets,
gen, success_response, gen, success_response,
boxed, allow_oob, allow_preconfig, boxed, allow_oob, allow_preconfig))
self._make_features(features, info)))
def _def_event(self, expr, info, doc): def _def_event(self, expr, info, doc):
name = expr['event'] name = expr['event']
data = expr.get('data') data = expr.get('data')
boxed = expr.get('boxed', False) boxed = expr.get('boxed', False)
ifcond = expr.get('if') ifcond = expr.get('if')
features = self._make_features(expr, info)
if isinstance(data, OrderedDict): if isinstance(data, OrderedDict):
data = self._make_implicit_object_type( data = self._make_implicit_object_type(
name, info, ifcond, 'arg', self._make_members(data, info)) name, info, ifcond,
self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed)) 'arg', self._make_members(data, info))
self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, features,
data, boxed))
def _def_exprs(self, exprs): def _def_exprs(self, exprs):
for expr_elem in exprs: for expr_elem in exprs:

View File

@ -278,7 +278,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_type_cleanup_decl(name)) self._genh.add(gen_type_cleanup_decl(name))
self._genc.add(gen_type_cleanup(name)) self._genc.add(gen_type_cleanup(name))
def visit_enum_type(self, name, info, ifcond, members, prefix): def visit_enum_type(self, name, info, ifcond, features, members, prefix):
with ifcontext(ifcond, self._genh, self._genc): with ifcontext(ifcond, self._genh, self._genc):
self._genh.preamble_add(gen_enum(name, members, prefix)) self._genh.preamble_add(gen_enum(name, members, prefix))
self._genc.add(gen_enum_lookup(name, members, prefix)) self._genc.add(gen_enum_lookup(name, members, prefix))
@ -306,7 +306,7 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
# implicit types won't be directly allocated/freed # implicit types won't be directly allocated/freed
self._gen_type_cleanup(name) self._gen_type_cleanup(name)
def visit_alternate_type(self, name, info, ifcond, variants): def visit_alternate_type(self, name, info, ifcond, features, variants):
with ifcontext(ifcond, self._genh): with ifcontext(ifcond, self._genh):
self._genh.preamble_add(gen_fwd_object_or_array(name)) self._genh.preamble_add(gen_fwd_object_or_array(name))
self._genh.add(gen_object(name, ifcond, None, self._genh.add(gen_object(name, ifcond, None,

View File

@ -316,7 +316,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
''', ''',
types=types)) types=types))
def visit_enum_type(self, name, info, ifcond, members, prefix): def visit_enum_type(self, name, info, ifcond, features, members, prefix):
with ifcontext(ifcond, self._genh, self._genc): with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name, scalar=True)) self._genh.add(gen_visit_decl(name, scalar=True))
self._genc.add(gen_visit_enum(name)) self._genc.add(gen_visit_enum(name))
@ -342,7 +342,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_visit_decl(name)) self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_object(name, base, members, variants)) self._genc.add(gen_visit_object(name, base, members, variants))
def visit_alternate_type(self, name, info, ifcond, variants): def visit_alternate_type(self, name, info, ifcond, features, variants):
with ifcontext(ifcond, self._genh, self._genc): with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name)) self._genh.add(gen_visit_decl(name))
self._genc.add(gen_visit_alternate(name, variants)) self._genc.add(gen_visit_alternate(name, variants))

View File

@ -1,3 +1,3 @@
alternate-base.json: In alternate 'Alt': alternate-base.json: In alternate 'Alt':
alternate-base.json:4: alternate has unknown key 'base' alternate-base.json:4: alternate has unknown key 'base'
Valid keys are 'alternate', 'data', 'if'. Valid keys are 'alternate', 'data', 'features', 'if'.

View File

@ -53,10 +53,14 @@
# @Enum: # @Enum:
# @one: The _one_ {and only} # @one: The _one_ {and only}
# #
# Features:
# @enum-feat: Also _one_ {and only}
#
# @two is undocumented # @two is undocumented
## ##
{ 'enum': 'Enum', 'data': { 'enum': 'Enum', 'data':
[ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ], [ { 'name': 'one', 'if': 'defined(IFONE)' }, 'two' ],
'features': [ 'enum-feat' ],
'if': 'defined(IFCOND)' } 'if': 'defined(IFCOND)' }
## ##
@ -86,24 +90,34 @@
## ##
# @Object: # @Object:
# Features:
# @union-feat1: a feature
## ##
{ 'union': 'Object', { 'union': 'Object',
'features': [ 'union-feat1' ],
'base': 'Base', 'base': 'Base',
'discriminator': 'base1', 'discriminator': 'base1',
'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } } 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
## ##
# @SugaredUnion: # @SugaredUnion:
# Features:
# @union-feat2: a feature
## ##
{ 'union': 'SugaredUnion', { 'union': 'SugaredUnion',
'features': [ 'union-feat2' ],
'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } } 'data': { 'one': 'Variant1', 'two': { 'type': 'Variant2', 'if': 'IFTWO' } } }
## ##
# @Alternate: # @Alternate:
# @i: an integer # @i: an integer
# @b is undocumented # @b is undocumented
#
# Features:
# @alt-feat: a feature
## ##
{ 'alternate': 'Alternate', { 'alternate': 'Alternate',
'features': [ 'alt-feat' ],
'data': { 'i': 'int', 'b': 'bool' } } 'data': { 'i': 'int', 'b': 'bool' } }
## ##
@ -160,6 +174,9 @@
## ##
# @EVT-BOXED: # @EVT-BOXED:
# Features:
# @feat3: a feature
## ##
{ 'event': 'EVT-BOXED', 'boxed': true, { 'event': 'EVT-BOXED', 'boxed': true,
'features': [ 'feat3' ],
'data': 'Object' } 'data': 'Object' }

View File

@ -15,6 +15,7 @@ enum Enum
if ['defined(IFONE)'] if ['defined(IFONE)']
member two member two
if ['defined(IFCOND)'] if ['defined(IFCOND)']
feature enum-feat
object Base object Base
member base1: Enum optional=False member base1: Enum optional=False
object Variant1 object Variant1
@ -28,6 +29,7 @@ object Object
case one: Variant1 case one: Variant1
case two: Variant2 case two: Variant2
if ['IFTWO'] if ['IFTWO']
feature union-feat1
object q_obj_Variant1-wrapper object q_obj_Variant1-wrapper
member data: Variant1 optional=False member data: Variant1 optional=False
object q_obj_Variant2-wrapper object q_obj_Variant2-wrapper
@ -42,10 +44,12 @@ object SugaredUnion
case one: q_obj_Variant1-wrapper case one: q_obj_Variant1-wrapper
case two: q_obj_Variant2-wrapper case two: q_obj_Variant2-wrapper
if ['IFTWO'] if ['IFTWO']
feature union-feat2
alternate Alternate alternate Alternate
tag type tag type
case i: int case i: int
case b: bool case b: bool
feature alt-feat
object q_obj_cmd-arg object q_obj_cmd-arg
member arg1: int optional=False member arg1: int optional=False
member arg2: str optional=True member arg2: str optional=True
@ -60,6 +64,7 @@ command cmd-boxed Object -> None
feature cmd-feat2 feature cmd-feat2
event EVT-BOXED Object event EVT-BOXED Object
boxed=True boxed=True
feature feat3
doc freeform doc freeform
body= body=
= Section = Section
@ -112,6 +117,8 @@ doc symbol=Enum
The _one_ {and only} The _one_ {and only}
arg=two arg=two
feature=enum-feat
Also _one_ {and only}
section=None section=None
@two is undocumented @two is undocumented
doc symbol=Base doc symbol=Base
@ -134,11 +141,15 @@ doc symbol=Variant2
doc symbol=Object doc symbol=Object
body= body=
feature=union-feat1
a feature
doc symbol=SugaredUnion doc symbol=SugaredUnion
body= body=
arg=type arg=type
feature=union-feat2
a feature
doc symbol=Alternate doc symbol=Alternate
body= body=
@ -147,6 +158,8 @@ an integer
@b is undocumented @b is undocumented
arg=b arg=b
feature=alt-feat
a feature
doc freeform doc freeform
body= body=
== Another subsection == Another subsection
@ -197,3 +210,5 @@ another feature
doc symbol=EVT-BOXED doc symbol=EVT-BOXED
body= body=
feature=feat3
a feature

View File

@ -88,6 +88,12 @@ The @emph{one} @{and only@}
@item @code{two} @item @code{two}
Not documented Not documented
@end table @end table
@b{Features:}
@table @asis
@item @code{enum-feat}
Also @emph{one} @{and only@}
@end table
@code{two} is undocumented @code{two} is undocumented
@b{If:} @code{defined(IFCOND)} @b{If:} @code{defined(IFCOND)}
@ -151,6 +157,12 @@ a feature
@item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO}) @item The members of @code{Variant2} when @code{base1} is @t{"two"} (@b{If:} @code{IFTWO})
@end table @end table
@b{Features:}
@table @asis
@item @code{union-feat1}
a feature
@end table
@end deftp @end deftp
@ -167,6 +179,12 @@ One of @t{"one"}, @t{"two"}
@item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO}) @item @code{data: Variant2} when @code{type} is @t{"two"} (@b{If:} @code{IFTWO})
@end table @end table
@b{Features:}
@table @asis
@item @code{union-feat2}
a feature
@end table
@end deftp @end deftp
@ -184,6 +202,12 @@ an integer
Not documented Not documented
@end table @end table
@b{Features:}
@table @asis
@item @code{alt-feat}
a feature
@end table
@end deftp @end deftp
@ -283,5 +307,11 @@ another feature
@b{Arguments:} the members of @code{Object} @b{Arguments:} the members of @code{Object}
@b{Features:}
@table @asis
@item @code{feat3}
a feature
@end table
@end deftypefn @end deftypefn

View File

@ -252,7 +252,7 @@
'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } }, 'bar': { 'type': ['TestIfEnum'], 'if': 'defined(TEST_IF_EVT_BAR)' } },
'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' } 'if': 'defined(TEST_IF_EVT) && defined(TEST_IF_STRUCT)' }
# test 'features' for structs # test 'features'
{ 'struct': 'FeatureStruct0', { 'struct': 'FeatureStruct0',
'data': { 'foo': 'int' }, 'data': { 'foo': 'int' },
@ -281,7 +281,22 @@
'data': { 'foo': 'int' }, 'data': { 'foo': 'int' },
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)', 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] } 'defined(TEST_IF_COND_2)'] } ] }
{ 'command': 'test-features',
{ 'enum': 'FeatureEnum1',
'data': [ 'eins', 'zwei', 'drei' ],
'features': [ 'feature1' ] }
{ 'union': 'FeatureUnion1',
'base': { 'tag': 'FeatureEnum1' },
'discriminator': 'tag',
'data': { 'eins': 'FeatureStruct1' },
'features': [ 'feature1' ] }
{ 'alternate': 'FeatureAlternate1',
'data': { 'eins': 'FeatureStruct1' },
'features': [ 'feature1' ] }
{ 'command': 'test-features0',
'data': { 'fs0': 'FeatureStruct0', 'data': { 'fs0': 'FeatureStruct0',
'fs1': 'FeatureStruct1', 'fs1': 'FeatureStruct1',
'fs2': 'FeatureStruct2', 'fs2': 'FeatureStruct2',
@ -289,12 +304,9 @@
'fs4': 'FeatureStruct4', 'fs4': 'FeatureStruct4',
'cfs1': 'CondFeatureStruct1', 'cfs1': 'CondFeatureStruct1',
'cfs2': 'CondFeatureStruct2', 'cfs2': 'CondFeatureStruct2',
'cfs3': 'CondFeatureStruct3' } } 'cfs3': 'CondFeatureStruct3' },
# test 'features' for command
{ 'command': 'test-command-features0',
'features': [] } 'features': [] }
{ 'command': 'test-command-features1', { 'command': 'test-command-features1',
'features': [ 'feature1' ] } 'features': [ 'feature1' ] }
{ 'command': 'test-command-features3', { 'command': 'test-command-features3',
@ -308,3 +320,6 @@
{ 'command': 'test-command-cond-features3', { 'command': 'test-command-cond-features3',
'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)', 'features': [ { 'name': 'feature1', 'if': [ 'defined(TEST_IF_COND_1)',
'defined(TEST_IF_COND_2)'] } ] } 'defined(TEST_IF_COND_2)'] } ] }
{ 'event': 'TEST-EVENT-FEATURES1',
'features': [ 'feature1' ] }

View File

@ -387,7 +387,25 @@ object CondFeatureStruct3
member foo: int optional=False member foo: int optional=False
feature feature1 feature feature1
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
object q_obj_test-features-arg enum FeatureEnum1
member eins
member zwei
member drei
feature feature1
object q_obj_FeatureUnion1-base
member tag: FeatureEnum1 optional=False
object FeatureUnion1
base q_obj_FeatureUnion1-base
tag tag
case eins: FeatureStruct1
case zwei: q_empty
case drei: q_empty
feature feature1
alternate FeatureAlternate1
tag type
case eins: FeatureStruct1
feature feature1
object q_obj_test-features0-arg
member fs0: FeatureStruct0 optional=False member fs0: FeatureStruct0 optional=False
member fs1: FeatureStruct1 optional=False member fs1: FeatureStruct1 optional=False
member fs2: FeatureStruct2 optional=False member fs2: FeatureStruct2 optional=False
@ -396,9 +414,7 @@ object q_obj_test-features-arg
member cfs1: CondFeatureStruct1 optional=False member cfs1: CondFeatureStruct1 optional=False
member cfs2: CondFeatureStruct2 optional=False member cfs2: CondFeatureStruct2 optional=False
member cfs3: CondFeatureStruct3 optional=False member cfs3: CondFeatureStruct3 optional=False
command test-features q_obj_test-features-arg -> None command test-features0 q_obj_test-features0-arg -> None
gen=True success_response=True boxed=False oob=False preconfig=False
command test-command-features0 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
command test-command-features1 None -> None command test-command-features1 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
@ -421,6 +437,9 @@ command test-command-cond-features3 None -> None
gen=True success_response=True boxed=False oob=False preconfig=False gen=True success_response=True boxed=False oob=False preconfig=False
feature feature1 feature feature1
if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)'] if ['defined(TEST_IF_COND_1)', 'defined(TEST_IF_COND_2)']
event TEST-EVENT-FEATURES1 None
boxed=False
feature feature1
module include/sub-module.json module include/sub-module.json
include sub-sub-module.json include sub-sub-module.json
object SecondArrayRef object SecondArrayRef

View File

@ -30,7 +30,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
def visit_include(self, name, info): def visit_include(self, name, info):
print('include %s' % name) print('include %s' % name)
def visit_enum_type(self, name, info, ifcond, members, prefix): def visit_enum_type(self, name, info, ifcond, features, members, prefix):
print('enum %s' % name) print('enum %s' % name)
if prefix: if prefix:
print(' prefix %s' % prefix) print(' prefix %s' % prefix)
@ -38,6 +38,7 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
print(' member %s' % m.name) print(' member %s' % m.name)
self._print_if(m.ifcond, indent=8) self._print_if(m.ifcond, indent=8)
self._print_if(ifcond) self._print_if(ifcond)
self._print_features(features)
def visit_array_type(self, name, info, ifcond, element_type): def visit_array_type(self, name, info, ifcond, element_type):
if not info: if not info:
@ -58,10 +59,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
self._print_if(ifcond) self._print_if(ifcond)
self._print_features(features) self._print_features(features)
def visit_alternate_type(self, name, info, ifcond, variants): def visit_alternate_type(self, name, info, ifcond, features, variants):
print('alternate %s' % name) print('alternate %s' % name)
self._print_variants(variants) self._print_variants(variants)
self._print_if(ifcond) self._print_if(ifcond)
self._print_features(features)
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen, def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig, success_response, boxed, allow_oob, allow_preconfig,
@ -74,10 +76,11 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
self._print_if(ifcond) self._print_if(ifcond)
self._print_features(features) self._print_features(features)
def visit_event(self, name, info, ifcond, arg_type, boxed): def visit_event(self, name, info, ifcond, features, arg_type, boxed):
print('event %s %s' % (name, arg_type and arg_type.name)) print('event %s %s' % (name, arg_type and arg_type.name))
print(' boxed=%s' % boxed) print(' boxed=%s' % boxed)
self._print_if(ifcond) self._print_if(ifcond)
self._print_features(features)
@staticmethod @staticmethod
def _print_variants(variants): def _print_variants(variants):

View File

@ -45,7 +45,7 @@ void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp)
{ {
} }
void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1, void qmp_test_features0(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
FeatureStruct2 *fs2, FeatureStruct3 *fs3, FeatureStruct2 *fs2, FeatureStruct3 *fs3,
FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1, FeatureStruct4 *fs4, CondFeatureStruct1 *cfs1,
CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3, CondFeatureStruct2 *cfs2, CondFeatureStruct3 *cfs3,
@ -53,10 +53,6 @@ void qmp_test_features(FeatureStruct0 *fs0, FeatureStruct1 *fs1,
{ {
} }
void qmp_test_command_features0(Error **errp)
{
}
void qmp_test_command_features1(Error **errp) void qmp_test_command_features1(Error **errp)
{ {
} }