Bug 1268798 part 3 - Add LenientSetter extended attribute. r?khuey
MozReview-Commit-ID: 61wybyS36KE
--- a/dom/base/nsDeprecatedOperationList.h
+++ b/dom/base/nsDeprecatedOperationList.h
@@ -39,8 +39,9 @@ DEPRECATED_OPERATION(SyncXMLHttpRequest)
DEPRECATED_OPERATION(DataContainerEvent)
DEPRECATED_OPERATION(Window_Controllers)
DEPRECATED_OPERATION(ImportXULIntoContent)
DEPRECATED_OPERATION(PannerNodeDoppler)
DEPRECATED_OPERATION(NavigatorGetUserMedia)
DEPRECATED_OPERATION(WebrtcDeprecatedPrefix)
DEPRECATED_OPERATION(AppCache)
DEPRECATED_OPERATION(PrefixedFullscreenAPI)
+DEPRECATED_OPERATION(LenientSetter)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2543,17 +2543,18 @@ class AttrDefiner(PropertyDefiner):
jitinfo = ("&%s_getterinfo" %
IDLToCIdentifier(attr.identifier.name))
return "{ { %s, %s } }" % \
(accessor, jitinfo)
def setter(attr):
if (attr.readonly and
attr.getExtendedAttribute("PutForwards") is None and
- attr.getExtendedAttribute("Replaceable") is None):
+ attr.getExtendedAttribute("Replaceable") is None and
+ attr.getExtendedAttribute("LenientSetter") is None):
return "JSNATIVE_WRAPPER(nullptr)"
if self.static:
accessor = 'set_' + IDLToCIdentifier(attr.identifier.name)
jitinfo = "nullptr"
else:
if attr.hasLenientThis():
accessor = "genericLenientSetter"
elif IsCrossOriginWritable(attr, self.descriptor):
@@ -8827,16 +8828,34 @@ class CGSpecializedReplaceableSetter(CGS
def definition_body(self):
attrName = self.attr.identifier.name
# JS_DefineProperty can only deal with ASCII
assert all(ord(c) < 128 for c in attrName)
return ('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' %
attrName)
+class CGSpecializedLenientSetter(CGSpecializedSetter):
+ """
+ A class for generating the code for a specialized attribute setter with
+ LenientSetter that the JIT can call with lower overhead.
+ """
+ def __init__(self, descriptor, attr):
+ CGSpecializedSetter.__init__(self, descriptor, attr)
+
+ def definition_body(self):
+ attrName = self.attr.identifier.name
+ # JS_DefineProperty can only deal with ASCII
+ assert all(ord(c) < 128 for c in attrName)
+ return dedent("""
+ DeprecationWarning(cx, obj, nsIDocument::eLenientSetter);
+ return true;
+ """)
+
+
def memberReturnsNewObject(member):
return member.getExtendedAttribute("NewObject") is not None
class CGMemberJITInfo(CGThing):
"""
A class for generating the JITInfo for a property that points to
our specialized getter and setter.
@@ -8964,17 +8983,18 @@ class CGMemberJITInfo(CGThing):
result = self.defineJitInfo(getterinfo, getter, "Getter",
getterinfal, movable, eliminatable,
aliasSet, isAlwaysInSlot,
isLazilyCachedInSlot, slotIndex,
[self.member.type], None)
if (not self.member.readonly or
self.member.getExtendedAttribute("PutForwards") is not None or
- self.member.getExtendedAttribute("Replaceable") is not None):
+ self.member.getExtendedAttribute("Replaceable") is not None or
+ self.member.getExtendedAttribute("LenientSetter") is not None):
setterinfo = ("%s_setterinfo" %
IDLToCIdentifier(self.member.identifier.name))
# Actually a JSJitSetterOp, but JSJitGetterOp is first in the
# union.
setter = ("(JSJitGetterOp)set_%s" %
IDLToCIdentifier(self.member.identifier.name))
# Setters are always fallible, since they have to do a typed unwrap.
result += self.defineJitInfo(setterinfo, setter, "Setter",
@@ -11834,17 +11854,18 @@ def memberProperties(m, descriptor):
props.isCrossOriginSetter = True
elif descriptor.needsSpecialGenericOps():
props.isGenericSetter = True
elif m.getExtendedAttribute("PutForwards"):
if IsCrossOriginWritable(m, descriptor):
props.isCrossOriginSetter = True
elif descriptor.needsSpecialGenericOps():
props.isGenericSetter = True
- elif m.getExtendedAttribute("Replaceable"):
+ elif (m.getExtendedAttribute("Replaceable") or
+ m.getExtendedAttribute("LenientSetter")):
if descriptor.needsSpecialGenericOps():
props.isGenericSetter = True
return props
class CGDescriptor(CGThing):
def __init__(self, descriptor):
@@ -11946,16 +11967,18 @@ class CGDescriptor(CGThing):
if props.isCrossOriginSetter:
crossOriginSetters.add(m.identifier.name)
elif m.getExtendedAttribute("PutForwards"):
cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
if props.isCrossOriginSetter:
crossOriginSetters.add(m.identifier.name)
elif m.getExtendedAttribute("Replaceable"):
cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
+ elif m.getExtendedAttribute("LenientSetter"):
+ cgThings.append(CGSpecializedLenientSetter(descriptor, m))
if (not m.isStatic() and
descriptor.interface.hasInterfacePrototypeObject()):
cgThings.append(CGMemberJITInfo(descriptor, m))
hasMethod = hasMethod or props.isGenericMethod
hasPromiseReturningMethod = (hasPromiseReturningMethod or
props.isPromiseReturningMethod)
hasGetter = hasGetter or props.isGenericGetter
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -4057,16 +4057,34 @@ class IDLAttribute(IDLInterfaceMember):
"attributes", [attr.location, self.location])
if self.isStatic():
raise WebIDLError("[Replaceable] is only allowed on non-static "
"attributes", [attr.location, self.location])
if self.getExtendedAttribute("PutForwards") is not None:
raise WebIDLError("[PutForwards] and [Replaceable] can't both "
"appear on the same attribute",
[attr.location, self.location])
+ elif identifier == "LenientSetter":
+ if not attr.noArguments():
+ raise WebIDLError("[LenientSetter] must take no arguments",
+ [attr.location])
+ if not self.readonly:
+ raise WebIDLError("[LenientSetter] is only allowed on readonly "
+ "attributes", [attr.location, self.location])
+ if self.isStatic():
+ raise WebIDLError("[LenientSetter] is only allowed on non-static "
+ "attributes", [attr.location, self.location])
+ if self.getExtendedAttribute("PutForwards") is not None:
+ raise WebIDLError("[LenientSetter] and [PutForwards] can't both "
+ "appear on the same attribute",
+ [attr.location, self.location])
+ if self.getExtendedAttribute("Replaceable") is not None:
+ raise WebIDLError("[LenientSetter] and [Replaceable] can't both "
+ "appear on the same attribute",
+ [attr.location, self.location])
elif identifier == "LenientFloat":
if self.readonly:
raise WebIDLError("[LenientFloat] used on a readonly attribute",
[attr.location, self.location])
if not self.type.includesRestrictedFloat():
raise WebIDLError("[LenientFloat] used on an attribute with a "
"non-restricted-float type",
[attr.location, self.location])
@@ -4795,16 +4813,19 @@ class IDLMethod(IDLInterfaceMember, IDLS
raise WebIDLError("Methods must not be flagged as [SameObject]",
[attr.location, self.location])
elif identifier == "Constant":
raise WebIDLError("Methods must not be flagged as [Constant]",
[attr.location, self.location])
elif identifier == "PutForwards":
raise WebIDLError("Only attributes support [PutForwards]",
[attr.location, self.location])
+ elif identifier == "LenientSetter":
+ raise WebIDLError("Only attributes support [LenientSetter]",
+ [attr.location, self.location])
elif identifier == "LenientFloat":
# This is called before we've done overload resolution
assert len(self.signatures()) == 1
sig = self.signatures()[0]
if not sig[0].isVoid():
raise WebIDLError("[LenientFloat] used on a non-void method",
[attr.location, self.location])
if not any(arg.type.includesRestrictedFloat() for arg in sig[1]):
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_lenientSetter.py
@@ -0,0 +1,58 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+def should_throw(parser, harness, message, code):
+ parser = parser.reset();
+ threw = False
+ try:
+ parser.parse(code)
+ parser.finish()
+ except:
+ threw = True
+
+ harness.ok(threw, "Should have thrown: %s" % message)
+
+
+def WebIDLTest(parser, harness):
+ # The [LenientSetter] extended attribute MUST take no arguments.
+ should_throw(parser, harness, "no arguments", """
+ interface I {
+ [LenientSetter=X] readonly attribute long A;
+ };
+ """)
+
+ # An attribute with the [LenientSetter] extended attribute MUST NOT
+ # also be declared with the [PutForwards] extended attribute.
+ should_throw(parser, harness, "PutForwards", """
+ interface I {
+ [PutForwards=B, LenientSetter] readonly attribute J A;
+ };
+ interface J {
+ attribute long B;
+ };
+ """)
+
+ # An attribute with the [LenientSetter] extended attribute MUST NOT
+ # also be declared with the [Replaceable] extended attribute.
+ should_throw(parser, harness, "Replaceable", """
+ interface I {
+ [Replaceable, LenientSetter] readonly attribute J A;
+ };
+ """)
+
+ # The [LenientSetter] extended attribute MUST NOT be used on an
+ # attribute that is not read only.
+ should_throw(parser, harness, "writable attribute", """
+ interface I {
+ [LenientSetter] attribute long A;
+ };
+ """)
+
+ # The [LenientSetter] extended attribute MUST NOT be used on a
+ # static attribute.
+ should_throw(parser, harness, "static attribute", """
+ interface I {
+ [LenientSetter] static readonly attribute long A;
+ };
+ """)