Add support for ImplementedAs, Clamp, EnforceRange, TreatNullAs for dictionary members
authorjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Mar 2017 20:22:18 +0000 (20:22 +0000)
committerjonlee@apple.com <jonlee@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Mar 2017 20:22:18 +0000 (20:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169731

Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

Rebaseline tests. The results seem to show a problem in the original tests.
* web-platform-tests/WebCryptoAPI/encrypt_decrypt/aes_gcm.worker-expected.txt:
* web-platform-tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm-expected.txt:

Source/WebCore:

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateDictionaryImplementationContent): Create a new $implementationAsKey. Look for
ImplementedAs, and if it exists, override the value with the alias. Set the parameters of
convert<>() using JSValueToNative.
(IsValidContextForJSValueToNative): Update to include IDLDictionaryMembers.
(JSValueToNative): Bypass parseEnumeration serialization for enums if the context is an
IDLDictionaryMember. Dictionary members need convert<IDLEnumeration> which throw a TypeError
or return the enum (and utilizes parseEnumeration). parseEnumeration, in contrast, returns
an optional.

* bindings/scripts/test/TestObj.idl: Add test cases in TestDictionary.

Update test results.
* bindings/scripts/test/JS/JSTestEventConstructor.cpp:
* bindings/scripts/test/JS/JSTestObj.cpp:
* bindings/scripts/test/JS/JSTestStandaloneDictionary.cpp:

LayoutTests:

Rebaseline. The enhancement progressed the results of these tests.
* crypto/subtle/aes-gcm-encrypt-malformed-parameters-expected.txt:
* crypto/subtle/aes-generate-key-malformed-parameters-expected.txt:
* crypto/subtle/hmac-generate-key-malformed-parameters-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@214139 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/crypto/subtle/aes-gcm-encrypt-malformed-parameters-expected.txt
LayoutTests/crypto/subtle/aes-generate-key-malformed-parameters-expected.txt
LayoutTests/crypto/subtle/hmac-generate-key-malformed-parameters-expected.txt
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/encrypt_decrypt/aes_gcm.worker-expected.txt
LayoutTests/imported/w3c/web-platform-tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStandaloneDictionary.cpp
Source/WebCore/bindings/scripts/test/TestObj.idl

index dd5198a..c66932b 100644 (file)
@@ -1,3 +1,15 @@
+2017-03-18  Jon Lee  <jonlee@apple.com>
+
+        Add support for ImplementedAs, Clamp, EnforceRange, TreatNullAs for dictionary members
+        https://bugs.webkit.org/show_bug.cgi?id=169731
+
+        Reviewed by Alex Christensen.
+
+        Rebaseline. The enhancement progressed the results of these tests.
+        * crypto/subtle/aes-gcm-encrypt-malformed-parameters-expected.txt:
+        * crypto/subtle/aes-generate-key-malformed-parameters-expected.txt:
+        * crypto/subtle/hmac-generate-key-malformed-parameters-expected.txt:
+
 2017-03-18  Chris Dumez  <cdumez@apple.com>
 
         Allow setting the prototype of cross-origin objects, as long as they don't change
index a49c971..9f54c5c 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS crypto.subtle.encrypt({name: "aes-gcm", iv: asciiToUint8Array("jnOw99oOZFLIEPMrd"), tagLength: 0}, key, plainText) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
-PASS crypto.subtle.encrypt({name: "aes-gcm", iv: asciiToUint8Array("jnOw99oOZFLIEPMrd"), tagLength: -1}, key, plainText) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
+PASS crypto.subtle.encrypt({name: "aes-gcm", iv: asciiToUint8Array("jnOw99oOZFLIEPMrd"), tagLength: -1}, key, plainText) rejected promise  with TypeError: Value -1 is outside the range [0, 255].
 PASS crypto.subtle.encrypt({name: "aes-gcm", iv: asciiToUint8Array("jnOw99oOZFLIEPMrd"), tagLength: 129}, key, plainText) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
 PASS crypto.subtle.encrypt({name: "aes-gcm", iv: asciiToUint8Array("jnOw99oOZFLIEPMrd"), tagLength: 70}, key, plainText) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
 PASS successfullyParsed is true
