diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2018-09-14 11:15:35 +0200 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2018-09-14 14:48:41 +0200 |
commit | 2b574bbdf8f1306c4b31060fec54fee919cc3a18 (patch) | |
tree | f8c23e6cedf624781bb0148175b9ff7f0f9f19a0 /components/script/dom/bindings/codegen/parser | |
parent | 70a0174b0abef796a1d1500fa7a8b7dc395719e0 (diff) | |
download | servo-2b574bbdf8f1306c4b31060fec54fee919cc3a18.tar.gz servo-2b574bbdf8f1306c4b31060fec54fee919cc3a18.zip |
Update the WebIDL parser
Diffstat (limited to 'components/script/dom/bindings/codegen/parser')
6 files changed, 284 insertions, 108 deletions
diff --git a/components/script/dom/bindings/codegen/parser/WebIDL.py b/components/script/dom/bindings/codegen/parser/WebIDL.py index b2daa1bce20..b56a1765d57 100644 --- a/components/script/dom/bindings/codegen/parser/WebIDL.py +++ b/components/script/dom/bindings/codegen/parser/WebIDL.py @@ -684,7 +684,7 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet): class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): + isKnownNonPartial, toStringTag): assert isinstance(parentScope, IDLScope) assert isinstance(name, IDLUnresolvedIdentifier) assert isKnownNonPartial or not parent @@ -722,6 +722,8 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): # interface we're iterating for in order to get its nativeType. self.iterableInterface = None + self.toStringTag = toStringTag + IDLObjectWithScope.__init__(self, location, parentScope, name) IDLExposureMixins.__init__(self, location) @@ -1017,10 +1019,9 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): [self.location]) for m in self.members: - if ((m.isMethod() and m.isJsonifier()) or - m.identifier.name == "toJSON"): + if m.identifier.name == "toJSON": raise WebIDLError("Unforgeable interface %s has a " - "jsonifier so we won't be able to add " + "toJSON so we won't be able to add " "one ourselves" % self.identifier.name, [self.location, m.location]) @@ -1044,6 +1045,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): (member.getExtendedAttribute("StoreInSlot") or member.getExtendedAttribute("Cached"))) or member.isMaplikeOrSetlike()): + if self.isJSImplemented() and not member.isMaplikeOrSetlike(): + raise WebIDLError("Interface %s is JS-implemented and we " + "don't support [Cached] or [StoreInSlot] " + "on JS-implemented interfaces" % + self.identifier.name, + [self.location, member.location]) if member.slotIndices is None: member.slotIndices = dict() member.slotIndices[self.identifier.name] = self.totalMembersInSlots @@ -1115,15 +1122,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): memberType = "deleters" elif member.isStringifier(): memberType = "stringifiers" - elif member.isJsonifier(): - memberType = "jsonifiers" elif member.isLegacycaller(): memberType = "legacycallers" else: continue - if (memberType != "stringifiers" and memberType != "legacycallers" and - memberType != "jsonifiers"): + if (memberType != "stringifiers" and memberType != "legacycallers"): if member.isNamed(): memberType = "named " + memberType else: @@ -1573,9 +1577,12 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins): class IDLInterface(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, parent, members, - isKnownNonPartial): + isKnownNonPartial, classNameOverride=None, + toStringTag=None): IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - parent, members, isKnownNonPartial) + parent, members, isKnownNonPartial, + toStringTag) + self.classNameOverride = classNameOverride def __str__(self): return "Interface '%s'" % self.identifier.name @@ -1583,6 +1590,11 @@ class IDLInterface(IDLInterfaceOrNamespace): def isInterface(self): return True + def getClassName(self): + if self.classNameOverride: + return self.classNameOverride + return self.identifier.name + def addExtendedAttributes(self, attrs): for attr in attrs: identifier = attr.identifier() @@ -1677,14 +1689,6 @@ class IDLInterface(IDLInterfaceOrNamespace): elif newMethod not in self.namedConstructors: raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", [method.location, newMethod.location]) - elif (identifier == "ArrayClass"): - if not attr.noArguments(): - raise WebIDLError("[ArrayClass] must take no arguments", - [attr.location]) - if self.parent: - raise WebIDLError("[ArrayClass] must not be specified on " - "an interface with inherited interfaces", - [attr.location, self.location]) elif (identifier == "ExceptionClass"): if not attr.noArguments(): raise WebIDLError("[ExceptionClass] must take no arguments", @@ -1738,6 +1742,7 @@ class IDLInterface(IDLInterfaceOrNamespace): identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" or identifier == "NonOrdinaryGetPrototypeOf" or identifier == "Abstract" or identifier == "Inline"): @@ -1769,7 +1774,8 @@ class IDLInterface(IDLInterfaceOrNamespace): class IDLNamespace(IDLInterfaceOrNamespace): def __init__(self, location, parentScope, name, members, isKnownNonPartial): IDLInterfaceOrNamespace.__init__(self, location, parentScope, name, - None, members, isKnownNonPartial) + None, members, isKnownNonPartial, + toStringTag=None) def __str__(self): return "Namespace '%s'" % self.identifier.name @@ -2152,7 +2158,7 @@ class IDLType(IDLObject): # Should only call this on float types assert self.isFloat() - def isSerializable(self): + def isJSONType(self): return False def tag(self): @@ -2350,8 +2356,8 @@ class IDLNullableType(IDLParametrizedType): def isUnion(self): return self.inner.isUnion() - def isSerializable(self): - return self.inner.isSerializable() + def isJSONType(self): + return self.inner.isJSONType() def tag(self): return self.inner.tag() @@ -2430,8 +2436,8 @@ class IDLSequenceType(IDLParametrizedType): def isEnum(self): return False - def isSerializable(self): - return self.inner.isSerializable() + def isJSONType(self): + return self.inner.isJSONType() def tag(self): return IDLType.Tags.sequence @@ -2476,6 +2482,9 @@ class IDLRecordType(IDLParametrizedType): def isRecord(self): return True + def isJSONType(self): + return self.inner.isJSONType() + def tag(self): return IDLType.Tags.record @@ -2525,8 +2534,8 @@ class IDLUnionType(IDLType): def isUnion(self): return True - def isSerializable(self): - return all(m.isSerializable() for m in self.memberTypes) + def isJSONType(self): + return all(m.isJSONType() for m in self.memberTypes) def includesRestrictedFloat(self): return any(t.includesRestrictedFloat() for t in self.memberTypes) @@ -2676,6 +2685,9 @@ class IDLTypedefType(IDLType): def isVoid(self): return self.inner.isVoid() + def isJSONType(self): + return self.inner.isJSONType() + def isSequence(self): return self.inner.isSequence() @@ -2817,15 +2829,25 @@ class IDLWrapperType(IDLType): def isEnum(self): return isinstance(self.inner, IDLEnum) - def isSerializable(self): + def isJSONType(self): if self.isInterface(): if self.inner.isExternal(): return False - return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) + iface = self.inner + while iface: + if any(m.isMethod() and m.isToJSON() for m in iface.members): + return True + iface = iface.parent + return False elif self.isEnum(): return True elif self.isDictionary(): - return all(m.type.isSerializable() for m in self.inner.members) + dictionary = self.inner + while dictionary: + if not all(m.type.isJSONType() for m in dictionary.members): + return False + dictionary = dictionary.parent + return True else: raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " "is serializable" % type(self.inner), [self.location]) @@ -3111,8 +3133,8 @@ class IDLBuiltinType(IDLType): return (self._typeTag == IDLBuiltinType.Types.unrestricted_float or self._typeTag == IDLBuiltinType.Types.unrestricted_double) - def isSerializable(self): - return self.isPrimitive() or self.isString() or self.isDate() + def isJSONType(self): + return self.isPrimitive() or self.isString() or self.isObject() def includesRestrictedFloat(self): return self.isFloat() and not self.isUnrestricted() @@ -4665,7 +4687,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def __init__(self, location, identifier, returnType, arguments, static=False, getter=False, setter=False, deleter=False, specialType=NamedOrIndexed.Neither, - legacycaller=False, stringifier=False, jsonifier=False, + legacycaller=False, stringifier=False, maplikeOrSetlikeOrIterable=None, htmlConstructor=False): # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. IDLInterfaceMember.__init__(self, location, identifier, @@ -4690,8 +4712,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self._legacycaller = legacycaller assert isinstance(stringifier, bool) self._stringifier = stringifier - assert isinstance(jsonifier, bool) - self._jsonifier = jsonifier assert maplikeOrSetlikeOrIterable is None or isinstance(maplikeOrSetlikeOrIterable, IDLMaplikeOrSetlikeOrIterableBase) self.maplikeOrSetlikeOrIterable = maplikeOrSetlikeOrIterable assert isinstance(htmlConstructor, bool) @@ -4739,12 +4759,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert len(overload.arguments) == 0 assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] - if self._jsonifier: - assert len(self._overloads) == 1 - overload = self._overloads[0] - assert len(overload.arguments) == 0 - assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object] - def isStatic(self): return self._static @@ -4776,8 +4790,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope): def isStringifier(self): return self._stringifier - def isJsonifier(self): - return self._jsonifier + def isToJSON(self): + return self.identifier.name == "toJSON" + + def isDefaultToJSON(self): + return self.isToJSON() and self.getExtendedAttribute("Default") def isMaplikeOrSetlikeOrIterableMethod(self): """ @@ -4791,8 +4808,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope): self.isSetter() or self.isDeleter() or self.isLegacycaller() or - self.isStringifier() or - self.isJsonifier()) + self.isStringifier()) def isHTMLConstructor(self): return self._htmlConstructor @@ -4848,8 +4864,6 @@ class IDLMethod(IDLInterfaceMember, IDLScope): assert not method.isDeleter() assert not self.isStringifier() assert not method.isStringifier() - assert not self.isJsonifier() - assert not method.isJsonifier() assert not self.isHTMLConstructor() assert not method.isHTMLConstructor() @@ -4972,6 +4986,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): " methods on JS-implemented classes only.", [self.location]) + # Ensure that toJSON methods satisfy the spec constraints on them. + if self.identifier.name == "toJSON": + if len(self.signatures()) != 1: + raise WebIDLError("toJSON method has multiple overloads", + [self._overloads[0].location, + self._overloads[1].location]) + if len(self.signatures()[0][1]) != 0: + raise WebIDLError("toJSON method has arguments", + [self.location]) + if not self.signatures()[0][0].isJSONType(): + raise WebIDLError("toJSON method has non-JSON return type", + [self.location]) + def overloadsForArgCount(self, argc): return [overload for overload in self._overloads if len(overload.arguments) == argc or @@ -5105,6 +5132,19 @@ class IDLMethod(IDLInterfaceMember, IDLScope): raise WebIDLError("[CEReactions] is only allowed on operation, " "attribute, setter, and deleter", [attr.location, self.location]) + elif identifier == "Default": + if not attr.noArguments(): + raise WebIDLError("[Default] must take no arguments", + [attr.location]) + + if not self.isToJSON(): + raise WebIDLError("[Default] is only allowed on toJSON operations", + [attr.location, self.location]) + + if self.signatures()[0][0] != BuiltinTypes[IDLBuiltinType.Types.object]: + raise WebIDLError("The return type of the default toJSON " + "operation must be 'object'", + [attr.location, self.location]); elif (identifier == "Throws" or identifier == "CanOOM" or identifier == "NewObject" or @@ -5292,7 +5332,6 @@ class Tokenizer(object): "false": "FALSE", "serializer": "SERIALIZER", "stringifier": "STRINGIFIER", - "jsonifier": "JSONIFIER", "unrestricted": "UNRESTRICTED", "attribute": "ATTRIBUTE", "readonly": "READONLY", @@ -6123,19 +6162,6 @@ class Parser(Tokenizer): stringifier=True) p[0] = method - def p_Jsonifier(self, p): - """ - Operation : JSONIFIER SEMICOLON - """ - identifier = IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), - "__jsonifier", allowDoubleUnderscore=True) - method = IDLMethod(self.getLocation(p, 1), - identifier, - returnType=BuiltinTypes[IDLBuiltinType.Types.object], - arguments=[], - jsonifier=True) - p[0] = method - def p_QualifierStatic(self, p): """ Qualifier : STATIC @@ -6289,7 +6315,6 @@ class Parser(Tokenizer): | SETTER | STATIC | STRINGIFIER - | JSONIFIER | TYPEDEF | UNRESTRICTED | NAMESPACE @@ -6441,7 +6466,6 @@ class Parser(Tokenizer): | SHORT | STATIC | STRINGIFIER - | JSONIFIER | TRUE | TYPEDEF | UNSIGNED @@ -6958,9 +6982,12 @@ class Parser(Tokenizer): nextMethod.addExtendedAttributes([simpleExtendedAttr("Throws")]) itr_ident = IDLUnresolvedIdentifier(iface.location, iface.identifier.name + "Iterator") + toStringTag = iface.identifier.name + " Iterator" itr_iface = IDLInterface(iface.location, self.globalScope(), itr_ident, None, [nextMethod], - isKnownNonPartial=True) + isKnownNonPartial=True, + classNameOverride=toStringTag, + toStringTag=toStringTag) itr_iface.addExtendedAttributes([simpleExtendedAttr("NoInterfaceObject")]) # Make sure the exposure set for the iterator interface is the # same as the exposure set for the iterable interface, because diff --git a/components/script/dom/bindings/codegen/parser/abstract.patch b/components/script/dom/bindings/codegen/parser/abstract.patch index e43d12eb988..cf4c89b84d0 100644 --- a/components/script/dom/bindings/codegen/parser/abstract.patch +++ b/components/script/dom/bindings/codegen/parser/abstract.patch @@ -1,9 +1,9 @@ --- WebIDL.py +++ WebIDL.py @@ -1744,7 +1744,8 @@ - identifier == "ProbablyShortLivingWrapper" or identifier == "LegacyUnenumerableNamedProperties" or identifier == "RunConstructorInCallerCompartment" or + identifier == "WantsEventListenerHooks" or - identifier == "NonOrdinaryGetPrototypeOf"): + identifier == "NonOrdinaryGetPrototypeOf" or + identifier == "Abstract"): diff --git a/components/script/dom/bindings/codegen/parser/inline.patch b/components/script/dom/bindings/codegen/parser/inline.patch index 5d1056d2b58..028fb9345d0 100644 --- a/components/script/dom/bindings/codegen/parser/inline.patch +++ b/components/script/dom/bindings/codegen/parser/inline.patch @@ -9,4 +9,4 @@ + identifier == "Inline"): # Known extended attributes that do not take values if not attr.noArguments(): - raise WebIDLError("[%s] must take no arguments" % identifier,
\ No newline at end of file + raise WebIDLError("[%s] must take no arguments" % identifier, diff --git a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py index a1e5e78630f..dba16f53302 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_cereactions.py @@ -131,17 +131,3 @@ def WebIDLTest(parser, harness): harness.ok(threw, "Should have thrown for [CEReactions] used on a stringifier") - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface Foo { - [CEReactions] jsonifier; - }; - """) - - results = parser.finish() - except: - threw = True - - harness.ok(threw, "Should have thrown for [CEReactions] used on a jsonifier") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_interface.py b/components/script/dom/bindings/codegen/parser/tests/test_interface.py index e8ed67b54b3..a23243abe61 100644 --- a/components/script/dom/bindings/codegen/parser/tests/test_interface.py +++ b/components/script/dom/bindings/codegen/parser/tests/test_interface.py @@ -374,32 +374,3 @@ def WebIDLTest(parser, harness): threw = True harness.ok(threw, "Should not allow unknown extended attributes on interfaces") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - interface B {}; - [ArrayClass] - interface A : B { - }; - """) - results = parser.finish() - except: - threw = True - harness.ok(threw, - "Should not allow [ArrayClass] on interfaces with parents") - - parser = parser.reset() - threw = False - try: - parser.parse(""" - [ArrayClass] - interface A { - }; - """) - results = parser.finish() - except: - threw = True - harness.ok(not threw, - "Should allow [ArrayClass] on interfaces without parents") diff --git a/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py new file mode 100644 index 00000000000..b8b4f796ccb --- /dev/null +++ b/components/script/dom/bindings/codegen/parser/tests/test_toJSON.py @@ -0,0 +1,192 @@ +def WebIDLTest(parser, harness): + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(object arg); + object toJSON(long arg); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow overloads of a toJSON method.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + object toJSON(object arg); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a toJSON method with arguments.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a toJSON method with 'long' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] object toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(not threw, "Should allow a default toJSON method with 'object' as return type.") + + parser = parser.reset() + threw = False + try: + parser.parse( + """ + interface Test { + [Default] long toJSON(); + }; + """) + results = parser.finish() + except: + threw = True + harness.ok(threw, "Should not allow a default toJSON method with non-'object' as return type.") + + JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long", + "unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean", + "DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ] + + nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array", + "Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ] + + def doTest(testIDL, shouldThrow, description): + p = parser.reset() + threw = False + try: + p.parse(testIDL + + """ + enum Enum { "a", "b", "c" }; + interface InterfaceWithToJSON { long toJSON(); }; + interface InterfaceWithoutToJSON {}; + """); + p.finish(); + except Exception as x: + threw = True + harness.ok(x.message == "toJSON method has non-JSON return type", x) + harness.check(threw, shouldThrow, description) + + + for type in JsonTypes: + doTest("interface Test { %s toJSON(); };" % type, False, + "%s should be a JSON type" % type) + + doTest("interface Test { sequence<%s> toJSON(); };" % type, False, + "sequence<%s> should be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; " + "interface Test { Foo toJSON(); }; " % type, False, + "dictionary containing only JSON type (%s) should be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; " + "interface Test { Bar toJSON(); }; " % type, False, + "dictionary whose ancestors only contain JSON types should be a JSON type") + + doTest("dictionary Foo { any foo; }; dictionary Bar : Foo { %s bar; };" + "interface Test { Bar toJSON(); };" % type, True, + "dictionary whose ancestors contain non-JSON types should not be a JSON type") + + doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, False, + "record<DOMString, %s> should be a JSON type" % type) + + doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False, + "record<ByteString, %s> should be a JSON type" % type) + + doTest("interface Test { record<USVString, %s> toJSON(); };" % type, False, + "record<USVString, %s> should be a JSON type" % type) + + otherUnionType = "Foo" if type != "object" else "long" + doTest("interface Foo { object toJSON(); };" + "interface Test { (%s or %s) toJSON(); };" % (otherUnionType, type), False, + "union containing only JSON types (%s or %s) should be a JSON type" %(otherUnionType, type)) + + doTest("interface test { %s? toJSON(); };" % type, False, + "Nullable type (%s) should be a JSON type" % type) + + doTest("interface Foo : InterfaceWithoutToJSON { %s toJSON(); };" + "interface Test { Foo toJSON(); };" % type, False, + "interface with toJSON should be a JSON type") + + doTest("interface Foo : InterfaceWithToJSON { };" + "interface Test { Foo toJSON(); };", False, + "inherited interface with toJSON should be a JSON type") + + for type in nonJsonTypes: + doTest("interface Test { %s toJSON(); };" % type, True, + "%s should not be a JSON type" % type) + + doTest("interface Test { sequence<%s> toJSON(); };" % type, True, + "sequence<%s> should not be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; " + "interface Test { Foo toJSON(); }; " % type, True, + "Dictionary containing a non-JSON type (%s) should not be a JSON type" % type) + + doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; " + "interface Test { Bar toJSON(); }; " % type, True, + "dictionary whose ancestors only contain non-JSON types should not be a JSON type") + + doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, True, + "record<DOMString, %s> should not be a JSON type" % type) + + doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, True, + "record<ByteString, %s> should not be a JSON type" % type) + + doTest("interface Test { record<USVString, %s> toJSON(); };" % type, True, + "record<USVString, %s> should not be a JSON type" % type) + + if type != "any": + doTest("interface Foo { object toJSON(); }; " + "interface Test { (Foo or %s) toJSON(); };" % type, True, + "union containing a non-JSON type (%s) should not be a JSON type" % type) + + doTest("interface test { %s? toJSON(); };" % type, True, + "Nullable type (%s) should not be a JSON type" % type) + + doTest("dictionary Foo { long foo; any bar; };" + "interface Test { Foo toJSON(); };", True, + "dictionary containing a non-JSON type should not be a JSON type") + + doTest("interface Foo : InterfaceWithoutToJSON { }; " + "interface Test { Foo toJSON(); };", True, + "interface without toJSON should not be a JSON type") |