diff --git a/resources/idlharness.js b/resources/idlharness.js index 10d96f6a4e34b62..f3a2f6704bb4906 100644 --- a/resources/idlharness.js +++ b/resources/idlharness.js @@ -177,27 +177,9 @@ self.IdlArray = function() * might contain a partial interface or includes statement that depends * on a later one. Save these up and handle them right before we run * tests. - * - * .partials is simply an array of objects from WebIDLParser.js' - * "partialinterface" production. .includes maps strings to arrays of - * strings, such that - * - * A includes B; - * A includes C; - * D includes E; - * - * results in this["includes"] = { A: ["B", "C"], D: ["E"] }. - * - * Similarly, - * - * interface A : B {}; - * interface B : C {}; - * - * results in this["inheritance"] = { A: "B", B: "C" } */ this.partials = []; - this["includes"] = {}; - this["inheritance"] = {}; + this.includes = []; /** * Record of skipped IDL items, in case we later realize that they are a @@ -249,11 +231,15 @@ IdlArray.prototype.internal_add_dependency_idls = function(parsed_idls, options) const new_options = { only: [] } const all_deps = new Set(); - Object.values(this.inheritance).forEach(v => all_deps.add(v)); - // NOTE: If 'A includes B' for B that we care about, then A is also a dep. - Object.keys(this.includes).forEach(k => { - all_deps.add(k); - this.includes[k].forEach(v => all_deps.add(v)); + Object.values(this.members).forEach(v => { + if (v.base) { + all_deps.add(v.base); + } + }); + // Add both 'A' and 'B' for each 'A includes B' entry. + this.includes.forEach(i => { + all_deps.add(i.target); + all_deps.add(i.includes); }); this.partials.forEach(p => all_deps.add(p.name)); // Add 'TypeOfType' for each "typedef TypeOfType MyType;" entry. @@ -434,11 +420,7 @@ IdlArray.prototype.internal_add_idls = function(parsed_idls, options) { return; } - if (!(parsed_idl.target in this["includes"])) - { - this["includes"][parsed_idl.target] = []; - } - this["includes"][parsed_idl.target].push(parsed_idl["includes"]); + this.includes.push(parsed_idl); return; } @@ -452,16 +434,6 @@ IdlArray.prototype.internal_add_idls = function(parsed_idls, options) throw new IdlHarnessError("Duplicate identifier " + parsed_idl.name); } - if (parsed_idl["inheritance"]) { - // NOTE: Clash should be impossible (would require redefinition of parsed_idl.name). - if (parsed_idl.name in this["inheritance"] - && parsed_idl["inheritance"] != this["inheritance"][parsed_idl.name]) { - throw new IdlHarnessError( - `Inheritance for ${parsed_idl.name} was already defined`); - } - this["inheritance"][parsed_idl.name] = parsed_idl["inheritance"]; - } - switch(parsed_idl.type) { case "interface": @@ -529,34 +501,6 @@ IdlArray.prototype.prevent_multiple_testing = function(name) this.members[name].prevent_multiple_testing = true; }; -IdlArray.prototype.recursively_get_includes = function(interface_name) -{ - /** - * Helper function for test(). Returns an array of things that implement - * interface_name, so if the IDL contains - * - * A includes B; - * B includes C; - * B includes D; - * - * then recursively_get_includes("A") should return ["B", "C", "D"]. - */ - var ret = this["includes"][interface_name]; - if (ret === undefined) - { - return []; - } - for (var i = 0; i < this["includes"][interface_name].length; i++) - { - ret = ret.concat(this.recursively_get_includes(ret[i])); - if (ret.indexOf(ret[i]) != ret.lastIndexOf(ret[i])) - { - throw new IdlHarnessError("Circular includes statements involving " + ret[i]); - } - } - return ret; -}; - IdlArray.prototype.is_json_type = function(type) { /** @@ -753,37 +697,8 @@ IdlArray.prototype.test = function() /** Entry point. See documentation at beginning of file. */ // First merge in all partial definitions and interface mixins. - this.collapse_partials(); - - for (var lhs in this["includes"]) - { - this.recursively_get_includes(lhs).forEach(function(rhs) - { - var errStr = lhs + " includes " + rhs + ", but "; - if (!(lhs in this.members)) throw errStr + lhs + " is undefined."; - if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface."; - if (!(rhs in this.members)) throw errStr + rhs + " is undefined."; - if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface."; - - if (this.members[rhs].members.length) { - test(function () { - var clash = this.members[rhs].members.find(function(member) { - return this.members[lhs].members.find(function(m) { - return this.are_duplicate_members(m, member); - }.bind(this)); - }.bind(this)); - this.members[rhs].members.forEach(function(member) { - assert_true( - this.members[lhs].members.every(m => !this.are_duplicate_members(m, member)), - "member " + member.name + " is unique"); - this.members[lhs].members.push(new IdlInterfaceMember(member)); - }.bind(this)); - assert_true(!clash, "member " + (clash && clash.name) + " is unique"); - }.bind(this), lhs + " includes " + rhs + ": member names are unique"); - } - }.bind(this)); - } - this["includes"] = {}; + this.merge_partials(); + this.merge_includes(); // Assert B defined for A : B for (const member of Object.values(this.members).filter(m => m.base)) { @@ -832,7 +747,7 @@ IdlArray.prototype.test = function() } }; -IdlArray.prototype.collapse_partials = function() +IdlArray.prototype.merge_partials = function() { const testedPartials = new Map(); this.partials.forEach(function(parsed_idl) @@ -926,6 +841,39 @@ IdlArray.prototype.collapse_partials = function() this.partials = []; } +IdlArray.prototype.merge_includes = function() +{ + for (const parsed_idl of this.includes) + { + const lhs = parsed_idl.target; + const rhs = parsed_idl.includes; + + var errStr = lhs + " includes " + rhs + ", but "; + if (!(lhs in this.members)) throw errStr + lhs + " is undefined."; + if (!(this.members[lhs] instanceof IdlInterface)) throw errStr + lhs + " is not an interface."; + if (!(rhs in this.members)) throw errStr + rhs + " is undefined."; + if (!(this.members[rhs] instanceof IdlInterface)) throw errStr + rhs + " is not an interface."; + + if (this.members[rhs].members.length) { + test(function () { + var clash = this.members[rhs].members.find(function(member) { + return this.members[lhs].members.find(function(m) { + return this.are_duplicate_members(m, member); + }.bind(this)); + }.bind(this)); + this.members[rhs].members.forEach(function(member) { + assert_true( + this.members[lhs].members.every(m => !this.are_duplicate_members(m, member)), + "member " + member.name + " is unique"); + this.members[lhs].members.push(new IdlInterfaceMember(member)); + }.bind(this)); + assert_true(!clash, "member " + (clash && clash.name) + " is unique"); + }.bind(this), lhs + " includes " + rhs + ": member names are unique"); + } + } + this.includes = []; +} + IdlArray.prototype.are_duplicate_members = function(m1, m2) { if (m1.name !== m2.name) { return false; @@ -1416,7 +1364,7 @@ IdlInterface.prototype.get_inheritance_stack = function() { */ IdlInterface.prototype.default_to_json_operation = function(callback) { var map = new Map(), isDefault = false; - this.traverse_inherited_and_consequential_interfaces(function(I) { + this.get_inheritance_stack().forEach(function(I) { if (I.has_default_to_json_regular_operation()) { isDefault = true; I.members.forEach(function(m) { @@ -1431,56 +1379,6 @@ IdlInterface.prototype.default_to_json_operation = function(callback) { return isDefault ? map : null; }; -/** - * Traverses inherited interfaces from the top down - * and imeplemented interfaces inside out. - * Invokes |callback| on each interface. - * - * This is an abstract implementation of the traversal - * algorithm specified in: - * https://heycam.github.io/webidl/#collect-attribute-values - * Given the following inheritance tree: - * - * F - * | - * C E - I - * | | - * B - D - * | - * G - A - H - J - * - * Invoking traverse_inherited_and_consequential_interfaces() on A - * would traverse the tree in the following order: - * C -> B -> F -> E -> I -> D -> A -> G -> H -> J - */ - -IdlInterface.prototype.traverse_inherited_and_consequential_interfaces = function(callback) { - if (typeof callback != "function") { - throw new TypeError(); - } - var stack = this.get_inheritance_stack(); - _traverse_inherited_and_consequential_interfaces(stack, callback); -}; - -function _traverse_inherited_and_consequential_interfaces(stack, callback) { - var I = stack.pop(); - callback(I); - var mixins = I.array["includes"][I.name]; - if (mixins) { - mixins.forEach(function(id) { - var mixin = I.array.members[id]; - if (!mixin) { - throw new Error("Interface mixin " + id + " not found (included by " + I.name + ")"); - } - var interfaces = mixin.get_inheritance_stack(); - _traverse_inherited_and_consequential_interfaces(interfaces, callback); - }); - } - if (stack.length > 0) { - _traverse_inherited_and_consequential_interfaces(stack, callback); - } -} - IdlInterface.prototype.test = function() { if (this.has_extended_attribute("LegacyNoInterfaceObject") || this.is_mixin()) diff --git a/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html b/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html index 5ee3fe7e893f19e..05e6e0b1e06c634 100644 --- a/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html +++ b/resources/test/tests/functional/idlharness/IdlDictionary/test_partial_interface_of.html @@ -41,7 +41,7 @@ idlArray.add_idls(` partial dictionary C {}; namespace C {};`); - idlArray.collapse_partials(); + idlArray.merge_partials(); })();