index b781d00..e193e71 100644 (file)
@@ -9,8 +9,8 @@ PASS crypto.subtle.generateKey({name: "aes-cbc", length: true}, extractable, ["e
 PASS crypto.subtle.generateKey({name: "aes-cbc", length: null}, extractable, ["encrypt", "decrypt"]) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
 PASS crypto.subtle.generateKey({name: "aes-cbc", length: undefined}, extractable, ["encrypt", "decrypt"]) rejected promise  with TypeError: Member AesKeyParams.length is required and must be an instance of unsigned short.
 PASS crypto.subtle.generateKey({name: "aes-cbc", length: Symbol()}, extractable, ["encrypt", "decrypt"]) rejected promise  with TypeError: Cannot convert a symbol to a number.
-PASS crypto.subtle.generateKey({name: "aes-cbc", length: { }}, extractable, ["encrypt", "decrypt"]) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
-PASS crypto.subtle.generateKey({name: "aes-cbc", length: "foo"}, extractable, ["encrypt", "decrypt"]) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
+PASS crypto.subtle.generateKey({name: "aes-cbc", length: { }}, extractable, ["encrypt", "decrypt"]) rejected promise  with TypeError: Value NaN is outside the range [0, 65535].
+PASS crypto.subtle.generateKey({name: "aes-cbc", length: "foo"}, extractable, ["encrypt", "decrypt"]) rejected promise  with TypeError: Value NaN is outside the range [0, 65535].
 PASS crypto.subtle.generateKey({name: "aes-cbc", length: 128}, extractable, ["sign"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
 PASS crypto.subtle.generateKey({name: "aes-cbc", length: 128}, extractable, ["verify"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
 PASS crypto.subtle.generateKey({name: "aes-cbc", length: 128}, extractable, ["deriveKey"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
index 796264c..3ba6757 100644 (file)
@@ -7,8 +7,8 @@ PASS crypto.subtle.generateKey("hmac", extractable, ["sign", "verify"]) rejected
 PASS crypto.subtle.generateKey({name: "hmac"}, extractable, ["sign", "verify"]) rejected promise  with TypeError: Member HmacKeyParams.hash is required and must be an instance of any.
 PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: null}, extractable, ["sign", "verify"]) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
 PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: Symbol()}, extractable, ["sign", "verify"]) rejected promise  with TypeError: Cannot convert a symbol to a number.
-PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: { }}, extractable, ["sign", "verify"]) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
-PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: "foo"}, extractable, ["sign", "verify"]) rejected promise  with OperationError (DOM Exception 34): The operation failed for an operation-specific reason.
+PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: { }}, extractable, ["sign", "verify"]) rejected promise  with TypeError: Value NaN is outside the range [0, 4294967295].
+PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1", length: "foo"}, extractable, ["sign", "verify"]) rejected promise  with TypeError: Value NaN is outside the range [0, 4294967295].
 PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1"}, extractable, ["encrypt"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
 PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1"}, extractable, ["decrypt"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
 PASS crypto.subtle.generateKey({name: "hmac", hash: "sha-1"}, extractable, ["deriveKey"]) rejected promise  with SyntaxError (DOM Exception 12): A required parameter was missing or out-of-range.
index 325f2c0..fc6c9f2 100644 (file)
@@ -1,3 +1,14 @@
+2017-03-18  Jon Lee  <jonlee@apple.com>
+
+        Add support for ImplementedAs, Clamp, EnforceRange, TreatNullAs for dictionary members
+        https://bugs.webkit.org/show_bug.cgi?id=169731
+
+        Reviewed by Alex Christensen.
+
+        Rebaseline tests. The results seem to show a problem in the original tests.
+        * web-platform-tests/WebCryptoAPI/encrypt_decrypt/aes_gcm.worker-expected.txt:
+        * web-platform-tests/WebCryptoAPI/encrypt_decrypt/test_aes_gcm-expected.txt:
+
 2017-03-18  Chris Dumez  <cdumez@apple.com>
 
         innerText setter inserts empty text node if value starts with newline
index b912f91..00d491b 100644 (file)
@@ -298,35 +298,35 @@ PASS AES-GCM 128-bit key, illegal tag length 48-bits
 PASS AES-GCM 128-bit key, illegal tag length 72-bits 
 PASS AES-GCM 128-bit key, illegal tag length 95-bits 
 PASS AES-GCM 128-bit key, illegal tag length 129-bits 
