diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-10-29 20:06:08 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-10-29 20:06:08 +0000 |
commit | 16884391c750d0c5e863f55ad7aaaa146fc5181e (patch) | |
tree | 7909241a593eea7f9cafaea658e9b101a7682626 /scripts/qapi/schema.py | |
parent | 1cfe28cdcabd10e31b0e05db8a2cfd9993f315e2 (diff) | |
parent | e151941d1b691402f7914750e025209b7839a1c0 (diff) |
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2019-10-29' into staging
QAPI patches for 2019-10-29
# gpg: Signature made Tue 29 Oct 2019 06:40:56 GMT
# gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653
# gpg: issuer "armbru@redhat.com"
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full]
# gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full]
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653
* remotes/armbru/tags/pull-qapi-2019-10-29:
qapi: Check feature documentation against the schema
qapi: Polish reporting of bogus member documentation
qapi: Lift features into QAPISchemaEntity
qapi: Fold normalize_enum() into check_enum()
qapi: Fold normalize_features() into check_features()
qapi: Fold normalize_if() into check_if()
qapi: Eliminate .check_doc() overrides
qapi: Simplify ._make_implicit_object_type()
qapi: Fix doc comment checking for commands and events
qapi: Clean up doc comment checking for implicit union base
qapi: Fix enum doc comment checking
qapi: Split .connect_doc(), .check_doc() off .check()
qapi: De-duplicate entity documentation generation code
qapi: Implement boxed event argument documentation
qemu-doc: Belatedly document QMP command deprecation
tests/qapi-schema: Fix feature documentation testing
tests/qapi-schema: Cover alternate documentation comments
tests/qapi-schema: Demonstrate command and event doc comment bugs
tests/qapi-schema: Demonstrate feature and enum doc comment bugs
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'scripts/qapi/schema.py')
-rw-r--r-- | scripts/qapi/schema.py | 97 |
1 files changed, 59 insertions, 38 deletions
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py index f7d68a35f4..cf0045f34e 100644 --- a/scripts/qapi/schema.py +++ b/scripts/qapi/schema.py @@ -27,8 +27,11 @@ from qapi.parser import QAPISchemaParser class QAPISchemaEntity(object): meta = None - def __init__(self, name, info, doc, ifcond=None): + def __init__(self, name, info, doc, ifcond=None, features=None): assert name is None or isinstance(name, str) + for f in features or []: + assert isinstance(f, QAPISchemaFeature) + f.set_defined_in(name) self.name = name self._module = None # For explicitly defined entities, info points to the (explicit) @@ -39,6 +42,7 @@ class QAPISchemaEntity(object): self.info = info self.doc = doc self._ifcond = ifcond or [] + self.features = features or [] self._checked = False def c_name(self): @@ -49,8 +53,21 @@ class QAPISchemaEntity(object): if self.info: self._module = os.path.relpath(self.info.fname, os.path.dirname(schema.fname)) + seen = {} + for f in self.features: + f.check_clash(self.info, seen) + if self.doc: + self.doc.connect_feature(f) + self._checked = True + def connect_doc(self, doc=None): + pass + + def check_doc(self): + if self.doc: + self.doc.check() + @property def ifcond(self): assert self._checked @@ -217,8 +234,12 @@ class QAPISchemaEnumType(QAPISchemaType): seen = {} for m in self.members: m.check_clash(self.info, seen) - if self.doc: - self.doc.connect_member(m) + + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + for m in self.members: + doc.connect_member(m) def is_implicit(self): # See QAPISchema._make_implicit_enum_type() and ._def_predefineds() @@ -296,7 +317,7 @@ class QAPISchemaObjectType(QAPISchemaType): # struct has local_members, optional base, and no variants # flat union has base, variants, and no local_members # simple union has local_members, variants, and no base - QAPISchemaType.__init__(self, name, info, doc, ifcond) + QAPISchemaType.__init__(self, name, info, doc, ifcond, features) self.meta = 'union' if variants else 'struct' assert base is None or isinstance(base, str) for m in local_members: @@ -305,15 +326,11 @@ class QAPISchemaObjectType(QAPISchemaType): if variants is not None: assert isinstance(variants, QAPISchemaObjectTypeVariants) variants.set_defined_in(name) - for f in features: - assert isinstance(f, QAPISchemaFeature) - f.set_defined_in(name) self._base_name = base self.base = None self.local_members = local_members self.variants = variants self.members = None - self.features = features def check(self, schema): # This calls another type T's .check() exactly when the C @@ -345,22 +362,12 @@ class QAPISchemaObjectType(QAPISchemaType): for m in self.local_members: m.check(schema) m.check_clash(self.info, seen) - if self.doc: - self.doc.connect_member(m) members = seen.values() if self.variants: self.variants.check(schema, seen) self.variants.check_clash(self.info, seen) - # Features are in a name space separate from members - seen = {} - for f in self.features: - f.check_clash(self.info, seen) - - if self.doc: - self.doc.check() - self.members = members # mark completed # Check that the members of this type do not cause duplicate JSON members, @@ -372,6 +379,14 @@ class QAPISchemaObjectType(QAPISchemaType): for m in self.members: m.check_clash(info, seen) + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + if self.base and self.base.is_implicit(): + self.base.connect_doc(doc) + for m in self.local_members: + doc.connect_member(m) + @property def ifcond(self): assert self._checked @@ -639,10 +654,12 @@ class QAPISchemaAlternateType(QAPISchemaType): "%s can't be distinguished from '%s'" % (v.describe(self.info), types_seen[qt])) types_seen[qt] = v.name - if self.doc: - self.doc.connect_member(v) - if self.doc: - self.doc.check() + + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + for v in self.variants.variants: + doc.connect_member(v) def c_type(self): return c_name(self.name) + pointer_suffix @@ -662,12 +679,9 @@ class QAPISchemaCommand(QAPISchemaEntity): def __init__(self, name, info, doc, ifcond, arg_type, ret_type, gen, success_response, boxed, allow_oob, allow_preconfig, features): - QAPISchemaEntity.__init__(self, name, info, doc, ifcond) + QAPISchemaEntity.__init__(self, name, info, doc, ifcond, features) assert not arg_type or isinstance(arg_type, str) assert not ret_type or isinstance(ret_type, str) - for f in features: - assert isinstance(f, QAPISchemaFeature) - f.set_defined_in(name) self._arg_type_name = arg_type self.arg_type = None self._ret_type_name = ret_type @@ -677,7 +691,6 @@ class QAPISchemaCommand(QAPISchemaEntity): self.boxed = boxed self.allow_oob = allow_oob self.allow_preconfig = allow_preconfig - self.features = features def check(self, schema): QAPISchemaEntity.check(self, schema) @@ -707,10 +720,11 @@ class QAPISchemaCommand(QAPISchemaEntity): "command's 'returns' cannot take %s" % self.ret_type.describe()) - # Features are in a name space separate from members - seen = {} - for f in self.features: - f.check_clash(self.info, seen) + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + if self.arg_type and self.arg_type.is_implicit(): + self.arg_type.connect_doc(doc) def visit(self, visitor): QAPISchemaEntity.visit(self, visitor) @@ -748,6 +762,12 @@ class QAPISchemaEvent(QAPISchemaEntity): "event's 'data' can take %s only with 'boxed': true" % self.arg_type.describe()) + def connect_doc(self, doc=None): + doc = doc or self.doc + if doc: + if self.arg_type and self.arg_type.is_implicit(): + self.arg_type.connect_doc(doc) + def visit(self, visitor): QAPISchemaEntity.visit(self, visitor) visitor.visit_event(self.name, self.info, self.ifcond, @@ -873,8 +893,7 @@ class QAPISchema(object): self._def_entity(QAPISchemaArrayType(name, info, element_type)) return name - def _make_implicit_object_type(self, name, info, doc, ifcond, - role, members): + def _make_implicit_object_type(self, name, info, ifcond, role, members): if not members: return None # See also QAPISchemaObjectTypeMember.describe() @@ -892,7 +911,7 @@ class QAPISchema(object): # TODO kill simple unions or implement the disjunction assert (ifcond or []) == typ._ifcond # pylint: disable=protected-access else: - self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, + self._def_entity(QAPISchemaObjectType(name, info, None, ifcond, None, members, None, [])) return name @@ -939,7 +958,7 @@ class QAPISchema(object): assert len(typ) == 1 typ = self._make_array_type(typ[0], info) typ = self._make_implicit_object_type( - typ, info, None, self.lookup_type(typ), + typ, info, self.lookup_type(typ), 'wrapper', [self._make_member('data', typ, None, info)]) return QAPISchemaObjectTypeVariant(case, info, typ, ifcond) @@ -952,7 +971,7 @@ class QAPISchema(object): tag_member = None if isinstance(base, dict): base = self._make_implicit_object_type( - name, info, doc, ifcond, + name, info, ifcond, 'base', self._make_members(base, info)) if tag_name: variants = [self._make_variant(key, value['type'], @@ -999,7 +1018,7 @@ class QAPISchema(object): features = expr.get('features', []) if isinstance(data, OrderedDict): data = self._make_implicit_object_type( - name, info, doc, ifcond, 'arg', self._make_members(data, info)) + name, info, ifcond, 'arg', self._make_members(data, info)) if isinstance(rets, list): assert len(rets) == 1 rets = self._make_array_type(rets[0], info) @@ -1015,7 +1034,7 @@ class QAPISchema(object): ifcond = expr.get('if') if isinstance(data, OrderedDict): data = self._make_implicit_object_type( - name, info, doc, ifcond, 'arg', self._make_members(data, info)) + name, info, ifcond, 'arg', self._make_members(data, info)) self._def_entity(QAPISchemaEvent(name, info, doc, ifcond, data, boxed)) def _def_exprs(self, exprs): @@ -1043,6 +1062,8 @@ class QAPISchema(object): def check(self): for ent in self._entity_list: ent.check(self) + ent.connect_doc() + ent.check_doc() def visit(self, visitor): visitor.visit_begin(self) |