qapi: leave the ifcond attribute undefined until check()

We commonly initialize attributes to None in .init(), then set their
real value in .check().  Accessing the attribute before .check()
yields None.  If we're lucky, the code that accesses the attribute
prematurely chokes on None.

It won't for .ifcond, because None is a legitimate value.

Leave the ifcond attribute undefined until check().

Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20180703155648.11933-4-marcandre.lureau@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
Marc-André Lureau 2018-07-03 17:56:37 +02:00 committed by Markus Armbruster
parent 2cbc94376e
commit 4fca21c1b0

View File

@ -1021,13 +1021,19 @@ class QAPISchemaEntity(object):
# such place). # such place).
self.info = info self.info = info
self.doc = doc self.doc = doc
self.ifcond = listify_cond(ifcond) self._ifcond = ifcond # self.ifcond is set only after .check()
def c_name(self): def c_name(self):
return c_name(self.name) return c_name(self.name)
def check(self, schema): def check(self, schema):
pass if isinstance(self._ifcond, QAPISchemaType):
# inherit the condition from a type
typ = self._ifcond
typ.check(schema)
self.ifcond = typ.ifcond
else:
self.ifcond = listify_cond(self._ifcond)
def is_implicit(self): def is_implicit(self):
return not self.info return not self.info
@ -1164,6 +1170,7 @@ class QAPISchemaEnumType(QAPISchemaType):
self.prefix = prefix self.prefix = prefix
def check(self, schema): def check(self, schema):
QAPISchemaType.check(self, schema)
seen = {} seen = {}
for v in self.values: for v in self.values:
v.check_clash(self.info, seen) v.check_clash(self.info, seen)
@ -1196,8 +1203,10 @@ class QAPISchemaArrayType(QAPISchemaType):
self.element_type = None self.element_type = None
def check(self, schema): def check(self, schema):
QAPISchemaType.check(self, schema)
self.element_type = schema.lookup_type(self._element_type_name) self.element_type = schema.lookup_type(self._element_type_name)
assert self.element_type assert self.element_type
self.element_type.check(schema)
self.ifcond = self.element_type.ifcond self.ifcond = self.element_type.ifcond
def is_implicit(self): def is_implicit(self):
@ -1240,6 +1249,7 @@ class QAPISchemaObjectType(QAPISchemaType):
self.members = None self.members = None
def check(self, schema): def check(self, schema):
QAPISchemaType.check(self, schema)
if self.members is False: # check for cycles if self.members is False: # check for cycles
raise QAPISemError(self.info, raise QAPISemError(self.info,
"Object %s contains itself" % self.name) "Object %s contains itself" % self.name)
@ -1430,6 +1440,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
self.variants = variants self.variants = variants
def check(self, schema): def check(self, schema):
QAPISchemaType.check(self, schema)
self.variants.tag_member.check(schema) self.variants.tag_member.check(schema)
# Not calling self.variants.check_clash(), because there's nothing # Not calling self.variants.check_clash(), because there's nothing
# to clash with # to clash with
@ -1474,6 +1485,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
self.allow_preconfig = allow_preconfig self.allow_preconfig = allow_preconfig
def check(self, schema): def check(self, schema):
QAPISchemaEntity.check(self, schema)
if self._arg_type_name: if self._arg_type_name:
self.arg_type = schema.lookup_type(self._arg_type_name) self.arg_type = schema.lookup_type(self._arg_type_name)
assert (isinstance(self.arg_type, QAPISchemaObjectType) or assert (isinstance(self.arg_type, QAPISchemaObjectType) or
@ -1509,6 +1521,7 @@ class QAPISchemaEvent(QAPISchemaEntity):
self.boxed = boxed self.boxed = boxed
def check(self, schema): def check(self, schema):
QAPISchemaEntity.check(self, schema)
if self._arg_type_name: if self._arg_type_name:
self.arg_type = schema.lookup_type(self._arg_type_name) self.arg_type = schema.lookup_type(self._arg_type_name)
assert (isinstance(self.arg_type, QAPISchemaObjectType) or assert (isinstance(self.arg_type, QAPISchemaObjectType) or
@ -1642,7 +1655,7 @@ class QAPISchema(object):
# But it's not tight: the disjunction need not imply it. We # But it's not tight: the disjunction need not imply it. We
# may end up compiling useless wrapper types. # may end up compiling useless wrapper types.
# TODO kill simple unions or implement the disjunction # TODO kill simple unions or implement the disjunction
assert ifcond == typ.ifcond assert ifcond == typ._ifcond # pylint: disable=protected-access
else: else:
self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond, self._def_entity(QAPISchemaObjectType(name, info, doc, ifcond,
None, members, None)) None, members, None))
@ -1688,7 +1701,7 @@ class QAPISchema(object):
assert len(typ) == 1 assert len(typ) == 1
typ = self._make_array_type(typ[0], info) typ = self._make_array_type(typ[0], info)
typ = self._make_implicit_object_type( typ = self._make_implicit_object_type(
typ, info, None, self.lookup_type(typ).ifcond, typ, info, None, self.lookup_type(typ),
'wrapper', [self._make_member('data', typ, info)]) 'wrapper', [self._make_member('data', typ, info)])
return QAPISchemaObjectTypeVariant(case, typ) return QAPISchemaObjectTypeVariant(case, typ)