qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PULL v2 06/25] qapi: Reserve 'q_*' and 'has_*' member names
Date: Mon,  2 Nov 2015 10:13:11 +0100	[thread overview]
Message-ID: <1446455610-15739-7-git-send-email-armbru@redhat.com> (raw)
In-Reply-To: <1446455610-15739-1-git-send-email-armbru@redhat.com>

From: Eric Blake <eblake@redhat.com>

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>
---
 docs/qapi-code-gen.txt                     | 11 +++++++----
 scripts/qapi.py                            |  8 +++++++-
 tests/qapi-schema/reserved-command-q.err   |  1 +
 tests/qapi-schema/reserved-command-q.exit  |  2 +-
 tests/qapi-schema/reserved-command-q.json  |  6 ++----
 tests/qapi-schema/reserved-command-q.out   |  5 -----
 tests/qapi-schema/reserved-member-has.err  |  1 +
 tests/qapi-schema/reserved-member-has.exit |  2 +-
 tests/qapi-schema/reserved-member-has.json |  7 +++----
 tests/qapi-schema/reserved-member-has.out  |  6 ------
 tests/qapi-schema/reserved-member-q.err    |  1 +
 tests/qapi-schema/reserved-member-q.exit   |  2 +-
 tests/qapi-schema/reserved-member-q.json   |  6 ++----
 tests/qapi-schema/reserved-member-q.out    |  4 ----
 14 files changed, 27 insertions(+), 35 deletions(-)

diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index c4264a8..4d8c2fc 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -112,7 +112,9 @@ and field names within a type, should be all lower case with words
 separated by a hyphen.  However, some existing older commands and
 complex types use underscore; when extending such expressions,
 consistency is preferred over blindly avoiding underscore.  Event
-names should be ALL_CAPS with words separated by underscore.
+names should be ALL_CAPS with words separated by underscore.  Field
+names cannot start with 'has-' or 'has_', as this is reserved for
+tracking optional fields.
 
 Any name (command, event, type, field, or enum value) beginning with
 "x-" is marked experimental, and may be withdrawn or changed
@@ -123,9 +125,10 @@ vendor), even if the rest of the name uses dash (example:
 __com.redhat_drive-mirror).  Other than downstream extensions (with
 leading underscore and the use of dots), all names should begin with a
 letter, and contain only ASCII letters, digits, dash, and underscore.
-It is okay to reuse names that match C keywords; the generator will
-rename a field named "default" in the QAPI to "q_default" in the
-generated C code.
+Names beginning with 'q_' are reserved for the generator: QMP names
+that resemble C keywords or other problematic strings will be munged
+in C to use this prefix.  For example, a field named "default" in
+qapi becomes "q_default" in the generated C code.
 
 In the rest of this document, usage lines are given for each
 expression type, with literal strings written in lower case and