-PASS AES-GCM 128-bit key, illegal tag length 256-bits 
+FAIL AES-GCM 128-bit key, illegal tag length 256-bits assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 192-bit key, illegal tag length 24-bits 
 PASS AES-GCM 192-bit key, illegal tag length 48-bits 
 PASS AES-GCM 192-bit key, illegal tag length 72-bits 
 PASS AES-GCM 192-bit key, illegal tag length 95-bits 
 PASS AES-GCM 192-bit key, illegal tag length 129-bits 
-PASS AES-GCM 192-bit key, illegal tag length 256-bits 
+FAIL AES-GCM 192-bit key, illegal tag length 256-bits assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 256-bit key, illegal tag length 24-bits 
 PASS AES-GCM 256-bit key, illegal tag length 48-bits 
 PASS AES-GCM 256-bit key, illegal tag length 72-bits 
 PASS AES-GCM 256-bit key, illegal tag length 95-bits 
 PASS AES-GCM 256-bit key, illegal tag length 129-bits 
-PASS AES-GCM 256-bit key, illegal tag length 256-bits 
+FAIL AES-GCM 256-bit key, illegal tag length 256-bits assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 128-bit key, illegal tag length 24-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 48-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 72-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 95-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 129-bits decryption 
-PASS AES-GCM 128-bit key, illegal tag length 256-bits decryption 
+FAIL AES-GCM 128-bit key, illegal tag length 256-bits decryption assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 192-bit key, illegal tag length 24-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 48-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 72-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 95-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 129-bits decryption 
-PASS AES-GCM 192-bit key, illegal tag length 256-bits decryption 
+FAIL AES-GCM 192-bit key, illegal tag length 256-bits decryption assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 256-bit key, illegal tag length 24-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 48-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 72-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 95-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 129-bits decryption 
-PASS AES-GCM 256-bit key, illegal tag length 256-bits decryption 
+FAIL AES-GCM 256-bit key, illegal tag length 256-bits decryption assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 
index c82d1f9..a6ba7b1 100644 (file)
@@ -300,35 +300,35 @@ PASS AES-GCM 128-bit key, illegal tag length 48-bits
 PASS AES-GCM 128-bit key, illegal tag length 72-bits 
 PASS AES-GCM 128-bit key, illegal tag length 95-bits 
 PASS AES-GCM 128-bit key, illegal tag length 129-bits 
-PASS AES-GCM 128-bit key, illegal tag length 256-bits 
+FAIL AES-GCM 128-bit key, illegal tag length 256-bits assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 192-bit key, illegal tag length 24-bits 
 PASS AES-GCM 192-bit key, illegal tag length 48-bits 
 PASS AES-GCM 192-bit key, illegal tag length 72-bits 
 PASS AES-GCM 192-bit key, illegal tag length 95-bits 
 PASS AES-GCM 192-bit key, illegal tag length 129-bits 
-PASS AES-GCM 192-bit key, illegal tag length 256-bits 
+FAIL AES-GCM 192-bit key, illegal tag length 256-bits assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 256-bit key, illegal tag length 24-bits 
 PASS AES-GCM 256-bit key, illegal tag length 48-bits 
 PASS AES-GCM 256-bit key, illegal tag length 72-bits 
 PASS AES-GCM 256-bit key, illegal tag length 95-bits 
 PASS AES-GCM 256-bit key, illegal tag length 129-bits 
-PASS AES-GCM 256-bit key, illegal tag length 256-bits 
+FAIL AES-GCM 256-bit key, illegal tag length 256-bits assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 128-bit key, illegal tag length 24-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 48-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 72-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 95-bits decryption 
 PASS AES-GCM 128-bit key, illegal tag length 129-bits decryption 
-PASS AES-GCM 128-bit key, illegal tag length 256-bits decryption 
+FAIL AES-GCM 128-bit key, illegal tag length 256-bits decryption assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 192-bit key, illegal tag length 24-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 48-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 72-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 95-bits decryption 
 PASS AES-GCM 192-bit key, illegal tag length 129-bits decryption 
