diff --git a/netwerk/base/nsIURI.idl b/netwerk/base/nsIURI.idl index 6a66bd1d81d7..df1a98e8730f 100644 --- a/netwerk/base/nsIURI.idl +++ b/netwerk/base/nsIURI.idl @@ -183,18 +183,7 @@ interface nsIURI : nsISupports * to GetScheme, thereby saving extra allocating and freeing. Returns true if * the schemes match (case ignored). */ - boolean schemeIs(in string scheme); - - /* - * Infallible version of SchemeIs for C++ callers. - */ - %{C++ - bool SchemeIs(const char* aScheme) { - bool ret; - mozilla::Unused << SchemeIs(aScheme, &ret); - return ret; - } - %} + [infallible] boolean schemeIs(in string scheme); /** * This method resolves a relative string into an absolute URI string, diff --git a/xpcom/idl-parser/xpidl/header.py b/xpcom/idl-parser/xpidl/header.py index 5ce87948d2c4..fb842deddc9b 100644 --- a/xpcom/idl-parser/xpidl/header.py +++ b/xpcom/idl-parser/xpidl/header.py @@ -33,8 +33,8 @@ def attributeParamName(a): return "a" + firstCap(a.name) -def attributeParamNames(a, getter): - if getter and a.notxpcom: +def attributeParamNames(a, getter, return_param=True): + if getter and (a.notxpcom or not return_param): l = [] else: l = [attributeParamName(a)] @@ -48,6 +48,24 @@ def attributeNativeName(a, getter): return "%s%s" % (getter and 'Get' or 'Set', binaryname) +def attributeAttributes(a, getter): + ret = "" + + if a.must_use: + ret = "[[nodiscard]] " + ret + + # Ideally, we'd set MOZ_CAN_RUN_SCRIPT in the "scriptable and not + # builtinclass" case too, so we'd just have memberCanRunScript() check + # explicit_setter_can_run_script/explicit_setter_can_run_script and call it + # here. But that would likely require a fair amount of Gecko-side + # annotation work. See bug 1534292. + if ((a.explicit_getter_can_run_script and getter) or + (a.explicit_setter_can_run_script and not getter)): + ret = "MOZ_CAN_RUN_SCRIPT " + ret + + return ret + + def attributeReturnType(a, getter, macro): """macro should be NS_IMETHOD or NS_IMETHODIMP""" # Pick the type to be returned from the getter/setter. @@ -67,22 +85,11 @@ def attributeReturnType(a, getter, macro): else: ret = "%s_(%s)" % (macro, ret) - if a.must_use: - ret = "[[nodiscard]] " + ret - - # Ideally, we'd set MOZ_CAN_RUN_SCRIPT in the "scriptable and not - # builtinclass" case too, so we'd just have memberCanRunScript() check - # explicit_setter_can_run_script/explicit_setter_can_run_script and call it - # here. But that would likely require a fair amount of Gecko-side - # annotation work. See bug 1534292. - if ((a.explicit_getter_can_run_script and getter) or - (a.explicit_setter_can_run_script and not getter)): - ret = "MOZ_CAN_RUN_SCRIPT " + ret - return ret + return attributeAttributes(a, getter) + ret -def attributeParamlist(a, getter): - if getter and a.notxpcom: +def attributeParamlist(a, getter, return_param=True): + if getter and (a.notxpcom or not return_param): l = [] else: l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'), @@ -104,6 +111,22 @@ def methodNativeName(m): return m.binaryname is not None and m.binaryname or firstCap(m.name) +def methodAttributes(m): + ret = "" + + if m.must_use: + ret = "[[nodiscard]] " + ret + + # Ideally, we'd set MOZ_CAN_RUN_SCRIPT in the "scriptable and not + # builtinclass" case too, so we'd just have memberCanRunScript() check + # explicit_can_run_script and call it here. But that would likely require + # a fair amount of Gecko-side annotation work. See bug 1534292. + if m.explicit_can_run_script: + ret = "MOZ_CAN_RUN_SCRIPT " + ret + + return ret + + def methodReturnType(m, macro): """macro should be NS_IMETHOD or NS_IMETHODIMP""" if m.notxpcom: @@ -122,16 +145,7 @@ def methodReturnType(m, macro): else: ret = "%s_(%s)" % (macro, ret) - if m.must_use: - ret = "[[nodiscard]] " + ret - - # Ideally, we'd set MOZ_CAN_RUN_SCRIPT in the "scriptable and not - # builtinclass" case too, so we'd just have memberCanRunScript() check - # explicit_can_run_script and call it here. But that would likely require - # a fair amount of Gecko-side annotation work. See bug 1534292. - if m.explicit_can_run_script: - ret = "MOZ_CAN_RUN_SCRIPT " + ret - return ret + return methodAttributes(m) + ret def methodAsNative(m, declType='NS_IMETHOD'): @@ -140,7 +154,7 @@ def methodAsNative(m, declType='NS_IMETHOD'): paramlistAsNative(m)) -def paramlistAsNative(m, empty='void'): +def paramlistAsNative(m, empty='void', return_param=True): l = [paramAsNative(p) for p in m.params] if m.implicit_jscontext: @@ -149,7 +163,7 @@ def paramlistAsNative(m, empty='void'): if m.optional_argc: l.append('uint8_t _argc') - if not m.notxpcom and m.realtype.name != 'void': + if not m.notxpcom and m.realtype.name != 'void' and return_param: l.append(paramAsNative(xpidl.Param( paramtype='out', type=None, name='_retval', attlist=[], location=None, realtype=m.realtype))) @@ -191,7 +205,7 @@ def paramAsNative(p): default_spec) -def paramlistNames(m): +def paramlistNames(m, return_param=True): names = [p.name for p in m.params] if m.implicit_jscontext: @@ -200,7 +214,7 @@ def paramlistNames(m): if m.optional_argc: names.append('_argc') - if not m.notxpcom and m.realtype.name != 'void': + if not m.notxpcom and m.realtype.name != 'void' and return_param: names.append('_retval') if len(names) == 0: @@ -273,20 +287,19 @@ def print_header(idl, fd, filename, relpath): # Include some extra files if any attributes are infallible. interfaces = [p for p in idl.productions if p.kind == 'interface'] wroteRunScriptIncludes = False + wroteInfallibleIncludes = False for iface in interfaces: - attrs = [m for m in iface.members if isinstance(m, xpidl.Attribute)] - for attr in attrs: - if attr.infallible: + for member in iface.members: + if not isinstance(member, xpidl.Attribute) and not isinstance(member, xpidl.Method): + continue + if not wroteInfallibleIncludes and member.infallible: fd.write(infallible_includes) - break - - if not wroteRunScriptIncludes: - methods = [m for m in iface.members if isinstance(m, xpidl.Method)] - for member in itertools.chain(attrs, methods): - if memberCanRunScript(member): - fd.write(can_run_script_includes) - wroteRunScriptIncludes = True - break + wroteInfallibleIncludes = True + if not wroteRunScriptIncludes and memberCanRunScript(member): + fd.write(can_run_script_includes) + wroteRunScriptIncludes = True + if wroteRunScriptIncludes and wroteInfallibleIncludes: + break fd.write('\n') fd.write(header_end) @@ -377,8 +390,8 @@ iface_forward_safe = """ /* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */ #define NS_FORWARD_SAFE_%(macroname)s(_to) """ # NOQA: E501 -attr_builtin_infallible_tmpl = """\ - inline %(realtype)s%(nativename)s(%(args)s) +builtin_infallible_tmpl = """\ + %(attributes)sinline %(realtype)s %(nativename)s(%(args)s) { %(realtype)sresult; mozilla::DebugOnly rv = %(nativename)s(%(argnames)s&result); @@ -390,8 +403,8 @@ attr_builtin_infallible_tmpl = """\ # NOTE: We don't use RefPtr::forget here because we don't want to need the # definition of %(realtype)s in scope, which we would need for the # AddRef/Release calls. -attr_refcnt_infallible_tmpl = """\ - inline already_AddRefed<%(realtype)s>%(nativename)s(%(args)s) +refcnt_infallible_tmpl = """\ + %(attributes)s inline already_AddRefed<%(realtype)s> %(nativename)s(%(args)s) { %(realtype)s* result = nullptr; mozilla::DebugOnly rv = %(nativename)s(%(argnames)s&result); @@ -401,6 +414,37 @@ attr_refcnt_infallible_tmpl = """\ """ +def infallibleDecl(member): + isattr = isinstance(member, xpidl.Attribute) + ismethod = isinstance(member, xpidl.Method) + assert isattr or ismethod + + realtype = member.realtype.nativeType('in') + tmpl = builtin_infallible_tmpl + + if member.realtype.kind != 'builtin' and member.realtype.kind != 'cenum': + assert realtype.endswith(' *'), "bad infallible type" + tmpl = refcnt_infallible_tmpl + realtype = realtype[:-2] # strip trailing pointer + + if isattr: + nativename = attributeNativeName(member, getter=True) + args = attributeParamlist(member, getter=True, return_param=False) + argnames = attributeParamNames(member, getter=True, return_param=False) + attributes = attributeAttributes(member, getter=True) + else: + nativename = methodNativeName(member) + args = paramlistAsNative(member, return_param=False) + argnames = paramlistNames(member, return_param=False) + attributes = methodAttributes(member) + + return tmpl % {'attributes': attributes, + 'realtype': realtype, + 'nativename': nativename, + 'args': args, + 'argnames': argnames + ', ' if argnames else ''} + + def write_interface(iface, fd): if iface.namemap is None: raise Exception("Interface was not resolved.") @@ -448,6 +492,9 @@ def write_interface(iface, fd): fd.write(" %s%s = 0;\n\n" % (runScriptAnnotation(m), methodAsNative(m))) + if m.infallible: + fd.write(infallibleDecl(m)) + def write_attr_decl(a): printComments(fd, a.doccomments, ' ') @@ -456,18 +503,7 @@ def write_interface(iface, fd): fd.write(" %s%s = 0;\n" % (runScriptAnnotation(a), attributeAsNative(a, True))) if a.infallible: - realtype = a.realtype.nativeType('in') - tmpl = attr_builtin_infallible_tmpl - - if a.realtype.kind != 'builtin' and a.realtype.kind != 'cenum': - assert realtype.endswith(' *'), "bad infallible type" - tmpl = attr_refcnt_infallible_tmpl - realtype = realtype[:-2] # strip trailing pointer - - fd.write(tmpl % {'realtype': realtype, - 'nativename': attributeNativeName(a, getter=True), - 'args': '' if not a.implicit_jscontext else 'JSContext* cx', - 'argnames': '' if not a.implicit_jscontext else 'cx, '}) + fd.write(infallibleDecl(a)) if not a.readonly: fd.write(" %s%s = 0;\n" % (runScriptAnnotation(a), diff --git a/xpcom/idl-parser/xpidl/xpidl.py b/xpcom/idl-parser/xpidl/xpidl.py index 22edc5e78305..2cef2341923a 100755 --- a/xpcom/idl-parser/xpidl/xpidl.py +++ b/xpcom/idl-parser/xpidl/xpidl.py @@ -965,6 +965,32 @@ class CEnum(object): return "\tcenum %s : %d { %s };\n" % (self.name, self.width, body) +# Infallible doesn't work for all return types. +# +# It also must be implemented on a builtinclass (otherwise it'd be unsound as +# it could be implemented by JS). +def ensureInfallibleIsSound(methodOrAttribute): + if not methodOrAttribute.infallible: + return + if methodOrAttribute.realtype.kind not in ['builtin', + 'interface', + 'forward', + 'webidl', + 'cenum']: + raise IDLError('[infallible] only works on interfaces, domobjects, and builtin types ' + '(numbers, booleans, cenum, and raw char types)', + methodOrAttribute.location) + if not methodOrAttribute.iface.attributes.builtinclass: + raise IDLError('[infallible] attributes and methods are only allowed on ' + '[builtinclass] interfaces', + methodOrAttribute.location) + + if methodOrAttribute.notxpcom: + raise IDLError('[infallible] does not make sense for a [notxpcom] ' + 'method or attribute', + methodOrAttribute.location) + + # An interface cannot be implemented by JS if it has a notxpcom # method or attribute, so it must be marked as builtinclass. # @@ -1060,19 +1086,8 @@ class Attribute(object): def resolve(self, iface): self.iface = iface self.realtype = iface.idl.getName(self.type, self.location) - if self.infallible and self.realtype.kind not in ['builtin', - 'interface', - 'forward', - 'webidl', - 'cenum']: - raise IDLError('[infallible] only works on interfaces, domobjects, and builtin types ' - '(numbers, booleans, cenum, and raw char types)', - self.location) - if self.infallible and not iface.attributes.builtinclass: - raise IDLError('[infallible] attributes are only allowed on ' - '[builtinclass] interfaces', - self.location) + ensureInfallibleIsSound(self) ensureBuiltinClassIfNeeded(self) def toIDL(self): @@ -1106,6 +1121,7 @@ class Method(object): # explicit_can_run_script is true if the method is explicitly annotated # as being able to cause script to run. explicit_can_run_script = False + infallible = False def __init__(self, type, name, attlist, paramlist, location, doccomments, raises): self.type = type @@ -1144,6 +1160,8 @@ class Method(object): self.must_use = True elif name == 'can_run_script': self.explicit_can_run_script = True + elif name == 'infallible': + self.infallible = True else: raise IDLError("Unexpected attribute '%s'" % name, aloc) @@ -1155,6 +1173,7 @@ class Method(object): self.iface = iface self.realtype = self.iface.idl.getName(self.type, self.location) + ensureInfallibleIsSound(self) ensureBuiltinClassIfNeeded(self) for p in self.params: