]> git.proxmox.com Git - mirror_qemu.git/commitdiff
qapi: Better error messages for bad expressions
authorEric Blake <eblake@redhat.com>
Mon, 4 May 2015 15:05:15 +0000 (09:05 -0600)
committerMarkus Armbruster <armbru@redhat.com>
Tue, 5 May 2015 16:39:01 +0000 (18:39 +0200)
The previous commit demonstrated that the generator overlooked some
fairly basic broken expressions:
- missing metataype
- metatype key has a non-string value
- unknown key in relation to the metatype
- conflicting metatype (this patch treats the second metatype as an
unknown key of the first key visited, which is not necessarily the
first key the user typed)

Add check_keys to cover these situations, and update testcases to
match.  A couple other tests (enum-missing-data, indented-expr) had
to change since the validation added here occurs so early.
Conversely, changes to ident-with-escape results show that we still
have problems where our handling of escape sequences differs from
true JSON, which will matter down the road if we allow arbitrary
default string values for optional parameters (but for now is not
too bad, as we currently can avoid unicode escaping as we don't
need to represent anything beyond C identifier material).

While valid .json files won't trigger any of these cases, we might
as well be nicer to developers that make a typo while trying to add
new QAPI code.

Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
24 files changed:
scripts/qapi.py
tests/qapi-schema/alternate-base.err
tests/qapi-schema/bad-type-dict.err
tests/qapi-schema/bad-type-dict.exit
tests/qapi-schema/bad-type-dict.json
tests/qapi-schema/bad-type-dict.out
tests/qapi-schema/double-type.err
tests/qapi-schema/double-type.exit
tests/qapi-schema/double-type.json
tests/qapi-schema/double-type.out
tests/qapi-schema/enum-missing-data.err
tests/qapi-schema/ident-with-escape.err
tests/qapi-schema/ident-with-escape.exit
tests/qapi-schema/ident-with-escape.out
tests/qapi-schema/indented-expr.json
tests/qapi-schema/indented-expr.out
tests/qapi-schema/missing-type.err
tests/qapi-schema/missing-type.exit
tests/qapi-schema/missing-type.json
tests/qapi-schema/missing-type.out
tests/qapi-schema/unknown-expr-key.err
tests/qapi-schema/unknown-expr-key.exit
tests/qapi-schema/unknown-expr-key.json
tests/qapi-schema/unknown-expr-key.out

index 05c38c5b00e879118e7b63177abf9eed080d9520..868f08b59326ef23349aaa903099458b319f90ce 100644 (file)
@@ -348,11 +348,6 @@ def check_alternate(expr, expr_info):
     values = { 'MAX': '(automatic)' }
     types_seen = {}
 
-    if expr.get('base') is not None:
-        raise QAPIExprError(expr_info,
-                            "Alternate '%s' must not have a base"
-                            % name)
-
     # Check every branch
     for (key, value) in members.items():
         # Check for conflicts in the generated enum
@@ -414,6 +409,26 @@ def check_exprs(schema):
         elif expr.has_key('event'):
             check_event(expr, info)
 
+def check_keys(expr_elem, meta, required, optional=[]):
+    expr = expr_elem['expr']
+    info = expr_elem['info']
+    name = expr[meta]
+    if not isinstance(name, str):
+        raise QAPIExprError(info,
+                            "'%s' key must have a string value" % meta)
+    required = required + [ meta ]
+    for (key, value) in expr.items():
+        if not key in required and not key in optional:
+            raise QAPIExprError(info,
+                                "Unknown key '%s' in %s '%s'"
+                                % (key, meta, name))
+    for key in required:
+        if not expr.has_key(key):
+            raise QAPIExprError(info,
+                                "Key '%s' is missing from %s '%s'"
+                                % (key, meta, name))
+
+
 def parse_schema(input_file):
     # First pass: read entire file into memory
     try:
@@ -425,15 +440,30 @@ def parse_schema(input_file):
     exprs = []
 
     try:
-        # Next pass: learn the types.
+        # Next pass: learn the types and check for valid expression keys. At
+        # this point, top-level 'include' has already been flattened.
         for expr_elem in schema.exprs:
             expr = expr_elem['expr']
             if expr.has_key('enum'):
-                add_enum(expr['enum'], expr.get('data'))
+                check_keys(expr_elem, 'enum', ['data'])
+                add_enum(expr['enum'], expr['data'])
             elif expr.has_key('union'):
+                check_keys(expr_elem, 'union', ['data'],
+                           ['base', 'discriminator'])
                 add_union(expr)
+            elif expr.has_key('alternate'):
+                check_keys(expr_elem, 'alternate', ['data'])
             elif expr.has_key('type'):
+                check_keys(expr_elem, 'type', ['data'], ['base'])
                 add_struct(expr)
+            elif expr.has_key('command'):
+                check_keys(expr_elem, 'command', [],
+                           ['data', 'returns', 'gen', 'success-response'])
+            elif expr.has_key('event'):
+                check_keys(expr_elem, 'event', [], ['data'])
+            else:
+                raise QAPIExprError(expr_elem['info'],
+                                    "Expression is missing metatype")
             exprs.append(expr)
 
         # Try again for hidden UnionKind enum