-PASS AES-GCM 192-bit key, illegal tag length 256-bits decryption 
+FAIL AES-GCM 192-bit key, illegal tag length 256-bits decryption assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 PASS AES-GCM 256-bit key, illegal tag length 24-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 48-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 72-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 95-bits decryption 
 PASS AES-GCM 256-bit key, illegal tag length 129-bits decryption 
-PASS AES-GCM 256-bit key, illegal tag length 256-bits decryption 
+FAIL AES-GCM 256-bit key, illegal tag length 256-bits decryption assert_equals: Should throw an OperationError instead of Type error expected "OperationError" but got "TypeError"
 
index 89927e9..df41d45 100644 (file)
@@ -1,3 +1,27 @@
+2017-03-18  Jon Lee  <jonlee@apple.com>
+
+        Add support for ImplementedAs, Clamp, EnforceRange, TreatNullAs for dictionary members
+        https://bugs.webkit.org/show_bug.cgi?id=169731
+
+        Reviewed by Alex Christensen.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateDictionaryImplementationContent): Create a new $implementationAsKey. Look for
+        ImplementedAs, and if it exists, override the value with the alias. Set the parameters of
+        convert<>() using JSValueToNative.
+        (IsValidContextForJSValueToNative): Update to include IDLDictionaryMembers.
+        (JSValueToNative): Bypass parseEnumeration serialization for enums if the context is an
+        IDLDictionaryMember. Dictionary members need convert<IDLEnumeration> which throw a TypeError
+        or return the enum (and utilizes parseEnumeration). parseEnumeration, in contrast, returns
+        an optional.
+
+        * bindings/scripts/test/TestObj.idl: Add test cases in TestDictionary.
+
+        Update test results.
+        * bindings/scripts/test/JS/JSTestEventConstructor.cpp:
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        * bindings/scripts/test/JS/JSTestStandaloneDictionary.cpp:
+
 2017-03-18  Simon Fraser  <simon.fraser@apple.com>
 
         Use initializers for Document member variables
index 8a043df..468aaa3 100644 (file)
@@ -1562,6 +1562,7 @@ sub GenerateDictionaryImplementationContent
 
             # 5.1. Let key be the identifier of member.
             my $key = $member->name;
+            my $implementedAsKey = $member->extendedAttributes->{"ImplementedAs"} ? $member->extendedAttributes->{"ImplementedAs"} : $key;
 
             # 5.2. Let value be an ECMAScript value, depending on Type(V):
             $result .= "    JSValue ${key}Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, \"${key}\"));\n";
@@ -1570,14 +1571,16 @@ sub GenerateDictionaryImplementationContent
 
             # 5.3. If value is not undefined, then:
             $result .= "    if (!${key}Value.isUndefined()) {\n";
