mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 05:15:45 +00:00
Bug 793267. Add support for [Unforgeable] in WebIDL. r=peterv
Unforgeable attributes are defined directly on the object, not on the prototype. So we keep them in a separate spec array and define them during object creation as needed. This means that we have to pass that separate spec array to the Xray helpers, unfortunately, which somewhat complicates those.
This commit is contained in:
parent
e76c2ec778
commit
fbeee7dfd0
@ -88,6 +88,14 @@ DefinePrefable(JSContext* cx, JSObject* obj, Prefable<T>* props)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
DefineUnforgeableAttributes(JSContext* cx, JSObject* obj,
|
||||
Prefable<JSPropertySpec>* props)
|
||||
{
|
||||
return DefinePrefable(cx, obj, props);
|
||||
}
|
||||
|
||||
|
||||
// We should use JSFunction objects for interface objects, but we need a custom
|
||||
// hasInstance hook because we have new interface objects on prototype chains of
|
||||
// old (XPConnect-based) bindings. Because Function.prototype.toString throws if
|
||||
@ -499,49 +507,58 @@ XrayResolveProperty(JSContext* cx, JSObject* wrapper, jsid id,
|
||||
}
|
||||
}
|
||||
|
||||
if (nativeProperties->attributes) {
|
||||
Prefable<JSPropertySpec>* attr;
|
||||
for (attr = nativeProperties->attributes; attr->specs; ++attr) {
|
||||
if (attr->enabled) {
|
||||
// Set i to be the index into our full list of ids/specs that we're
|
||||
// looking at now.
|
||||
size_t i = attr->specs - nativeProperties->attributeSpecs;
|
||||
for ( ; nativeProperties->attributeIds[i] != JSID_VOID; ++i) {
|
||||
if (id == nativeProperties->attributeIds[i]) {
|
||||
JSPropertySpec& attrSpec = nativeProperties->attributeSpecs[i];
|
||||
// Because of centralization, we need to make sure we fault in the
|
||||
// JitInfos as well. At present, until the JSAPI changes, the easiest
|
||||
// way to do this is wrap them up as functions ourselves.
|
||||
desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
|
||||
// They all have getters, so we can just make it.
|
||||
JSObject *global = JS_GetGlobalForObject(cx, wrapper);
|
||||
JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
|
||||
0, 0, global, nullptr);
|
||||
if (!fun)
|
||||
return false;
|
||||
SET_JITINFO(fun, attrSpec.getter.info);
|
||||
JSObject *funobj = JS_GetFunctionObject(fun);
|
||||
desc->getter = js::CastAsJSPropertyOp(funobj);
|
||||
desc->attrs |= JSPROP_GETTER;
|
||||
if (attrSpec.setter.op) {
|
||||
// We have a setter! Make it.
|
||||
fun = JS_NewFunction(cx, (JSNative)attrSpec.setter.op, 1, 0,
|
||||
global, nullptr);
|
||||
JSPropertySpec* attributeSpecs = nativeProperties->attributeSpecs;
|
||||
Prefable<JSPropertySpec>* attr = nativeProperties->attributes;
|
||||
jsid* attributeIds = nativeProperties->attributeIds;
|
||||
// Do the attribute stuff for attributes, then for unforgeable attributes
|
||||
for (int attrIteration = 0; attrIteration < 2; ++attrIteration) {
|
||||
if (attr) {
|
||||
for (; attr->specs; ++attr) {
|
||||
if (attr->enabled) {
|
||||
// Set i to be the index into our full list of ids/specs that we're
|
||||
// looking at now.
|
||||
size_t i = attr->specs - attributeSpecs;
|
||||
for ( ; attributeIds[i] != JSID_VOID; ++i) {
|
||||
if (id == attributeIds[i]) {
|
||||
JSPropertySpec& attrSpec = attributeSpecs[i];
|
||||
// Because of centralization, we need to make sure we fault in the
|
||||
// JitInfos as well. At present, until the JSAPI changes, the easiest
|
||||
// way to do this is wrap them up as functions ourselves.
|
||||
desc->attrs = attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS;
|
||||
// They all have getters, so we can just make it.
|
||||
JSObject *global = JS_GetGlobalForObject(cx, wrapper);
|
||||
JSFunction *fun = JS_NewFunction(cx, (JSNative)attrSpec.getter.op,
|
||||
0, 0, global, nullptr);
|
||||
if (!fun)
|
||||
return false;
|
||||
SET_JITINFO(fun, attrSpec.setter.info);
|
||||
funobj = JS_GetFunctionObject(fun);
|
||||
desc->setter = js::CastAsJSStrictPropertyOp(funobj);
|
||||
desc->attrs |= JSPROP_SETTER;
|
||||
} else {
|
||||
desc->setter = nullptr;
|
||||
SET_JITINFO(fun, attrSpec.getter.info);
|
||||
JSObject *funobj = JS_GetFunctionObject(fun);
|
||||
desc->getter = js::CastAsJSPropertyOp(funobj);
|
||||
desc->attrs |= JSPROP_GETTER;
|
||||
if (attrSpec.setter.op) {
|
||||
// We have a setter! Make it.
|
||||
fun = JS_NewFunction(cx, (JSNative)attrSpec.setter.op, 1, 0,
|
||||
global, nullptr);
|
||||
if (!fun)
|
||||
return false;
|
||||
SET_JITINFO(fun, attrSpec.setter.info);
|
||||
funobj = JS_GetFunctionObject(fun);
|
||||
desc->setter = js::CastAsJSStrictPropertyOp(funobj);
|
||||
desc->attrs |= JSPROP_SETTER;
|
||||
} else {
|
||||
desc->setter = nullptr;
|
||||
}
|
||||
desc->obj = wrapper;
|
||||
return true;
|
||||
}
|
||||
desc->obj = wrapper;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attributeSpecs = nativeProperties->unforgeableAttributeSpecs;
|
||||
attr = nativeProperties->unforgeableAttributes;
|
||||
attributeIds = nativeProperties->unforgeableAttributeIds;
|
||||
}
|
||||
|
||||
if (nativeProperties->constants) {
|
||||
@ -608,21 +625,30 @@ XrayEnumerateProperties(JS::AutoIdVector& props,
|
||||
}
|
||||
}
|
||||
|
||||
if (nativeProperties->attributes) {
|
||||
Prefable<JSPropertySpec>* attr;
|
||||
for (attr = nativeProperties->attributes; attr->specs; ++attr) {
|
||||
if (attr->enabled) {
|
||||
// Set i to be the index into our full list of ids/specs that we're
|
||||
// looking at now.
|
||||
size_t i = attr->specs - nativeProperties->attributeSpecs;
|
||||
for ( ; nativeProperties->attributeIds[i] != JSID_VOID; ++i) {
|
||||
if ((nativeProperties->attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
|
||||
!props.append(nativeProperties->attributeIds[i])) {
|
||||
return false;
|
||||
JSPropertySpec* attributeSpecs = nativeProperties->attributeSpecs;
|
||||
Prefable<JSPropertySpec>* attr = nativeProperties->attributes;
|
||||
jsid* attributeIds = nativeProperties->attributeIds;
|
||||
// Do the attribute stuff for attributes, then for unforgeable attributes
|
||||
for (int attrIteration = 0; attrIteration < 2; ++attrIteration) {
|
||||
if (attr) {
|
||||
for (; attr->specs; ++attr) {
|
||||
if (attr->enabled) {
|
||||
// Set i to be the index into our full list of ids/specs that we're
|
||||
// looking at now.
|
||||
size_t i = attr->specs - attributeSpecs;
|
||||
for ( ; attributeIds[i] != JSID_VOID; ++i) {
|
||||
if ((attributeSpecs[i].flags & JSPROP_ENUMERATE) &&
|
||||
!props.append(attributeIds[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
attributeSpecs = nativeProperties->unforgeableAttributeSpecs;
|
||||
attr = nativeProperties->unforgeableAttributes;
|
||||
attributeIds = nativeProperties->unforgeableAttributeIds;
|
||||
}
|
||||
|
||||
if (nativeProperties->constants) {
|
||||
|
@ -350,6 +350,9 @@ struct NativeProperties
|
||||
Prefable<JSPropertySpec>* attributes;
|
||||
jsid* attributeIds;
|
||||
JSPropertySpec* attributeSpecs;
|
||||
Prefable<JSPropertySpec>* unforgeableAttributes;
|
||||
jsid* unforgeableAttributeIds;
|
||||
JSPropertySpec* unforgeableAttributeSpecs;
|
||||
Prefable<ConstantSpec>* constants;
|
||||
jsid* constantIds;
|
||||
ConstantSpec* constantSpecs;
|
||||
@ -402,6 +405,13 @@ CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
|
||||
const NativeProperties* chromeProperties,
|
||||
const char* name);
|
||||
|
||||
/*
|
||||
* Define the unforgeable attributes on an object.
|
||||
*/
|
||||
bool
|
||||
DefineUnforgeableAttributes(JSContext* cx, JSObject* obj,
|
||||
Prefable<JSPropertySpec>* props);
|
||||
|
||||
inline bool
|
||||
MaybeWrapValue(JSContext* cx, JSObject* obj, JS::Value* vp)
|
||||
{
|
||||
|
@ -136,7 +136,7 @@ DOMJSClass Class = {
|
||||
%s, /* trace */
|
||||
JSCLASS_NO_INTERNAL_MEMBERS
|
||||
},
|
||||
%s
|
||||
%s
|
||||
};
|
||||
""" % (self.descriptor.interface.identifier.name,
|
||||
ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
|
||||
@ -892,6 +892,7 @@ class PropertyDefiner:
|
||||
# We only need Xrays for methods, attributes and constants, but in
|
||||
# workers there are no Xrays.
|
||||
return (self.name is "Methods" or self.name is "Attributes" or
|
||||
self.name is "UnforgeableAttributes" or
|
||||
self.name is "Constants") and not self.descriptor.workers
|
||||
|
||||
def __str__(self):
|
||||
@ -1084,19 +1085,30 @@ class MethodDefiner(PropertyDefiner):
|
||||
pref, specData, doIdArrays)
|
||||
|
||||
class AttrDefiner(PropertyDefiner):
|
||||
def __init__(self, descriptor, name):
|
||||
def __init__(self, descriptor, name, unforgeable):
|
||||
PropertyDefiner.__init__(self, descriptor, name)
|
||||
self.name = name
|
||||
attributes = [m for m in descriptor.interface.members if m.isAttr()]
|
||||
attributes = [m for m in descriptor.interface.members
|
||||
if m.isAttr() and m.isUnforgeable() == unforgeable]
|
||||
self.chrome = [m for m in attributes if isChromeOnly(m)]
|
||||
self.regular = [m for m in attributes if not isChromeOnly(m)]
|
||||
self.unforgeable = unforgeable
|
||||
|
||||
if unforgeable and len(attributes) != 0 and descriptor.proxy:
|
||||
raise TypeError("Unforgeable properties are not supported on "
|
||||
"proxy bindings without [NamedPropertiesObject]. "
|
||||
"And not even supported on the ones with "
|
||||
"[NamedPropertiesObject] yet, but we should fix "
|
||||
"that, since they're safe there.")
|
||||
|
||||
def generateArray(self, array, name, doIdArrays):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
|
||||
def flags(attr):
|
||||
return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
|
||||
unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
|
||||
return ("JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" +
|
||||
unforgeable)
|
||||
|
||||
def getter(attr):
|
||||
native = ("genericLenientGetter" if attr.hasLenientThis()
|
||||
@ -1155,16 +1167,19 @@ class PropertyArrays():
|
||||
def __init__(self, descriptor):
|
||||
self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True)
|
||||
self.methods = MethodDefiner(descriptor, "Methods", False)
|
||||
self.attrs = AttrDefiner(descriptor, "Attributes")
|
||||
self.attrs = AttrDefiner(descriptor, "Attributes", unforgeable=False)
|
||||
self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes",
|
||||
unforgeable=True)
|
||||
self.consts = ConstDefiner(descriptor, "Constants")
|
||||
|
||||
@staticmethod
|
||||
def arrayNames():
|
||||
return [ "staticMethods", "methods", "attrs", "consts" ]
|
||||
return [ "staticMethods", "methods", "attrs", "unforgeableAttrs",
|
||||
"consts" ]
|
||||
|
||||
@staticmethod
|
||||
def xrayRelevantArrayNames():
|
||||
return [ "methods", "attrs", "consts" ]
|
||||
return [ "methods", "attrs", "unforgeableAttrs", "consts" ]
|
||||
|
||||
def hasChromeOnly(self):
|
||||
return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames())
|
||||
@ -1311,10 +1326,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||
else:
|
||||
properties = "nullptr"
|
||||
if self.properties.hasChromeOnly():
|
||||
if self.descriptor.workers:
|
||||
accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
|
||||
else:
|
||||
accessCheck = "xpc::AccessCheck::isChrome(aGlobal)"
|
||||
accessCheck = GetAccessCheck(self.descriptor, "aGlobal")
|
||||
chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr"
|
||||
else:
|
||||
chromeProperties = "nullptr"
|
||||
@ -1514,14 +1526,59 @@ def CreateBindingJSObject(descriptor, parent):
|
||||
"""
|
||||
return create % parent
|
||||
|
||||
def GetAccessCheck(descriptor, globalName):
|
||||
"""
|
||||
globalName is the name of the global JSObject*
|
||||
|
||||
returns a string
|
||||
"""
|
||||
if descriptor.workers:
|
||||
accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
|
||||
else:
|
||||
accessCheck = "xpc::AccessCheck::isChrome(%s)" % globalName
|
||||
return accessCheck
|
||||
|
||||
def InitUnforgeableProperties(descriptor, properties):
|
||||
"""
|
||||
properties is a PropertyArrays instance
|
||||
"""
|
||||
defineUnforgeables = ("if (!DefineUnforgeableAttributes(aCx, obj, %s)) {\n"
|
||||
" return nullptr;\n"
|
||||
"}")
|
||||
unforgeableAttrs = properties.unforgeableAttrs
|
||||
unforgeables = []
|
||||
if unforgeableAttrs.hasNonChromeOnly():
|
||||
unforgeables.append(CGGeneric(defineUnforgeables %
|
||||
unforgeableAttrs.variableName(False)))
|
||||
if unforgeableAttrs.hasChromeOnly():
|
||||
unforgeables.append(
|
||||
CGIfWrapper(CGGeneric(defineUnforgeables %
|
||||
unforgeableAttrs.variableName(True)),
|
||||
GetAccessCheck(descriptor, "global")))
|
||||
|
||||
return CGIndenter(CGWrapper(
|
||||
CGList(unforgeables, "\n"),
|
||||
pre=("\n"
|
||||
"// Important: do unforgeable property setup after we have handed\n"
|
||||
"// over ownership of the C++ object to obj as needed, so that if\n"
|
||||
"// we fail and it ends up GCed it won't have problems in the\n"
|
||||
"// finalizer trying to drop its ownership of the C++ object.\n"),
|
||||
post="\n")).define() if len(unforgeables) > 0 else ""
|
||||
|
||||
class CGWrapWithCacheMethod(CGAbstractMethod):
|
||||
def __init__(self, descriptor):
|
||||
"""
|
||||
Create a wrapper JSObject for a given native that implements nsWrapperCache.
|
||||
|
||||
properties should be a PropertyArrays instance.
|
||||
"""
|
||||
def __init__(self, descriptor, properties):
|
||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
|
||||
Argument(descriptor.nativeType + '*', 'aObject'),
|
||||
Argument('nsWrapperCache*', 'aCache'),
|
||||
Argument('bool*', 'aTriedToWrap')]
|
||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
|
||||
self.properties = properties
|
||||
|
||||
def definition_body(self):
|
||||
if self.descriptor.workers:
|
||||
@ -1544,11 +1601,12 @@ class CGWrapWithCacheMethod(CGAbstractMethod):
|
||||
}
|
||||
|
||||
%s
|
||||
|
||||
%s
|
||||
aCache->SetWrapper(obj);
|
||||
|
||||
return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
|
||||
CreateBindingJSObject(self.descriptor, "parent"))
|
||||
CreateBindingJSObject(self.descriptor, "parent"),
|
||||
InitUnforgeableProperties(self.descriptor, self.properties))
|
||||
|
||||
class CGWrapMethod(CGAbstractMethod):
|
||||
def __init__(self, descriptor):
|
||||
@ -1562,12 +1620,19 @@ class CGWrapMethod(CGAbstractMethod):
|
||||
return " return Wrap(aCx, aScope, aObject, aObject, aTriedToWrap);"
|
||||
|
||||
class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
|
||||
def __init__(self, descriptor):
|
||||
"""
|
||||
Create a wrapper JSObject for a given native that does not implement
|
||||
nsWrapperCache.
|
||||
|
||||
properties should be a PropertyArrays instance.
|
||||
"""
|
||||
def __init__(self, descriptor, properties):
|
||||
# XXX can we wrap if we don't have an interface prototype object?
|
||||
assert descriptor.interface.hasInterfacePrototypeObject()
|
||||
args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
|
||||
Argument(descriptor.nativeType + '*', 'aObject')]
|
||||
CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
|
||||
self.properties = properties
|
||||
|
||||
def definition_body(self):
|
||||
return """
|
||||
@ -1578,8 +1643,9 @@ class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
|
||||
}
|
||||
|
||||
%s
|
||||
|
||||
return obj;""" % CreateBindingJSObject(self.descriptor, "global")
|
||||
%s
|
||||
return obj;""" % (CreateBindingJSObject(self.descriptor, "global"),
|
||||
InitUnforgeableProperties(self.descriptor, self.properties))
|
||||
|
||||
builtinNames = {
|
||||
IDLType.Tags.bool: 'bool',
|
||||
@ -5331,10 +5397,11 @@ class CGDescriptor(CGThing):
|
||||
cgThings.append(CGDOMJSClass(descriptor))
|
||||
|
||||
if descriptor.wrapperCache:
|
||||
cgThings.append(CGWrapWithCacheMethod(descriptor))
|
||||
cgThings.append(CGWrapWithCacheMethod(descriptor, properties))
|
||||
cgThings.append(CGWrapMethod(descriptor))
|
||||
else:
|
||||
cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
|
||||
cgThings.append(CGWrapNonWrapperCacheMethod(descriptor,
|
||||
properties))
|
||||
|
||||
cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
|
||||
cgThings = CGWrapper(cgThings, pre='\n', post='\n')
|
||||
|
@ -517,6 +517,22 @@ class IDLInterface(IDLObjectWithScope):
|
||||
self.parent.identifier.name),
|
||||
[self.location, self.parent.location])
|
||||
|
||||
# Now make sure our parent doesn't have any [Unforgeable]
|
||||
# attributes. We don't need to check its ancestors, because it has
|
||||
# already checked those. We don't need to check its consequential
|
||||
# interfaces, because it has already imported those into its
|
||||
# .members.
|
||||
unforgeableParentMembers = [
|
||||
attr for attr in parent.members
|
||||
if attr.isAttr() and attr.isUnforgeable() ]
|
||||
if len(unforgeableParentMembers) != 0:
|
||||
locs = [self.location, parent.location]
|
||||
locs.extend(attr.location for attr in unforgeableParentMembers)
|
||||
raise WebIDLError("Interface %s inherits from %s, which has "
|
||||
"[Unforgeable] members" %
|
||||
(self.identifier.name, parent.identifier.name),
|
||||
locs)
|
||||
|
||||
for iface in self.implementedInterfaces:
|
||||
iface.finish(scope)
|
||||
|
||||
@ -1946,6 +1962,7 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
self.inherit = inherit
|
||||
self.static = static
|
||||
self.lenientThis = False
|
||||
self._unforgeable = False
|
||||
|
||||
if readonly and inherit:
|
||||
raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'",
|
||||
@ -2007,6 +2024,11 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
raise WebIDLError("[LenientThis] is only allowed on non-static "
|
||||
"attributes", [attr.location, self.location])
|
||||
self.lenientThis = True
|
||||
elif identifier == "Unforgeable":
|
||||
if not self.readonly:
|
||||
raise WebIDLError("[Unforgeable] is only allowed on readonly "
|
||||
"attributes", [attr.location, self.location])
|
||||
self._unforgeable = True
|
||||
IDLInterfaceMember.handleExtendedAttribute(self, attr)
|
||||
|
||||
def resolve(self, parentScope):
|
||||
@ -2021,6 +2043,9 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
def hasLenientThis(self):
|
||||
return self.lenientThis
|
||||
|
||||
def isUnforgeable(self):
|
||||
return self._unforgeable
|
||||
|
||||
class IDLArgument(IDLObjectWithIdentifier):
|
||||
def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False):
|
||||
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
|
||||
@ -2469,10 +2494,14 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
raise WebIDLError("Methods must not be flagged as "
|
||||
"[GetterInfallible]",
|
||||
[attr.location, self.location])
|
||||
if identifier == "SetterInfallible":
|
||||
elif identifier == "SetterInfallible":
|
||||
raise WebIDLError("Methods must not be flagged as "
|
||||
"[SetterInfallible]",
|
||||
[attr.location, self.location])
|
||||
elif identifier == "Unforgeable":
|
||||
raise WebIDLError("Methods must not be flagged as "
|
||||
"[Unforgeable]",
|
||||
[attr.location, self.location])
|
||||
IDLInterfaceMember.handleExtendedAttribute(self, attr)
|
||||
|
||||
class IDLImplementsStatement(IDLObject):
|
||||
|
50
dom/bindings/parser/tests/test_unforgeable.py
Normal file
50
dom/bindings/parser/tests/test_unforgeable.py
Normal file
@ -0,0 +1,50 @@
|
||||
def WebIDLTest(parser, harness):
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface Child : Parent {
|
||||
};
|
||||
interface Parent {
|
||||
[Unforgeable] readonly attribute long foo;
|
||||
};
|
||||
""")
|
||||
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw, "Should have thrown.")
|
||||
|
||||
parser = parser.reset();
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface Child : Parent {
|
||||
};
|
||||
interface Parent {};
|
||||
interface Consequential {
|
||||
[Unforgeable] readonly attribute long foo;
|
||||
};
|
||||
Parent implements Consequential;
|
||||
""")
|
||||
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw, "Should have thrown.")
|
||||
|
||||
parser = parser.reset();
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface iface {
|
||||
[Unforgeable] attribute long foo;
|
||||
};
|
||||
""")
|
||||
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
|
||||
harness.ok(threw, "Should have thrown.")
|
@ -415,6 +415,8 @@ public:
|
||||
// Miscellania
|
||||
int32_t AttrWithLenientThis();
|
||||
void SetAttrWithLenientThis(int32_t);
|
||||
uint32_t UnforgeableAttr();
|
||||
uint32_t UnforgeableAttr2();
|
||||
|
||||
// Methods and properties imported via "implements"
|
||||
bool ImplementedProperty();
|
||||
|
@ -333,6 +333,8 @@ interface TestInterface {
|
||||
|
||||
// Miscellania
|
||||
[LenientThis] attribute long attrWithLenientThis;
|
||||
[Unforgeable] readonly attribute long unforgeableAttr;
|
||||
[Unforgeable, ChromeOnly] readonly attribute long unforgeableAttr2;
|
||||
|
||||
// If you add things here, add them to TestExampleGen as well
|
||||
};
|
||||
|
@ -303,6 +303,8 @@ interface TestExampleInterface {
|
||||
|
||||
// Miscellania
|
||||
[LenientThis] attribute long attrWithLenientThis;
|
||||
[Unforgeable] readonly attribute long unforgeableAttr;
|
||||
[Unforgeable, ChromeOnly] readonly attribute long unforgeableAttr2;
|
||||
|
||||
// If you add things here, add them to TestCodeGen as well
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user