Bug 1708660 - Remove support for map/setLike in JS-implemented WebIDL. r=edgar

Differential Revision: https://phabricator.services.mozilla.com/D113949
This commit is contained in:
Peter Van der Beken 2021-05-05 08:08:52 +00:00
parent 581f3fd2ca
commit 1be1c3b5b0
9 changed files with 14 additions and 315 deletions

View File

@ -19884,24 +19884,6 @@ class CGJSImplClass(CGBindingImplClass):
)
)
if (
descriptor.interface.isJSImplemented()
and descriptor.interface.maplikeOrSetlikeOrIterable
and descriptor.interface.maplikeOrSetlikeOrIterable.isMaplike()
):
self.methodDecls.append(
ClassMethod(
"__OnGet",
"void",
[
Argument("JS::Handle<JS::Value>", "aKey"),
Argument("JS::Handle<JS::Value>", "aValue"),
Argument("ErrorResult&", "aRv"),
],
body="mImpl->__OnGet(aKey, aValue, aRv);\n",
)
)
CGClass.__init__(
self,
descriptor.name,
@ -20406,15 +20388,6 @@ class CGCallbackInterface(CGCallback):
methods.append(CGJSImplInitOperation(sigs[0], descriptor))
needInitId = True
needOnGetId = False
if (
iface.isJSImplemented()
and iface.maplikeOrSetlikeOrIterable
and iface.maplikeOrSetlikeOrIterable.isMaplike()
):
methods.append(CGJSImplOnGetOperation(descriptor))
needOnGetId = True
idlist = [
descriptor.binaryNameFor(m.identifier.name)
for m in iface.members
@ -20422,8 +20395,6 @@ class CGCallbackInterface(CGCallback):
]
if needInitId:
idlist.append("__init")
if needOnGetId:
idlist.append("__onget")
if iface.isJSImplemented() and iface.getExtendedAttribute(
"WantsEventListenerHooks"
@ -21137,35 +21108,6 @@ class CGJSImplInitOperation(CallbackOperationBase):
return "__init"
class CGJSImplOnGetOperation(CallbackOperationBase):
"""
Codegen the __OnGet() method used to notify the JS impl that a get() is
happening on a JS-implemented maplike. This method takes two arguments
(key and value) and returns nothing.
"""
def __init__(self, descriptor):
CallbackOperationBase.__init__(
self,
(
BuiltinTypes[IDLBuiltinType.Types.void],
[
FakeArgument(BuiltinTypes[IDLBuiltinType.Types.any], None, "key"),
FakeArgument(BuiltinTypes[IDLBuiltinType.Types.any], None, "value"),
],
),
"__onget",
"__OnGet",
descriptor,
singleOperation=False,
rethrowContentException=True,
spiderMonkeyInterfacesAreStructs=True,
)
def getPrettyName(self):
return "__onget"
class CGJSImplEventHookOperation(CallbackOperationBase):
"""
Codegen the hooks on a JS impl for adding/removing event listeners.
@ -21546,28 +21488,7 @@ class CGMaplikeOrSetlikeMethodGenerator(CGThing):
]
arguments = ["&result"]
callOnGet = []
if (
self.descriptor.interface.isJSImplemented()
and not self.helperImpl # For C++ MaplikeHelper Get method, we don't notify underlying js implementation
):
callOnGet = [
CGGeneric(
dedent(
"""
{
JS::ExposeValueToActiveJS(result);
ErrorResult onGetResult;
self->__OnGet(arg0Val, result, onGetResult);
if (onGetResult.MaybeSetPendingException(cx)) {
return false;
}
}
"""
)
)
]
return self.mergeTuples(r, (code, arguments, callOnGet))
return self.mergeTuples(r, (code, arguments, []))
def has(self):
"""
@ -22012,13 +21933,6 @@ class GlobalGenRoots:
if d.interface.isJSImplemented() and d.interface.ctor():
# We'll have an __init() method.
members.append(FakeMember("__init"))
if (
d.interface.isJSImplemented()
and d.interface.maplikeOrSetlikeOrIterable
and d.interface.maplikeOrSetlikeOrIterable.isMaplike()
):
# We'll have an __onget() method.
members.append(FakeMember("__onget"))
if d.interface.isJSImplemented() and d.interface.getExtendedAttribute(
"WantsEventListenerHooks"
):

View File

@ -1021,6 +1021,13 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
# things like exposure setting.
for member in self.members:
if member.isMaplikeOrSetlikeOrIterable():
if self.isJSImplemented():
raise WebIDLError(
"%s declaration used on "
"interface that is implemented in JS"
% (member.maplikeOrSetlikeOrIterableType),
[member.location],
)
# Check that we only have one interface declaration (currently
# there can only be one maplike/setlike declaration per
# interface)
@ -1038,9 +1045,7 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
self.maplikeOrSetlikeOrIterable = member
# If we've got a maplike or setlike declaration, we'll be building all of
# our required methods in Codegen. Generate members now.
self.maplikeOrSetlikeOrIterable.expand(
self.members, self.isJSImplemented()
)
self.maplikeOrSetlikeOrIterable.expand(self.members)
assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder)
parent = self.parent.finish(scope) if self.parent else None
@ -4605,7 +4610,7 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
self.valueType,
)
def expand(self, members, isJSImplemented):
def expand(self, members):
"""
In order to take advantage of all of the method machinery in Codegen,
we generate our functions as if they were part of the interface
@ -4691,7 +4696,7 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
self.keyType,
)
def expand(self, members, isJSImplemented):
def expand(self, members):
"""
In order to take advantage of all of the method machinery in Codegen,
we generate our functions as if they were part of the interface
@ -4782,28 +4787,6 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
[getKeyArg()],
)
# Always generate underscored functions (e.g. __add, __clear) for js
# implemented interfaces as convenience functions.
if isJSImplemented:
# void clear()
self.addMethod(
"clear",
members,
True,
BuiltinTypes[IDLBuiltinType.Types.void],
[],
chromeOnly=True,
)
# boolean delete(keyType key)
self.addMethod(
"delete",
members,
True,
BuiltinTypes[IDLBuiltinType.Types.boolean],
[getKeyArg()],
chromeOnly=True,
)
if self.isSetlike():
if not self.readonly:
# Add returns the set object it just added to.
@ -4816,15 +4799,6 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
BuiltinTypes[IDLBuiltinType.Types.object],
[getKeyArg()],
)
if isJSImplemented:
self.addMethod(
"add",
members,
True,
BuiltinTypes[IDLBuiltinType.Types.object],
[getKeyArg()],
chromeOnly=True,
)
return
# If we get this far, we're a maplike declaration.
@ -4861,15 +4835,6 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
BuiltinTypes[IDLBuiltinType.Types.object],
[getKeyArg(), getValueArg()],
)
if isJSImplemented:
self.addMethod(
"set",
members,
True,
BuiltinTypes[IDLBuiltinType.Types.object],
[getKeyArg(), getValueArg()],
chromeOnly=True,
)
class IDLConst(IDLInterfaceMember):

