forked from mirrors/gecko-dev
Bug 1895261 - Only generate an equality operator for WebIDL dictionaries when they have a [GenerateEqualityOperator] extended attribute. r=farre
This also extends the check for supported types to the types of inherited members, and automatically generates an equality operator in the base classes if needed. It also deletes the equality operator if a dictionary doesn't need one but its parent does. Differential Revision: https://phabricator.services.mozilla.com/D210846
This commit is contained in:
parent
4f5ef67dd3
commit
b6e624e324
4 changed files with 159 additions and 14 deletions
|
|
@ -13629,12 +13629,14 @@ class ClassMethod(ClassItem):
|
|||
override=False,
|
||||
canRunScript=False,
|
||||
noDiscard=False,
|
||||
delete=False,
|
||||
):
|
||||
"""
|
||||
override indicates whether to flag the method as override
|
||||
"""
|
||||
assert not override or virtual
|
||||
assert not (override and static)
|
||||
assert not (delete and body)
|
||||
self.returnType = returnType
|
||||
self.args = args
|
||||
self.inline = inline or bodyInHeader
|
||||
|
|
@ -13649,6 +13651,7 @@ class ClassMethod(ClassItem):
|
|||
self.override = override
|
||||
self.canRunScript = canRunScript
|
||||
self.noDiscard = noDiscard
|
||||
self.delete = delete
|
||||
ClassItem.__init__(self, name, visibility)
|
||||
|
||||
def getDecorators(self, declaring):
|
||||
|
|
@ -13680,7 +13683,9 @@ class ClassMethod(ClassItem):
|
|||
else ""
|
||||
)
|
||||
args = ", ".join([a.declare() for a in self.args])
|
||||
if self.bodyInHeader:
|
||||
if self.delete:
|
||||
body = " = delete;\n"
|
||||
elif self.bodyInHeader:
|
||||
body = indent(self.getBody())
|
||||
body = "\n{\n" + body + "}\n"
|
||||
else:
|
||||
|
|
@ -13703,7 +13708,7 @@ class ClassMethod(ClassItem):
|
|||
)
|
||||
|
||||
def define(self, cgClass):
|
||||
if self.bodyInHeader:
|
||||
if self.delete or self.bodyInHeader:
|
||||
return ""
|
||||
|
||||
templateArgs = cgClass.templateArgs
|
||||
|
|
@ -17691,23 +17696,48 @@ class CGDictionary(CGThing):
|
|||
body=body.define(),
|
||||
)
|
||||
|
||||
def canHaveEqualsOperator(self):
|
||||
return all(
|
||||
m.type.isString() or m.type.isPrimitive() for (m, _) in self.memberInfo
|
||||
)
|
||||
def equalityOperator(self):
|
||||
# For now we only allow equality operators if our members have a string
|
||||
# type, a primitive type or an enum type.
|
||||
if not all(
|
||||
m.type.isString() or m.type.isPrimitive() or m.type.isEnum()
|
||||
for m in self.dictionary.members
|
||||
):
|
||||
err = (
|
||||
"[GenerateEqualityOperator] set on %s, but it"
|
||||
% self.dictionary.needsEqualityOperator.identifier.name
|
||||
)
|
||||
if self.dictionary.needsEqualityOperator != self.dictionary:
|
||||
err += "s ancestor %s" % self.dictionary.identifier.name
|
||||
err += " contains types other than string, primitive or enum types."
|
||||
raise TypeError(err)
|
||||
|
||||
def equalsOperator(self):
|
||||
body = CGList([])
|
||||
|
||||
if self.dictionary.parent:
|
||||
# If we have a parent dictionary we have to call its equals
|
||||
# operator.
|
||||
parentTest = CGGeneric(
|
||||
fill(
|
||||
"""
|
||||
if (!${base}::operator==(aOther)) {
|
||||
return false;
|
||||
}
|
||||
""",
|
||||
base=self.makeClassName(self.dictionary.parent),
|
||||
)
|
||||
)
|
||||
body.append(parentTest)
|
||||
|
||||
for m, _ in self.memberInfo:
|
||||
memberName = self.makeMemberName(m.identifier.name)
|
||||
memberTest = CGGeneric(
|
||||
fill(
|
||||
"""
|
||||
if (${memberName} != aOther.${memberName}) {
|
||||
return false;
|
||||
}
|
||||
""",
|
||||
if (${memberName} != aOther.${memberName}) {
|
||||
return false;
|
||||
}
|
||||
""",
|
||||
memberName=memberName,
|
||||
)
|
||||
)
|
||||
|
|
@ -17829,8 +17859,22 @@ class CGDictionary(CGThing):
|
|||
else:
|
||||
disallowCopyConstruction = True
|
||||
|
||||
if self.canHaveEqualsOperator():
|
||||
methods.append(self.equalsOperator())
|
||||
if d.needsEqualityOperator:
|
||||
methods.append(self.equalityOperator())
|
||||
elif d.parent and d.parent.needsEqualityOperator:
|
||||
methods.append(
|
||||
ClassMethod(
|
||||
"operator==",
|
||||
"bool",
|
||||
[
|
||||
Argument(
|
||||
"const %s&" % self.makeClassName(self.dictionary), "aOther"
|
||||
)
|
||||
],
|
||||
visibility="public",
|
||||
delete=True,
|
||||
)
|
||||
)
|
||||
|
||||
struct = CGClass(
|
||||
selfName,
|
||||
|
|
|
|||
|
|
@ -2232,6 +2232,7 @@ class IDLDictionary(IDLObjectWithScope):
|
|||
"_extendedAttrDict",
|
||||
"needsConversionToJS",
|
||||
"needsConversionFromJS",
|
||||
"needsEqualityOperator",
|
||||
)
|
||||
|
||||
def __init__(self, location, parentScope, name, parent, members):
|
||||
|
|
@ -2246,6 +2247,7 @@ class IDLDictionary(IDLObjectWithScope):
|
|||
self._extendedAttrDict = {}
|
||||
self.needsConversionToJS = False
|
||||
self.needsConversionFromJS = False
|
||||
self.needsEqualityOperator = None
|
||||
|
||||
IDLObjectWithScope.__init__(self, location, parentScope, name)
|
||||
|
||||
|
|
@ -2310,6 +2312,14 @@ class IDLDictionary(IDLObjectWithScope):
|
|||
[self.identifier.location],
|
||||
)
|
||||
inheritedMembers.extend(ancestor.members)
|
||||
if (
|
||||
self.getExtendedAttribute("GenerateEqualityOperator")
|
||||
and ancestor.needsEqualityOperator is None
|
||||
):
|
||||
# Store the dictionary that has the [GenerateEqualityOperator]
|
||||
# extended attribute, so we can use it when generating error
|
||||
# messages.
|
||||
ancestor.needsEqualityOperator = self
|
||||
ancestor = ancestor.parent
|
||||
|
||||
# Catch name duplication
|
||||
|
|
@ -2435,6 +2445,13 @@ class IDLDictionary(IDLObjectWithScope):
|
|||
# implement ToJSON by converting to a JS object and
|
||||
# then using JSON.stringify.
|
||||
self.needsConversionToJS = True
|
||||
elif identifier == "GenerateEqualityOperator":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError(
|
||||
"[GenerateEqualityOperator] must take no arguments",
|
||||
[attr.location],
|
||||
)
|
||||
self.needsEqualityOperator = self
|
||||
elif identifier == "Unsorted":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError(
|
||||
|
|
|
|||
|
|
@ -933,7 +933,7 @@ dictionary ParentProcInfoDictionary {
|
|||
* serialization, deserialization, and inheritance.
|
||||
* (3) Update the methods on mozilla::OriginAttributesPattern, including matching.
|
||||
*/
|
||||
[GenerateInitFromJSON]
|
||||
[GenerateInitFromJSON, GenerateEqualityOperator]
|
||||
dictionary OriginAttributesDictionary {
|
||||
unsigned long userContextId = 0;
|
||||
unsigned long privateBrowsingId = 0;
|
||||
|
|
|
|||
|
|
@ -1903,6 +1903,90 @@ worker involved is a `ChromeWorker` or not. At the moment the only
|
|||
possible caller types are `System` (representing system-principal
|
||||
callers) and `NonSystem`.
|
||||
|
||||
### `[GenerateInit]`
|
||||
|
||||
When set on a dictionary it will add two `Init` methods to the generated C++
|
||||
class with the following signatures:
|
||||
|
||||
``` cpp
|
||||
bool Init(BindingCallContext& cx, JS::Handle<JS::Value> val, const char* sourceDescription="Value", bool passedToJSImpl=false);
|
||||
bool Init(JSContext* cx_, JS::Handle<JS::Value> val, const char* sourceDescription="Value", bool passedToJSImpl=false);
|
||||
```
|
||||
|
||||
These methods will initialize the dictionary from `val` by following WebIDL's
|
||||
[JavaScript type mapping](https://webidl.spec.whatwg.org/#js-dictionary).
|
||||
|
||||
### `[GenerateInitFromJSON]`
|
||||
|
||||
When set on a dictionary it will add an `Init` method to the generated C++
|
||||
class with the following signature:
|
||||
|
||||
``` cpp
|
||||
bool Init(const nsAString& aJSON);
|
||||
```
|
||||
|
||||
This extended attribute will only have an effect if all of the types of the
|
||||
dictionary's members are representable in JSON (they are a string type, a
|
||||
primitive type that's not an unrestricted float/double, a void type, or a
|
||||
sequence, union, dictionary or record containing these types).
|
||||
|
||||
The method is expected to be called with a JSON string as input. The JSON string
|
||||
will be parsed into a JavaScript value, and then the dictionary is initialized
|
||||
with this value by following WebIDL's
|
||||
[JavaScript type mapping](https://webidl.spec.whatwg.org/#js-dictionary).
|
||||
|
||||
Note: As a side-effect of how this is implemented it will also add the two
|
||||
`Init` methods that would be added by a [`[GenerateInit]`](#generateinit)
|
||||
extended attribute.
|
||||
|
||||
### `[GenerateToJSON]`
|
||||
|
||||
When set on a dictionary it will add a `ToJSON` method to the generated C++
|
||||
class with the following signature:
|
||||
|
||||
``` cpp
|
||||
bool ToJSON(nsAString& aJSON);
|
||||
```
|
||||
|
||||
The method will generate a JSON representation of the dictionary members' values
|
||||
in `aJSON` by converting the dictionary to a JavaScript object by following
|
||||
WebIDL's [JavaScript type mapping](https://webidl.spec.whatwg.org/#js-dictionary)
|
||||
and then converting that object to a JSON string.
|
||||
|
||||
The same restrictions on types applies as on
|
||||
[`[GenerateInitFromJSON]`](#generateinitfromjson).
|
||||
|
||||
Note: As a side-effect of how this is implemented it will also add the
|
||||
`ToObjectInternal` method that would be added by a
|
||||
[`[GenerateConversionToJS]`](#generateconversiontojs) extended attribute.
|
||||
|
||||
### `[GenerateConversionToJS]`
|
||||
|
||||
When set on a dictionary it will add a `ToObjectInternal` method to the
|
||||
generated C++ class with the following signature:
|
||||
|
||||
``` cpp
|
||||
bool ToObjectInternal(JSContext* cx, JS::MutableHandle<JS::Value> rval);
|
||||
```
|
||||
|
||||
The method will create a JavaScript object by following WebIDL's
|
||||
[JavaScript type mapping](https://webidl.spec.whatwg.org/#js-dictionary).
|
||||
|
||||
### `[GenerateEqualityOperator]`
|
||||
|
||||
When set on a dictionary it will add an equality operator to the generated C++
|
||||
class.
|
||||
|
||||
This is only allowed on dictionaries who only have members (own or inherited)
|
||||
with string, primitive or enum types.
|
||||
|
||||
### `[Unsorted]`
|
||||
|
||||
When set on a dictionary the dictionary's members will not be sorted in
|
||||
lexicographic order (which is specified by WebIDL).
|
||||
|
||||
This should only ever be used on internal APIs that are not exposed to the Web!
|
||||
|
||||
## Helper objects
|
||||
|
||||
The C++ side of the bindings uses a number of helper objects.
|
||||
|
|
|
|||
Loading…
Reference in a new issue