diff mbox

[RFC,03/10] qapi script: check correctness of discriminator values in union

Message ID 1383611860-9053-4-git-send-email-xiawenc@linux.vnet.ibm.com
State New
Headers show

Commit Message

Wayne Xia Nov. 5, 2013, 12:37 a.m. UTC
It will check whether the values specfied are wrotten correctly when
discriminator is a pre-defined enum type, which help check whether the
schema is in good form.

It is allowed that, not every value in enum is used, so do not check
that case.

Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
---
 scripts/qapi-visit.py |   11 +++++++++++
 scripts/qapi.py       |   33 +++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 0 deletions(-)

Comments

Eric Blake Nov. 5, 2013, 1:25 p.m. UTC | #1
On 11/04/2013 05:37 PM, Wenchao Xia wrote:
> It will check whether the values specfied are wrotten correctly when

s/specfied/specified/
s/wrotten/written/

> discriminator is a pre-defined enum type, which help check whether the
> schema is in good form.
> 
> It is allowed that, not every value in enum is used, so do not check

s/that,/that/

> that case.

Why do you allow partial coverage?  That feels like an accident waiting
to happen.  Does the user get a sane error message if they request an
enum value that wasn't mapped to a union branch?  I think it would be
wiser to mandate that if the discriminator is an enum, then the union
must cover all values of the enum.

> +
> +# Return the descriminator enum define, if discriminator is specified in

s/descriminator/discriminator/

> +# @expr and it is a pre-defined enum type
> +def descriminator_find_enum_define(expr):

s/descriminator/discriminator/ - and fix all callers

> +    discriminator = expr.get('discriminator')
> +    base = expr.get('base')
> +
> +    # Only support discriminator when base present
> +    if not (discriminator and base):
> +        return None
> +
> +    base_fields = find_base_fields(base)
> +
> +    if not base_fields:
> +        sys.stderr.write("Base '%s' is not a valid type\n"
> +                         % base)
> +        sys.exit(1)
> +
> +    descriminator_type = base_fields.get(discriminator)

s/descriminator/discriminator/
Wayne Xia Nov. 6, 2013, 3:02 a.m. UTC | #2
于 2013/11/5 21:25, Eric Blake 写道:
> On 11/04/2013 05:37 PM, Wenchao Xia wrote:
>> It will check whether the values specfied are wrotten correctly when
>
> s/specfied/specified/
> s/wrotten/written/
>
>> discriminator is a pre-defined enum type, which help check whether the
>> schema is in good form.
>>
>> It is allowed that, not every value in enum is used, so do not check
>
> s/that,/that/
>
>> that case.
>
> Why do you allow partial coverage?  That feels like an accident waiting
> to happen.  Does the user get a sane error message if they request an
> enum value that wasn't mapped to a union branch?  I think it would be
> wiser to mandate that if the discriminator is an enum, then the union
> must cover all values of the enum.
>
   abort() will be called in qapi-visit.c, it is OK for output visitor,
but bad for input visitor since user input may trigger it. I think
change abort() to error_set() could solve the problem, then we allow
map part of enum value.

>> +
>> +# Return the descriminator enum define, if discriminator is specified in
>
> s/descriminator/discriminator/
>
>> +# @expr and it is a pre-defined enum type
>> +def descriminator_find_enum_define(expr):
>
> s/descriminator/discriminator/ - and fix all callers
>
>> +    discriminator = expr.get('discriminator')
>> +    base = expr.get('base')
>> +
>> +    # Only support discriminator when base present
>> +    if not (discriminator and base):
>> +        return None
>> +
>> +    base_fields = find_base_fields(base)
>> +
>> +    if not base_fields:
>> +        sys.stderr.write("Base '%s' is not a valid type\n"
>> +                         % base)
>> +        sys.exit(1)
>> +
>> +    descriminator_type = base_fields.get(discriminator)
>
> s/descriminator/discriminator/
>
diff mbox

Patch

diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index c39e628..803d3eb 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -249,6 +249,17 @@  def generate_visit_union(expr):
         assert not base
         return generate_visit_anon_union(name, members)
 
+    # If discriminator is specified and it is a pre-defined enum in schema,
+    # check its correctness
+    enum_define = descriminator_find_enum_define(expr)
+    if enum_define:
+        for key in members:
+            if not key in enum_define["enum_values"]:
+                sys.stderr.write("Discriminator value '%s' not found in "
+                                 "enum '%s'\n" %
+                                 (key, enum_define["enum_name"]))
+                sys.exit(1)
+
     ret = generate_visit_enum('%sKind' % name, members.keys())
 
     if base:
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 82f586e..235df4f 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -383,3 +383,36 @@  def guardend(name):
 
 ''',
                  name=guardname(name))
+
+# This function can be used to check whether "base" is valid
+def find_base_fields(base):
+    base_struct_define = find_struct(base)
+    if not base_struct_define:
+        return None
+    return base_struct_define.get('data')
+
+# Return the descriminator enum define, if discriminator is specified in
+# @expr and it is a pre-defined enum type
+def descriminator_find_enum_define(expr):
+    discriminator = expr.get('discriminator')
+    base = expr.get('base')
+
+    # Only support discriminator when base present
+    if not (discriminator and base):
+        return None
+
+    base_fields = find_base_fields(base)
+
+    if not base_fields:
+        sys.stderr.write("Base '%s' is not a valid type\n"
+                         % base)
+        sys.exit(1)
+
+    descriminator_type = base_fields.get(discriminator)
+
+    if not descriminator_type:
+        sys.stderr.write("Discriminator '%s' not found in schema\n"
+                         % discriminator)
+        sys.exit(1)
+
+    return find_enum(descriminator_type)