diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 347636d6a379..51cde3e729ca 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -2433,7 +2433,8 @@ class JSToNativeConversionInfo(): ${declName} replaced by the declaration's name ${haveValue} replaced by an expression that evaluates to a boolean for whether we have a JS::Value. Only used when - defaultValue is not None. + defaultValue is not None or when True is passed for + checkForValue to instantiateJSToNativeConversion. declType: A CGThing representing the native C++ type we're converting to. This is allowed to be None if the conversion code is @@ -3197,7 +3198,10 @@ for (uint32_t i = 0; i < length; ++i) { treatAs = { "Default": "eStringify", "EmptyString": "eEmpty", - "Null": "eNull" + "Null": "eNull", + # For Missing it doesn't matter what we use here, since we'll never + # call ConvertJSValueToString on undefined in that case. + "Missing": "eStringify" } if type.nullable(): # For nullable strings null becomes a null string. @@ -3207,8 +3211,6 @@ for (uint32_t i = 0; i < length; ++i) { if treatUndefinedAs == "Default": treatUndefinedAs = "Null" nullBehavior = treatAs[treatNullAs] - if treatUndefinedAs == "Missing": - raise TypeError("We don't support [TreatUndefinedAs=Missing]") undefinedBehavior = treatAs[treatUndefinedAs] def getConversionCode(varName): @@ -3559,22 +3561,21 @@ for (uint32_t i = 0; i < length; ++i) { return JSToNativeConversionInfo(template, declType=declType, dealWithOptional=isOptional) -def instantiateJSToNativeConversion(info, replacements, argcAndIndex=None): +def instantiateJSToNativeConversion(info, replacements, checkForValue=False): """ Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo and a set of replacements as required by the strings in such an object, 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. + If checkForValue is True, then the conversion will get wrapped in + a check for ${haveValue}. """ (templateBody, declType, holderType, dealWithOptional) = ( info.template, info.declType, info.holderType, info.dealWithOptional) - if dealWithOptional and argcAndIndex is None: + if dealWithOptional and not checkForValue: raise TypeError("Have to deal with optional things, but don't know how") - if argcAndIndex is not None and declType is None: + if checkForValue and declType is None: raise TypeError("Need to predeclare optional things, so they will be " "outside the check for big enough arg count!"); @@ -3623,7 +3624,7 @@ def instantiateJSToNativeConversion(info, replacements, argcAndIndex=None): string.Template(templateBody).substitute(replacements) ) - if argcAndIndex is not None: + if checkForValue: if dealWithOptional: declConstruct = CGIndenter( CGGeneric("%s.Construct(%s);" % @@ -3644,8 +3645,8 @@ def instantiateJSToNativeConversion(info, replacements, argcAndIndex=None): conversion = CGList( [CGGeneric( - string.Template("if (${index} < ${argc}) {").substitute( - argcAndIndex + string.Template("if (${haveValue}) {").substitute( + replacements )), declConstruct, holderConstruct, @@ -3710,9 +3711,12 @@ class CGArgumentConverter(CGThing): self.replacementVariables["valMutableHandle"] = ( "JS::MutableHandle::fromMarkedLocation(%s)" % self.replacementVariables["valPtr"]) - if argument.defaultValue: - self.replacementVariables["haveValue"] = string.Template( - "${index} < ${argc}").substitute(replacer) + haveValueCheck = string.Template("${index} < ${argc}").substitute(replacer) + if argument.treatUndefinedAs == "Missing": + haveValueCheck = (haveValueCheck + + (" && !%s.isUndefined()" % + self.replacementVariables["valHandle"])) + self.replacementVariables["haveValue"] = haveValueCheck self.descriptorProvider = descriptorProvider if self.argument.optional and not self.argument.defaultValue: self.argcAndIndex = replacer @@ -3742,7 +3746,7 @@ class CGArgumentConverter(CGThing): return instantiateJSToNativeConversion( typeConversion, self.replacementVariables, - self.argcAndIndex).define() + self.argcAndIndex is not None).define() # Variadic arguments get turned into a sequence. if typeConversion.dealWithOptional: @@ -4707,6 +4711,15 @@ class CGMethodCall(CGThing): CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n")) return + # We don't handle [TreatUndefinedAs=Missing] arguments in overload + # resolution yet. + for (_, sigArgs) in signatures: + for arg in sigArgs: + if arg.treatUndefinedAs == "Missing": + raise TypeError("No support for [TreatUndefinedAs=Missing] " + "handling in overload resolution yet: %s" % + arg.location) + # Need to find the right overload maxArgCount = method.maxArgCount allowedArgCounts = method.allowedArgCounts diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 8f9430381a84..151d6ea7c0fa 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -398,25 +398,33 @@ class IDLObjectWithIdentifier(IDLObject): [self.location]) self.treatNullAs = value elif identifier == "TreatUndefinedAs": - if not self.type.isString(): - raise WebIDLError("[TreatUndefinedAs] is only allowed on " - "arguments or attributes whose type is " - "DOMString or DOMString?", - [self.location]) if isDictionaryMember: raise WebIDLError("[TreatUndefinedAs] is not allowed for " "dictionary members", [self.location]) - if value == 'Null': - if not self.type.nullable(): - raise WebIDLError("[TreatUndefinedAs=Null] is only " - "allowed on arguments whose type is " - "DOMString?", [self.location]) - elif value == 'Missing': + if value == 'Missing': if not isOptional: raise WebIDLError("[TreatUndefinedAs=Missing] is only " "allowed on optional arguments", [self.location]) - elif value != 'EmptyString': + elif value == 'Null': + if not self.type.isString(): + raise WebIDLError("[TreatUndefinedAs=Null] is only " + "allowed on arguments or " + "attributes whose type is " + "DOMString or DOMString?", + [self.location]) + if not self.type.nullable(): + raise WebIDLError("[TreatUndefinedAs=Null] is only " + "allowed on arguments whose type " + "is DOMString?", [self.location]) + elif value == 'EmptyString': + if not self.type.isString(): + raise WebIDLError("[TreatUndefinedAs=EmptyString] " + "is only allowed on arguments or " + "attributes whose type is " + "DOMString or DOMString?", + [self.location]) + else: raise WebIDLError("[TreatUndefinedAs] must take the " "identifiers EmptyString or Null or " "Missing", [self.location]) diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index 74becadc8c3d..66cb4e3fcf47 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -156,7 +156,9 @@ public: void PassByte(int8_t); int8_t ReceiveByte(); void PassOptionalByte(const Optional&); + void PassOptionalUndefinedMissingByte(const Optional&); void PassOptionalByteWithDefault(int8_t); + void PassOptionalUndefinedMissingByteWithDefault(int8_t); void PassNullableByte(const Nullable&); void PassOptionalNullableByte(const Optional< Nullable >&); void PassVariadicByte(const Sequence&); @@ -400,7 +402,9 @@ public: void PassString(const nsAString&); void PassNullableString(const nsAString&); void PassOptionalString(const Optional&); + void PassOptionalUndefinedMissingString(const Optional&); void PassOptionalStringWithDefaultValue(const nsAString&); + void PassOptionalUndefinedMissingStringWithDefaultValue(const nsAString&); void PassOptionalNullableString(const Optional&); void PassOptionalNullableStringWithDefaultValue(const nsAString&); void PassVariadicString(const Sequence&); diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl index 8e6c3d74246c..222ce939df51 100644 --- a/dom/bindings/test/TestCodeGen.webidl +++ b/dom/bindings/test/TestCodeGen.webidl @@ -118,7 +118,9 @@ interface TestInterface { void passByte(byte arg); byte receiveByte(); void passOptionalByte(optional byte arg); + void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg); void passOptionalByteWithDefault(optional byte arg = 0); + void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0); void passNullableByte(byte? arg); void passOptionalNullableByte(optional byte? arg); void passVariadicByte(byte... arg); @@ -368,7 +370,9 @@ interface TestInterface { void passString(DOMString arg); void passNullableString(DOMString? arg); void passOptionalString(optional DOMString arg); + void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg); void passOptionalStringWithDefaultValue(optional DOMString arg = "abc"); + void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc"); void passOptionalNullableString(optional DOMString? arg); void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null); void passVariadicString(DOMString... arg); diff --git a/dom/bindings/test/TestExampleGen.webidl b/dom/bindings/test/TestExampleGen.webidl index 6a8a00985e44..ead8c634d71e 100644 --- a/dom/bindings/test/TestExampleGen.webidl +++ b/dom/bindings/test/TestExampleGen.webidl @@ -23,7 +23,9 @@ interface TestExampleInterface { void passByte(byte arg); byte receiveByte(); void passOptionalByte(optional byte arg); + void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg); void passOptionalByteWithDefault(optional byte arg = 0); + void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0); void passNullableByte(byte? arg); void passOptionalNullableByte(optional byte? arg); void passVariadicByte(byte... arg); @@ -266,7 +268,9 @@ interface TestExampleInterface { void passString(DOMString arg); void passNullableString(DOMString? arg); void passOptionalString(optional DOMString arg); + void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg); void passOptionalStringWithDefaultValue(optional DOMString arg = "abc"); + void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc"); void passOptionalNullableString(optional DOMString? arg); void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null); void passVariadicString(DOMString... arg); diff --git a/dom/bindings/test/TestJSImplGen.webidl b/dom/bindings/test/TestJSImplGen.webidl index 71c57948e1e5..3fd57f044833 100644 --- a/dom/bindings/test/TestJSImplGen.webidl +++ b/dom/bindings/test/TestJSImplGen.webidl @@ -35,7 +35,9 @@ interface TestJSImplInterface { void passByte(byte arg); byte receiveByte(); void passOptionalByte(optional byte arg); + void passOptionalUndefinedMissingByte([TreatUndefinedAs=Missing] optional byte arg); void passOptionalByteWithDefault(optional byte arg = 0); + void passOptionalUndefinedMissingByteWithDefault([TreatUndefinedAs=Missing] optional byte arg = 0); void passNullableByte(byte? arg); void passOptionalNullableByte(optional byte? arg); void passVariadicByte(byte... arg); @@ -289,7 +291,9 @@ interface TestJSImplInterface { void passString(DOMString arg); void passNullableString(DOMString? arg); void passOptionalString(optional DOMString arg); + void passOptionalUndefinedMissingString([TreatUndefinedAs=Missing] optional DOMString arg); void passOptionalStringWithDefaultValue(optional DOMString arg = "abc"); + void passOptionalUndefinedMissingStringWithDefaultValue([TreatUndefinedAs=Missing] optional DOMString arg = "abc"); void passOptionalNullableString(optional DOMString? arg); void passOptionalNullableStringWithDefaultValue(optional DOMString? arg = null); void passVariadicString(DOMString... arg);