mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1353867
- Add code generation for array of cross origin properties. r=bzbarsky
Differential Revision: https://phabricator.services.mozilla.com/D12654 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
05c586c0a9
commit
b816d68b07
@ -2088,6 +2088,75 @@ class PropertyDefiner:
|
||||
interfaceMember.getExtendedAttribute("SecureContext") is not None,
|
||||
nonExposureSet)
|
||||
|
||||
@staticmethod
|
||||
def generatePrefableArrayValues(array, descriptor, specFormatter, specTerminator,
|
||||
getCondition, getDataTuple,
|
||||
switchToCondition=None):
|
||||
"""
|
||||
This method generates an array of spec entries for interface members. It returns
|
||||
a tuple containing the array of spec entries and the maximum of the number of
|
||||
spec entries per condition.
|
||||
|
||||
array is an array of interface members.
|
||||
|
||||
descriptor is the descriptor for the interface that array contains members of.
|
||||
|
||||
specFormatter is a function that takes a single argument, a tuple,
|
||||
and returns a string, a spec array entry.
|
||||
|
||||
specTerminator is a terminator for the spec array (inserted every time
|
||||
our controlling pref changes and at the end of the array).
|
||||
|
||||
getCondition is a callback function that takes an array entry and
|
||||
returns the corresponding MemberCondition.
|
||||
|
||||
getDataTuple is a callback function that takes an array entry and
|
||||
returns a tuple suitable to be passed to specFormatter.
|
||||
|
||||
switchToCondition is a function that takes a MemberCondition and an array of
|
||||
previously generated spec entries. If None is passed for this function then all
|
||||
the interface members should return the same value from getCondition.
|
||||
"""
|
||||
def unsupportedSwitchToCondition(condition, specs):
|
||||
# If no specs have been added yet then this is just the first call to
|
||||
# switchToCondition that we call to avoid putting a specTerminator at the
|
||||
# front of the list.
|
||||
if len(specs) == 0:
|
||||
return
|
||||
raise "Not supported"
|
||||
|
||||
if switchToCondition is None:
|
||||
switchToCondition = unsupportedSwitchToCondition
|
||||
|
||||
specs = []
|
||||
numSpecsInCurPrefable = 0
|
||||
maxNumSpecsInPrefable = 0
|
||||
|
||||
# So we won't put a specTerminator at the very front of the list:
|
||||
lastCondition = getCondition(array[0], descriptor)
|
||||
|
||||
switchToCondition(lastCondition, specs)
|
||||
|
||||
for member in array:
|
||||
curCondition = getCondition(member, descriptor)
|
||||
if lastCondition != curCondition:
|
||||
# Terminate previous list
|
||||
specs.append(specTerminator)
|
||||
if numSpecsInCurPrefable > maxNumSpecsInPrefable:
|
||||
maxNumSpecsInPrefable = numSpecsInCurPrefable
|
||||
numSpecsInCurPrefable = 0
|
||||
# And switch to our new condition
|
||||
switchToCondition(curCondition, specs)
|
||||
lastCondition = curCondition
|
||||
# And the actual spec
|
||||
specs.append(specFormatter(getDataTuple(member, descriptor)))
|
||||
numSpecsInCurPrefable += 1
|
||||
if numSpecsInCurPrefable > maxNumSpecsInPrefable:
|
||||
maxNumSpecsInPrefable = numSpecsInCurPrefable
|
||||
specs.append(specTerminator)
|
||||
|
||||
return (specs, maxNumSpecsInPrefable)
|
||||
|
||||
def generatePrefableArray(self, array, name, specFormatter, specTerminator,
|
||||
specType, getCondition, getDataTuple):
|
||||
"""
|
||||
@ -2119,10 +2188,7 @@ class PropertyDefiner:
|
||||
# pref control is added to members while still allowing us to define all
|
||||
# the members in the smallest number of JSAPI calls.
|
||||
assert len(array) != 0
|
||||
# So we won't put a specTerminator at the very front of the list:
|
||||
lastCondition = getCondition(array[0], self.descriptor)
|
||||
|
||||
specs = []
|
||||
disablers = []
|
||||
prefableSpecs = []
|
||||
|
||||
@ -2137,11 +2203,11 @@ class PropertyDefiner:
|
||||
prefableWithoutDisablersTemplate = ' { nullptr, &%s_specs[%d] }'
|
||||
prefCacheTemplate = '&%s[%d].disablers->enabled'
|
||||
|
||||
def switchToCondition(props, condition):
|
||||
def switchToCondition(condition, specs):
|
||||
# Remember the info about where our pref-controlled
|
||||
# booleans live.
|
||||
if condition.pref is not None:
|
||||
props.prefCacheData.append(
|
||||
self.prefCacheData.append(
|
||||
(condition.pref,
|
||||
prefCacheTemplate % (name, len(prefableSpecs))))
|
||||
# Set up pointers to the new sets of specs inside prefableSpecs
|
||||
@ -2157,28 +2223,9 @@ class PropertyDefiner:
|
||||
prefableSpecs.append(prefableWithoutDisablersTemplate %
|
||||
(name, len(specs)))
|
||||
|
||||
switchToCondition(self, lastCondition)
|
||||
|
||||
numSpecsInCurPrefable = 0
|
||||
maxNumSpecsInPrefable = 0
|
||||
|
||||
for member in array:
|
||||
curCondition = getCondition(member, self.descriptor)
|
||||
if lastCondition != curCondition:
|
||||
# Terminate previous list
|
||||
specs.append(specTerminator)
|
||||
if numSpecsInCurPrefable > maxNumSpecsInPrefable:
|
||||
maxNumSpecsInPrefable = numSpecsInCurPrefable
|
||||
numSpecsInCurPrefable = 0
|
||||
# And switch to our new condition
|
||||
switchToCondition(self, curCondition)
|
||||
lastCondition = curCondition
|
||||
# And the actual spec
|
||||
specs.append(specFormatter(getDataTuple(member)))
|
||||
numSpecsInCurPrefable += 1
|
||||
specs.append(specTerminator)
|
||||
if numSpecsInCurPrefable > maxNumSpecsInPrefable:
|
||||
maxNumSpecsInPrefable = numSpecsInCurPrefable
|
||||
specs, maxNumSpecsInPrefable = self.generatePrefableArrayValues(
|
||||
array, self.descriptor, specFormatter, specTerminator, getCondition,
|
||||
getDataTuple, switchToCondition)
|
||||
prefableSpecs.append(" { nullptr, nullptr }")
|
||||
|
||||
specType = "const " + specType
|
||||
@ -2266,7 +2313,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
"""
|
||||
A class for defining methods on a prototype object.
|
||||
"""
|
||||
def __init__(self, descriptor, name, static, unforgeable=False):
|
||||
def __init__(self, descriptor, name, crossOriginOnly, static, unforgeable=False):
|
||||
assert not (static and unforgeable)
|
||||
PropertyDefiner.__init__(self, descriptor, name)
|
||||
|
||||
@ -2279,6 +2326,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
methods = [m for m in descriptor.interface.members if
|
||||
m.isMethod() and m.isStatic() == static and
|
||||
MemberIsUnforgeable(m, descriptor) == unforgeable and
|
||||
(not crossOriginOnly or m.getExtendedAttribute("CrossOriginCallable")) and
|
||||
not m.isIdentifierLess()]
|
||||
else:
|
||||
methods = []
|
||||
@ -2315,16 +2363,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
})
|
||||
continue
|
||||
|
||||
method = {
|
||||
"name": m.identifier.name,
|
||||
"methodInfo": not m.isStatic(),
|
||||
"length": methodLength(m),
|
||||
"flags": EnumerabilityFlags(m),
|
||||
"condition": PropertyDefiner.getControllingCondition(m, descriptor),
|
||||
"allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
|
||||
"returnsPromise": m.returnsPromise(),
|
||||
"hasIteratorAlias": "@@iterator" in m.aliases
|
||||
}
|
||||
method = self.methodData(m, descriptor)
|
||||
|
||||
if m.isStatic():
|
||||
method["nativeName"] = CppKeywords.checkMethodName(IDLToCIdentifier(m.identifier.name))
|
||||
@ -2459,70 +2498,86 @@ class MethodDefiner(PropertyDefiner):
|
||||
# non-static methods go on the interface prototype object
|
||||
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
|
||||
|
||||
@staticmethod
|
||||
def methodData(m, descriptor, overrideFlags=None):
|
||||
return {
|
||||
"name": m.identifier.name,
|
||||
"methodInfo": not m.isStatic(),
|
||||
"length": methodLength(m),
|
||||
"flags": EnumerabilityFlags(m) if (overrideFlags is None) else overrideFlags,
|
||||
"condition": PropertyDefiner.getControllingCondition(m, descriptor),
|
||||
"allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
|
||||
"returnsPromise": m.returnsPromise(),
|
||||
"hasIteratorAlias": "@@iterator" in m.aliases
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def formatSpec(fields):
|
||||
if fields[0].startswith("@@"):
|
||||
fields = (fields[0][2:],) + fields[1:]
|
||||
return ' JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
|
||||
return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
|
||||
|
||||
@staticmethod
|
||||
def specData(m, descriptor, unforgeable=False):
|
||||
def flags(m, unforgeable):
|
||||
unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if unforgeable else ""
|
||||
return m["flags"] + unforgeable
|
||||
|
||||
if "selfHostedName" in m:
|
||||
selfHostedName = '"%s"' % m["selfHostedName"]
|
||||
assert not m.get("methodInfo", True)
|
||||
accessor = "nullptr"
|
||||
jitinfo = "nullptr"
|
||||
else:
|
||||
selfHostedName = "nullptr"
|
||||
# When defining symbols, function name may not match symbol name
|
||||
methodName = m.get("methodName", m["name"])
|
||||
accessor = m.get("nativeName", IDLToCIdentifier(methodName))
|
||||
if m.get("methodInfo", True):
|
||||
if m.get("returnsPromise", False):
|
||||
exceptionPolicy = "ConvertExceptionsToPromises"
|
||||
else:
|
||||
exceptionPolicy = "ThrowExceptions"
|
||||
|
||||
# Cast this in case the methodInfo is a
|
||||
# JSTypedMethodJitInfo.
|
||||
jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
|
||||
if m.get("allowCrossOriginThis", False):
|
||||
accessor = ("(GenericMethod<CrossOriginThisPolicy, %s>)" %
|
||||
exceptionPolicy)
|
||||
elif descriptor.interface.isOnGlobalProtoChain():
|
||||
accessor = ("(GenericMethod<MaybeGlobalThisPolicy, %s>)" %
|
||||
exceptionPolicy)
|
||||
else:
|
||||
accessor = ("(GenericMethod<NormalThisPolicy, %s>)" %
|
||||
exceptionPolicy)
|
||||
else:
|
||||
if m.get("returnsPromise", False):
|
||||
jitinfo = "&%s_methodinfo" % accessor
|
||||
accessor = "StaticMethodPromiseWrapper"
|
||||
else:
|
||||
jitinfo = "nullptr"
|
||||
|
||||
return (m["name"], accessor, jitinfo, m["length"], flags(m, unforgeable), selfHostedName)
|
||||
|
||||
@staticmethod
|
||||
def condition(m, d):
|
||||
return m["condition"]
|
||||
|
||||
def generateArray(self, array, name):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
|
||||
def condition(m, d):
|
||||
return m["condition"]
|
||||
|
||||
def flags(m):
|
||||
unforgeable = " | JSPROP_PERMANENT | JSPROP_READONLY" if self.unforgeable else ""
|
||||
return m["flags"] + unforgeable
|
||||
|
||||
def specData(m):
|
||||
if "selfHostedName" in m:
|
||||
selfHostedName = '"%s"' % m["selfHostedName"]
|
||||
assert not m.get("methodInfo", True)
|
||||
accessor = "nullptr"
|
||||
jitinfo = "nullptr"
|
||||
else:
|
||||
selfHostedName = "nullptr"
|
||||
# When defining symbols, function name may not match symbol name
|
||||
methodName = m.get("methodName", m["name"])
|
||||
accessor = m.get("nativeName", IDLToCIdentifier(methodName))
|
||||
if m.get("methodInfo", True):
|
||||
if m.get("returnsPromise", False):
|
||||
exceptionPolicy = "ConvertExceptionsToPromises"
|
||||
else:
|
||||
exceptionPolicy = "ThrowExceptions"
|
||||
|
||||
# Cast this in case the methodInfo is a
|
||||
# JSTypedMethodJitInfo.
|
||||
jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
|
||||
if m.get("allowCrossOriginThis", False):
|
||||
accessor = ("(GenericMethod<CrossOriginThisPolicy, %s>)" %
|
||||
exceptionPolicy)
|
||||
elif self.descriptor.interface.isOnGlobalProtoChain():
|
||||
accessor = ("(GenericMethod<MaybeGlobalThisPolicy, %s>)" %
|
||||
exceptionPolicy)
|
||||
else:
|
||||
accessor = ("(GenericMethod<NormalThisPolicy, %s>)" %
|
||||
exceptionPolicy)
|
||||
else:
|
||||
if m.get("returnsPromise", False):
|
||||
jitinfo = "&%s_methodinfo" % accessor
|
||||
accessor = "StaticMethodPromiseWrapper"
|
||||
else:
|
||||
jitinfo = "nullptr"
|
||||
|
||||
return (m["name"], accessor, jitinfo, m["length"], flags(m), selfHostedName)
|
||||
|
||||
def formatSpec(fields):
|
||||
if fields[0].startswith("@@"):
|
||||
fields = (fields[0][2:],) + fields[1:]
|
||||
return ' JS_SYM_FNSPEC(%s, %s, %s, %s, %s, %s)' % fields
|
||||
return ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)' % fields
|
||||
|
||||
return self.generatePrefableArray(
|
||||
array, name,
|
||||
formatSpec,
|
||||
self.formatSpec,
|
||||
' JS_FS_END',
|
||||
'JSFunctionSpec',
|
||||
condition, specData)
|
||||
self.condition, functools.partial(self.specData, unforgeable=self.unforgeable))
|
||||
|
||||
|
||||
def IsCrossOriginWritable(attr, descriptor):
|
||||
def isCrossOriginWritable(attr, descriptor):
|
||||
"""
|
||||
Return whether the IDLAttribute in question is cross-origin writable on the
|
||||
interface represented by descriptor. This is needed to handle the fact that
|
||||
@ -2543,29 +2598,27 @@ def isNonExposedNavigatorObjectGetter(attr, descriptor):
|
||||
not descriptor.getDescriptor(attr.type.inner.identifier.name).register)
|
||||
|
||||
class AttrDefiner(PropertyDefiner):
|
||||
def __init__(self, descriptor, name, static, unforgeable=False):
|
||||
def __init__(self, descriptor, name, crossOriginOnly, static, unforgeable=False):
|
||||
assert not (static and unforgeable)
|
||||
PropertyDefiner.__init__(self, descriptor, name)
|
||||
self.name = name
|
||||
# Ignore non-static attributes for interfaces without a proto object
|
||||
if descriptor.interface.hasInterfacePrototypeObject() or static:
|
||||
attributes = [m for m in descriptor.interface.members if
|
||||
m.isAttr() and m.isStatic() == static and
|
||||
MemberIsUnforgeable(m, descriptor) == unforgeable and
|
||||
not isNonExposedNavigatorObjectGetter(m, descriptor)]
|
||||
idlAttrs = [m for m in descriptor.interface.members if
|
||||
m.isAttr() and m.isStatic() == static and
|
||||
MemberIsUnforgeable(m, descriptor) == unforgeable and
|
||||
(not crossOriginOnly or m.getExtendedAttribute("CrossOriginReadable") or
|
||||
isCrossOriginWritable(m, descriptor)) and
|
||||
not isNonExposedNavigatorObjectGetter(m, descriptor)]
|
||||
else:
|
||||
attributes = []
|
||||
|
||||
attributes = [
|
||||
{"name": name, "attr": attr}
|
||||
for attr in attributes
|
||||
for name in [attr.identifier.name] + attr.bindingAliases
|
||||
]
|
||||
idlAttrs = []
|
||||
|
||||
attributes = []
|
||||
for attr in idlAttrs:
|
||||
attributes.extend(self.attrData(attr, unforgeable))
|
||||
self.chrome = [m for m in attributes if isChromeOnly(m["attr"])]
|
||||
self.regular = [m for m in attributes if not isChromeOnly(m["attr"])]
|
||||
self.static = static
|
||||
self.unforgeable = unforgeable
|
||||
|
||||
if static:
|
||||
if not descriptor.interface.hasInterfaceObject():
|
||||
@ -2576,19 +2629,25 @@ class AttrDefiner(PropertyDefiner):
|
||||
# non-static attributes go on the interface prototype object
|
||||
assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
|
||||
|
||||
def generateArray(self, array, name):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
@staticmethod
|
||||
def attrData(attr, unforgeable=False, overrideFlags=None):
|
||||
if overrideFlags is None:
|
||||
permanent = " | JSPROP_PERMANENT" if unforgeable else ""
|
||||
flags = EnumerabilityFlags(attr) + permanent
|
||||
else:
|
||||
flags = overrideFlags
|
||||
return ({"name": name, "attr": attr, "flags": flags} for name in [attr.identifier.name] + attr.bindingAliases)
|
||||
|
||||
def condition(m, d):
|
||||
return PropertyDefiner.getControllingCondition(m["attr"], d)
|
||||
|
||||
def flags(attr):
|
||||
unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else ""
|
||||
return EnumerabilityFlags(attr) + unforgeable
|
||||
@staticmethod
|
||||
def condition(m, d):
|
||||
return PropertyDefiner.getControllingCondition(m["attr"], d)
|
||||
|
||||
@staticmethod
|
||||
def specData(entry, descriptor, static=False, crossOriginOnly=False):
|
||||
def getter(attr):
|
||||
if self.static:
|
||||
if crossOriginOnly and not attr.getExtendedAttribute("CrossOriginReadable"):
|
||||
return "nullptr, nullptr"
|
||||
if static:
|
||||
if attr.type.isPromise():
|
||||
raise TypeError("Don't know how to handle "
|
||||
"static Promise-returning "
|
||||
@ -2614,7 +2673,7 @@ class AttrDefiner(PropertyDefiner):
|
||||
elif attr.getExtendedAttribute("CrossOriginReadable"):
|
||||
accessor = ("GenericGetter<CrossOriginThisPolicy, %s>" %
|
||||
exceptionPolicy)
|
||||
elif self.descriptor.interface.isOnGlobalProtoChain():
|
||||
elif descriptor.interface.isOnGlobalProtoChain():
|
||||
accessor = ("GenericGetter<MaybeGlobalThisPolicy, %s>" %
|
||||
exceptionPolicy)
|
||||
else:
|
||||
@ -2631,20 +2690,22 @@ class AttrDefiner(PropertyDefiner):
|
||||
attr.getExtendedAttribute("Replaceable") is None and
|
||||
attr.getExtendedAttribute("LenientSetter") is None):
|
||||
return "nullptr, nullptr"
|
||||
if self.static:
|
||||
if crossOriginOnly and not isCrossOriginWritable(attr, descriptor):
|
||||
return "nullptr, nullptr"
|
||||
if static:
|
||||
accessor = 'set_' + IDLToCIdentifier(attr.identifier.name)
|
||||
jitinfo = "nullptr"
|
||||
else:
|
||||
if attr.hasLenientThis():
|
||||
if IsCrossOriginWritable(attr, self.descriptor):
|
||||
if isCrossOriginWritable(attr, descriptor):
|
||||
raise TypeError("Can't handle lenient cross-origin "
|
||||
"writable attribute %s.%s" %
|
||||
(self.descriptor.name,
|
||||
(descriptor.name,
|
||||
attr.identifier.name))
|
||||
accessor = "GenericSetter<LenientThisPolicy>"
|
||||
elif IsCrossOriginWritable(attr, self.descriptor):
|
||||
elif isCrossOriginWritable(attr, descriptor):
|
||||
accessor = "GenericSetter<CrossOriginThisPolicy>"
|
||||
elif self.descriptor.interface.isOnGlobalProtoChain():
|
||||
elif descriptor.interface.isOnGlobalProtoChain():
|
||||
accessor = "GenericSetter<MaybeGlobalThisPolicy>"
|
||||
else:
|
||||
accessor = "GenericSetter<NormalThisPolicy>"
|
||||
@ -2652,16 +2713,22 @@ class AttrDefiner(PropertyDefiner):
|
||||
return "%s, %s" % \
|
||||
(accessor, jitinfo)
|
||||
|
||||
def specData(entry):
|
||||
name, attr = entry["name"], entry["attr"]
|
||||
return (name, flags(attr), getter(attr), setter(attr))
|
||||
name, attr, flags = entry["name"], entry["attr"], entry["flags"]
|
||||
return (name, flags, getter(attr), setter(attr))
|
||||
|
||||
@staticmethod
|
||||
def formatSpec(fields):
|
||||
return ' { "%s", %s, %s, %s }' % fields
|
||||
|
||||
def generateArray(self, array, name):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
|
||||
return self.generatePrefableArray(
|
||||
array, name,
|
||||
lambda fields: ' { "%s", %s, %s, %s }' % fields,
|
||||
' { nullptr, 0, nullptr, nullptr, nullptr, nullptr }',
|
||||
array, name, self.formatSpec,
|
||||
' JS_PS_END',
|
||||
'JSPropertySpec',
|
||||
condition, specData)
|
||||
self.condition, functools.partial(self.specData, static=self.static))
|
||||
|
||||
|
||||
class ConstDefiner(PropertyDefiner):
|
||||
@ -2679,7 +2746,7 @@ class ConstDefiner(PropertyDefiner):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
|
||||
def specData(const):
|
||||
def specData(const, descriptor):
|
||||
return (const.identifier.name,
|
||||
convertConstIDLValueToJSVal(const.value))
|
||||
|
||||
@ -2692,17 +2759,19 @@ class ConstDefiner(PropertyDefiner):
|
||||
|
||||
|
||||
class PropertyArrays():
|
||||
def __init__(self, descriptor):
|
||||
self.staticMethods = MethodDefiner(descriptor, "StaticMethods",
|
||||
def __init__(self, descriptor, crossOriginOnly=False):
|
||||
self.staticMethods = MethodDefiner(descriptor, "StaticMethods", crossOriginOnly,
|
||||
static=True)
|
||||
self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes",
|
||||
self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes", crossOriginOnly,
|
||||
static=True)
|
||||
self.methods = MethodDefiner(descriptor, "Methods", static=False)
|
||||
self.attrs = AttrDefiner(descriptor, "Attributes", static=False)
|
||||
self.methods = MethodDefiner(descriptor, "Methods", crossOriginOnly, static=False)
|
||||
self.attrs = AttrDefiner(descriptor, "Attributes", crossOriginOnly, static=False)
|
||||
self.unforgeableMethods = MethodDefiner(descriptor, "UnforgeableMethods",
|
||||
static=False, unforgeable=True)
|
||||
crossOriginOnly, static=False,
|
||||
unforgeable=True)
|
||||
self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes",
|
||||
static=False, unforgeable=True)
|
||||
crossOriginOnly, static=False,
|
||||
unforgeable=True)
|
||||
self.consts = ConstDefiner(descriptor, "Constants")
|
||||
|
||||
@staticmethod
|
||||
@ -4081,6 +4150,77 @@ class CGClearCachedValueMethod(CGAbstractMethod):
|
||||
regetMember=regetMember)
|
||||
|
||||
|
||||
class CGCrossOriginProperties(CGThing):
|
||||
def __init__(self, descriptor):
|
||||
attrs = []
|
||||
methods = []
|
||||
for m in descriptor.interface.members:
|
||||
if m.isAttr() and (m.getExtendedAttribute("CrossOriginReadable") or isCrossOriginWritable(m, descriptor)):
|
||||
if m.isStatic():
|
||||
raise TypeError("Don't know how to deal with static method %s" %
|
||||
m.identifier.name)
|
||||
if PropertyDefiner.getControllingCondition(m, descriptor).hasDisablers():
|
||||
raise TypeError("Don't know how to deal with disabler for %s" %
|
||||
m.identifier.name)
|
||||
if len(m.bindingAliases) > 0:
|
||||
raise TypeError("Don't know how to deal with aliases for %s" %
|
||||
m.identifier.name)
|
||||
attrs.extend(AttrDefiner.attrData(m, overrideFlags="0"))
|
||||
elif m.isMethod() and m.getExtendedAttribute("CrossOriginCallable"):
|
||||
if m.isStatic():
|
||||
raise TypeError("Don't know how to deal with static method %s" %
|
||||
m.identifier.name)
|
||||
if PropertyDefiner.getControllingCondition(m, descriptor).hasDisablers():
|
||||
raise TypeError("Don't know how to deal with disabler for %s" %
|
||||
m.identifier.name)
|
||||
if len(m.aliases) > 0:
|
||||
raise TypeError("Don't know how to deal with aliases for %s" %
|
||||
m.identifier.name)
|
||||
methods.append(MethodDefiner.methodData(m, descriptor, overrideFlags="JSPROP_READONLY"))
|
||||
|
||||
if len(attrs) > 0:
|
||||
self.attributeSpecs, _ = PropertyDefiner.generatePrefableArrayValues(
|
||||
attrs, descriptor, AttrDefiner.formatSpec, ' JS_PS_END\n',
|
||||
AttrDefiner.condition, functools.partial(AttrDefiner.specData, crossOriginOnly=True))
|
||||
else:
|
||||
self.attributeSpecs = [' JS_PS_END\n']
|
||||
if len(methods) > 0:
|
||||
self.methodSpecs, _ = PropertyDefiner.generatePrefableArrayValues(
|
||||
methods, descriptor, MethodDefiner.formatSpec, ' JS_FS_END\n',
|
||||
MethodDefiner.condition, MethodDefiner.specData)
|
||||
else:
|
||||
self.methodSpecs = [' JS_FS_END\n']
|
||||
|
||||
def declare(self):
|
||||
return fill("""
|
||||
extern JSPropertySpec sCrossOriginAttributes[${attributesLength}];
|
||||
extern JSFunctionSpec sCrossOriginMethods[${methodsLength}];
|
||||
""",
|
||||
attributesLength=len(self.attributeSpecs),
|
||||
methodsLength=len(self.methodSpecs))
|
||||
|
||||
def define(self):
|
||||
return fill(
|
||||
"""
|
||||
// We deliberately use brace-elision to make Visual Studio produce better initalization code.
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
#endif
|
||||
JSPropertySpec sCrossOriginAttributes[] = {
|
||||
$*{attributeSpecs}
|
||||
};
|
||||
JSFunctionSpec sCrossOriginMethods[] = {
|
||||
$*{methodSpecs}
|
||||
};
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
""",
|
||||
attributeSpecs=",\n".join(self.attributeSpecs),
|
||||
methodSpecs=",\n".join(self.methodSpecs))
|
||||
|
||||
|
||||
class CGIsPermittedMethod(CGAbstractMethod):
|
||||
"""
|
||||
crossOriginGetters/Setters/Methods are sets of names of the relevant members.
|
||||
@ -12398,14 +12538,14 @@ def memberProperties(m, descriptor):
|
||||
props.isCrossOriginGetter = True
|
||||
if not m.readonly:
|
||||
if not m.isStatic() and descriptor.interface.hasInterfacePrototypeObject():
|
||||
if IsCrossOriginWritable(m, descriptor):
|
||||
if isCrossOriginWritable(m, descriptor):
|
||||
props.isCrossOriginSetter = True
|
||||
elif m.getExtendedAttribute("PutForwards"):
|
||||
if IsCrossOriginWritable(m, descriptor):
|
||||
if isCrossOriginWritable(m, descriptor):
|
||||
props.isCrossOriginSetter = True
|
||||
elif (m.getExtendedAttribute("Replaceable") or
|
||||
m.getExtendedAttribute("LenientSetter")):
|
||||
if IsCrossOriginWritable(m, descriptor):
|
||||
if isCrossOriginWritable(m, descriptor):
|
||||
props.isCrossOriginSetter = True
|
||||
|
||||
return props
|
||||
@ -12648,6 +12788,7 @@ class CGDescriptor(CGThing):
|
||||
|
||||
# See whether we need we need to generate an IsPermitted method
|
||||
if crossOriginGetters or crossOriginSetters or crossOriginMethods:
|
||||
cgThings.append(CGCrossOriginProperties(descriptor))
|
||||
cgThings.append(CGIsPermittedMethod(descriptor,
|
||||
crossOriginGetters,
|
||||
crossOriginSetters,
|
||||
|
@ -5138,6 +5138,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[%s] must take no arguments" % identifier,
|
||||
[attr.location])
|
||||
if identifier == "CrossOriginCallable" and self.isStatic():
|
||||
raise WebIDLError("[CrossOriginCallable] is only allowed on non-static "
|
||||
"attributes"
|
||||
[attr.location, self.location])
|
||||
elif identifier == "Pure":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[Pure] must take no arguments",
|
||||
|
Loading…
Reference in New Issue
Block a user