-            $result .= "        result.$key = convert<${IDLType}>(state, ${key}Value);\n";
+
+            my ($nativeValue, $mayThrowException) = JSValueToNative($typeScope, $member, "${key}Value", $member->extendedAttributes->{Conditional}, "&state", "state");
+            $result .= "        result.$implementedAsKey = $nativeValue;\n";
             $result .= "        RETURN_IF_EXCEPTION(throwScope, { });\n";
 
             # Value is undefined.
             # 5.4. Otherwise, if value is undefined but the dictionary member has a default value, then:
             if (!$member->isRequired && defined $member->default) {
                 $result .= "    } else\n";
-                $result .= "        result.$key = " . GenerateDefaultValue($typeScope, $member, $member->type, $member->default) . ";\n";
+                $result .= "        result.$implementedAsKey = " . GenerateDefaultValue($typeScope, $member, $member->type, $member->default) . ";\n";
             } elsif ($member->isRequired) {
                 # 5.5. Otherwise, if value is undefined and the dictionary member is a required dictionary member, then throw a TypeError.
                 $result .= "    } else {\n";
@@ -1611,20 +1614,21 @@ sub GenerateDictionaryImplementationContent
             my @sortedMembers = sort { $a->name cmp $b->name } @{$dictionary->members};
             foreach my $member (@sortedMembers) {
                 my $key = $member->name;
-                my $IDLType = GetIDLType($typeScope, $member->type);
+                my $implementedAsKey = $member->extendedAttributes->{"ImplementedAs"} ? $member->extendedAttributes->{"ImplementedAs"} : $key;
 
                 # 1. Let key be the identifier of member.
                 # 2. If the dictionary member named key is present in V, then:
                     # 1. Let idlValue be the value of member on V.
                     # 2. Let value be the result of converting idlValue to an ECMAScript value.
                     # 3. Perform ! CreateDataProperty(O, key, value).
+                my $IDLType = GetIDLType($typeScope, $member->type);
                 if (!$member->isRequired && not defined $member->default) {
-                    $result .= "    if (!${IDLType}::isNullValue(dictionary.${key})) {\n";
-                    $result .= "        auto ${key}Value = toJS<$IDLType>(state, globalObject, ${IDLType}::extractValueFromNullable(dictionary.${key}));\n";
+                    $result .= "    if (!${IDLType}::isNullValue(dictionary.${implementedAsKey})) {\n";
+                    $result .= "        auto ${key}Value = toJS<$IDLType>(state, globalObject, ${IDLType}::extractValueFromNullable(dictionary.${implementedAsKey}));\n";
                     $result .= "        result->putDirect(vm, JSC::Identifier::fromString(&vm, \"${key}\"), ${key}Value);\n";
                     $result .= "    }\n";
                 } else {
-                    $result .= "    auto ${key}Value = toJS<$IDLType>(state, globalObject, dictionary.${key});\n";
+                    $result .= "    auto ${key}Value = toJS<$IDLType>(state, globalObject, dictionary.${implementedAsKey});\n";
                     $result .= "    result->putDirect(vm, JSC::Identifier::fromString(&vm, \"${key}\"), ${key}Value);\n";
                 }
             }
@@ -5511,8 +5515,7 @@ sub JSValueToNativeDOMConvertNeedsGlobalObject
 sub IsValidContextForJSValueToNative
 {
     my $context = shift;
-    
-    return ref($context) eq "IDLAttribute" || ref($context) eq "IDLArgument";
+    return ref($context) eq "IDLAttribute" || ref($context) eq "IDLArgument" || ref($context) eq "IDLDictionaryMember";
 }
 
 # Returns (convertString, mayThrowException).
@@ -5537,7 +5540,9 @@ sub JSValueToNative
         return ("$value.toString($statePointer)->toAtomicString($statePointer)", 1) if $context->extendedAttributes->{AtomicString};
     }
 