View File

@ -317,7 +317,7 @@ def WebIDLTest(parser, harness):
numProductions=2,
)
shouldPass(
shouldFail(
"JS Implemented maplike interface",
"""
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"]
@ -326,10 +326,9 @@ def WebIDLTest(parser, harness):
setlike<long>;
};
""",
setRWChromeMembers,
)
shouldPass(
shouldFail(
"JS Implemented maplike interface",
"""
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"]
@ -338,7 +337,6 @@ def WebIDLTest(parser, harness):
maplike<long, long>;
};
""",
mapRWChromeMembers,
)
#
@ -746,31 +744,6 @@ def WebIDLTest(parser, harness):
setROMembers + [("clear", WebIDL.IDLAttribute)],
)
shouldPass(
"JS Implemented read-only interface with readonly allowable overrides",
"""
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"]
interface Foo1 {
constructor();
readonly setlike<long>;
readonly attribute boolean clear;
};
""",
setROChromeMembers + [("clear", WebIDL.IDLAttribute)],
)
shouldFail(
"JS Implemented read-write interface with non-readwrite allowable overrides",
"""
[JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1"]
interface Foo1 {
constructor();
setlike<long>;
readonly attribute boolean clear;
};
""",
)
r = shouldPass(
"Check proper override of clear/delete/set",
"""

View File

@ -1,4 +1,2 @@
component {2ac4e026-cf25-47d5-b067-78d553c3cad8} TestInterfaceJS.js
contract @mozilla.org/dom/test-interface-js;1 {2ac4e026-cf25-47d5-b067-78d553c3cad8}
component {4bc6f6f3-e005-4f0a-b42d-4d1663a9013a} TestInterfaceJSMaplike.js
contract @mozilla.org/dom/test-interface-js-maplike;1 {4bc6f6f3-e005-4f0a-b42d-4d1663a9013a}

View File

@ -1,44 +0,0 @@
/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
"use strict";
const { ComponentUtils } = ChromeUtils.import(
"resource://gre/modules/ComponentUtils.jsm"
);
function TestInterfaceJSMaplike() {}
TestInterfaceJSMaplike.prototype = {
classID: Components.ID("{4bc6f6f3-e005-4f0a-b42d-4d1663a9013a}"),
contractID: "@mozilla.org/dom/test-interface-js-maplike;1",
QueryInterface: ChromeUtils.generateQI(["nsIDOMGlobalPropertyInitializer"]),
init(win) {
this._win = win;
},
__init() {},
setInternal(aKey, aValue) {
return this.__DOM_IMPL__.__set(aKey, aValue);
},
deleteInternal(aKey) {
return this.__DOM_IMPL__.__delete(aKey);
},
clearInternal() {
return this.__DOM_IMPL__.__clear();
},
__onget(key, value) {
/* no-op */
},
};
this.NSGetFactory = ComponentUtils.generateNSGetFactory([
TestInterfaceJSMaplike,
]);

View File

@ -15,7 +15,6 @@ Library("dombindings_test_s")
EXTRA_COMPONENTS += [
"TestInterfaceJS.js",
"TestInterfaceJS.manifest",
"TestInterfaceJSMaplike.js",
]
MOCHITEST_MANIFESTS += ["mochitest.ini"]

View File

@ -9,7 +9,7 @@
</head>
<body>
<script class="testbody" type="application/javascript">
/* global TestInterfaceMaplike, TestInterfaceSetlike, TestInterfaceMaplikeObject, TestInterfaceJSMaplike, TestInterfaceMaplikeJSObject*/
/* global TestInterfaceMaplike, TestInterfaceSetlike, TestInterfaceMaplikeObject, TestInterfaceMaplikeJSObject*/
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]}, function() {
var base_properties = [["has", "function", 1],
@ -233,34 +233,6 @@
is(m.size, 0, "JSObjectMapConvenience: size should be 0 after clearInternal");
// JS implemented map creation convenience function test
info("JSMapConvenience: Testing JS implemented map creation convenience functions");
m = new TestInterfaceJSMaplike();
ok(m, "JSMapConvenience: got a TestInterfaceJSMaplike object");
is(m.size, 0, "JSMapConvenience: size should be zero");
ok(!m.has("test"), "JSMapConvenience: maplike has should return false");
m.setInternal("test", 1);
is(m.size, 1, "JSMapConvenience: size should be 1");
ok(m.has("test"), "JSMapConvenience: maplike has should return true");
is(m.get("test"), 1, "JSMapConvenience: maplike get should return value entered");
m.setInternal("test2", 2);
is(m.size, 2, "JSMapConvenience: size should be 2");
ok(m.has("test2"), "JSMapConvenience: maplike has should return true");
is(m.get("test2"), 2, "JSMapConvenience: maplike get should return value entered");
is(m.deleteInternal("test2"), true, "JSMapConvenience: maplike deleteInternal should return true");
is(m.size, 1, "JSMapConvenience: size should be 1");
for (let k of m.keys()) {
is(k, "test", "JSMapConvenience: first keys element should be 'test'");
}
for (let v of m.values()) {
is(v, 1, "JSMapConvenience: first values elements should be 1");
}
for (let e of m.entries()) {
is(e[0], "test", "JSMapConvenience: entries first array element should be 'test'");
is(e[1], 1, "JSMapConvenience: entries second array element should be 1");
}
m.clearInternal();
is(m.size, 0, "JSMapConvenience: size should be 0 after clearInternal");
// Test this override for forEach
info("ForEachThisOverride: Testing this override for forEach");
m = new TestInterfaceMaplike();

View File

@ -2653,71 +2653,6 @@ the chrome implementation object. This property only appears after the
content-side object has been created. So it is available in ``__init``
but not in ``init``.
.. _MaplikeSetlike_declaration_helpers_in_Javascript_implementations:
Maplike/Setlike declaration helpers in Javascript implementations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to manipulate the storage for maplike and setlike declarations
on WebIDL interfaces from javascript implementations, certain functions
are generated that can be used by the implementation. Retrieval from
storage can happen via the publicly exposed maplike functions for the
interface, but these helpers guarantee that access is available to
manipulate storage from chrome JS, even in the case of the interface
declaration being readonly.
.. _Maplike_2:
Maplike
^^^^^^^
The following interface:
.. code:: notranslate
[JSImplementation="@mozilla.org/dom/string-to-long-js-maplike;1",
Constructor()]
interface StringToLongMaplike {
readonly maplike<DOMString, long>;
};
Has these JS functions available to it:
.. code:: brush:
// Sets a certain key with a certain value. Exception thrown on wrong types.
this.__DOM_IMPL__.__set(aKey, aValue);
// Deletes a key. Returns a boolean, true if key exists and was deleted, false otherwise.
this.__DOM_IMPL__.__delete(aKey);
// Completely clear all values from maplike storage
this.__DOM_IMPL__.__clear();
.. _Setlike_2:
Setlike
^^^^^^^
The following interface:
.. code:: notranslate
[JSImplementation="@mozilla.org/dom/string-js-setlike;1",
Constructor()]
interface StringSetlike {
readonly setlike<DOMString>;
};
Has these JS functions available to it:
.. code:: brush:
// Adds a key to a set. Exception thrown on wrong types.
this.__DOM_IMPL__.__add(aKey);
// Deletes a key. Returns a boolean, true if key exists and was deleted, false otherwise.
this.__DOM_IMPL__.__delete(aKey)
// Completely clear all values from maplike storage
this.__DOM_IMPL__.__clear();
.. _Determining_the_principal_of_the_caller_that_invoked_the_WebIDL_API:
Determining the principal of the caller that invoked the WebIDL API

View File

@ -49,19 +49,6 @@ interface TestInterfaceMaplikeJSObject {
object? getInternal(DOMString aKey);
};
[Pref="dom.expose_test_interfaces",
JSImplementation="@mozilla.org/dom/test-interface-js-maplike;1",
Exposed=Window]
interface TestInterfaceJSMaplike {
[Throws]
constructor();
readonly maplike<DOMString, long>;
void setInternal(DOMString aKey, long aValue);
void clearInternal();
boolean deleteInternal(DOMString aKey);
};
[Pref="dom.expose_test_interfaces",
Exposed=Window]
interface TestInterfaceSetlike {