qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v6 07/12] qapi: Detect collisions in C member na


From: Markus Armbruster
Subject: Re: [Qemu-devel] [PATCH v6 07/12] qapi: Detect collisions in C member names
Date: Fri, 02 Oct 2015 19:11:56 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Eric Blake <address@hidden> writes:

> On 10/02/2015 07:19 AM, Markus Armbruster wrote:
>> Eric Blake <address@hidden> writes:
>> 
>>> 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.  Doing this was made
>>> easier by adding a member.c_name() helper function.
>> 
>> This gains protection against colliding C names.  It keeps protection
>> against colliding QMP names as long as QMP name collision implies C name
>> collision.  I think that's the case, but it's definitely worth spelling
>> out in the code, and possibly in the commit message.
>> 
>>> As this is the first error raised within the QAPISchema*.check()
>>> methods, we also have to pass 'info' through the call stack, and
>>> fix the overall 'try' to display errors detected during the
>>> check() phase.
>> 
>> Could also be a separate patch, if the parts are easier to review.
>
> I'm still debating about that.
>
>
>>> +    def check(self, schema, info, all_members, seen):
>>> +        if self.c_name() in seen:
>>> +            raise QAPIExprError(info,
>>> +                                "%s collides with %s"
>>> +                                % (self.describe(),
>>> +                                   seen[self.c_name()].describe()))
>>>          self.type = schema.lookup_type(self._type_name)
>>>          assert self.type
>>>          all_members.append(self)
>>> -        seen[self.name] = self
>>> +        seen[self.c_name()] = self
>>> +
>>> +    def c_name(self):
>>> +        return c_name(self.name)
>> 
>> Why wrap function c_name() in a method?  Why not simply call the
>> function?
>
> 'self.c_name()' is shorter than 'c_name(self.name)'.  And I already had
> long lines with that seen[self.c_name()].describe() pattern.

You could also try a local variable: cnam = c_name(self.name).

>> It's method in QAPISchemaEntity only because this lets us add special
>> cases in a neat way.
>
> True, but I _did_ mention in the commit message that I did it for less
> typing.
>
> But as to special cases, yes, I have one in mind (although I have not
> played with it yet).  In v5 19/46 Simplify visiting of alternate types,
> I want to change alternates to have variants.tag_member == None, and the
> generated C code to use 'qtype_code type;' as the tag variable.  In the
> v5 representation, it led to a lot of special-casing (many uses of
> QAPISchemaObjectTypeVariants became more complex because tag_member was
> not always defined).  But now that I've been working on these front-end
> patches, my idea was to do something like:
>
> class QAPISchemaVariantTag(QAPISchemaObjectTypeMember):
>     def __init__(self, info):
>         QAPISchemaObjectTypeMember(self, 'type', None, False)
>
>     def c_type(self):
>         return 'qtype_code'
>
> and then, we WOULD need member.c_type() rather than member.type.c_type()
> (at which point having member.c_name() to match member.c_type() makes
> more sense).

I'm afraid I don't have enough context to grok this late on Friday :)

>>> @@ -1028,23 +1037,24 @@ class QAPISchemaObjectTypeVariants(object):
>>>          self.tag_member = tag_member
>>>          self.variants = variants
>>>
>>> -    def check(self, schema, members, seen):
>>> +    def check(self, schema, info, members, seen):
>>>          if self.tag_name:
>>> -            self.tag_member = seen[self.tag_name]
>>> +            self.tag_member = seen[c_name(self.tag_name)]
>>> +            assert self.tag_name == self.tag_member.name
>> 
>> Assertion should hold before the patch, but it's kind of trivial then.
>
> My worry here was that if I have:
>
> { 'enum': 'Enum', 'data': ['a'] }
> { 'base': 'Base', 'data': { 'b-c': 'Enum' } }
> { 'union': 'Flat', 'base': 'Base', 'discriminator': 'b_c',
>   'data': { 'a': 'Struct...' } }
>
> the old ad hoc parser rejects 'b_c' as not being a member of Enum (bad
> discriminator).  But once we convert from the old parser to the check()
> method (basically, anywhere the check() methods now have an assert will
> become if statements that raise an exception), we need to make sure that
> we don't get confused by the fact that seen[c_name('b_c')] maps to the
> same value as seen[c_name('b-c')], so that we are still flagging the
> flat union as invalid.

I had already flagged a few assertions as "holds before the patch" when
I got here, and felt an urge to flag this one, too, for completeness.  I
don't object to you adding the assertion.

>> I'm fine with not splitting this patch.  I'd be also fine with splitting
>> it up.  Your choice.
>
> I'm still thinking about it; may depend on how much other refactoring I do.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]