From 702a4a496f92f591a5e5eb756cdabc8082afe18f Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 29 May 2012 23:45:18 -0400 Subject: [PATCH] Bug 743906 part 2. Use Optional<> for optional arguments that don't have default values. r=peterv --- content/base/src/nsXMLHttpRequest.cpp | 24 ++- content/base/src/nsXMLHttpRequest.h | 7 +- dom/bindings/BindingUtils.h | 73 ++++++++++ dom/bindings/Codegen.py | 201 ++++++++++++++++++++------ dom/bindings/test/TestBindingHeader.h | 156 ++++++++++++++++++++ dom/bindings/test/TestCodeGen.webidl | 89 +++++++++++- dom/workers/XMLHttpRequest.cpp | 47 ++++-- dom/workers/XMLHttpRequest.h | 3 +- 8 files changed, 530 insertions(+), 70 deletions(-) diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index b5f02d9a8e87..4f6490a143df 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -1767,13 +1767,21 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url, // No optional arguments were passed in. Default async to true. async = true; } - return Open(method, url, async, user, password); + Optional realUser; + if (optional_argc > 1) { + realUser = &user; + } + Optional realPassword; + if (optional_argc > 2) { + realPassword = &password; + } + return Open(method, url, async, realUser, realPassword); } nsresult nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url, - bool async, const nsAString& user, - const nsAString& password) + bool async, const Optional& user, + const Optional& password) { NS_ENSURE_ARG(!method.IsEmpty()); @@ -1870,12 +1878,14 @@ nsXMLHttpRequest::Open(const nsACString& method, const nsACString& url, return NS_ERROR_CONTENT_BLOCKED; } - if (!user.IsEmpty()) { + // XXXbz this is wrong: we should only be looking at whether + // user/password were passed, not at the values! See bug 759624. + if (user.WasPassed() && !user.Value().IsEmpty()) { nsCAutoString userpass; - CopyUTF16toUTF8(user, userpass); - if (!password.IsEmpty()) { + CopyUTF16toUTF8(user.Value(), userpass); + if (password.WasPassed() && !password.Value().IsEmpty()) { userpass.Append(':'); - AppendUTF16toUTF8(password, userpass); + AppendUTF16toUTF8(password.Value(), userpass); } uri->SetUserPass(userpass); } diff --git a/content/base/src/nsXMLHttpRequest.h b/content/base/src/nsXMLHttpRequest.h index 69952c1ce4d3..2c065ae3534f 100644 --- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -252,7 +252,9 @@ public: // request void Open(const nsAString& aMethod, const nsAString& aUrl, bool aAsync, - const nsAString& aUser, const nsAString& aPassword, ErrorResult& aRv) + const mozilla::dom::Optional& aUser, + const mozilla::dom::Optional& aPassword, + ErrorResult& aRv) { aRv = Open(NS_ConvertUTF16toUTF8(aMethod), NS_ConvertUTF16toUTF8(aUrl), aAsync, aUser, aPassword); @@ -536,7 +538,8 @@ protected: void OnRedirectVerifyCallback(nsresult result); nsresult Open(const nsACString& method, const nsACString& url, bool async, - const nsAString& user, const nsAString& password); + const mozilla::dom::Optional& user, + const mozilla::dom::Optional& password); nsCOMPtr mContext; nsCOMPtr mPrincipal; diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index be4b4b5bcb62..018966afb0e0 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -631,6 +631,12 @@ public: return *ptr; } + operator const T&() const { + MOZ_ASSERT(inited); + MOZ_ASSERT(ptr, "NonNull was set to null"); + return *ptr; + } + void operator=(T* t) { ptr = t; MOZ_ASSERT(ptr); @@ -745,6 +751,71 @@ ConvertJSValueToString(JSContext* cx, const JS::Value& v, JS::Value* pval, return true; } +// Class for representing optional arguments. +template +class Optional { +public: + Optional() {} + + bool WasPassed() const { + return !mImpl.empty(); + } + + void Construct() { + mImpl.construct(); + } + + template + void Construct(const T1 &t1, const T2 &t2) { + mImpl.construct(t1, t2); + } + + const T& Value() const { + return mImpl.ref(); + } + + T& Value() { + return mImpl.ref(); + } + +private: + // Forbid copy-construction and assignment + Optional(const Optional& other) MOZ_DELETE; + const Optional &operator=(const Optional &other) MOZ_DELETE; + + Maybe mImpl; +}; + +// Specialization for strings. +template<> +class Optional { +public: + Optional() : mPassed(false) {} + + bool WasPassed() const { + return mPassed; + } + + void operator=(const nsAString* str) { + MOZ_ASSERT(str); + mStr = str; + mPassed = true; + } + + const nsAString& Value() const { + MOZ_ASSERT(WasPassed()); + return *mStr; + } + +private: + // Forbid copy-construction and assignment + Optional(const Optional& other) MOZ_DELETE; + const Optional &operator=(const Optional &other) MOZ_DELETE; + + bool mPassed; + const nsAString* mStr; +}; + // Class for representing sequences in arguments. We use an auto array that can // hold 16 elements, to avoid having to allocate in common cases. This needs to // be fallible because web content controls the length of the array, and can @@ -752,6 +823,8 @@ ConvertJSValueToString(JSContext* cx, const JS::Value& v, JS::Value* pval, template class Sequence : public AutoFallibleTArray { +public: + Sequence() : AutoFallibleTArray() {} }; } // namespace dom diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 020f7505494b..9f3195f63fcb 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1301,7 +1301,8 @@ ${target} = tmp.forget();""").substitute(self.substitution) def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, isDefinitelyObject=False, - isSequenceMember=False): + isSequenceMember=False, + isOptional=False): """ Get a template for converting a JS value to a native object based on the given type and descriptor. If failureCode is given, then we're actually @@ -1315,7 +1316,12 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, If isDefinitelyObject is True, that means we know the value isObject() and we have no need to recheck that. - The return value from this function is a tuple consisting of three things: + if isSequenceMember is True, we're being converted as part of a sequence. + + If isOptional is true, then we are doing conversion of an optional + argument with no default value. + + The return value from this function is a tuple consisting of four things: 1) A string representing the conversion code. This will have template substitution performed on it as follows: @@ -1331,6 +1337,11 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, 3) A CGThing representing the type of a "holder" (holderType) which will hold a possible reference to the C++ thing whose type we returned in #1, or None if no such holder is needed. + 4) A boolean indicating whether the caller has to do optional-argument handling. + This will only be true if isOptional is true and if the returned template + expects both declType and holderType to be wrapped in Optional<>, with + ${declName} and ${holderName} adjusted to point to the Value() of the + Optional, and Construct() calls to be made on the Optional<>s as needed. ${declName} must be in scope before the generated code is entered. @@ -1383,17 +1394,24 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, # We don't know anything about the object-ness of the things # we wrap, so don't pass through isDefinitelyObject (elementTemplate, elementDeclType, - elementHolderType) = getJSToNativeConversionTemplate( + elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate( elementType, descriptorProvider, isSequenceMember=True) + if dealWithOptional: + raise TypeError("Shouldn't have optional things in sequences") if elementHolderType is not None: raise TypeError("Shouldn't need holders for sequences") typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >") if nullable: typeName = CGWrapper(typeName, pre="Nullable< ", post=" >") - arrayRef = "${holderName}.Value()" + arrayRef = "${declName}.Value()" else: - arrayRef = "${holderName}" + arrayRef = "${declName}" + # If we're optional, the const will come from the Optional + mutableTypeName = typeName + if not isOptional: + typeName = CGWrapper(typeName, pre="const ") + templateBody = ("""JSObject* seq = &${val}.toObject();\n if (!IsArrayLike(cx, seq)) { return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS); @@ -1403,7 +1421,7 @@ uint32_t length; if (!JS_GetArrayLength(cx, seq, &length)) { return false; } -Sequence< %s > &arr = %s; +Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s); if (!arr.SetCapacity(length)) { return Throw<%s>(cx, NS_ERROR_OUT_OF_MEMORY); } @@ -1413,6 +1431,7 @@ for (uint32_t i = 0; i < length; ++i) { return false; } """ % (toStringBool(descriptorProvider.workers), + elementDeclType.define(), elementDeclType.define(), arrayRef, toStringBool(descriptorProvider.workers))) @@ -1427,15 +1446,10 @@ for (uint32_t i = 0; i < length; ++i) { templateBody += "\n}" templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject, - type, "${holderName}.SetNull()", + type, + "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define(), descriptorProvider.workers) - # And now at the very end (so we make sure it happens in the - # null case too, set our declName. - templateBody += ("\n" + "${declName} = &${holderName};") - # This is a bit of a hack: we're using NonNull with a const type inside - # to effectively produce a const ref from a non-const object. - return (templateBody, CGWrapper(typeName, pre="NonNull to hold our typed array. And in the optional + # non-nullable case we want to pass Optional to consumers, not + # Optional >, so jump though some hoops to do that. holderType = "Maybe<%s>" % name + constructLoc = "${holderName}" + constructMethod = "construct" if type.nullable(): - declType = name + "*" + if isOptional: + declType = "const Optional<" + name + "*>" + else: + declType = name + "*" else: - declType = "NonNull<" + name + ">" + if isOptional: + declType = "const Optional<" + name + ">" + # We don't need a holder in this case + holderType = None + constructLoc = "(const_cast& >(${declName}))" + constructMethod = "Construct" + else: + declType = "NonNull<" + name + ">" template = ( "if (!JS_Is%s(&${val}.toObject(), cx)) {\n" " %s" # No newline here because onFailure() handles that "}\n" - "${holderName}.construct(cx, &${val}.toObject());\n" % - (jsname, onFailure(failureCode, descriptorProvider.workers).define())) - if type.nullable: + "%s.%s(cx, &${val}.toObject());\n" % + (jsname, onFailure(failureCode, descriptorProvider.workers).define(), + constructLoc, constructMethod)) + nullableTarget = "" + if type.nullable(): + if isOptional: + mutableDecl = "(const_cast& >(${declName}))" + template += "%s.Construct();\n" % mutableDecl + nullableTarget = "%s.Value()" % mutableDecl + else: + nullableTarget = "${declName}" + template += "%s = ${holderName}.addr();" % nullableTarget + elif not isOptional: template += "${declName} = ${holderName}.addr();" - else: - template += "${declName} = ${holderName}.ref();" template = wrapObjectTemplate(template, isDefinitelyObject, type, - "${declName} = NULL", + "%s = NULL" % nullableTarget, descriptorProvider.workers, failureCode) - return (template, CGGeneric(declType), CGGeneric(holderType)) + if holderType is not None: + holderType = CGGeneric(holderType) + # We handle all the optional stuff ourselves; no need for caller to do it. + return (template, CGGeneric(declType), holderType, False) if type.isString(): if isSequenceMember: @@ -1587,12 +1627,19 @@ for (uint32_t i = 0; i < length; ++i) { nullBehavior = "eStringify" undefinedBehavior = "eStringify" + if isOptional: + declType = "Optional" + else: + declType = "NonNull" return ( "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, ${holderName})) {\n" " return false;\n" "}\n" - "${declName} = &${holderName};" % (nullBehavior, undefinedBehavior), - CGGeneric("NonNull"), CGGeneric("nsDependentString")) + "const_cast<%s&>(${declName}) = &${holderName};" % + (nullBehavior, undefinedBehavior, declType), + CGGeneric("const " + declType), CGGeneric("nsDependentString"), + # No need to deal with Optional here; we have handled it already + False) if type.isEnum(): if type.nullable(): @@ -1608,7 +1655,7 @@ for (uint32_t i = 0; i < length; ++i) { " }\n" "}" % { "enumtype" : enum, "values" : enum + "Values::strings" }, - CGGeneric(enum), None) + CGGeneric(enum), None, isOptional) if type.isCallback(): if isSequenceMember: @@ -1620,12 +1667,12 @@ for (uint32_t i = 0; i < length; ++i) { " ${declName} = &${val}.toObject();\n" "} else {\n" " ${declName} = NULL;\n" - "}", CGGeneric("JSObject*"), None) + "}", CGGeneric("JSObject*"), None, isOptional) if type.isAny(): if isSequenceMember: raise TypeError("Can't handle sequences of 'any'") - return ("${declName} = ${val};", CGGeneric("JS::Value"), None) + return ("${declName} = ${val};", CGGeneric("JS::Value"), None, isOptional) if type.isObject(): if isSequenceMember: @@ -1638,7 +1685,7 @@ for (uint32_t i = 0; i < length; ++i) { declType = CGGeneric("JSObject*") else: declType = CGGeneric("NonNull") - return (template, declType, None) + return (template, declType, None, isOptional) if not type.isPrimitive(): raise TypeError("Need conversion for argument type '%s'" % type) @@ -1650,33 +1697,91 @@ for (uint32_t i = 0; i < length; ++i) { " ${declName}.SetNull();\n" "} else if (!ValueToPrimitive<" + typeName + ">(cx, ${val}, &${declName}.SetValue())) {\n" " return false;\n" - "}", CGGeneric("Nullable<" + typeName + ">"), None) + "}", CGGeneric("Nullable<" + typeName + ">"), None, isOptional) else: return ("if (!ValueToPrimitive<" + typeName + ">(cx, ${val}, &${declName})) {\n" " return false;\n" - "}", CGGeneric(typeName), None) + "}", CGGeneric(typeName), None, isOptional) -def instantiateJSToNativeConversionTemplate(templateTuple, replacements): +def instantiateJSToNativeConversionTemplate(templateTuple, replacements, + argcAndIndex=None): """ Take a tuple as returned by getJSToNativeConversionTemplate and a set of replacements as required by the strings in such a tuple, and generate code to convert into stack C++ types. + + If argcAndIndex is not None it must be a dict that can be used to + replace ${argc} and ${index}, where ${index} is the index of this + argument (0-based) and ${argc} is the total number of arguments. """ - (templateBody, declType, holderType) = templateTuple + (templateBody, declType, holderType, dealWithOptional) = templateTuple + + if dealWithOptional and argcAndIndex is None: + raise TypeError("Have to deal with optional things, but don't know how") + if argcAndIndex is not None and declType is None: + raise TypeError("Need to predeclare optional things, so they will be " + "outside the check for big enough arg count!"); + result = CGList([], "\n") + # Make a copy of "replacements" since we may be about to start modifying it + replacements = dict(replacements) + originalHolderName = replacements["holderName"] if holderType is not None: + if dealWithOptional: + replacements["holderName"] = ( + "const_cast< %s & >(%s.Value())" % + (holderType.define(), originalHolderName)) + mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >") + holderType = CGWrapper(mutableHolderType, pre="const ") result.append( CGList([holderType, CGGeneric(" "), - CGGeneric(replacements["holderName"]), + CGGeneric(originalHolderName), CGGeneric(";")])) + + originalDeclName = replacements["declName"] if declType is not None: + if dealWithOptional: + replacements["declName"] = ( + "const_cast< %s & >(%s.Value())" % + (declType.define(), originalDeclName)) + mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >") + declType = CGWrapper(mutableDeclType, pre="const ") result.append( CGList([declType, CGGeneric(" "), - CGGeneric(replacements["declName"]), + CGGeneric(originalDeclName), CGGeneric(";")])) - result.append(CGGeneric( + + conversion = CGGeneric( string.Template(templateBody).substitute(replacements) - )) + ) + + if argcAndIndex is not None: + if dealWithOptional: + declConstruct = CGIndenter( + CGGeneric("const_cast< %s &>(%s).Construct();" % + (mutableDeclType.define(), originalDeclName))) + if holderType is not None: + holderConstruct = CGIndenter( + CGGeneric("const_cast< %s &>(%s).Construct();" % + (mutableHolderType.define(), originalHolderName))) + else: + holderConstruct = None + else: + declConstruct = None + holderConstruct = None + + conversion = CGList( + [CGGeneric( + string.Template("if (${index} < ${argc}) {").substitute( + argcAndIndex + )), + declConstruct, + holderConstruct, + CGIndenter(conversion), + CGGeneric("}")], + "\n") + + result.append(conversion) # Add an empty CGGeneric to get an extra newline after the argument # conversion. result.append(CGGeneric("")) @@ -1702,7 +1807,8 @@ def convertConstIDLValueToJSVal(value): def convertIDLDefaultValueToJSVal(value): if value.type: tag = value.type.tag() - if tag == IDLType.Tags.domstring: + if (tag == IDLType.Tags.domstring and + (not value.type.nullable() or not isinstance(value, IDLNullValue))): assert False # Not implemented! return convertConstIDLValueToJSVal(value) @@ -1743,12 +1849,18 @@ class CGArgumentConverter(CGThing): self.replacementVariables["valPtr"] = ( "&" + self.replacementVariables["val"]) self.descriptorProvider = descriptorProvider + if self.argument.optional and not self.argument.defaultValue: + self.argcAndIndex = replacer + else: + self.argcAndIndex = None def define(self): return instantiateJSToNativeConversionTemplate( getJSToNativeConversionTemplate(self.argument.type, - self.descriptorProvider), - self.replacementVariables).define() + self.descriptorProvider, + isOptional=(self.argcAndIndex is not None)), + self.replacementVariables, + self.argcAndIndex).define() def getWrapTemplateForType(type, descriptorProvider, result, successCode): """ @@ -2036,7 +2148,7 @@ class CGCallGenerator(CGThing): for (i, a) in enumerate(arguments): arg = "arg" + str(i) # This is a workaround for a bug in Apple's clang. - if a.type.isObject() and not a.type.nullable(): + if a.type.isObject() and not a.type.nullable() and not a.optional: arg = "(JSObject&)" + arg args.append(CGGeneric(arg)) resultOutParam = (returnType is not None and @@ -2387,7 +2499,10 @@ class CGMethodCall(CGThing): for sig in interfacesSigs: caseBody.append(CGIndenter(CGGeneric("do {"))); type = sig[1][distinguishingIndex].type - + + # The argument at index distinguishingIndex can't possibly + # be unset here, because we've already checked that argc is + # large enough that we can examine this argument. testCode = instantiateJSToNativeConversionTemplate( getJSToNativeConversionTemplate(type, descriptor, failureCode="break;", diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index 8b1ccf9ef435..810ca5d10a33 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -10,7 +10,10 @@ #include "nsWrapperCache.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/TypedArray.h" #include "nsCOMPtr.h" +// We don't export TestCodeGenBinding.h, but it's right in our parent dir. +#include "../TestCodeGenBinding.h" namespace mozilla { namespace dom { @@ -52,54 +55,75 @@ public: virtual nsISupports* GetParentObject(); // And now our actual WebIDL API + // Integer types int8_t GetReadonlyByte(ErrorResult&); int8_t GetWritableByte(ErrorResult&); void SetWritableByte(int8_t, ErrorResult&); void PassByte(int8_t, ErrorResult&); int8_t ReceiveByte(ErrorResult&); + void PassOptionalByte(const Optional&, ErrorResult&); + void PassOptionalByteWithDefault(int8_t, ErrorResult&); + void PassNullableByte(Nullable&, ErrorResult&); + void PassOptionalNullableByte(const Optional< Nullable >&, + ErrorResult&); int16_t GetReadonlyShort(ErrorResult&); int16_t GetWritableShort(ErrorResult&); void SetWritableShort(int16_t, ErrorResult&); void PassShort(int16_t, ErrorResult&); int16_t ReceiveShort(ErrorResult&); + void PassOptionalShort(const Optional&, ErrorResult&); + void PassOptionalShortWithDefault(int16_t, ErrorResult&); int32_t GetReadonlyLong(ErrorResult&); int32_t GetWritableLong(ErrorResult&); void SetWritableLong(int32_t, ErrorResult&); void PassLong(int32_t, ErrorResult&); int16_t ReceiveLong(ErrorResult&); + void PassOptionalLong(const Optional&, ErrorResult&); + void PassOptionalLongWithDefault(int32_t, ErrorResult&); int64_t GetReadonlyLongLong(ErrorResult&); int64_t GetWritableLongLong(ErrorResult&); void SetWritableLongLong(int64_t, ErrorResult&); void PassLongLong(int64_t, ErrorResult&); int64_t ReceiveLongLong(ErrorResult&); + void PassOptionalLongLong(const Optional&, ErrorResult&); + void PassOptionalLongLongWithDefault(int64_t, ErrorResult&); uint8_t GetReadonlyOctet(ErrorResult&); uint8_t GetWritableOctet(ErrorResult&); void SetWritableOctet(uint8_t, ErrorResult&); void PassOctet(uint8_t, ErrorResult&); uint8_t ReceiveOctet(ErrorResult&); + void PassOptionalOctet(const Optional&, ErrorResult&); + void PassOptionalOctetWithDefault(uint8_t, ErrorResult&); uint16_t GetReadonlyUnsignedShort(ErrorResult&); uint16_t GetWritableUnsignedShort(ErrorResult&); void SetWritableUnsignedShort(uint16_t, ErrorResult&); void PassUnsignedShort(uint16_t, ErrorResult&); uint16_t ReceiveUnsignedShort(ErrorResult&); + void PassOptionalUnsignedShort(const Optional&, ErrorResult&); + void PassOptionalUnsignedShortWithDefault(uint16_t, ErrorResult&); uint32_t GetReadonlyUnsignedLong(ErrorResult&); uint32_t GetWritableUnsignedLong(ErrorResult&); void SetWritableUnsignedLong(uint32_t, ErrorResult&); void PassUnsignedLong(uint32_t, ErrorResult&); uint32_t ReceiveUnsignedLong(ErrorResult&); + void PassOptionalUnsignedLong(const Optional&, ErrorResult&); + void PassOptionalUnsignedLongWithDefault(uint32_t, ErrorResult&); uint64_t GetReadonlyUnsignedLongLong(ErrorResult&); uint64_t GetWritableUnsignedLongLong(ErrorResult&); void SetWritableUnsignedLongLong(uint64_t, ErrorResult&); void PassUnsignedLongLong(uint64_t, ErrorResult&); uint64_t ReceiveUnsignedLongLong(ErrorResult&); + void PassOptionalUnsignedLongLong(const Optional&, ErrorResult&); + void PassOptionalUnsignedLongLongWithDefault(uint64_t, ErrorResult&); + // Interface types already_AddRefed ReceiveSelf(ErrorResult&); already_AddRefed ReceiveNullableSelf(ErrorResult&); TestInterface* ReceiveWeakSelf(ErrorResult&); @@ -111,6 +135,9 @@ public: void SetNonNullSelf(TestInterface&, ErrorResult&); already_AddRefed GetNullableSelf(ErrorResult&); void SetNullableSelf(TestInterface*, ErrorResult&); + void PassOptionalSelf(const Optional &, ErrorResult&); + void PassOptionalNonNullSelf(const Optional >&, ErrorResult&); + void PassOptionalSelfWithDefault(TestInterface*, ErrorResult&); already_AddRefed ReceiveOther(ErrorResult&); already_AddRefed ReceiveNullableOther(ErrorResult&); @@ -123,6 +150,9 @@ public: void SetNonNullOther(TestNonCastableInterface&, ErrorResult&); already_AddRefed GetNullableOther(ErrorResult&); void SetNullableOther(TestNonCastableInterface*, ErrorResult&); + void PassOptionalOther(const Optional&, ErrorResult&); + void PassOptionalNonNullOther(const Optional >&, ErrorResult&); + void PassOptionalOtherWithDefault(TestNonCastableInterface*, ErrorResult&); already_AddRefed ReceiveExternal(ErrorResult&); already_AddRefed ReceiveNullableExternal(ErrorResult&); @@ -135,7 +165,11 @@ public: void SetNonNullExternal(TestExternalInterface*, ErrorResult&); already_AddRefed GetNullableExternal(ErrorResult&); void SetNullableExternal(TestExternalInterface*, ErrorResult&); + void PassOptionalExternal(const Optional&, ErrorResult&); + void PassOptionalNonNullExternal(const Optional&, ErrorResult&); + void PassOptionalExternalWithDefault(TestExternalInterface*, ErrorResult&); + // Sequence types void ReceiveSequence(nsTArray&, ErrorResult&); void ReceiveNullableSequence(Nullable< nsTArray >&, ErrorResult&); void PassSequence(const Sequence &, ErrorResult&); @@ -168,6 +202,56 @@ public: ErrorResult&); void PassNullableCastableObjectNullableSequence(const Nullable< Sequence< nsRefPtr > >&, ErrorResult&); + void PassOptionalSequence(const Optional >&, + ErrorResult&); + void PassOptionalNullableSequence(const Optional > >&, + ErrorResult&); + void PassOptionalNullableSequenceWithDefaultValue(const Nullable< Sequence >&, + ErrorResult&); + void PassOptionalObjectSequence(const Optional > >&, + ErrorResult&); + + // Typed array types + void PassArrayBuffer(ArrayBuffer&, ErrorResult&); + void PassNullableArrayBuffer(ArrayBuffer*, ErrorResult&); + void PassOptionalArrayBuffer(const Optional&, ErrorResult&); + void PassOptionalNullableArrayBuffer(const Optional&, ErrorResult&); + void PassOptionalNullableArrayBufferWithDefaultValue(ArrayBuffer*, ErrorResult&); + + // String types + void PassString(const nsAString&, ErrorResult&); + void PassNullableString(const nsAString&, ErrorResult&); + void PassOptionalString(const Optional&, ErrorResult&); + void PassOptionalNullableString(const Optional&, ErrorResult&); + void PassOptionalNullableStringWithDefaultValue(const nsAString&, ErrorResult&); + + // Enumarated types + void PassEnum(TestEnum, ErrorResult&); + void PassOptionalEnum(const Optional&, ErrorResult&); + TestEnum ReceiveEnum(ErrorResult&); + + // Callback types + void PassCallback(JSObject*, ErrorResult&); + void PassNullableCallback(JSObject*, ErrorResult&); + void PassOptionalCallback(const Optional&, ErrorResult&); + void PassOptionalNullableCallback(const Optional&, ErrorResult&); + void PassOptionalNullableCallbackWithDefaultValue(JSObject*, ErrorResult&); + JSObject* ReceiveCallback(ErrorResult&); + JSObject* ReceiveNullableCallback(ErrorResult&); + + // Any types + void PassAny(JS::Value, ErrorResult&); + void PassOptionalAny(const Optional&, ErrorResult&); + JS::Value ReceiveAny(ErrorResult&); + + void PassObject(JSContext*, JSObject&, ErrorResult&); + void PassNullableObject(JSContext*, JSObject*, ErrorResult&); + void PassOptionalObject(JSContext*, const Optional >&, ErrorResult&); + void PassOptionalNullableObject(JSContext*, const Optional&, ErrorResult&); + void PassOptionalNullableObjectWithDefaultValue(JSContext*, JSObject*, ErrorResult&); + JSObject* ReceiveObject(JSContext*, ErrorResult&); + JSObject* ReceiveNullableObject(JSContext*, ErrorResult&); + private: // We add signatures here that _could_ start matching if the codegen // got data types wrong. That way if it ever does we'll have a call @@ -177,51 +261,123 @@ private: void SetWritableByte(T, ErrorResult&) MOZ_DELETE; template void PassByte(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalByte(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalByteWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyShort(int16_t, ErrorResult&) MOZ_DELETE; template void SetWritableShort(T, ErrorResult&) MOZ_DELETE; template void PassShort(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalShort(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalShortWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyLong(int32_t, ErrorResult&) MOZ_DELETE; template void SetWritableLong(T, ErrorResult&) MOZ_DELETE; template void PassLong(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalLong(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalLongWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyLongLong(int64_t, ErrorResult&) MOZ_DELETE; template void SetWritableLongLong(T, ErrorResult&) MOZ_DELETE; template void PassLongLong(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalLongLong(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalLongLongWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyOctet(uint8_t, ErrorResult&) MOZ_DELETE; template void SetWritableOctet(T, ErrorResult&) MOZ_DELETE; template void PassOctet(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalOctet(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalOctetWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyUnsignedShort(uint16_t, ErrorResult&) MOZ_DELETE; template void SetWritableUnsignedShort(T, ErrorResult&) MOZ_DELETE; template void PassUnsignedShort(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalUnsignedShort(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalUnsignedShortWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyUnsignedLong(uint32_t, ErrorResult&) MOZ_DELETE; template void SetWritableUnsignedLong(T, ErrorResult&) MOZ_DELETE; template void PassUnsignedLong(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalUnsignedLong(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalUnsignedLongWithDefault(T, ErrorResult&) MOZ_DELETE; void SetReadonlyUnsignedLongLong(uint64_t, ErrorResult&) MOZ_DELETE; template void SetWritableUnsignedLongLong(T, ErrorResult&) MOZ_DELETE; template void PassUnsignedLongLong(T, ErrorResult&) MOZ_DELETE; + template + void PassOptionalUnsignedLongLong(const Optional&, ErrorResult&) MOZ_DELETE; + template + void PassOptionalUnsignedLongLongWithDefault(T, ErrorResult&) MOZ_DELETE; + // Enforce that only const things are passed for sequences void PassSequence(Sequence &, ErrorResult&) MOZ_DELETE; void PassNullableSequence(Nullable< Sequence >&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableSequenceWithDefaultValue(Nullable< Sequence >&, + ErrorResult&) MOZ_DELETE; + + // Enforce that only const things are passed for optional + void PassOptionalByte(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableByte(Optional >&, + ErrorResult&) MOZ_DELETE; + void PassOptionalShort(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalLong(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalLongLong(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalOctet(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalUnsignedShort(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalUnsignedLong(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalUnsignedLongLong(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalSelf(Optional &, ErrorResult&) MOZ_DELETE; + void PassOptionalNonNullSelf(Optional >&, ErrorResult&) MOZ_DELETE; + void PassOptionalOther(Optional&, ErrorResult&); + void PassOptionalNonNullOther(Optional >&, ErrorResult&); + void PassOptionalExternal(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalNonNullExternal(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalSequence(Optional >&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableSequence(Optional > >&, + ErrorResult&) MOZ_DELETE; + void PassOptionalObjectSequence(Optional > >&, + ErrorResult&) MOZ_DELETE; + void PassOptionalArrayBuffer(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableArrayBuffer(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalEnum(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalCallback(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableCallback(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalAny(Optional&, ErrorResult) MOZ_DELETE; + + // And test that string stuff is always const + void PassString(nsAString&, ErrorResult&) MOZ_DELETE; + void PassNullableString(nsAString&, ErrorResult&) MOZ_DELETE; + void PassOptionalString(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableString(Optional&, ErrorResult&) MOZ_DELETE; + void PassOptionalNullableStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE; + }; } // namespace dom diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index c17ff01eb2f5..b59e55d33e6a 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -9,6 +9,13 @@ interface TestExternalInterface; interface TestNonCastableInterface { }; +enum TestEnum { + "a", + "b" +}; + +callback TestCallback = void(); + interface TestInterface { // Integer types // XXXbz add tests for infallible versions of all the integer stuff @@ -16,41 +23,59 @@ interface TestInterface { attribute byte writableByte; void passByte(byte arg); byte receiveByte(); + void passOptionalByte(optional byte arg); + void passOptionalByteWithDefault(optional byte arg = 0); + void passNullableByte(byte? arg); + void passOptionalNullableByte(optional byte? arg); readonly attribute short readonlyShort; attribute short writableShort; void passShort(short arg); short receiveShort(); + void passOptionalShort(optional short arg); + void passOptionalShortWithDefault(optional short arg = 0); readonly attribute long readonlyLong; attribute long writableLong; void passLong(long arg); long receiveLong(); + void passOptionalLong(optional long arg); + void passOptionalLongWithDefault(optional long arg = 0); readonly attribute long long readonlyLongLong; - attribute long long writableLongLong; + attribute long long writableLongLong; void passLongLong(long long arg); long long receiveLongLong(); + void passOptionalLongLong(optional long long arg); + void passOptionalLongLongWithDefault(optional long long arg = 0); readonly attribute octet readonlyOctet; attribute octet writableOctet; void passOctet(octet arg); octet receiveOctet(); + void passOptionalOctet(optional octet arg); + void passOptionalOctetWithDefault(optional octet arg = 0); readonly attribute unsigned short readonlyUnsignedShort; attribute unsigned short writableUnsignedShort; void passUnsignedShort(unsigned short arg); unsigned short receiveUnsignedShort(); + void passOptionalUnsignedShort(optional unsigned short arg); + void passOptionalUnsignedShortWithDefault(optional unsigned short arg = 0); readonly attribute unsigned long readonlyUnsignedLong; attribute unsigned long writableUnsignedLong; void passUnsignedLong(unsigned long arg); unsigned long receiveUnsignedLong(); + void passOptionalUnsignedLong(optional unsigned long arg); + void passOptionalUnsignedLongWithDefault(optional unsigned long arg = 0); readonly attribute unsigned long long readonlyUnsignedLongLong; attribute unsigned long long writableUnsignedLongLong; void passUnsignedLongLong(unsigned long long arg); unsigned long long receiveUnsignedLongLong(); + void passOptionalUnsignedLongLong(optional unsigned long long arg); + void passOptionalUnsignedLongLongWithDefault(optional unsigned long long arg = 0); // Castable interface types // XXXbz add tests for infallible versions of all the castable interface stuff @@ -65,6 +90,10 @@ interface TestInterface { void passNullableSelf(TestInterface? arg); attribute TestInterface nonNullSelf; attribute TestInterface? nullableSelf; + // Optional arguments + void passOptionalSelf(optional TestInterface? arg); + void passOptionalNonNullSelf(optional TestInterface arg); + void passOptionalSelfWithDefault(optional TestInterface? arg = null); // Non-castable interface types TestNonCastableInterface receiveOther(); @@ -78,6 +107,10 @@ interface TestInterface { void passNullableOther(TestNonCastableInterface? arg); attribute TestNonCastableInterface nonNullOther; attribute TestNonCastableInterface? nullableOther; + // Optional arguments + void passOptionalOther(optional TestNonCastableInterface? arg); + void passOptionalNonNullOther(optional TestNonCastableInterface arg); + void passOptionalOtherWithDefault(optional TestNonCastableInterface? arg = null); // External interface types TestExternalInterface receiveExternal(); @@ -91,6 +124,10 @@ interface TestInterface { void passNullableExternal(TestExternalInterface? arg); attribute TestExternalInterface nonNullExternal; attribute TestExternalInterface? nullableExternal; + // Optional arguments + void passOptionalExternal(optional TestExternalInterface? arg); + void passOptionalNonNullExternal(optional TestExternalInterface arg); + void passOptionalExternalWithDefault(optional TestExternalInterface? arg = null); // Sequence types sequence receiveSequence(); @@ -109,4 +146,54 @@ interface TestInterface { void passNullableCastableObjectSequence(sequence arg); void passCastableObjectNullableSequence(sequence? arg); void passNullableCastableObjectNullableSequence(sequence? arg); + void passOptionalSequence(optional sequence arg); + void passOptionalNullableSequence(optional sequence? arg); + void passOptionalNullableSequenceWithDefaultValue(optional sequence? arg = null); + void passOptionalObjectSequence(optional sequence arg); + + // Typed array types + void passArrayBuffer(ArrayBuffer arg); + void passNullableArrayBuffer(ArrayBuffer? arg); + void passOptionalArrayBuffer(optional ArrayBuffer arg); + void passOptionalNullableArrayBuffer(optional ArrayBuffer? arg); + void passOptionalNullableArrayBufferWithDefaultValue(optional ArrayBuffer? arg= null); + + // String types + void passString(DOMString arg); + void passNullableString(DOMString? arg); + void passOptionalString(optional DOMString arg); + void passOptionalNullableString(optional DOMString? arg); + void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null); + + // Enumerated types + void passEnum(TestEnum arg); + // No support for nullable enums yet + // void passNullableEnum(TestEnum? arg); + void passOptionalEnum(optional TestEnum arg); + // void passOptionalNullableEnum(optional TestEnum? arg); + // void passOptionalNullableEnumWithDefaultValue(optional TestEnum? arg = null); + TestEnum receiveEnum(); + + // Callback types + void passCallback(TestCallback arg); + void passNullableCallback(TestCallback? arg); + void passOptionalCallback(optional TestCallback arg); + void passOptionalNullableCallback(optional TestCallback? arg); + void passOptionalNullableCallbackWithDefaultValue(optional TestCallback? arg = null); + TestCallback receiveCallback(); + TestCallback? receiveNullableCallback(); + + // Any types + void passAny(any arg); + void passOptionalAny(optional any arg); + any receiveAny(); + + // object types + void passObject(object arg); + void passNullableObject(object? arg); + void passOptionalObject(optional object arg); + void passOptionalNullableObject(optional object? arg); + void passOptionalNullableObjectWithDefaultValue(optional object? arg = null); + object receiveObject(); + object? receiveNullableObject(); }; diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 1efd2e8527e2..bfcc61608467 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -1028,10 +1028,12 @@ public: class OpenRunnable : public WorkerThreadProxySyncRunnable { - nsCString mMethod; - nsCString mURL; - nsString mUser; - nsString mPassword; + nsString mMethod; + nsString mURL; + Optional mUser; + nsString mUserStr; + Optional mPassword; + nsString mPasswordStr; bool mMultipart; bool mBackgroundRequest; bool mWithCredentials; @@ -1039,15 +1041,25 @@ class OpenRunnable : public WorkerThreadProxySyncRunnable public: OpenRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, - const nsACString& aMethod, const nsACString& aURL, - const nsAString& aUser, const nsAString& aPassword, + const nsAString& aMethod, const nsAString& aURL, + const Optional& aUser, + const Optional& aPassword, bool aMultipart, bool aBackgroundRequest, bool aWithCredentials, PRUint32 aTimeout) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMethod(aMethod), - mURL(aURL), mUser(aUser), mPassword(aPassword), mMultipart(aMultipart), + mURL(aURL), mMultipart(aMultipart), mBackgroundRequest(aBackgroundRequest), mWithCredentials(aWithCredentials), mTimeout(aTimeout) - { } + { + if (aUser.WasPassed()) { + mUserStr = aUser.Value(); + mUser = &mUserStr; + } + if (aPassword.WasPassed()) { + mPasswordStr = aPassword.Value(); + mPassword = &mPasswordStr; + } + } nsresult MainThreadRun() @@ -1093,15 +1105,18 @@ public: NS_ASSERTION(!mProxy->mInOpen, "Reentrancy is bad!"); mProxy->mInOpen = true; - rv = mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, 1); + ErrorResult rv2; + mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, rv2); NS_ASSERTION(mProxy->mInOpen, "Reentrancy is bad!"); mProxy->mInOpen = false; - if (NS_SUCCEEDED(rv)) { - rv = mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text")); + if (rv2.Failed()) { + return rv2.ErrorCode(); } + rv = mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text")); + return rv; } }; @@ -1702,8 +1717,8 @@ XMLHttpRequest::Notify(JSContext* aCx, Status aStatus) void XMLHttpRequest::Open(const nsAString& aMethod, const nsAString& aUrl, - bool aAsync, const nsAString& aUser, - const nsAString& aPassword, ErrorResult& aRv) + bool aAsync, const Optional& aUser, + const Optional& aPassword, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); @@ -1725,9 +1740,9 @@ XMLHttpRequest::Open(const nsAString& aMethod, const nsAString& aUrl, mProxy->mOuterEventStreamId++; nsRefPtr runnable = - new OpenRunnable(mWorkerPrivate, mProxy, NS_ConvertUTF16toUTF8(aMethod), - NS_ConvertUTF16toUTF8(aUrl), aUser, aPassword, mMultipart, - mBackgroundRequest, mWithCredentials, mTimeout); + new OpenRunnable(mWorkerPrivate, mProxy, aMethod, aUrl, aUser, aPassword, + mMultipart, mBackgroundRequest, mWithCredentials, + mTimeout); if (!runnable->Dispatch(GetJSContext())) { ReleaseProxy(); diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index d7f98a24c721..26aa52b31991 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -103,7 +103,8 @@ public: void Open(const nsAString& aMethod, const nsAString& aUrl, bool aAsync, - const nsAString& aUser, const nsAString& aPassword, ErrorResult& aRv); + const Optional& aUser, const Optional& aPassword, + ErrorResult& aRv); void SetRequestHeader(const nsAString& aHeader, const nsAString& aValue,