diff --git a/qapi-schema.json b/qapi-schema.json index a386605b6a..702b7b5dbd 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3415,6 +3415,17 @@ 'cpuid-register': 'X86CPURegister32', 'features': 'int' } } +## +# @DummyForceArrays +# +# Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally +# +# Since 2.5 +## +{ 'struct': 'DummyForceArrays', + 'data': { 'unused': ['X86CPUFeatureWordInfo'] } } + + ## # @RxState: # diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py index 7d39320174..c0dad6679c 100644 --- a/scripts/qapi-introspect.py +++ b/scripts/qapi-introspect.py @@ -54,7 +54,6 @@ class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor): self._jsons = [] self._used_types = [] self._name_map = {} - return QAPISchemaType # don't visit types for now def visit_end(self): # visit the types that are actually used @@ -82,6 +81,10 @@ const char %(c_name)s[] = %(c_string)s; self._used_types = None self._name_map = None + def visit_needed(self, entity): + # Ignore types on first pass; visit_end() will pick up used types + return not isinstance(entity, QAPISchemaType) + def _name(self, name): if self._unmask: return name diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index d405f8d670..4fe618ef3c 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -233,6 +233,11 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): self.decl = self._btin + self.decl self._btin = None + def visit_needed(self, entity): + # Visit everything except implicit objects + return not (entity.is_implicit() and + isinstance(entity, QAPISchemaObjectType)) + def _gen_type_cleanup(self, name): self.decl += gen_type_cleanup_decl(name) self.defn += gen_type_cleanup(name) @@ -254,14 +259,13 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): self._gen_type_cleanup(name) def visit_object_type(self, name, info, base, members, variants): - if info: - self._fwdecl += gen_fwd_object_or_array(name) - if variants: - assert not members # not implemented - self.decl += gen_union(name, base, variants) - else: - self.decl += gen_struct(name, base, members) - self._gen_type_cleanup(name) + self._fwdecl += gen_fwd_object_or_array(name) + if variants: + assert not members # not implemented + self.decl += gen_union(name, base, variants) + else: + self.decl += gen_struct(name, base, members) + self._gen_type_cleanup(name) def visit_alternate_type(self, name, info, variants): self._fwdecl += gen_fwd_object_or_array(name) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 4f97781348..d0759d739a 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -301,7 +301,9 @@ void visit_type_%(c_name)s(Visitor *v, %(c_name)s **obj, const char *name, Error out_obj: error_propagate(errp, err); err = NULL; - visit_end_union(v, !!(*obj)->data, &err); + if (*obj) { + visit_end_union(v, !!(*obj)->data, &err); + } error_propagate(errp, err); err = NULL; visit_end_struct(v, &err); @@ -333,6 +335,11 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.decl = self._btin + self.decl self._btin = None + def visit_needed(self, entity): + # Visit everything except implicit objects + return not (entity.is_implicit() and + isinstance(entity, QAPISchemaObjectType)) + def visit_enum_type(self, name, info, values, prefix): self.decl += gen_visit_decl(name, scalar=True) self.defn += gen_visit_enum(name) @@ -349,13 +356,12 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.defn += defn def visit_object_type(self, name, info, base, members, variants): - if info: - self.decl += gen_visit_decl(name) - if variants: - assert not members # not implemented - self.defn += gen_visit_union(name, base, variants) - else: - self.defn += gen_visit_struct(name, base, members) + self.decl += gen_visit_decl(name) + if variants: + assert not members # not implemented + self.defn += gen_visit_union(name, base, variants) + else: + self.defn += gen_visit_struct(name, base, members) def visit_alternate_type(self, name, info, variants): self.decl += gen_visit_decl(name) diff --git a/scripts/qapi.py b/scripts/qapi.py index 26cff3f05c..9d53255320 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -56,9 +56,6 @@ returns_whitelist = [ 'guest-set-vcpus', 'guest-sync', 'guest-sync-delimited', - - # From qapi-schema-test: - 'user_def_cmd3', ] enum_types = [] @@ -103,6 +100,7 @@ class QAPISchemaError(Exception): class QAPIExprError(Exception): def __init__(self, expr_info, msg): Exception.__init__(self) + assert expr_info self.info = expr_info self.msg = msg @@ -792,6 +790,11 @@ class QAPISchemaEntity(object): def __init__(self, name, info): assert isinstance(name, str) self.name = name + # For explicitly defined entities, info points to the (explicit) + # definition. For builtins (and their arrays), info is None. + # For implicitly defined entities, info points to a place that + # triggered the implicit definition (there may be more than one + # such place). self.info = info def c_name(self): @@ -800,6 +803,9 @@ class QAPISchemaEntity(object): def check(self, schema): pass + def is_implicit(self): + return not self.info + def visit(self, visitor): pass @@ -811,6 +817,10 @@ class QAPISchemaVisitor(object): def visit_end(self): pass + def visit_needed(self, entity): + # Default to visiting everything + return True + def visit_builtin_type(self, name, info, json_type): pass @@ -898,6 +908,10 @@ class QAPISchemaEnumType(QAPISchemaType): def check(self, schema): assert len(set(self.values)) == len(self.values) + def is_implicit(self): + # See QAPISchema._make_implicit_enum_type() + return self.name[-4:] == 'Kind' + def c_type(self, is_param=False): return c_name(self.name) @@ -924,6 +938,9 @@ class QAPISchemaArrayType(QAPISchemaType): self.element_type = schema.lookup_type(self._element_type_name) assert self.element_type + def is_implicit(self): + return True + def json_type(self): return 'array' @@ -960,6 +977,7 @@ class QAPISchemaObjectType(QAPISchemaType): members = [] seen = {} for m in members: + assert c_name(m.name) not in seen seen[m.name] = m for m in self.local_members: m.check(schema, members, seen) @@ -967,12 +985,16 @@ class QAPISchemaObjectType(QAPISchemaType): self.variants.check(schema, members, seen) self.members = members + def is_implicit(self): + # See QAPISchema._make_implicit_object_type() + return self.name[0] == ':' + def c_name(self): - assert self.info + assert not self.is_implicit() return QAPISchemaType.c_name(self) def c_type(self, is_param=False): - assert self.info + assert not self.is_implicit() return QAPISchemaType.c_type(self) def json_type(self): @@ -1004,18 +1026,18 @@ class QAPISchemaObjectTypeMember(object): class QAPISchemaObjectTypeVariants(object): - def __init__(self, tag_name, tag_enum, variants): - assert tag_name is None or isinstance(tag_name, str) - assert tag_enum is None or isinstance(tag_enum, str) + def __init__(self, tag_name, tag_member, variants): + # Flat unions pass tag_name but not tag_member. + # Simple unions and alternates pass tag_member but not tag_name. + # After check(), tag_member is always set, and tag_name remains + # a reliable witness of being used by a flat union. + assert bool(tag_member) != bool(tag_name) + assert (isinstance(tag_name, str) or + isinstance(tag_member, QAPISchemaObjectTypeMember)) for v in variants: assert isinstance(v, QAPISchemaObjectTypeVariant) self.tag_name = tag_name - if tag_name: - assert not tag_enum - self.tag_member = None - else: - self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum, - False) + self.tag_member = tag_member self.variants = variants def check(self, schema, members, seen): @@ -1040,7 +1062,8 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): # This function exists to support ugly simple union special cases # TODO get rid of them, and drop the function def simple_union_type(self): - if isinstance(self.type, QAPISchemaObjectType) and not self.type.info: + if (self.type.is_implicit() and + isinstance(self.type, QAPISchemaObjectType)): assert len(self.type.members) == 1 assert not self.type.variants return self.type.members[0].type @@ -1112,15 +1135,19 @@ class QAPISchema(object): def __init__(self, fname): try: self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs) + self._entity_dict = {} + self._predefining = True + self._def_predefineds() + self._predefining = False + self._def_exprs() + self.check() except (QAPISchemaError, QAPIExprError), err: print >>sys.stderr, err exit(1) - self._entity_dict = {} - self._def_predefineds() - self._def_exprs() - self.check() def _def_entity(self, ent): + # Only the predefined types are allowed to not have info + assert ent.info or self._predefining assert ent.name not in self._entity_dict self._entity_dict[ent.name] = ent @@ -1136,7 +1163,12 @@ class QAPISchema(object): def _def_builtin_type(self, name, json_type, c_type, c_null): self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type, c_null)) - self._make_array_type(name) # TODO really needed? + # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple + # qapi-types.h from a single .c, all arrays of builtins must be + # declared in the first file whether or not they are used. Nicer + # would be to use lazy instantiation, while figuring out how to + # avoid compilation issues with multiple qapi-types.h. + self._make_array_type(name, None) def _def_predefineds(self): for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'), @@ -1158,23 +1190,25 @@ class QAPISchema(object): [], None) self._def_entity(self.the_empty_object_type) - def _make_implicit_enum_type(self, name, values): - name = name + 'Kind' - self._def_entity(QAPISchemaEnumType(name, None, values, None)) + def _make_implicit_enum_type(self, name, info, values): + name = name + 'Kind' # Use namespace reserved by add_name() + self._def_entity(QAPISchemaEnumType(name, info, values, None)) return name - def _make_array_type(self, element_type): + def _make_array_type(self, element_type, info): + # TODO fooList namespace is not reserved; user can create collisions, + # or abuse our type system with ['fooList'] for 2D array name = element_type + 'List' if not self.lookup_type(name): - self._def_entity(QAPISchemaArrayType(name, None, element_type)) + self._def_entity(QAPISchemaArrayType(name, info, element_type)) return name - def _make_implicit_object_type(self, name, role, members): + def _make_implicit_object_type(self, name, info, role, members): if not members: return None name = ':obj-%s-%s' % (name, role) if not self.lookup_entity(name, QAPISchemaObjectType): - self._def_entity(QAPISchemaObjectType(name, None, None, + self._def_entity(QAPISchemaObjectType(name, info, None, members, None)) return name @@ -1183,20 +1217,19 @@ class QAPISchema(object): data = expr['data'] prefix = expr.get('prefix') self._def_entity(QAPISchemaEnumType(name, info, data, prefix)) - self._make_array_type(name) # TODO really needed? - def _make_member(self, name, typ): + def _make_member(self, name, typ, info): optional = False if name.startswith('*'): name = name[1:] optional = True if isinstance(typ, list): assert len(typ) == 1 - typ = self._make_array_type(typ[0]) + typ = self._make_array_type(typ[0], info) return QAPISchemaObjectTypeMember(name, typ, optional) - def _make_members(self, data): - return [self._make_member(key, value) + def _make_members(self, data, info): + return [self._make_member(key, value, info) for (key, value) in data.iteritems()] def _def_struct_type(self, expr, info): @@ -1204,58 +1237,56 @@ class QAPISchema(object): base = expr.get('base') data = expr['data'] self._def_entity(QAPISchemaObjectType(name, info, base, - self._make_members(data), + self._make_members(data, info), None)) - self._make_array_type(name) # TODO really needed? def _make_variant(self, case, typ): return QAPISchemaObjectTypeVariant(case, typ) - def _make_simple_variant(self, case, typ): + def _make_simple_variant(self, case, typ, info): if isinstance(typ, list): assert len(typ) == 1 - typ = self._make_array_type(typ[0]) - typ = self._make_implicit_object_type(typ, 'wrapper', - [self._make_member('data', typ)]) + typ = self._make_array_type(typ[0], info) + typ = self._make_implicit_object_type( + typ, info, 'wrapper', [self._make_member('data', typ, info)]) return QAPISchemaObjectTypeVariant(case, typ) - def _make_tag_enum(self, type_name, variants): - return self._make_implicit_enum_type(type_name, - [v.name for v in variants]) + def _make_implicit_tag(self, type_name, info, variants): + typ = self._make_implicit_enum_type(type_name, info, + [v.name for v in variants]) + return QAPISchemaObjectTypeMember('type', typ, False) def _def_union_type(self, expr, info): name = expr['union'] data = expr['data'] base = expr.get('base') tag_name = expr.get('discriminator') - tag_enum = None + tag_member = None if tag_name: variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] else: - variants = [self._make_simple_variant(key, value) + variants = [self._make_simple_variant(key, value, info) for (key, value) in data.iteritems()] - tag_enum = self._make_tag_enum(name, variants) + tag_member = self._make_implicit_tag(name, info, variants) self._def_entity( QAPISchemaObjectType(name, info, base, - self._make_members(OrderedDict()), + self._make_members(OrderedDict(), info), QAPISchemaObjectTypeVariants(tag_name, - tag_enum, + tag_member, variants))) - self._make_array_type(name) # TODO really needed? def _def_alternate_type(self, expr, info): name = expr['alternate'] data = expr['data'] variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] - tag_enum = self._make_tag_enum(name, variants) + tag_member = self._make_implicit_tag(name, info, variants) self._def_entity( QAPISchemaAlternateType(name, info, QAPISchemaObjectTypeVariants(None, - tag_enum, + tag_member, variants))) - self._make_array_type(name) # TODO really needed? def _def_command(self, expr, info): name = expr['command'] @@ -1264,11 +1295,11 @@ class QAPISchema(object): gen = expr.get('gen', True) success_response = expr.get('success-response', True) if isinstance(data, OrderedDict): - data = self._make_implicit_object_type(name, 'arg', - self._make_members(data)) + data = self._make_implicit_object_type( + name, info, 'arg', self._make_members(data, info)) if isinstance(rets, list): assert len(rets) == 1 - rets = self._make_array_type(rets[0]) + rets = self._make_array_type(rets[0], info) self._def_entity(QAPISchemaCommand(name, info, data, rets, gen, success_response)) @@ -1276,8 +1307,8 @@ class QAPISchema(object): name = expr['event'] data = expr.get('data') if isinstance(data, OrderedDict): - data = self._make_implicit_object_type(name, 'arg', - self._make_members(data)) + data = self._make_implicit_object_type( + name, info, 'arg', self._make_members(data, info)) self._def_entity(QAPISchemaEvent(name, info, data)) def _def_exprs(self): @@ -1304,10 +1335,10 @@ class QAPISchema(object): ent.check(self) def visit(self, visitor): - ignore = visitor.visit_begin(self) - for name in sorted(self._entity_dict.keys()): - if not ignore or not isinstance(self._entity_dict[name], ignore): - self._entity_dict[name].visit(visitor) + visitor.visit_begin(self) + for (name, entity) in sorted(self._entity_dict.items()): + if visitor.visit_needed(entity): + entity.visit(visitor) visitor.visit_end() diff --git a/tests/Makefile b/tests/Makefile index 209eca9bae..cb221dec22 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -230,7 +230,6 @@ qapi-schema += alternate-clash.json qapi-schema += alternate-conflict-dict.json qapi-schema += alternate-conflict-string.json qapi-schema += alternate-empty.json -qapi-schema += alternate-good.json qapi-schema += alternate-nested.json qapi-schema += alternate-unknown.json qapi-schema += args-alternate.json @@ -240,7 +239,6 @@ qapi-schema += args-array-unknown.json qapi-schema += args-int.json qapi-schema += args-invalid.json qapi-schema += args-member-array-bad.json -qapi-schema += args-member-array.json qapi-schema += args-member-unknown.json qapi-schema += args-name-clash.json qapi-schema += args-union.json @@ -261,7 +259,6 @@ qapi-schema += enum-bad-name.json qapi-schema += enum-bad-prefix.json qapi-schema += enum-clash-member.json qapi-schema += enum-dict-member.json -qapi-schema += enum-empty.json qapi-schema += enum-int-member.json qapi-schema += enum-max-member.json qapi-schema += enum-missing-data.json @@ -288,7 +285,6 @@ qapi-schema += flat-union-invalid-branch-key.json qapi-schema += flat-union-invalid-discriminator.json qapi-schema += flat-union-no-base.json qapi-schema += flat-union-optional-discriminator.json -qapi-schema += flat-union-reverse-define.json qapi-schema += flat-union-string-discriminator.json qapi-schema += funny-char.json qapi-schema += ident-with-escape.json @@ -320,7 +316,6 @@ qapi-schema += redefined-type.json qapi-schema += returns-alternate.json qapi-schema += returns-array-bad.json qapi-schema += returns-dict.json -qapi-schema += returns-int.json qapi-schema += returns-unknown.json qapi-schema += returns-whitelist.json qapi-schema += struct-base-clash-base.json diff --git a/tests/qapi-schema/alternate-good.err b/tests/qapi-schema/alternate-good.err deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/qapi-schema/alternate-good.exit b/tests/qapi-schema/alternate-good.exit deleted file mode 100644 index 573541ac97..0000000000 --- a/tests/qapi-schema/alternate-good.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/qapi-schema/alternate-good.json b/tests/qapi-schema/alternate-good.json deleted file mode 100644 index 33717704ce..0000000000 --- a/tests/qapi-schema/alternate-good.json +++ /dev/null @@ -1,9 +0,0 @@ -# Working example of alternate -{ 'struct': 'Data', - 'data': { '*number': 'int', '*name': 'str' } } -{ 'enum': 'Enum', - 'data': [ 'hello', 'world' ] } -{ 'alternate': 'Alt', - 'data': { 'value': 'int', - 'string': 'Enum', - 'struct': 'Data' } } diff --git a/tests/qapi-schema/alternate-good.out b/tests/qapi-schema/alternate-good.out deleted file mode 100644 index 65af7278f4..0000000000 --- a/tests/qapi-schema/alternate-good.out +++ /dev/null @@ -1,10 +0,0 @@ -object :empty -alternate Alt - case value: int - case string: Enum - case struct: Data -enum AltKind ['value', 'string', 'struct'] -object Data - member number: int optional=True - member name: str optional=True -enum Enum ['hello', 'world'] diff --git a/tests/qapi-schema/args-member-array.err b/tests/qapi-schema/args-member-array.err deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/qapi-schema/args-member-array.exit b/tests/qapi-schema/args-member-array.exit deleted file mode 100644 index 573541ac97..0000000000 --- a/tests/qapi-schema/args-member-array.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/qapi-schema/args-member-array.json b/tests/qapi-schema/args-member-array.json deleted file mode 100644 index e6f7f5da13..0000000000 --- a/tests/qapi-schema/args-member-array.json +++ /dev/null @@ -1,4 +0,0 @@ -# valid array members -{ 'enum': 'abc', 'data': [ 'a', 'b', 'c' ] } -{ 'struct': 'def', 'data': { 'array': [ 'abc' ] } } -{ 'command': 'okay', 'data': { 'member1': [ 'int' ], 'member2': [ 'def' ] } } diff --git a/tests/qapi-schema/args-member-array.out b/tests/qapi-schema/args-member-array.out deleted file mode 100644 index b3b92dfc8e..0000000000 --- a/tests/qapi-schema/args-member-array.out +++ /dev/null @@ -1,9 +0,0 @@ -object :empty -object :obj-okay-arg - member member1: intList optional=False - member member2: defList optional=False -enum abc ['a', 'b', 'c'] -object def - member array: abcList optional=False -command okay :obj-okay-arg -> None - gen=True success_response=True diff --git a/tests/qapi-schema/enum-empty.err b/tests/qapi-schema/enum-empty.err deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/qapi-schema/enum-empty.exit b/tests/qapi-schema/enum-empty.exit deleted file mode 100644 index 573541ac97..0000000000 --- a/tests/qapi-schema/enum-empty.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/qapi-schema/enum-empty.json b/tests/qapi-schema/enum-empty.json deleted file mode 100644 index 40d4e85a2f..0000000000 --- a/tests/qapi-schema/enum-empty.json +++ /dev/null @@ -1,2 +0,0 @@ -# An empty enum, although unusual, is currently acceptable -{ 'enum': 'MyEnum', 'data': [ ] } diff --git a/tests/qapi-schema/enum-empty.out b/tests/qapi-schema/enum-empty.out deleted file mode 100644 index a449d455fb..0000000000 --- a/tests/qapi-schema/enum-empty.out +++ /dev/null @@ -1,2 +0,0 @@ -object :empty -enum MyEnum [] diff --git a/tests/qapi-schema/flat-union-reverse-define.err b/tests/qapi-schema/flat-union-reverse-define.err deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/qapi-schema/flat-union-reverse-define.exit b/tests/qapi-schema/flat-union-reverse-define.exit deleted file mode 100644 index 573541ac97..0000000000 --- a/tests/qapi-schema/flat-union-reverse-define.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/qapi-schema/flat-union-reverse-define.json b/tests/qapi-schema/flat-union-reverse-define.json deleted file mode 100644 index 648bbfe2b7..0000000000 --- a/tests/qapi-schema/flat-union-reverse-define.json +++ /dev/null @@ -1,17 +0,0 @@ -{ 'union': 'TestUnion', - 'base': 'TestBase', - 'discriminator': 'enum1', - 'data': { 'value1': 'TestTypeA', - 'value2': 'TestTypeB' } } - -{ 'struct': 'TestBase', - 'data': { 'enum1': 'TestEnum' } } - -{ 'enum': 'TestEnum', - 'data': [ 'value1', 'value2' ] } - -{ 'struct': 'TestTypeA', - 'data': { 'string': 'str' } } - -{ 'struct': 'TestTypeB', - 'data': { 'integer': 'int' } } diff --git a/tests/qapi-schema/flat-union-reverse-define.out b/tests/qapi-schema/flat-union-reverse-define.out deleted file mode 100644 index a5a9134e7e..0000000000 --- a/tests/qapi-schema/flat-union-reverse-define.out +++ /dev/null @@ -1,13 +0,0 @@ -object :empty -object TestBase - member enum1: TestEnum optional=False -enum TestEnum ['value1', 'value2'] -object TestTypeA - member string: str optional=False -object TestTypeB - member integer: int optional=False -object TestUnion - base TestBase - tag enum1 - case value1: TestTypeA - case value2: TestTypeB diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index abe59fd137..4e2d7c2063 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -1,10 +1,15 @@ # *-*- Mode: Python -*-* +# This file is a stress test of supported qapi constructs that must +# parse and compile correctly. + # for testing enums -{ 'enum': 'EnumOne', - 'data': [ 'value1', 'value2', 'value3' ] } { 'struct': 'NestedEnumsOne', - 'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } } + 'data': { 'enum1': 'EnumOne', # Intentional forward reference + '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } } + +# An empty enum, although unusual, is currently acceptable +{ 'enum': 'MyEnum', 'data': [ ] } # for testing override of default naming heuristic { 'enum': 'QEnumTwo', @@ -14,7 +19,11 @@ # for testing nested structs { 'struct': 'UserDefOne', 'base': 'UserDefZero', # intentional forward reference - 'data': { 'string': 'str', '*enum1': 'EnumOne' } } + 'data': { 'string': 'str', + '*enum1': 'EnumOne' } } # intentional forward reference + +{ 'enum': 'EnumOne', + 'data': [ 'value1', 'value2', 'value3' ] } { 'struct': 'UserDefZero', 'data': { 'integer': 'int' } } @@ -31,6 +40,10 @@ 'data': { 'string0': 'str', 'dict1': 'UserDefTwoDict' } } +# dummy struct to force generation of array types not otherwise mentioned +{ 'struct': 'ForceArrays', + 'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'] } } + # for testing unions # Among other things, test that a name collision between branches does # not cause any problems (since only one branch can be in use at a time), @@ -98,9 +111,10 @@ { 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' } -{ 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' }, + +# Returning a non-dictionary requires a name from the whitelist +{ 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } -# note: command name 'guest-sync' chosen to avoid "cannot use built-in" error { 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' } # For testing integer range flattening in opts-visitor. The following schema diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 8f817842df..a6c80e04d7 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -17,6 +17,9 @@ object :obj-anyList-wrapper member data: anyList optional=False object :obj-boolList-wrapper member data: boolList optional=False +object :obj-guest-get-time-arg + member a: int optional=False + member b: int optional=True object :obj-guest-sync-arg member arg: any optional=False object :obj-int16List-wrapper @@ -50,9 +53,6 @@ object :obj-user_def_cmd1-arg object :obj-user_def_cmd2-arg member ud1a: UserDefOne optional=False member ud1b: UserDefOne optional=True -object :obj-user_def_cmd3-arg - member a: int optional=False - member b: int optional=True alternate AltIntNum case i: int case n: number @@ -86,6 +86,10 @@ object EventStructOne member struct1: UserDefOne optional=False member string: str optional=False member enum2: EnumOne optional=True +object ForceArrays + member unused1: UserDefOneList optional=False + member unused2: UserDefTwoList optional=False +enum MyEnum [] object NestedEnumsOne member enum1: EnumOne optional=False member enum2: EnumOne optional=True @@ -183,6 +187,8 @@ object __org.qemu_x-Union2 case __org.qemu_x-value: __org.qemu_x-Struct2 command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1 gen=True success_response=True +command guest-get-time :obj-guest-get-time-arg -> int + gen=True success_response=True command guest-sync :obj-guest-sync-arg -> any gen=True success_response=True command user_def_cmd None -> None @@ -191,5 +197,3 @@ command user_def_cmd1 :obj-user_def_cmd1-arg -> None gen=True success_response=True command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo gen=True success_response=True -command user_def_cmd3 :obj-user_def_cmd3-arg -> int - gen=True success_response=True diff --git a/tests/qapi-schema/returns-int.err b/tests/qapi-schema/returns-int.err deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tests/qapi-schema/returns-int.exit b/tests/qapi-schema/returns-int.exit deleted file mode 100644 index 573541ac97..0000000000 --- a/tests/qapi-schema/returns-int.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/tests/qapi-schema/returns-int.json b/tests/qapi-schema/returns-int.json deleted file mode 100644 index 870ec6366b..0000000000 --- a/tests/qapi-schema/returns-int.json +++ /dev/null @@ -1,3 +0,0 @@ -# It is okay (although not extensible) to return a non-dictionary -# But to make it work, the name must be in a whitelist -{ 'command': 'guest-get-time', 'returns': 'int' } diff --git a/tests/qapi-schema/returns-int.out b/tests/qapi-schema/returns-int.out deleted file mode 100644 index a2da259be4..0000000000 --- a/tests/qapi-schema/returns-int.out +++ /dev/null @@ -1,3 +0,0 @@ -object :empty -command guest-get-time None -> int - gen=True success_response=True diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c index 8d5249e7e4..bc59835835 100644 --- a/tests/test-qmp-commands.c +++ b/tests/test-qmp-commands.c @@ -46,7 +46,7 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, return ret; } -int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp) +int64_t qmp_guest_get_time(int64_t a, bool has_b, int64_t b, Error **errp) { return a + (has_b ? b : 0); } @@ -160,7 +160,7 @@ static void test_dispatch_cmd_io(void) qdict_put(args3, "a", qint_from_int(66)); qdict_put(req, "arguments", args3); - qdict_put(req, "execute", qstring_from_str("user_def_cmd3")); + qdict_put(req, "execute", qstring_from_str("guest-get-time")); ret3 = qobject_to_qint(test_qmp_dispatch(req)); assert(qint_get_int(ret3) == 66);