index 4a2566eed3f303ef5d05acf99dc85c07c8e58db6..30d8a343734307ad77d421b5dfe03c4095b42974 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/alternate-base.json:4: Alternate 'Alt' must not have a base
+tests/qapi-schema/alternate-base.json:4: Unknown key 'base' in alternate 'Alt'
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0b2a2aeac429ab61cb9397b9d82b9828bfdcea0a 100644 (file)
@@ -0,0 +1 @@
+tests/qapi-schema/bad-type-dict.json:2: 'command' key must have a string value
index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 (file)
@@ -1 +1 @@
-0
+1
index 3c392a7cbd5a928d999a9ce2f31491f36be9aec0..2a91b241f8e4c50ec5193a5565e78c5812d0a0ce 100644 (file)
@@ -1,2 +1,2 @@
-# FIXME: we should reject an expression with a metatype that is not a string
+# we reject an expression with a metatype that is not a string
 { 'command': { } }
index c62f1edb7603cd0ddd13f8b57c37ed8c188f22e0..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-[OrderedDict([('command', OrderedDict())])]
-[]
-[]
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ceb6e46cfed15edcecd68e1e1383aa792efbc3c9 100644 (file)
@@ -0,0 +1 @@
+tests/qapi-schema/double-type.json:2: Unknown key 'command' in type 'bar'
index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 (file)
@@ -1 +1 @@
-0
+1
index 6ca96b97c198dd62a80fec79e4b0e294df8260ec..471623a2e571db4b42564d6de3d81eaff2d7a8ce 100644 (file)
@@ -1,2 +1,2 @@
-# FIXME: we should reject an expression with ambiguous metatype
+# we reject an expression with ambiguous metatype
 { 'command': 'foo', 'type': 'bar', 'data': { } }
index 3e244f5780ad3f573b713638ec0be2dd61c628fe..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-[OrderedDict([('command', 'foo'), ('type', 'bar'), ('data', OrderedDict())])]
-[]
-[OrderedDict([('command', 'foo'), ('type', 'bar'), ('data', OrderedDict())])]
index b8ccae071b2873aae902b734c09583c4112589cf..ba4873ae69ada3459aa27e3d4acceca1a958fe1c 100644 (file)
@@ -1 +1 @@
-tests/qapi-schema/enum-missing-data.json:2: Enum 'MyEnum' requires an array for 'data'
+tests/qapi-schema/enum-missing-data.json:2: Key 'data' is missing from enum 'MyEnum'
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f7d1c5532739626b51ee50b9cd4c0be03c7962b2 100644 (file)
@@ -0,0 +1 @@
+tests/qapi-schema/ident-with-escape.json:3: Expression is missing metatype
index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 (file)
@@ -1 +1 @@
-0
+1
index a44623fa4a556ff98c48e6399feb2797f73d574c..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-[OrderedDict([('cu006fmmand', 'u0066u006fu006FA'), ('du0061ta', OrderedDict([('u0062u0061u00721', 'u0073u0074u0072')]))])]
-[]
-[]
index d80af6056401ffe5b9e2a6304de64b3a3f1d4547..7115d3131e81bc59603d41c47f46345fc077b709 100644 (file)
@@ -1,2 +1,2 @@
-{ 'id' : 'eins' }
- { 'id' : 'zwei' }
+{ 'command' : 'eins' }
+ { 'command' : 'zwei' }
index 98af89aa1d17cdb7b48ff517926ec93543dcc79f..b5ce9151bcdd0821eba75c0dfece647d8d373567 100644 (file)
@@ -1,3 +1,3 @@
-[OrderedDict([('id', 'eins')]), OrderedDict([('id', 'zwei')])]
+[OrderedDict([('command', 'eins')]), OrderedDict([('command', 'zwei')])]
 []
 []
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b3e7b14e420a27d2e86fc79dfca03c2ac609505a 100644 (file)
@@ -0,0 +1 @@
+tests/qapi-schema/missing-type.json:2: Expression is missing metatype
index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 (file)
@@ -1 +1 @@
-0
+1
index 1696f5c139c8677eeed887d67cfac53c2273c62f..ff5349d3febe4778e78a50a786d49a2449673947 100644 (file)
@@ -1,2 +1,2 @@
-# FIXME: we should reject an expression with missing metatype
+# we reject an expression with missing metatype
 { 'data': { } }
index 67fd4fa6767d172dd702ce6d5b3cd6d1b31ca345..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-[OrderedDict([('data', OrderedDict())])]
-[]
-[]
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0a35bfdbd62e4843dec8e03dc39cb28d98cf7d38 100644 (file)
@@ -0,0 +1 @@
+tests/qapi-schema/unknown-expr-key.json:2: Unknown key 'bogus' in type 'bar'
index 573541ac9702dd3969c9bc859d2b91ec1f7e6e56..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d 100644 (file)
@@ -1 +1 @@
-0
+1
index 1e9282d8e1ece68089247c7eb14830169ab22fa8..ba7bdf3ed6699482ec3971891e8d097217046727 100644 (file)
@@ -1,2 +1,2 @@
-# FIXME: we should reject an expression with unknown top-level keys
+# we reject an expression with unknown top-level keys
 { 'type': 'bar', 'data': { 'string': 'str'}, 'bogus': { } }
index c93f020aebde6b7064097daf5d7b251cd3c22648..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-[OrderedDict([('type', 'bar'), ('data', OrderedDict([('string', 'str')])), ('bogus', OrderedDict())])]
-[]
-[OrderedDict([('type', 'bar'), ('data', OrderedDict([('string', 'str')])), ('bogus', OrderedDict())])]