From dd35b25d3ea936f9d164b9cfb7c7e943c973d0a6 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Wed, 15 Mar 2023 15:44:42 +0000 Subject: [PATCH] Bug 1765992 - Support regular and static WebIDL operations with the same identifier on the same interface. r=edgar Differential Revision: https://phabricator.services.mozilla.com/D171703 --- dom/bindings/parser/WebIDL.py | 53 ++++++++- ...ace_identifier_conflicts_across_members.py | 110 +++++++++++++++++- 2 files changed, 156 insertions(+), 7 deletions(-) diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 715e5e3cec2fd..c696b411932bd 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -283,6 +283,9 @@ def ensureUnique(self, identifier, object): self._dict[identifier.name] = replacement return + self.addNewIdentifier(identifier, object) + + def addNewIdentifier(self, identifier, object): assert object self._dict[identifier.name] = object @@ -727,6 +730,15 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): exposureSet.update(globalScope.globalNameMapping[name]) +# Because WebIDL allows static and regular operations with the same identifier +# we use a special class to be able to store them both in the scope for the +# same identifier. +class IDLOperations: + def __init__(self, static=None, regular=None): + self.static = static + self.regular = regular + + class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins): def __init__(self, location, parentScope, name): assert isinstance(parentScope, IDLScope) @@ -756,15 +768,52 @@ def finish(self, scope): self.addExtendedAttributes(partial.propagatedExtendedAttrs) self.members.extend(partial.members) + def addNewIdentifier(self, identifier, object): + if isinstance(object, IDLMethod): + if object.isStatic(): + object = IDLOperations(static=object) + else: + object = IDLOperations(regular=object) + + IDLScope.addNewIdentifier(self, identifier, object) + def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): assert isinstance(scope, IDLScope) - assert isinstance(originalObject, IDLInterfaceMember) assert isinstance(newObject, IDLInterfaceMember) + if isinstance(newObject, IDLMethod): + assert isinstance(originalObject, IDLOperations) + + originalOperations = originalObject + if newObject.isStatic(): + if originalOperations.static is None: + originalOperations.static = newObject + return originalOperations + + originalObject = originalOperations.static + else: + if originalOperations.regular is None: + originalOperations.regular = newObject + return originalOperations + + originalObject = originalOperations.regular + + assert isinstance(originalObject, IDLMethod) + else: + assert isinstance(originalObject, IDLInterfaceMember) + retval = IDLScope.resolveIdentifierConflict( self, scope, identifier, originalObject, newObject ) + if isinstance(newObject, IDLMethod): + if newObject.isStatic(): + originalOperations.static = retval + else: + originalOperations.regular = retval + + retval = originalOperations + # Might be a ctor, which isn't in self.members if newObject in self.members: self.members.remove(newObject) @@ -995,7 +1044,7 @@ def ctor(self): self.location, "constructor", allowForbidden=True ) try: - return self._lookupIdentifier(identifier) + return self._lookupIdentifier(identifier).static except Exception: return None diff --git a/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py b/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py index abafda9677f8c..d8398d46ba768 100644 --- a/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py +++ b/dom/bindings/parser/tests/test_interface_identifier_conflicts_across_members.py @@ -14,8 +14,9 @@ def WebIDLTest(parser, harness): except Exception: threw = True - harness.ok(threw, "Should have thrown.") + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers1.") + parser = parser.reset() threw = False try: parser.parse( @@ -31,8 +32,9 @@ def WebIDLTest(parser, harness): except Exception: threw = True - harness.ok(threw, "Should have thrown.") + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers2.") + parser = parser.reset() threw = False try: parser.parse( @@ -48,13 +50,14 @@ def WebIDLTest(parser, harness): except Exception: threw = True - harness.ok(threw, "Should have thrown.") + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers3.") + parser = parser.reset() threw = False try: parser.parse( """ - interface IdentifierConflictAcrossMembers1 { + interface IdentifierConflictAcrossMembers4 { const byte thing1 = 1; long thing1(); }; @@ -65,4 +68,101 @@ def WebIDLTest(parser, harness): except Exception: threw = True - harness.ok(threw, "Should have thrown.") + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers4.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface IdentifierConflictAcrossMembers5 { + static long thing1(); + undefined thing1(); + }; + """ + ) + + parser.finish() + except Exception: + threw = True + + harness.ok( + not threw, "Should not have thrown for IdentifierConflictAcrossMembers5." + ) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface mixin IdentifierConflictAcrossMembers6Mixin { + undefined thing1(); + }; + interface IdentifierConflictAcrossMembers6 { + static long thing1(); + }; + IdentifierConflictAcrossMembers6 includes IdentifierConflictAcrossMembers6Mixin; + """ + ) + + parser.finish() + except Exception: + threw = True + + harness.ok( + not threw, "Should not have thrown for IdentifierConflictAcrossMembers6." + ) + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface IdentifierConflictAcrossMembers7 { + const byte thing1 = 1; + static readonly attribute long thing1; + }; + """ + ) + + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers7.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface IdentifierConflictAcrossMembers8 { + readonly attribute long thing1 = 1; + static readonly attribute long thing1; + }; + """ + ) + + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers8.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface IdentifierConflictAcrossMembers9 { + void thing1(); + static readonly attribute long thing1; + }; + """ + ) + + parser.finish() + except Exception: + threw = True + + harness.ok(threw, "Should have thrown for IdentifierConflictAcrossMembers9.")