diff --git a/scripts/qapi.py b/scripts/qapi.py
index d53b5c4..3ff7b11 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -376,7 +376,9 @@ def check_name(expr_info, source, name, allow_optional=False,
     # code always prefixes it with the enum name
     if enum_member:
         membername = '_' + membername
-    if not valid_name.match(membername):
+    # Reserve the entire 'q_' namespace for c_name()
+    if not valid_name.match(membername) or \
+       c_name(membername, False).startswith('q_'):
         raise QAPIExprError(expr_info,
                             "%s uses invalid name '%s'" % (source, name))
 
@@ -488,6 +490,10 @@ def check_type(expr_info, source, value, allow_array=False,
     for (key, arg) in value.items():
         check_name(expr_info, "Member of %s" % source, key,
                    allow_optional=allow_optional)
+        if c_name(key, False).startswith('has_'):
+            raise QAPIExprError(expr_info,
+                                "Member of %s uses reserved name '%s'"
+                                % (source, key))
         # Todo: allow dictionaries to represent default values of
         # an optional argument.
         check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
diff --git a/tests/qapi-schema/reserved-command-q.err b/tests/qapi-schema/reserved-command-q.err
index e69de29..f939e04 100644
--- a/tests/qapi-schema/reserved-command-q.err
+++ b/tests/qapi-schema/reserved-command-q.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix'
diff --git a/tests/qapi-schema/reserved-command-q.exit b/tests/qapi-schema/reserved-command-q.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/reserved-command-q.exit
+++ b/tests/qapi-schema/reserved-command-q.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/reserved-command-q.json b/tests/qapi-schema/reserved-command-q.json
index be9944c..99f8aae 100644
--- a/tests/qapi-schema/reserved-command-q.json
+++ b/tests/qapi-schema/reserved-command-q.json
@@ -1,7 +1,5 @@
 # C entity name collision
-# FIXME - This parses, but fails to compile, because it attempts to declare
-# two 'qmp_q_unix' functions (one for 'q-unix', the other because c_name()
-# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
-# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
+# We reject names like 'q-unix', because they can collide with the mangled
+# name for 'unix' in generated C.
 { 'command': 'unix' }
 { 'command': 'q-unix' }
diff --git a/tests/qapi-schema/reserved-command-q.out b/tests/qapi-schema/reserved-command-q.out
index b31b38f..e69de29 100644
--- a/tests/qapi-schema/reserved-command-q.out
+++ b/tests/qapi-schema/reserved-command-q.out
@@ -1,5 +0,0 @@
-object :empty
-command q-unix None -> None
-   gen=True success_response=True
-command unix None -> None
-   gen=True success_response=True
diff --git a/tests/qapi-schema/reserved-member-has.err b/tests/qapi-schema/reserved-member-has.err
index e69de29..e755771 100644
--- a/tests/qapi-schema/reserved-member-has.err
+++ b/tests/qapi-schema/reserved-member-has.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a'
diff --git a/tests/qapi-schema/reserved-member-has.exit b/tests/qapi-schema/reserved-member-has.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/reserved-member-has.exit
+++ b/tests/qapi-schema/reserved-member-has.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/reserved-member-has.json b/tests/qapi-schema/reserved-member-has.json
index a2197de..45b9109 100644
--- a/tests/qapi-schema/reserved-member-has.json
+++ b/tests/qapi-schema/reserved-member-has.json
@@ -1,6 +1,5 @@
 # C member name collision
-# FIXME - This parses, but fails to compile, because the C struct is given
-# two 'has_a' members, one from the flag for optional 'a', and the other
-# from member 'has-a'.  Either reject this at parse time, or munge the C
-# names to avoid the collision.
+# We reject names like 'has-a', because they can collide with the flag
+# for an optional 'a' in generated C.
+# TODO we could munge the optional flag name to avoid the collision.
 { 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } }
diff --git a/tests/qapi-schema/reserved-member-has.out b/tests/qapi-schema/reserved-member-has.out
index 5a18b6b..e69de29 100644
--- a/tests/qapi-schema/reserved-member-has.out
+++ b/tests/qapi-schema/reserved-member-has.out
@@ -1,6 +0,0 @@
-object :empty
-object :obj-oops-arg
-    member a: str optional=True
-    member has-a: str optional=False
-command oops :obj-oops-arg -> None
-   gen=True success_response=True
diff --git a/tests/qapi-schema/reserved-member-q.err b/tests/qapi-schema/reserved-member-q.err
index e69de29..f3d5dd7 100644
--- a/tests/qapi-schema/reserved-member-q.err
+++ b/tests/qapi-schema/reserved-member-q.err
@@ -0,0 +1 @@
+tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix'
diff --git a/tests/qapi-schema/reserved-member-q.exit b/tests/qapi-schema/reserved-member-q.exit
index 573541a..d00491f 100644
--- a/tests/qapi-schema/reserved-member-q.exit
+++ b/tests/qapi-schema/reserved-member-q.exit
@@ -1 +1 @@
-0
+1
diff --git a/tests/qapi-schema/reserved-member-q.json b/tests/qapi-schema/reserved-member-q.json
index 1602ed3..62fed8f 100644
--- a/tests/qapi-schema/reserved-member-q.json
+++ b/tests/qapi-schema/reserved-member-q.json
@@ -1,6 +1,4 @@
 # C member name collision
-# FIXME - This parses, but fails to compile, because it attempts to declare
-# two 'q_unix' members (one for 'q-unix', the other because c_name()
-# munges 'unix' to 'q_unix' to avoid reserved word collisions). We should
-# reject attempts to explicitly use 'q_' names, to reserve it for qapi.
+# We reject names like 'q-unix', because they can collide with the mangled
+# name for 'unix' in generated C.
 { 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } }
diff --git a/tests/qapi-schema/reserved-member-q.out b/tests/qapi-schema/reserved-member-q.out
index 0d8685a..e69de29 100644
--- a/tests/qapi-schema/reserved-member-q.out
+++ b/tests/qapi-schema/reserved-member-q.out
@@ -1,4 +0,0 @@
-object :empty
-object Foo
-    member unix: int optional=False
-    member q-unix: bool optional=False
-- 
2.4.3

  parent reply	other threads:[~2015-11-02  9:13 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-02  9:13 [Qemu-devel] [PULL v2 00/25] QAPI patches Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 01/25] qapi-schema: mark InetSocketAddress as mandatory again Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 02/25] tests/qapi-schema: Test for reserved names, empty struct Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 03/25] qapi: More idiomatic string operations Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 04/25] qapi: More robust conditions for when labels are needed Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 05/25] qapi: Reserve '*List' type names for list types Markus Armbruster
2015-11-02  9:13 ` Markus Armbruster [this message]
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 07/25] vnc: Hoist allocation of VncBasicInfo to callers Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 08/25] qapi-visit: Split off visit_type_FOO_fields forward decl Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 09/25] qapi-types: Refactor base fields output Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 10/25] qapi: Prefer typesafe upcasts to qapi base classes Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 11/25] qapi: Unbox base members Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 12/25] qapi-visit: Remove redundant functions for flat union base Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 13/25] qapi: Start converting to new qapi union layout Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 14/25] qapi-visit: Convert " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 15/25] tests: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 16/25] block: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 17/25] sockets: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 18/25] net: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 19/25] char: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 20/25] input: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 21/25] memory: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 22/25] tpm: " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 23/25] qapi: Finish converting " Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 24/25] qapi: Reserve 'u' member name Markus Armbruster
2015-11-02  9:13 ` [Qemu-devel] [PULL v2 25/25] qapi: Simplify gen_struct_field() Markus Armbruster
2015-11-02 12:02 ` [Qemu-devel] [PULL v2 00/25] QAPI patches Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1446455610-15739-7-git-send-email-armbru@redhat.com \
    --to=armbru@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).