-    if ($codeGenerator->IsEnumType($type)) {
+    # parseEnumeration<> returns a std::optional. For dictionary members we need convert<IDLEnumeration>() which guarantee
+    # the enum, or throws a TypeError. Bypass this check for IDLDictionaryMembers.
+    if ($codeGenerator->IsEnumType($type) && ref($context) ne "IDLDictionaryMember") {
         return ("parseEnumeration<" . GetEnumerationClassName($type, $interface) . ">($stateReference, $value)", 1);
     }
 
index 51c10fe..1283fb1 100644 (file)
@@ -68,13 +68,13 @@ template<> TestEventConstructor::Init convertDictionary<TestEventConstructor::In
         result.composed = false;
     JSValue attr2Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "attr2"));
     if (!attr2Value.isUndefined()) {
-        result.attr2 = convert<IDLDOMString>(state, attr2Value);
+        result.attr2 = convert<IDLDOMString>(state, attr2Value, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.attr2 = emptyString();
     JSValue attr3Value = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "attr3"));
     if (!attr3Value.isUndefined()) {
-        result.attr3 = convert<IDLDOMString>(state, attr3Value);
+        result.attr3 = convert<IDLDOMString>(state, attr3Value, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.attr3 = emptyString();
index 4bd4a91..0a9307b 100644 (file)
@@ -532,31 +532,43 @@ template<> TestObj::Dictionary convertDictionary<TestObj::Dictionary>(ExecState&
         result.enumerationValueWithoutDefault = convert<IDLEnumeration<TestObj::EnumType>>(state, enumerationValueWithoutDefaultValue);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
+    JSValue fooAliasValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "fooAlias"));
+    if (!fooAliasValue.isUndefined()) {
+        result.foo = convert<IDLAny>(state, fooAliasValue);
+        RETURN_IF_EXCEPTION(throwScope, { });
+    } else
+        result.foo = jsUndefined();
+    JSValue fooWithDefaultAliasValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "fooWithDefaultAlias"));
+    if (!fooWithDefaultAliasValue.isUndefined()) {
+        result.fooWithDefault = convert<IDLAny>(state, fooWithDefaultAliasValue);
+        RETURN_IF_EXCEPTION(throwScope, { });
+    } else
+        result.fooWithDefault = 0;
     JSValue integerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "integer"));
     if (!integerValue.isUndefined()) {
-        result.integer = convert<IDLLong>(state, integerValue);
+        result.integer = convert<IDLLong>(state, integerValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue integerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "integerWithDefault"));
     if (!integerWithDefaultValue.isUndefined()) {
-        result.integerWithDefault = convert<IDLLong>(state, integerWithDefaultValue);
+        result.integerWithDefault = convert<IDLLong>(state, integerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.integerWithDefault = 0;
     JSValue largeIntegerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "largeInteger"));
     if (!largeIntegerValue.isUndefined()) {
-        result.largeInteger = convert<IDLLongLong>(state, largeIntegerValue);
+        result.largeInteger = convert<IDLLongLong>(state, largeIntegerValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue largeIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "largeIntegerWithDefault"));
     if (!largeIntegerWithDefaultValue.isUndefined()) {
-        result.largeIntegerWithDefault = convert<IDLLongLong>(state, largeIntegerWithDefaultValue);
+        result.largeIntegerWithDefault = convert<IDLLongLong>(state, largeIntegerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.largeIntegerWithDefault = 0;
     JSValue nullableIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "nullableIntegerWithDefault"));
     if (!nullableIntegerWithDefaultValue.isUndefined()) {
-        result.nullableIntegerWithDefault = convert<IDLNullable<IDLLong>>(state, nullableIntegerWithDefaultValue);
+        result.nullableIntegerWithDefault = convert<IDLNullable<IDLLong>>(state, nullableIntegerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.nullableIntegerWithDefault = std::nullopt;
@@ -568,7 +580,7 @@ template<> TestObj::Dictionary convertDictionary<TestObj::Dictionary>(ExecState&
         result.nullableNode = nullptr;
     JSValue nullableStringWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "nullableStringWithDefault"));
     if (!nullableStringWithDefaultValue.isUndefined()) {
-        result.nullableStringWithDefault = convert<IDLNullable<IDLDOMString>>(state, nullableStringWithDefaultValue);
+        result.nullableStringWithDefault = convert<IDLNullable<IDLDOMString>>(state, nullableStringWithDefaultValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.nullableStringWithDefault = String();
@@ -607,34 +619,39 @@ template<> TestObj::Dictionary convertDictionary<TestObj::Dictionary>(ExecState&
     }
     JSValue smallIntegerClampedValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallIntegerClamped"));
     if (!smallIntegerClampedValue.isUndefined()) {
-        result.smallIntegerClamped = convert<IDLByte>(state, smallIntegerClampedValue);
+        result.smallIntegerClamped = convert<IDLByte>(state, smallIntegerClampedValue, IntegerConversionConfiguration::Clamp);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue smallIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallIntegerWithDefault"));
     if (!smallIntegerWithDefaultValue.isUndefined()) {
-        result.smallIntegerWithDefault = convert<IDLByte>(state, smallIntegerWithDefaultValue);
+        result.smallIntegerWithDefault = convert<IDLByte>(state, smallIntegerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue smallUnsignedIntegerEnforcedRangeValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallUnsignedIntegerEnforcedRange"));
     if (!smallUnsignedIntegerEnforcedRangeValue.isUndefined()) {
-        result.smallUnsignedIntegerEnforcedRange = convert<IDLOctet>(state, smallUnsignedIntegerEnforcedRangeValue);
+        result.smallUnsignedIntegerEnforcedRange = convert<IDLOctet>(state, smallUnsignedIntegerEnforcedRangeValue, IntegerConversionConfiguration::EnforceRange);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue smallUnsignedIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "smallUnsignedIntegerWithDefault"));
     if (!smallUnsignedIntegerWithDefaultValue.isUndefined()) {
-        result.smallUnsignedIntegerWithDefault = convert<IDLOctet>(state, smallUnsignedIntegerWithDefaultValue);
+        result.smallUnsignedIntegerWithDefault = convert<IDLOctet>(state, smallUnsignedIntegerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.smallUnsignedIntegerWithDefault = 0;
+    JSValue stringTreatNullAsEmptyStringValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringTreatNullAsEmptyString"));
+    if (!stringTreatNullAsEmptyStringValue.isUndefined()) {
+        result.stringTreatNullAsEmptyString = convert<IDLDOMString>(state, stringTreatNullAsEmptyStringValue, StringConversionConfiguration::TreatNullAsEmptyString);
+        RETURN_IF_EXCEPTION(throwScope, { });
+    }
     JSValue stringWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithDefault"));
     if (!stringWithDefaultValue.isUndefined()) {
-        result.stringWithDefault = convert<IDLDOMString>(state, stringWithDefaultValue);
+        result.stringWithDefault = convert<IDLDOMString>(state, stringWithDefaultValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.stringWithDefault = ASCIILiteral("defaultString");
     JSValue stringWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithoutDefault"));
     if (!stringWithoutDefaultValue.isUndefined()) {
-        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue);
+        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue unionMemberValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unionMember"));
@@ -666,23 +683,23 @@ template<> TestObj::Dictionary convertDictionary<TestObj::Dictionary>(ExecState&
         result.unrestrictedFloatWithDefault = 0;
     JSValue unsignedIntegerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedInteger"));
     if (!unsignedIntegerValue.isUndefined()) {
-        result.unsignedInteger = convert<IDLUnsignedLong>(state, unsignedIntegerValue);
+        result.unsignedInteger = convert<IDLUnsignedLong>(state, unsignedIntegerValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue unsignedIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedIntegerWithDefault"));
     if (!unsignedIntegerWithDefaultValue.isUndefined()) {
-        result.unsignedIntegerWithDefault = convert<IDLUnsignedLong>(state, unsignedIntegerWithDefaultValue);
+        result.unsignedIntegerWithDefault = convert<IDLUnsignedLong>(state, unsignedIntegerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.unsignedIntegerWithDefault = 0;
     JSValue unsignedLargeIntegerValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedLargeInteger"));
     if (!unsignedLargeIntegerValue.isUndefined()) {
-        result.unsignedLargeInteger = convert<IDLUnsignedLongLong>(state, unsignedLargeIntegerValue);
+        result.unsignedLargeInteger = convert<IDLUnsignedLongLong>(state, unsignedLargeIntegerValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     JSValue unsignedLargeIntegerWithDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "unsignedLargeIntegerWithDefault"));
     if (!unsignedLargeIntegerWithDefaultValue.isUndefined()) {
-        result.unsignedLargeIntegerWithDefault = convert<IDLUnsignedLongLong>(state, unsignedLargeIntegerWithDefaultValue);
+        result.unsignedLargeIntegerWithDefault = convert<IDLUnsignedLongLong>(state, unsignedLargeIntegerWithDefaultValue, IntegerConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     } else
         result.unsignedLargeIntegerWithDefault = 0;
@@ -723,6 +740,10 @@ JSC::JSObject* convertDictionaryToJS(JSC::ExecState& state, JSDOMGlobalObject& g
         auto enumerationValueWithoutDefaultValue = toJS<IDLEnumeration<TestObj::EnumType>>(state, globalObject, IDLEnumeration<TestObj::EnumType>::extractValueFromNullable(dictionary.enumerationValueWithoutDefault));
         result->putDirect(vm, JSC::Identifier::fromString(&vm, "enumerationValueWithoutDefault"), enumerationValueWithoutDefaultValue);
     }
+    auto fooAliasValue = toJS<IDLAny>(state, globalObject, dictionary.foo);
+    result->putDirect(vm, JSC::Identifier::fromString(&vm, "fooAlias"), fooAliasValue);
+    auto fooWithDefaultAliasValue = toJS<IDLAny>(state, globalObject, dictionary.fooWithDefault);
+    result->putDirect(vm, JSC::Identifier::fromString(&vm, "fooWithDefaultAlias"), fooWithDefaultAliasValue);
     if (!IDLLong::isNullValue(dictionary.integer)) {
         auto integerValue = toJS<IDLLong>(state, globalObject, IDLLong::extractValueFromNullable(dictionary.integer));
         result->putDirect(vm, JSC::Identifier::fromString(&vm, "integer"), integerValue);
@@ -773,6 +794,10 @@ JSC::JSObject* convertDictionaryToJS(JSC::ExecState& state, JSDOMGlobalObject& g
     }
     auto smallUnsignedIntegerWithDefaultValue = toJS<IDLOctet>(state, globalObject, dictionary.smallUnsignedIntegerWithDefault);
     result->putDirect(vm, JSC::Identifier::fromString(&vm, "smallUnsignedIntegerWithDefault"), smallUnsignedIntegerWithDefaultValue);
+    if (!IDLDOMString::isNullValue(dictionary.stringTreatNullAsEmptyString)) {
+        auto stringTreatNullAsEmptyStringValue = toJS<IDLDOMString>(state, globalObject, IDLDOMString::extractValueFromNullable(dictionary.stringTreatNullAsEmptyString));
+        result->putDirect(vm, JSC::Identifier::fromString(&vm, "stringTreatNullAsEmptyString"), stringTreatNullAsEmptyStringValue);
+    }
     auto stringWithDefaultValue = toJS<IDLDOMString>(state, globalObject, dictionary.stringWithDefault);
     result->putDirect(vm, JSC::Identifier::fromString(&vm, "stringWithDefault"), stringWithDefaultValue);
     if (!IDLDOMString::isNullValue(dictionary.stringWithoutDefault)) {
@@ -998,7 +1023,7 @@ template<> TestObj::ConditionalDictionaryA convertDictionary<TestObj::Conditiona
     TestObj::ConditionalDictionaryA result;
     JSValue stringWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithoutDefault"));
     if (!stringWithoutDefaultValue.isUndefined()) {
-        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue);
+        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     return result;
@@ -1025,7 +1050,7 @@ template<> TestObj::ConditionalDictionaryB convertDictionary<TestObj::Conditiona
     TestObj::ConditionalDictionaryB result;
     JSValue stringWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithoutDefault"));
     if (!stringWithoutDefaultValue.isUndefined()) {
-        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue);
+        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     return result;
@@ -1052,7 +1077,7 @@ template<> TestObj::ConditionalDictionaryC convertDictionary<TestObj::Conditiona
     TestObj::ConditionalDictionaryC result;
     JSValue stringWithoutDefaultValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringWithoutDefault"));
     if (!stringWithoutDefaultValue.isUndefined()) {
-        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue);
+        result.stringWithoutDefault = convert<IDLDOMString>(state, stringWithoutDefaultValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     return result;
index 5f406c2..0eefad1 100644 (file)
@@ -58,7 +58,7 @@ template<> DictionaryImplName convertDictionary<DictionaryImplName>(ExecState& s
     }
     JSValue stringMemberValue = isNullOrUndefined ? jsUndefined() : object->get(&state, Identifier::fromString(&state, "stringMember"));
     if (!stringMemberValue.isUndefined()) {
-        result.stringMember = convert<IDLDOMString>(state, stringMemberValue);
+        result.stringMember = convert<IDLDOMString>(state, stringMemberValue, StringConversionConfiguration::Normal);
         RETURN_IF_EXCEPTION(throwScope, { });
     }
     return result;
index 5fefc8b..1bec5ca 100644 (file)
@@ -436,13 +436,14 @@ typedef any AnyTypedef;
 
 [
     JSGenerateToJSObject
-]dictionary TestDictionary {
+] dictionary TestDictionary {
     TestEnumType enumerationValueWithoutDefault;
     TestEnumType enumerationValueWithDefault = "enumValue1";
     TestEnumType enumerationValueWithEmptyStringDefault = "";
     DOMString stringWithDefault = "defaultString";
     DOMString stringWithoutDefault;
     DOMString? nullableStringWithDefault = null;
+    [TreatNullAs=EmptyString] DOMString stringTreatNullAsEmptyString;
     boolean booleanWithDefault = false;
     boolean booleanWithoutDefault;
     sequence<DOMString> sequenceOfStrings;
@@ -470,6 +471,8 @@ typedef any AnyTypedef;
     Node? nullableNode = null;
     any anyValue;
     any anyValueWithNullDefault = null;
+    [ImplementedAs=foo] any fooAlias;
+    [ImplementedAs=fooWithDefault] any fooWithDefaultAlias = 0;
     AnyTypedef anyTypedefValue;
     TestDictionaryThatShouldTolerateNull dictionaryMember;
     (long or Node) unionMember;