summary refs log tree commit diff stats
path: root/scripts/qapi
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/qapi')
-rw-r--r--scripts/qapi/commands.py2
-rw-r--r--scripts/qapi/events.py2
-rw-r--r--scripts/qapi/gen.py2
-rw-r--r--scripts/qapi/schema.py48
-rw-r--r--scripts/qapi/types.py2
-rw-r--r--scripts/qapi/visit.py17
6 files changed, 67 insertions, 6 deletions
diff --git a/scripts/qapi/commands.py b/scripts/qapi/commands.py
index cf68aaf0bf..79c5e5c3a9 100644
--- a/scripts/qapi/commands.py
+++ b/scripts/qapi/commands.py
@@ -64,7 +64,7 @@ def gen_call(name: str,
     elif arg_type:
         assert not arg_type.variants
         for memb in arg_type.members:
-            if memb.optional:
+            if memb.need_has():
                 argstr += 'arg.has_%s, ' % c_name(memb.name)
             argstr += 'arg.%s, ' % c_name(memb.name)
 
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index e762d53d19..3cf01e96b6 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -60,7 +60,7 @@ def gen_param_var(typ: QAPISchemaObjectType) -> str:
     for memb in typ.members:
         ret += sep
         sep = ', '
-        if memb.optional:
+        if memb.need_has():
             ret += 'has_' + c_name(memb.name) + sep
         if memb.type.name == 'str':
             # Cast away const added in build_params()
diff --git a/scripts/qapi/gen.py b/scripts/qapi/gen.py
index 113b49134d..b5a8d03e8e 100644
--- a/scripts/qapi/gen.py
+++ b/scripts/qapi/gen.py
@@ -121,7 +121,7 @@ def build_params(arg_type: Optional[QAPISchemaObjectType],
         for memb in arg_type.members:
             ret += sep
             sep = ', '
-            if memb.optional:
+            if memb.need_has():
                 ret += 'bool has_%s, ' % c_name(memb.name)
             ret += '%s %s' % (memb.type.c_param_type(),
                               c_name(memb.name))
diff --git a/scripts/qapi/schema.py b/scripts/qapi/schema.py
index 3728340c37..58b00982ea 100644
--- a/scripts/qapi/schema.py
+++ b/scripts/qapi/schema.py
@@ -253,6 +253,11 @@ class QAPISchemaType(QAPISchemaEntity):
             return None
         return self.name
 
+    def need_has_if_optional(self):
+        # When FOO is a pointer, has_FOO == !!FOO, i.e. has_FOO is redundant.
+        # Except for arrays; see QAPISchemaArrayType.need_has_if_optional().
+        return not self.c_type().endswith(POINTER_SUFFIX)
+
     def check(self, schema):
         QAPISchemaEntity.check(self, schema)
         for feat in self.features:
@@ -352,6 +357,11 @@ class QAPISchemaArrayType(QAPISchemaType):
         self._element_type_name = element_type
         self.element_type = None
 
+    def need_has_if_optional(self):
+        # When FOO is an array, we still need has_FOO to distinguish
+        # absent (!has_FOO) from present and empty (has_FOO && !FOO).
+        return True
+
     def check(self, schema):
         super().check(schema)
         self.element_type = schema.resolve_type(
@@ -745,6 +755,44 @@ class QAPISchemaObjectTypeMember(QAPISchemaMember):
         self.optional = optional
         self.features = features or []
 
+    def need_has(self):
+        assert self.type
+        # Temporary hack to support dropping the has_FOO in reviewable chunks
+        opt_out = [
+            'qapi/acpi.json',
+            'qapi/audio.json',
+            'qapi/block-core.json',
+            'qapi/block-export.json',
+            'qapi/block.json',
+            'qapi/char.json',
+            'qapi/crypto.json',
+            'qapi/dump.json',
+            'qapi/introspect.json',
+            'qapi/job.json',
+            'qapi/machine.json',
+            'qapi/machine-target.json',
+            'qapi/migration.json',
+            'qapi/misc.json',
+            'qapi/net.json',
+            'qapi/pci.json',
+            'qapi/qdev.json',
+            'qapi/qom.json',
+            'qapi/replay.json',
+            'qapi/rocker.json',
+            'qapi/run-state.json',
+            'qapi/stats.json',
+            'qapi/tpm.json',
+            'qapi/transaction.json',
+            'qapi/ui.json',
+            'qapi/virtio.json',
+            'qga/qapi-schema.json',
+            'tests/qapi-schema/qapi-schema-test.json']
+        if self.info and any(self.info.fname.endswith(mod)
+                             for mod in opt_out):
+            return self.optional
+        # End of temporary hack
+        return self.optional and self.type.need_has_if_optional()
+
     def check(self, schema):
         assert self.defined_in
         self.type = schema.resolve_type(self._type_name, self.info,
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index 477d027001..c39d054d2c 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -142,7 +142,7 @@ def gen_struct_members(members: List[QAPISchemaObjectTypeMember]) -> str:
     ret = ''
     for memb in members:
         ret += memb.ifcond.gen_if()
-        if memb.optional:
+        if memb.need_has():
             ret += mcgen('''
     bool has_%(c_name)s;
 ''',
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 380fa197f5..26a584ee4c 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -71,6 +71,16 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
 ''',
                 c_name=c_name(name))
 
+    sep = ''
+    for memb in members:
+        if memb.optional and not memb.need_has():
+            ret += mcgen('''
+    bool has_%(c_name)s = !!obj->%(c_name)s;
+''',
+                         c_name=c_name(memb.name))
+            sep = '\n'
+    ret += sep
+
     if base:
         ret += mcgen('''
     if (!visit_type_%(c_type)s_members(v, (%(c_type)s *)obj, errp)) {
@@ -82,10 +92,13 @@ bool visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
     for memb in members:
         ret += memb.ifcond.gen_if()
         if memb.optional:
+            has = 'has_' + c_name(memb.name)
+            if memb.need_has():
+                has = 'obj->' + has
             ret += mcgen('''
-    if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
+    if (visit_optional(v, "%(name)s", &%(has)s)) {
 ''',
-                         name=memb.name, c_name=c_name(memb.name))
+                         name=memb.name, has=has)
             indent.increase()
         special_features = gen_special_features(memb.features)
         if special_features != '0':