aboutsummaryrefslogtreecommitdiff
path: root/scripts/qapi.py
AgeCommit message (Collapse)Author
2016-03-05qapi: Rename 'fields' to 'members' in generatorEric Blake
C types and JSON objects don't have fields, but members. We shouldn't gratuitously invent terminology. This patch is a strict renaming of generator code internals (including testsuite comments), before later patches rename C interfaces. No change to generated code with this patch. Suggested-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1457021813-10704-2-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-01qapi: rename InputAxis values.Gerd Hoffmann
Lowercase them. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
2016-03-01qapi: rename input buttonsGerd Hoffmann
All lowercase, use-dash instead of CamelCase. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Daniel P. Berrange <berrange@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
2016-02-19qapi: Don't box struct branch of alternateEric Blake
There's no reason to do two malloc's for an alternate type visiting a QAPI struct; let's just inline the struct directly as the C union branch of the struct. Surprisingly, no clients were actually using the struct member prior to this patch outside of the testsuite; an earlier patch in the series added some testsuite coverage to make the effect of this patch more obvious. In qapi.py, c_type() gains a new is_unboxed flag to control when we are emitting a C struct unboxed within the context of an outer struct (different from our other two modes of usage with no flags for normal local variable declarations, and with is_param for adding 'const' in a parameter list). I don't know if there is any more pythonic way of collapsing the two flags into a single parameter, as we never have a caller setting both flags at once. Ultimately, we want to also unbox branches for QAPI unions, but as that touches a lot more client code, it is better as separate patches. But since unions and alternates share gen_variants(), I had to hack in a way to test if we are visiting an alternate type for setting the is_unboxed flag: look for a non-object branch. This works because alternates have at least two branches, with at most one object branch, while unions have only object branches. The hack will go away in a later patch. The generated code difference to qapi-types.h is relatively small: | struct BlockdevRef { | QType type; | union { /* union tag is @type */ | void *data; |- BlockdevOptions *definition; |+ BlockdevOptions definition; | char *reference; | } u; | }; The corresponding spot in qapi-visit.c calls visit_type_FOO(), which first calls visit_start_struct() to allocate or deallocate the member and handle a layer of {} from the JSON stream, then visits the members. To peel off the indirection and the memory management that comes with it, we inline this call, then suppress allocation / deallocation by passing NULL to visit_start_struct(), and adjust the member visit: | switch ((*obj)->type) { | case QTYPE_QDICT: |- visit_type_BlockdevOptions(v, name, &(*obj)->u.definition, &err); |+ visit_start_struct(v, name, NULL, 0, &err); |+ if (err) { |+ break; |+ } |+ visit_type_BlockdevOptions_fields(v, &(*obj)->u.definition, &err); |+ error_propagate(errp, err); |+ err = NULL; |+ visit_end_struct(v, &err); | break; | case QTYPE_QSTRING: | visit_type_str(v, name, &(*obj)->u.reference, &err); The visit of non-object fields is unchanged. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1455778109-6278-13-git-send-email-eblake@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-19qapi: Forbid 'any' inside an alternateEric Blake
The whole point of an alternate is to allow some type-safety while still accepting more than one JSON type. Meanwhile, the 'any' type exists to bypass type-safety altogether. The two are incompatible: you can't accept every type, and still tell which branch of the alternate to use for the parse; fix this to give a sane error instead of a Python stack trace. Note that other types that can't be alternate members are caught earlier, by check_type(). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1455778109-6278-4-git-send-email-eblake@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-19qapi: Forbid empty unions and useless alternatesEric Blake
Empty unions serve no purpose, and while we compile with gcc which permits them, strict C99 forbids them. We happen to inject a dummy 'void *data' member into the C unions that represent QAPI unions and alternates, but we want to get rid of that member (it pollutes the namespace for no good reason), which would leave us with an empty union if the user didn't provide any branches. While empty structs make sense in QAPI, empty unions don't add any expressiveness to the QMP language. So prohibit them at parse time. Update the documentation and testsuite to match. Note that the documentation already mentioned that alternates should have "two or more JSON data types"; so this also fixes the code to enforce that. However, we have existing uses of a union type with only one branch, so the 2-or-more strictness is intentionally limited to alternates. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1455778109-6278-3-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-08qapi: Fix compilation failure on MIPS and SPARCEric Blake
Commit 86f4b687 broke compilation on MIPS and SPARC, which have a preprocessor pollution of '#define mips 1' and '#define sparc 1', respectively. Treat it the same way as we do for the pollution with 'unix', so that QMP remains backwards compatible and only the C code needs to use the alternative 'q_mips', 'q_sparc' spelling. CC: James Hogan <james.hogan@imgtec.com> CC: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Eric Blake <eblake@redhat.com> Tested-by: James Hogan <james.hogan@imgtec.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-08qapi: Swap visit_* arguments for consistent 'name' placementEric Blake
JSON uses "name":value, but many of our visitor interfaces were called with visit_type_FOO(v, &value, name, errp). This can be a bit confusing to have to mentally swap the parameter order to match JSON order. It's particularly bad for visit_start_struct(), where the 'name' parameter is smack in the middle of the otherwise-related group of 'obj, kind, size' parameters! It's time to do a global swap of the parameter ordering, so that the 'name' parameter is always immediately after the Visitor argument. Additional reason in favor of the swap: the existing include/qjson.h prefers listing 'name' first in json_prop_*(), and I have plans to unify that file with the qapi visitors; listing 'name' first in qapi will minimize churn to the (admittedly few) qjson.h clients. Later patches will then fix docs, object.h, visitor-impl.h, and those clients to match. Done by first patching scripts/qapi*.py by hand to make generated files do what I want, then by running the following Coccinelle script to affect the rest of the code base: $ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'` I then had to apply some touchups (Coccinelle insisted on TAB indentation in visitor.h, and botched the signature of visit_type_enum() by rewriting 'const char *const strings[]' to the syntactically invalid 'const char*const[] strings'). The movement of parameters is sufficient to provoke compiler errors if any callers were missed. // Part 1: Swap declaration order @@ type TV, TErr, TObj, T1, T2; identifier OBJ, ARG1, ARG2; @@ void visit_start_struct -(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp) +(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp) { ... } @@ type bool, TV, T1; identifier ARG1; @@ bool visit_optional -(TV v, T1 ARG1, const char *name) +(TV v, const char *name, T1 ARG1) { ... } @@ type TV, TErr, TObj, T1; identifier OBJ, ARG1; @@ void visit_get_next_type -(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp) +(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp) { ... } @@ type TV, TErr, TObj, T1, T2; identifier OBJ, ARG1, ARG2; @@ void visit_type_enum -(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp) +(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp) { ... } @@ type TV, TErr, TObj; identifier OBJ; identifier VISIT_TYPE =~ "^visit_type_"; @@ void VISIT_TYPE -(TV v, TObj OBJ, const char *name, TErr errp) +(TV v, const char *name, TObj OBJ, TErr errp) { ... } // Part 2: swap caller order @@ expression V, NAME, OBJ, ARG1, ARG2, ERR; identifier VISIT_TYPE =~ "^visit_type_"; @@ ( -visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR) +visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR) | -visit_optional(V, ARG1, NAME) +visit_optional(V, NAME, ARG1) | -visit_get_next_type(V, OBJ, ARG1, NAME, ERR) +visit_get_next_type(V, NAME, OBJ, ARG1, ERR) | -visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR) +visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR) | -VISIT_TYPE(V, OBJ, NAME, ERR) +VISIT_TYPE(V, NAME, OBJ, ERR) ) Signed-off-by: Eric Blake <eblake@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-08qapi: Improve generated event use of qapi visitorEric Blake
All other successful clients of visit_start_struct() were paired with an unconditional visit_end_struct(); but the generated code for events was relying on qmp_output_visitor_cleanup() to work on an incomplete visit. Alter the code to guarantee that the struct is completed, which will make a future patch to split visit_end_struct() easier to reason about. While at it, drop some assertions and comments that are not present in other uses of the qmp output visitor, and pass NULL rather than "" as the 'kind' parameter (matching most other uses where obj is NULL). The changes to the generated code look like: | qmp = qmp_event_build_dict("DEVICE_TRAY_MOVED"); | | qov = qmp_output_visitor_new(); |- g_assert(qov); |- | v = qmp_output_get_visitor(qov); |- g_assert(v); | |- /* Fake visit, as if all members are under a structure */ |- visit_start_struct(v, NULL, "", "DEVICE_TRAY_MOVED", 0, &err); |+ visit_start_struct(v, NULL, NULL, "DEVICE_TRAY_MOVED", 0, &err); | if (err) { | goto out; | } | visit_type_str(v, (char **)&device, "device", &err); | if (err) { |- goto out; |+ goto out_obj; | } | visit_type_bool(v, &tray_open, "tray-open", &err); | if (err) { |- goto out; |+ goto out_obj; | } |- visit_end_struct(v, &err); |+out_obj: |+ visit_end_struct(v, err ? NULL : &err); | if (err) { | goto out; | } | | obj = qmp_output_get_qobject(qov); |- g_assert(obj != NULL); |+ g_assert(obj); | | qdict_put_obj(qmp, "data", obj); | emit(QAPI_EVENT_DEVICE_TRAY_MOVED, qmp, &err); Note that the 'goto out_obj' with no intervening code before the label, as well as the construct of 'err ? NULL : &err', are both a bit unusual but also temporary; they get fixed in a later patch that splits visit_end_struct() to drop its errp parameter by moving some checking before the label. But until that time, this was the simplest way to avoid the appearance of passing a possibly-set error to visit_end_struct(), even though actual code inspection shows that visit_end_struct() for a QMP output visitor will never set an error. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1454075341-13658-11-git-send-email-eblake@redhat.com> [Commit message's code diff tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-08qapi: Drop dead parameter in gen_params()Eric Blake
Commit 5cdc8831 reworked gen_params() to be simpler, but forgot to clean up a now-unused errp named argument. No change to generated code. Reported-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1454075341-13658-6-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-02-08qapi: Use Python 2.6 "except E as ..." syntaxMarkus Armbruster
PEP 8 calls for it, because it's forward compatible with Python 3. Supported since Python 2.6, which we require (commit fec2103). Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Acked-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <1450425164-24969-2-git-send-email-armbru@redhat.com>
2015-12-17qapi: Detect base class loopsEric Blake
It should be fairly obvious that qapi base classes need to form an acyclic graph, since QMP cannot specify the same key more than once, while base classes are included as flat members alongside other members added by the child. But the old check_member_clash() parser function was not prepared to check for this, and entered an infinite recursion (at least until Python gives up, complaining about nesting too deep). Now that check_member_clash() has been recently removed, attempts at self-inheritance trigger an assertion failure introduced by commit ac88219a. The obvious fix is to turn the assertion into a conditional. This patch includes both the tests (base-cycle-direct and base-cycle-indirect) and the fix, since the .err file output for the unfixed case is not useful (particularly when it was warning about unbounded recursion, as that limit may be platform-specific). We don't need to worry about cycles in flat unions (neither the base type nor the type of a variant can be a union) nor in alternates (alternate branches cannot themselves be an alternate). But if we later allow a union type as a variant, we will still be okay, as QAPISchemaObjectTypeVariants.check() triggers the same QAPISchemaObjectType.check() that will detect any loops. Likewise, we need not worry about the case of diamond inheritance where the same class is used for a flat union base class and one of its variants; either both uses will introduce a collision in trying to insert the same member name twice, or the shared type is empty and changes nothing. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-16-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Move duplicate collision checks to schema check()Eric Blake
With the recent commit 'qapi: Detect collisions in C member names', we have two different locations for detecting clashes - one at parse time, and another at QAPISchema*.check() time. Remove all of the ad hoc parser checks, and delete associated code (for example, the global check_member_clash() method is no longer needed). Testing this showed that the test union-bad-branch wasn't adding much: union-clash-branches also exposes the error message when branches collide, and we've recently fixed things to avoid an implicit collision with max. Likewise, the error for enum-clash-member changes to report our new detection of upper case in a value name, unless we modify the test to use all lower case. The wording of several error messages has changed, but the change is generally an improvement rather than a regression. No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-15-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Enforce (or whitelist) case conventions on qapi membersEric Blake
We document that members of enums and objects should be 'lower-case', although we were not enforcing it. We have to whitelist a few pre-existing entities that violate the norms. Add three new tests to expose the new error message, each of which first uses the whitelisted name 'UuidInfo' to prove the whitelist works, then triggers the failure (this is the same pattern used in the existing returns-whitelist.json test). Note that by adding this check, we have effectively forbidden an entity with a case-insensitive clash of member names, for any entity that is not on the whitelist (although there is still the possibility to clash via '-' vs. '_'). Not done here: a future patch should also add naming convention support and whitelist exceptions for command, event, and type names. The additions to QAPISchemaMember.check_clash() check whether info['name'] is in the whitelist (the top-most entity name at the point 'info' tracks), rather than self.owner (the type, possibly implicit, that directly owns the member), because it is easier to maintain the whitelist by the names actually in the user's .json file, rather than worrying about the names of implicit types. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-14-git-send-email-eblake@redhat.com> [Simplified a bit as per discussion with Eric] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Track enum values by QAPISchemaMember, not stringEric Blake
Rather than using just an array of strings, make enum.values be an array of the new QAPISchemaMember type, and add a helper member_names() method to get back at the original list of names. Likewise, creating an enum requires wrapping strings, via a new QAPISchema._make_enum_members() method. The benefit of wrapping enum members in a QAPISchemaMember Python object is that we now share the existing code for C name clash detection (although the code is not yet active until a later commit removes the earlier ad hoc parser checks). In a related change, the QAPISchemaMember._pretty_owner() method needs to learn about one more implicit type name: the generated enum associated with a simple union. In the interest of keeping the changes of this patch local to one file, the visitor interface still passes just a list of names rather than the full list of QAPISchemaMember instances. We may want to revisit this in the future, if the consistency with visit_object_type() is worth it. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-12-git-send-email-eblake@redhat.com> [Eric's simplifying followup squashed in] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Prepare new QAPISchemaMember base classEric Blake
We want to share some clash detection code between enum values and object type members. To assist with that, split off part of QAPISchemaObjectTypeMember into a new base class QAPISchemaMember that tracks name, owner, and common clash detection code; while the former keeps the additional fields for type and optional flag. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-11-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Shorter visits of optional fieldsEric Blake
For less code, reflect the determined boolean value of an optional visit back to the caller instead of making the caller read the boolean after the fact. The resulting generated code has the following diff: |- visit_optional(v, &has_fdset_id, "fdset-id"); |- if (has_fdset_id) { |+ if (visit_optional(v, &has_fdset_id, "fdset-id")) { | visit_type_int(v, &fdset_id, "fdset-id", &err); | if (err) { | goto out; | } | } Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-10-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Simplify visits of optional fieldsEric Blake
None of the visitor callbacks would set an error when testing if an optional field was present; make this part of the interface contract by eliminating the errp argument. The resulting generated code has a nice diff: |- visit_optional(v, &has_fdset_id, "fdset-id", &err); |- if (err) { |- goto out; |- } |+ visit_optional(v, &has_fdset_id, "fdset-id"); | if (has_fdset_id) { | visit_type_int(v, &fdset_id, "fdset-id", &err); | if (err) { | goto out; | } | } Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-9-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Inline _make_implicit_tag()Eric Blake
Now that alternates no longer use an implicit tag, we can inline _make_implicit_tag() into its one caller, _def_union_type(). No change to generated code. Suggested-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-7-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Simplify visiting of alternate typesEric Blake
Previously, working with alternates required two lookup arrays and some indirection: for type Foo, we created Foo_qtypes[] which maps each qtype to a value of the generated FooKind enum, then look up that value in FooKind_lookup[] like we do for other union types. This has a couple of subtle bugs. First, the generator was creating a call with a parameter '(int *) &(*obj)->type' where type is an enum type; this is unsafe if the compiler chooses to store the enum type in a different size than int, where assigning through the wrong size pointer can corrupt data or cause a SIGBUS. Related bug, not not fixed in this patch: qapi-visit.py's gen_visit_enum() generates a cast of its enum * argument to int *. Marked FIXME. Second, since the values of the FooKind enum start at zero, all entries of the Foo_qtypes[] array that were not explicitly initialized will map to the same branch of the union as the first member of the alternate, rather than triggering a desired failure in visit_get_next_type(). Fortunately, the bug seldom bites; the very next thing the input visitor does is try to parse the incoming JSON with the wrong parser, which normally fails; the output visitor is not used with a C struct in that state, and the dealloc visitor has nothing to clean up (so there is no leak). However, the second bug IS observable in one case: parsing an integer causes unusual behavior in an alternate that contains at least a 'number' member but no 'int' member, because the 'number' parser accepts QTYPE_QINT in addition to the expected QTYPE_QFLOAT (that is, since 'int' is not a member, the type QTYPE_QINT accidentally maps to FooKind 0; if this enum value is the 'number' branch the integer parses successfully, but if the 'number' branch is not first, some other branch tries to parse the integer and rejects it). A later patch will worry about fixing alternates to always parse all inputs that a non-alternate 'number' would accept, for now this is still marked FIXME in the updated test-qmp-input-visitor.c, to merely point out that new undesired behavior of 'ans' matches the existing undesired behavior of 'asn'. This patch fixes the default-initialization bug by deleting the indirection, and modifying get_next_type() to directly assign a QTypeCode parameter. This in turn fixes the type-casting bug, as we are no longer casting a pointer to enum to a questionable size. There is no longer a need to generate an implicit FooKind enum associated with the alternate type (since the QMP wire format never uses the stringized counterparts of the C union member names). Since the updated visit_get_next_type() does not know which qtypes are expected, the generated visitor is modified to generate an error statement if an unexpected type is encountered. Callers now have to know the QTYPE_* mapping when looking at the discriminator; but so far, only the testsuite was even using the C struct of an alternate types. I considered the possibility of keeping the internal enum FooKind, but initialized differently than most generated arrays, as in: typedef enum FooKind { FOO_KIND_A = QTYPE_QDICT, FOO_KIND_B = QTYPE_QINT, } FooKind; to create nicer aliases for knowing when to use foo->a or foo->b when inspecting foo->type; but it turned out to add too much complexity, especially without a client. There is a user-visible side effect to this change, but I consider it to be an improvement. Previously, the invalid QMP command: {"execute":"blockdev-add", "arguments":{"options": {"driver":"raw", "id":"a", "file":true}}} failed with: {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'file', expected: QDict"}} (visit_get_next_type() succeeded, and the error comes from the visit_type_BlockdevOptions() expecting {}; there is no mention of the fact that a string would also work). Now it fails with: {"error": {"class": "GenericError", "desc": "Invalid parameter type for 'file', expected: BlockdevRef"}} (the error when the next type doesn't match any expected types for the overall alternate). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-5-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Convert QType into QAPI built-in enum typeEric Blake
What's more meta than using qapi to define qapi? :) Convert QType into a full-fledged[*] builtin qapi enum type, so that a subsequent patch can then use it as the discriminator type of qapi alternate types. Fortunately, the judicious use of 'prefix' in the qapi definition avoids churn to the spelling of the enum constants. To avoid circular definitions, we have to flip the order of inclusion between "qobject.h" vs. "qapi-types.h". Back in commit 28770e0, we had the latter include the former, so that we could use 'QObject *' for our implementation of 'any'. But that usage also works with only a forward declaration, whereas the definition of QObject requires QType to be a complete type. [*] The type has to be builtin, rather than declared in qapi/common.json, because we want to use it for alternates even when common.json is not included. But since it is the first builtin enum type, we have to add special cases to qapi-types and qapi-visit to only emit definitions once, even when two qapi files are being compiled into the same binary (the way we already handled builtin list types like 'intList'). We may need to revisit how multiple qapi files share common types, but that's a project for another day. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-4-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qobject: Rename qtype_code to QTypeEric Blake
The name QType matches our CODING_STYLE conventions for type names in CamelCase. It also matches the fact that we are already naming all the enum members with a prefix of QTYPE, not QTYPE_CODE. And doing the rename will also make it easier for the next patch to use QAPI for providing the enum, which also wants CamelCase type names. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1449033659-25497-3-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Change munging of CamelCase enum valuesEric Blake
When munging enum values, the fact that we were passing the entire prefix + value through camel_to_upper() meant that enum values spelled with CamelCase could be turned into CAMEL_CASE. However, this provides a potential collision (both OneTwo and One-Two would munge into ONE_TWO) for enum types, when the same two names are valid side-by-side as QAPI member names. By changing the generation of enum constants to always be prefix + '_' + c_name(value, False).upper(), and ensuring that there are no case collisions (in the next patches), we no longer have to worry about names that would be distinct as QAPI members but collide as variant tag names, without having to think about what munging the heuristics in camel_to_upper() will actually perform on an enum value. Making the change will affect enums that did not follow coding conventions, using 'CamelCase' rather than desired 'lower-case'. Thankfully, there are only two culprits: InputButton and ErrorClass. We already tweaked ErrorClass to make it an alias of QapiErrorClass, where only the alias needs changing rather than the whole tree. So the bulk of this change is modifying INPUT_BUTTON_WHEEL_UP to the new INPUT_BUTTON_WHEELUP (and likewise for WHEELDOWN). That part of this commit may later need reverting if we rename the enum constants from 'WheelUp' to 'wheel-up' as part of moving x-input-send-event to a stable interface; but at least we have documentation bread crumbs in place to remind us (commit 513e7cd), and it matches the fact that SDL constants are also spelled SDL_BUTTON_WHEELUP. Suggested by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-27-git-send-email-eblake@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Remove obsolete tests for MAX collisionEric Blake
Now that we no longer collide with an implicit _MAX enum member, we no longer need to reject it in the ad hoc parser, and can remove several tests that are no longer needed. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-24-git-send-email-eblake@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Don't let implicit enum MAX member collideEric Blake
Now that we guarantee the user doesn't have any enum values beginning with a single underscore, we can use that for our own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious that the sentinel is generated. This patch was mostly generated by applying a temporary patch: |diff --git a/scripts/qapi.py b/scripts/qapi.py |index e6d014b..b862ec9 100644 |--- a/scripts/qapi.py |+++ b/scripts/qapi.py |@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = { | max_index = c_enum_const(name, 'MAX', prefix) | ret += mcgen(''' | [%(max_index)s] = NULL, |+// %(max_index)s | }; | ''', | max_index=max_index) then running: $ cat qapi-{types,event}.c tests/test-qapi-types.c | sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list $ git grep -l _MAX | xargs sed -i -f list The only things not generated are the changes in scripts/qapi.py. Rejecting enum members named 'MAX' is now useless, and will be dropped in the next patch. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> [Rebased to current master, commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Tighten the regex on valid namesEric Blake
We already documented that qapi names should match specific patterns (such as starting with a letter unless it was an enum value or a downstream extension). Tighten that from a suggestion into a hard requirement, which frees up names beginning with a single underscore for qapi internal usage. The tighter regex doesn't forbid everything insane that a user could provide (for example, a user could name a type 'Foo-lookup' to collide with the generated 'Foo_lookup[]' for an enum 'Foo'), but does a good job at protecting the most obvious uses, and also happens to reserve single leading underscore for later use. The handling of enum values starting with a digit is tricky: commit 9fb081e introduced a subtle bug by using c_name() on a munged value, which would allow an enum to include the member 'q-int' in spite of our reservation. Furthermore, munging with a leading '_' would fail our tighter regex. So fix it by only munging for leading digits (which are never ticklish in c_name()) and by using a different prefix (I picked 'D', although any letter should do). Add new tests, reserved-member-underscore and reserved-enum-q, to demonstrate the tighter checking. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-22-git-send-email-eblake@redhat.com> Message-Id: <1447883135-18020-1-git-send-email-eblake@redhat.com> [Eric's fixup squashed in] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Fix c_name() mungingEric Blake
The method c_name() is supposed to do two different actions: munge '-' into '_', and add a 'q_' prefix to ticklish names. But it did these steps out of order, making it possible to submit input that is not ticklish until after munging, where the output then lacked the desired prefix. The failure is exposed easily if you have a compiler that recognizes C11 keywords, and try to name a member '_Thread-local', as it would result in trying to compile the declaration 'uint64_t _Thread_local;' which is not valid. However, this name violates our conventions (ultimately, want to enforce that no qapi names start with single underscore), so the test is slightly weaker by instead testing 'wchar-t'; the declaration 'uint64_t wchar_t;' is valid in C (where wchar_t is only a typedef) but would fail with a C++ compiler (where it is a keyword). Fix things by reversing the order of actions within c_name(). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-18-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Detect collisions in C member namesEric Blake
Detect attempts to declare two object members that would result in the same C member name, by keying the 'seen' dictionary off of the C name rather than the qapi name. It also requires passing info through the check_clash() methods. This addresses a TODO and fixes the previously-broken args-name-clash test. The resulting error message demonstrates the utility of the .describe() method added previously. No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-17-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Track owner of each object memberEric Blake
Future commits will migrate semantic checking away from parsing and over to the various QAPISchema*.check() methods. But to report an error message about an incorrect semantic use of a member of an object type, it helps to know which type, command, or event owns the member. In particular, when a member is inherited from a base type, it is desirable to associate the member name with the base type (and not the type calling member.check()). Rather than packing additional information into the seen array passed to each member.check() (as in seen[m.name] = {'member':m, 'owner':type}), it is easier to have each member track the name of the owner type in the first place (keeping things simpler with the existing seen[m.name] = m). The new member.owner field is set via a new set_owner() method, called when registering the members and variants arrays with an object or variant type. Track only a name, and not the actual type object, to avoid creating a circular python reference chain. Note that Variants.set_owner() method does not set the owner for the tag_member field; this field is set earlier either as part of an object's non-variant members, or explicitly by alternates. The source information is intended for human consumption in error messages, and a new describe() method is added to access the resulting information. For example, given the qapi: { 'command': 'foo', 'data': { 'string': 'str' } } an implementation of visit_command() that calls arg_type.members[0].describe() will see "'string' (parameter of foo)". To make the human-readable name of implicit types work without duplicating efforts, the describe() method has to reverse the name of implicit types, via the helper _pretty_owner(). No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-16-git-send-email-eblake@redhat.com> [Incorrect & unused -wrapper case in _pretty_owner() dropped] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Remove outdated tests related to QMP/branch collisionsEric Blake
Now that branches are in a separate C namespace, we can remove the restrictions in the parser that claim a branch name would collide with QMP, and delete the negative tests that are no longer problematic. A separate patch can then add positive tests to qapi-schema-test to test that any corner cases will compile correctly. This reverts the scripts/qapi.py portion of commit 7b2a5c2, now that the assertions that it plugged are no longer possible. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-15-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Hoist tag collision check to Variants.check()Eric Blake
Checking that a given QAPISchemaObjectTypeVariant.name is a member of the corresponding QAPISchemaEnumType of the owning QAPISchemaObjectTypeVariants.tag_member ensures that there are no collisions in the generated C union for those tag values (since the enum itself should have no collisions). However, ever since its introduction in f51d8c3d, this was the only additional action of of Variant.check(), beyond calling the superclass Member.check(). This forces a difference in .check() signatures, just to pass the enum type down. Simplify things by instead doing the tag name check as part of Variants.check(), at which point we can rely on inheritance instead of overriding Variant.check(). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-14-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Factor out QAPISchemaObjectType.check_clash()Eric Blake
Consolidate two common sequences of clash detection into a new QAPISchemaObjectType.check_clash() helper method. No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-13-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Check for QAPI collisions involving variant membersEric Blake
Right now, our ad hoc parser ensures that we cannot have a flat union that introduces any members that would clash with non-variant members inherited from the union's base type (see flat-union-clash-member.json). We want QAPISchemaObjectType.check() to make the same check, so we can later reduce some of the ad hoc checks. We already have a map 'seen' of all non-variant members. We still need to check for collisions between each variant type's members and the non-variant ones. To know the variant type's members, we need to call variant.type.check(). This also detects when a type contains itself in a variant, exactly like the existing base.check() detects when a type contains itself as a base. (Except that we currently forbid anything but a struct as the type of a variant, so we can't actually trigger this type of loop yet.) Slight complication: an alternate's variant can have arbitrary type, but only an object type's check() may be called outside QAPISchema.check(). We could either skip the call for variants of alternates, or skip it for non-object types. For now, do the latter, because it's easier. Then we call each variant member's check_clash() with the appropriate 'seen' map. Since members of different variants can't clash, we have to clone a fresh seen for each variant. Wrap this in a new helper method QAPISchemaObjectTypeVariants.check_clash(). Note that cloning 'seen' inside .check_clash() resembles the one we just removed from .check() in 'qapi: Drop obsolete tag value collision assertions'; the difference here is that we are now checking for clashes among the qapi members of the variant type, rather than for a single clash with the variant tag name itself. Note that, by construction, collisions can't actually happen for simple unions: each variant's type is a wrapper with a single member 'data', which will never collide with the only non-variant member 'type'. For alternates, there's nothing for a variant object type's members to clash with, and therefore no need to call the new variants.check_clash(). No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-12-git-send-email-eblake@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-12-17qapi: Simplify QAPISchemaObjectTypeVariants.check()Markus Armbruster
Reduce the ugly flat union / simple union conditional by doing just the essential work here, namely setting self.tag_member. Move the rest to callers. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-7-git-send-email-armbru@redhat.com> [rebase to earlier changes that moved tag_member.check() of alternate types, and tweak commit title and wording] Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-11-git-send-email-eblake@redhat.com>
2015-12-17qapi: Factor out QAPISchemaObjectTypeMember.check_clash()Markus Armbruster
While there, stick in a TODO change key of seen from QAPI name to C name. Can't do it right away, because it would fail the assertion for tests/qapi-schema/args-has-clash.json. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-6-git-send-email-armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-10-git-send-email-eblake@redhat.com>
2015-12-17qapi: Eliminate QAPISchemaObjectType.check() variable membersMarkus Armbruster
We can use seen.values() instead if we make it an OrderedDict. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-5-git-send-email-armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-9-git-send-email-eblake@redhat.com>
2015-12-17qapi: Fix up commit 7618b91's clash sanity checking changeMarkus Armbruster
This hunk @@ -964,6 +965,7 @@ class QAPISchemaObjectType(QAPISchemaType): members = [] seen = {} for m in members: + assert c_name(m.name) not in seen seen[m.name] = m for m in self.local_members: m.check(schema, members, seen) is plainly broken. Asserting the members inherited from base don't clash is somewhat redundant, because self.base.check() just checked that. But it doesn't hurt. The idea to use c_name(m.name) instead of m.name for collision checking is sound, because we need to catch clashes between the m.name and between the c_name(m.name), and when two m.name clash, then their c_name() also clash. However, using c_name(m.name) instead of m.name in one of several places doesn't work. See the very next line. Keep the assertion, but drop the c_name() for now. A future commit will bring it back. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-4-git-send-email-armbru@redhat.com> [change TABs in commit message to space] Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-8-git-send-email-eblake@redhat.com>
2015-12-17qapi: Clean up after previous commitMarkus Armbruster
QAPISchemaObjectTypeVariants.check() parameter members and QAPISchemaObjectTypeVariant.check() parameter seen are no longer used, drop them. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-3-git-send-email-armbru@redhat.com> [rebase to earlier changes that moved tag_member.check() of alternate types] Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-7-git-send-email-eblake@redhat.com>
2015-12-17qapi: Simplify QAPISchemaObjectTypeMember.check()Markus Armbruster
QAPISchemaObjectTypeMember.check() currently does four things: 1. Compute self.type 2. Accumulate members in all_members Only one caller cares: QAPISchemaObjectType.check() uses it to compute self.members. The other callers pass a throw-away accumulator. 3. Accumulate a map from names to members in seen Only one caller cares: QAPISchemaObjectType.check() uses it to compute its local variable seen, for self.variants.check(), which uses it to compute self.variants.tag_member from self.variants.tag_name. The other callers pass a throw-away accumulator. 4. Check for collisions This piggybacks on 3: before adding a new entry, we assert it's new. Only one caller cares: QAPISchemaObjectType.check() uses it to assert non-variant members don't clash. Simplify QAPISchemaObjectType.check(): move 2.-4. to QAPISchemaObjectType.check(), and drop parameters all_members and seen. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-2-git-send-email-armbru@redhat.com> [rebase to earlier changes that moved tag_member.check() of alternate types, commit message typo fix] Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-6-git-send-email-eblake@redhat.com>
2015-12-17qapi: Drop obsolete tag value collision assertionsMarkus Armbruster
Union tag values can't clash with member names in generated C anymore since commit e4ba22b, but QAPISchemaObjectTypeVariants.check() still asserts they don't. Drop it. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1446559499-26984-1-git-send-email-armbru@redhat.com> Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-5-git-send-email-eblake@redhat.com>
2015-12-17qapi: Track simple union tag in object.local_membersEric Blake
We were previously creating all unions with an empty list for local_members. However, it will make it easier to unify struct and union generation if we include the generated tag member in local_members. That way, we can have a common code pattern: visit the base (if any), visit the local members (if any), visit the variants (if any). The local_members of a flat union remains empty (because the discriminator is already visited as part of the base). Then, by visiting tag_member.check() during AlternateType.check(), we no longer need to call it during Variants.check(). The various front end entities now exist as follows: struct: optional base, optional local_members, no variants simple union: no base, one-element local_members, variants with tag_member from local_members flat union: base, no local_members, variants with tag_member from base alternate: no base, no local_members, variants With the new local members, we require a bit of finesse to avoid assertions in the clients. No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1447836791-369-2-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-02qapi: Reserve 'u' member nameEric Blake
Now that we have separated union tag values from colliding with non-variant C names, by naming the union 'u', we should reserve this name for our use. Note that we want to forbid 'u' even in a struct with no variants, because it is possible for a future qemu release to extend QMP in a backwards-compatible manner while converting from a struct to a flat union. Fortunately, no existing clients were using this member name. If we ever find the need for QMP to have a member 'u', we could at that time relax things, perhaps by having c_name() munge the QMP member to 'q_u'. Note that we cannot forbid 'u' everywhere (by adding the rejection code to check_name()), because the existing QKeyCode enum already uses it; therefore we only reserve it as a struct type member name. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1445898903-12082-24-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-02qapi: Start converting to new qapi union layoutEric Blake
We have two issues with our qapi union layout: 1) Even though the QMP wire format spells the tag 'type', the C code spells it 'kind', requiring some hacks in the generator. 2) The C struct uses an anonymous union, which places all tag values in the same namespace as all non-variant members. This leads to spurious collisions if a tag value matches a non-variant member's name. This patch is the front end for a series that converts to a saner qapi union layout. By the end of the series, we will no longer have the type/kind mismatch, and all tag values will be under a named union, which requires clients to access 'obj->u.value' instead of 'obj->value'. But since the conversion touches a number of files, it is easiest if we temporarily support BOTH layouts simultaneously. Given a simple union qapi type: { 'union':'Foo', 'data': { 'a':'int', 'b':'bool' } } make the following changes in generated qapi-types.h: | struct Foo { |- FooKind kind; |- union { /* union tag is @kind */ |+ union { |+ FooKind kind; |+ FooKind type; |+ }; |+ union { /* union tag is @type */ | void *data; | int64_t a; | bool b; |+ union { /* union tag is @type */ |+ void *data; |+ int64_t a; |+ bool b; |+ } u; | }; | }; Flat unions do not need the anonymous union for the tag member, as we already fixed that to use the member name instead of 'kind' back in commit 0f61af3e. One additional change is needed in qapi.py: check_union() now needs to check for collisions with 'type' in addition to those with 'kind'. Later, when the conversions are complete, we will remove the duplication hacks, and also drop the check_union() restrictions. Note, however, that we do not rename the generated enum, which is still 'FooKind'. A further patch could generate implicit enums as 'FooType', but while the generator already reserved the '*Kind' namespace (commit 4dc2e69), there are already QMP constructs with '*Type' naming, which means changing our reservation namespace would have lots of churn to C code to deal with a forced name change. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1445898903-12082-13-git-send-email-eblake@redhat.com> [Commit message tweaked slightly] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-02qapi: Reserve 'q_*' and 'has_*' member namesEric Blake
c_name() produces names starting with 'q_' when protecting a dictionary member name that would fail to directly compile, but in doing so can cause clashes with any member name already beginning with 'q-' or 'q_'. Likewise, we create a C name 'has_' for any optional member that can clash with any member name beginning with 'has-' or 'has_'. Technically, rather than blindly reserving the namespace, we could try to complain about user names only when an actual collision occurs, or even teach c_name() how to munge names to avoid collisions. But it is not trivial, especially when collisions can occur across multiple types (such as via inheritance or flat unions). Besides, no existing .json files are trying to use these names. So it's easier to just outright forbid the potential for collision. We can always relax things in the future if a real need arises for QMP to express member names that have been forbidden here. 'has_' only has to be reserved for struct/union member names, while 'q_' is reserved everywhere (matching the fact that only members can be optional, while we use c_name() for munging both members and entities). Note that we could relax 'q_' restrictions on entities independently from member names; for example, c_name('qmp_' + 'unix') would result in a different function name than our current 'qmp_' + c_name('unix'). Update and add tests to cover the new error messages. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1445898903-12082-6-git-send-email-eblake@redhat.com> [Consistently pass protect=False to c_name(); commit message tweaked slightly] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-02qapi: Reserve '*List' type names for list typesEric Blake
Type names ending in 'List' can clash with qapi list types in generated C. We don't currently use such names. It is easier to outlaw them now than to worry about how to resolve such a clash in the future. For precedence, see commit 4dc2e69, which did the same for names ending in 'Kind' versus implicit enum types for qapi unions. Update the testsuite to match. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1445898903-12082-5-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-02qapi: More idiomatic string operationsEric Blake
Rather than slicing the end of a string, we can use python's endswith(). And rather than creating a set of characters, we can search for a character within a string. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1445898903-12082-3-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-10-15qapi: Track location that created an implicit typeEric Blake
A future patch will move some error checking from the parser to the various QAPISchema*.check() methods, which run only after parsing completes. It will thus be possible to create a python instance representing an implicit QAPI type that parses fine but will fail validation during check(). Since all errors have to have an associated 'info' location, we need a location to be associated with those implicit types. The intuitive info to use is the location of the enclosing entity that caused the creation of the implicit type. Note that we do not anticipate builtin types being used in an error message (as they are not part of the user's QAPI input, the user can't cause a semantic error in their behavior), so we exempt those types from requiring info, by setting a flag to track the completion of _def_predefineds(), and tracking that flag in _def_entity(). No change to the generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1444710158-8723-13-git-send-email-eblake@redhat.com> [Missing QAPISchemaArrayType.is_implicit() supplied] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-10-15qapi: Create simple union type member earlierEric Blake
For simple unions, we were creating the implicit 'type' tag member during the QAPISchemaObjectTypeVariants constructor. This is different from every other implicit QAPISchemaEntity object, which get created by QAPISchema methods. Hoist the creation to the caller (renaming _make_tag_enum() to _make_implicit_tag()), and pass the entity rather than the string name, so that we have the nice property that no entities are created as a side effect within a different entity. A later patch will then have an easier time of associating location info with each entity creation. No change to generated code. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1444710158-8723-10-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-10-15qapi: Lazy creation of array typesEric Blake
Commit ac88219a had several TODO markers about whether we needed to automatically create the corresponding array type alongside any other type. It turns out that most of the time, we don't! There are a few exceptions: 1) We have a few situations where we use an array type in internal code but do not expose that type through QMP; fix it by declaring a dummy type that forces the generator to see that we want to use the array type. 2) The builtin arrays (such as intList for QAPI ['int']) must always be generated, because of the way our QAPI_TYPES_BUILTIN compile guard works: we have situations (at the very least tests/test-qmp-output-visitor.c) that include both top-level "qapi-types.h" (via "error.h") and a secondary "test-qapi-types.h". If we were to only emit the builtin types when used locally, then the first .h file would not include all types, but the second .h does not declare anything at all because the first .h set QAPI_TYPES_BUILTIN, and we would end up with compilation error due to things like unknown type 'int8List'. Actually, we may need to revisit how we do type guards, and change from a single QAPI_TYPES_BUILTIN over to a different usage pattern that does one #ifdef per qapi type - right now, the only types that are declared multiple times between two qapi .json files for inclusion by a single .c file happen to be the builtin arrays. But now that we have QAPI 'include' statements, it is logical to assume that we will soon reach a point where we want to reuse non-builtin types (yes, I'm thinking about what it will take to add introspection to QGA, where we will want to reuse the SchemaInfo type and friends). One #ifdef per type will help ensure that generating the same qapi type into more than one qapi-types.h won't cause collisions when both are included in the same .c file; but we also have to solve how to avoid creating duplicate qapi-types.c entry points. So that is a problem left for another day. Generated code for qapi-types and qapi-visit is drastically reduced; less than a third of the arrays that were blindly created were actually needed (a quick grep shows we dropped from 219 to 69 *List types), and the .o files lost more than 30% of their bulk. [For best results, diff the generated files with 'git diff --patience --no-index pre post'.] Interestingly, the introspection output is unchanged - this is because we already cull all types that are not indirectly reachable from a command or event, so introspection was already using only a subset of array types. The subset of types introspected is now a much larger percentage of the overall set of array types emitted in qapi-types.h (since the larger set shrunk), but still not 100% (evidence that the array types emitted for our new Dummy structs, and the new struct itself, don't affect QMP). Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1444710158-8723-9-git-send-email-eblake@redhat.com> [Moved array info tracking to a later patch] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-10-15qapi: Don't use info as witness of implicit object typeEric Blake
A future patch will enable error reporting from the various QAPISchema*.check() methods. But to report an error related to an implicit type, we'll need to associate a location with the type (the same location as the top-level entity that is causing the creation of the implicit type), and once we do that, keying off of whether foo.info exists is no longer a viable way to determine if foo is an implicit type. Instead, add an is_implicit() method to QAPISchemaEntity, and use it. It can be overridden later for ObjectType and EnumType, when implicit instances of those classes gain info. Signed-off-by: Eric Blake <eblake@redhat.com> Message-Id: <1444710158-8723-8-git-send-email-eblake@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>