[Bindings] Declare dictionary / enumeration template specializations in the header
https://bugs.webkit.org/show_bug.cgi?id=162929

Reviewed by Darin Adler.

Declare dictionary / enumeration template specializations in the header
so that:
- They can be used from custom bindings code.
- Dictionaries / enumerations can be used to their own IDL files to
  share them (Bug 162912).

No new tests, rebaselined bindings tests.

* WebCore.xcodeproj/project.pbxproj:
* bindings/generic/IDLTypes.h:
* bindings/js/JSDOMConvert.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateInterface):
(GenerateEnumerationImplementationContent):
(GenerateEnumerationHeaderContent):
(GenerateDictionaryHeaderContent):
(GenerateHeader):
(GenerateCallbackHeader):
(GenerateCallbackImplementation):
(GenerateDefaultValue): Deleted.
(GenerateDictionaryImplementationContent): Deleted.
(GenerateParametersCheck): Deleted.
* bindings/scripts/test/JS/JSTestObj.cpp:
* bindings/scripts/test/JS/JSTestObj.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@206812 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 3616662..1b0d70d 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,35 @@
+2016-10-05  Chris Dumez  <cdumez@apple.com>
+
+        [Bindings] Declare dictionary / enumeration template specializations in the header
+        https://bugs.webkit.org/show_bug.cgi?id=162929
+
+        Reviewed by Darin Adler.
+
+        Declare dictionary / enumeration template specializations in the header
+        so that:
+        - They can be used from custom bindings code.
+        - Dictionaries / enumerations can be used to their own IDL files to
+          share them (Bug 162912).
+
+        No new tests, rebaselined bindings tests.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/generic/IDLTypes.h:
+        * bindings/js/JSDOMConvert.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateInterface):
+        (GenerateEnumerationImplementationContent):
+        (GenerateEnumerationHeaderContent):
+        (GenerateDictionaryHeaderContent):
+        (GenerateHeader):
+        (GenerateCallbackHeader):
+        (GenerateCallbackImplementation):
+        (GenerateDefaultValue): Deleted.
+        (GenerateDictionaryImplementationContent): Deleted.
+        (GenerateParametersCheck): Deleted.
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        * bindings/scripts/test/JS/JSTestObj.h:
+
 2016-10-05  Zan Dobersek  <zdobersek@igalia.com>
 
         Rename ENABLE_ENCRYPTED_MEDIA_V2 to ENABLE_LEGACY_ENCRYPTED_MEDIA
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index 7ddd852..116a50f 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -2772,7 +2772,7 @@
 		7C93F34E1AA6BF0700A98BAB /* ContentExtensionCompiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C93F34C1AA6BF0700A98BAB /* ContentExtensionCompiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7C9DBFED1A9C49B1000D6B25 /* JSHTMLAttachmentElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C9DBFEB1A9C49B1000D6B25 /* JSHTMLAttachmentElement.cpp */; };
 		7C9DBFEE1A9C49B1000D6B25 /* JSHTMLAttachmentElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C9DBFEC1A9C49B1000D6B25 /* JSHTMLAttachmentElement.h */; };
-		7CC16FFB1D77375300CE0877 /* IDLTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CC16FFA1D77375300CE0877 /* IDLTypes.h */; };
+		7CC16FFB1D77375300CE0877 /* IDLTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CC16FFA1D77375300CE0877 /* IDLTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7CC289DF1AA0FE5D009A9CE3 /* URLRegistry.h in Headers */ = {isa = PBXBuildFile; fileRef = CDEE393817974274001D7580 /* URLRegistry.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7CC564B818BABEA6001B9652 /* TelephoneNumberDetector.h in Headers */ = {isa = PBXBuildFile; fileRef = 7CC564B618BABEA6001B9652 /* TelephoneNumberDetector.h */; };
 		7CC564BA18BAC720001B9652 /* TelephoneNumberDetectorCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7CC564B918BAC720001B9652 /* TelephoneNumberDetectorCocoa.cpp */; };
@@ -3099,7 +3099,7 @@
 		930705EB09E0C9F600B17FE4 /* JSCSSPrimitiveValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 930705EA09E0C9F600B17FE4 /* JSCSSPrimitiveValue.h */; };
 		9307F1D70AF2D59000DBA31A /* HitTestResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9307F1D50AF2D59000DBA31A /* HitTestResult.cpp */; };
 		9307F1D80AF2D59000DBA31A /* HitTestResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 9307F1D60AF2D59000DBA31A /* HitTestResult.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		930841341CDDB15500B0958C /* JSDOMConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = 930841331CDDB15500B0958C /* JSDOMConvert.h */; };
+		930841341CDDB15500B0958C /* JSDOMConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = 930841331CDDB15500B0958C /* JSDOMConvert.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		930908910AF7EDE40081DF01 /* HitTestRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 930908900AF7EDE40081DF01 /* HitTestRequest.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		930C90DD19CF965300D6C21A /* InlineIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930C90DC19CF965300D6C21A /* InlineIterator.cpp */; };
 		93153BDA14181F7A00FCF5BE /* missingImage@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 93153BD914181F7A00FCF5BE /* missingImage@2x.png */; };
diff --git a/Source/WebCore/bindings/generic/IDLTypes.h b/Source/WebCore/bindings/generic/IDLTypes.h
index 373f93d..887c1e6 100644
--- a/Source/WebCore/bindings/generic/IDLTypes.h
+++ b/Source/WebCore/bindings/generic/IDLTypes.h
@@ -27,6 +27,7 @@
 
 #include <wtf/Brigand.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/text/WTFString.h>
 
 namespace JSC {
 class JSValue;
diff --git a/Source/WebCore/bindings/js/JSDOMConvert.h b/Source/WebCore/bindings/js/JSDOMConvert.h
index ef635f1..54be2fb 100644
--- a/Source/WebCore/bindings/js/JSDOMConvert.h
+++ b/Source/WebCore/bindings/js/JSDOMConvert.h
@@ -408,4 +408,8 @@
     }
 };
 
+// Used for IDL enumerations.
+template<typename T> Optional<T> parse(JSC::ExecState&, JSC::JSValue);
+template<typename T> const char* expectedEnumerationValues();
+
 } // namespace WebCore
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
index 395c7a8..cd532a3 100644
--- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
+++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
@@ -128,10 +128,10 @@
     AddStringifierOperationIfNeeded($interface);
 
     if ($interface->isCallback) {
-        $object->GenerateCallbackHeader($interface);
+        $object->GenerateCallbackHeader($interface, $enumerations, $dictionaries);
         $object->GenerateCallbackImplementation($interface, $enumerations, $dictionaries);
     } else {
-        $object->GenerateHeader($interface);
+        $object->GenerateHeader($interface, $enumerations, $dictionaries);
         $object->GenerateImplementation($interface, $enumerations, $dictionaries);
     }
 }
@@ -808,14 +808,7 @@
 
     return "" unless @$enumerations;
 
-    # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
-    # used, which would require iterating over everything in the interface.
-
     my $result = "";
-
-    $result .= "template<typename T> Optional<T> parse(ExecState&, JSValue);\n";
-    $result .= "template<typename T> const char* expectedEnumerationValues();\n\n";
-
     foreach my $enumeration (@$enumerations) {
         my $name = $enumeration->name;
 
@@ -827,9 +820,6 @@
         my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
         $result .= "#if ${conditionalString}\n\n" if $conditionalString;
 
-        # Declare this instead of using "static" because it may be unused and we don't want warnings about that.
-        $result .= "JSString* jsStringWithCache(ExecState*, $className);\n\n";
-
         # Take an ExecState* instead of an ExecState& to match the jsStringWithCache from JSString.h.
         # FIXME: Change to take VM& instead of ExecState*.
         $result .= "JSString* jsStringWithCache(ExecState* state, $className enumerationValue)\n";
@@ -855,10 +845,6 @@
         $result .= "    return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);\n";
         $result .= "}\n\n";
 
-        $result .= "template<> struct JSValueTraits<$className> {\n";
-        $result .= "    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, $className value) { return jsStringWithCache(state, value); }\n";
-        $result .= "};\n\n";
-
         # FIXME: Change to take VM& instead of ExecState&.
         # FIXME: Consider using toStringOrNull to make exception checking faster.
         # FIXME: Consider finding a more efficient way to match against all the strings quickly.
@@ -892,7 +878,7 @@
         $result .= "    return result.value();\n";
         $result .= "}\n\n";
 
-        $result .= "template<> inline const char* expectedEnumerationValues<$className>()\n";
+        $result .= "template<> const char* expectedEnumerationValues<$className>()\n";
         $result .= "{\n";
         $result .= "    return \"\\\"" . join ("\\\", \\\"", @{$enumeration->values}) . "\\\"\";\n";
         $result .= "}\n\n";
@@ -902,6 +888,42 @@
     return $result;
 }
 
+sub GenerateEnumerationHeaderContent
+{
+    my ($interface, $enumerations) = @_;
+
+    return "" unless @$enumerations;
+
+    # FIXME: Could optimize this to only generate the parts of each enumeration that are actually
+    # used, which would require iterating over everything in the interface.
+
+    $headerIncludes{"JSDOMConvert.h"} = 1;
+
+    my $result = "";
+
+    foreach my $enumeration (@$enumerations) {
+        my $name = $enumeration->name;
+
+        my $className = GetEnumerationClassName($interface, $name);
+
+        my $conditionalString = $codeGenerator->GenerateConditionalString($enumeration);
+        $result .= "#if ${conditionalString}\n\n" if $conditionalString;
+
+        $result .= "JSC::JSString* jsStringWithCache(JSC::ExecState*, $className);\n\n";
+
+        $result .= "template<> struct JSValueTraits<$className> {\n";
+        $result .= "    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, $className value) { return jsStringWithCache(state, value); }\n";
+        $result .= "};\n\n";
+
+        $result .= "template<> Optional<$className> parse<$className>(JSC::ExecState&, JSC::JSValue);\n";
+        $result .= "template<> $className convert<$className>(JSC::ExecState&, JSC::JSValue);\n";
+        $result .= "template<> const char* expectedEnumerationValues<$className>();\n\n";
+
+        $result .= "#endif\n\n" if $conditionalString;
+    }
+    return $result;
+}
+
 sub GetDictionaryClassName
 {
     my ($interface, $name) = @_;
@@ -951,6 +973,31 @@
     return "";
 }
 
+sub GenerateDictionaryHeaderContent
+{
+    my ($interface, $allDictionaries) = @_;
+
+    return "" unless @$allDictionaries;
+
+    $headerIncludes{"JSDOMConvert.h"} = 1;
+
+    my $result = "";
+    foreach my $dictionary (@$allDictionaries) {
+        my $name = $dictionary->name;
+
+        my $conditionalString = $codeGenerator->GenerateConditionalString($dictionary);
+        $result .= "#if ${conditionalString}\n\n" if $conditionalString;
+
+        $headerIncludes{$interface->name . ".h"} = 1;
+
+        my $className = GetDictionaryClassName($interface, $name);
+        $result .= "template<> Optional<$className> convertDictionary<$className>(JSC::ExecState&, JSC::JSValue);\n\n";
+
+        $result .= "#endif\n\n" if $conditionalString;
+    }
+    return $result;
+}
+
 sub GenerateDictionaryImplementationContent
 {
     my ($interface, $allDictionaries) = @_;
@@ -1079,7 +1126,7 @@
 
 sub GenerateHeader
 {
-    my ($object, $interface) = @_;
+    my ($object, $interface, $enumerations, $dictionaries) = @_;
 
     my $interfaceName = $interface->name;
     my $className = "JS$interfaceName";
@@ -1571,6 +1618,9 @@
         push(@headerContent, "};\n");
     }
 
+    push(@headerContent, GenerateEnumerationHeaderContent($interface, $enumerations));
+    push(@headerContent, GenerateDictionaryHeaderContent($interface, $dictionaries));
+
     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
     push(@headerContent, "\n} // namespace WebCore\n");
     push(@headerContent, "\n#endif // ${conditionalString}\n") if $conditionalString;
@@ -4126,7 +4176,7 @@
 
 sub GenerateCallbackHeader
 {
-    my ($object, $interface) = @_;
+    my ($object, $interface, $enumerations, $dictionaries) = @_;
 
     my $interfaceName = $interface->name;
     my $className = "JS$interfaceName";
@@ -4185,6 +4235,9 @@
     push(@headerContent, "JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, $interfaceName&);\n");
     push(@headerContent, "inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, $interfaceName* impl) { return impl ? toJS(state, globalObject, *impl) : JSC::jsNull(); }\n\n");
 
+    push(@headerContent, GenerateEnumerationHeaderContent($interface, $enumerations));
+    push(@headerContent, GenerateDictionaryHeaderContent($interface, $dictionaries));
+
     push(@headerContent, "} // namespace WebCore\n");
 
     my $conditionalString = $codeGenerator->GenerateConditionalString($interface);
@@ -4193,7 +4246,7 @@
 
 sub GenerateCallbackImplementation
 {
-    my ($object, $interface, $enumerations) = @_;
+    my ($object, $interface, $enumerations, $dictionaries) = @_;
 
     my $interfaceName = $interface->name;
     my $visibleInterfaceName = $codeGenerator->GetVisibleInterfaceName($interface);
@@ -4211,6 +4264,7 @@
     push(@implContent, "namespace WebCore {\n\n");
 
     push(@implContent, GenerateEnumerationImplementationContent($interface, $enumerations));
+    push(@implContent, GenerateDictionaryImplementationContent($interface, $dictionaries));
 
     # Constructor
     push(@implContent, "${className}::${className}(JSObject* callback, JSDOMGlobalObject* globalObject)\n");
diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
index 486fe52..151bb2a 100644
--- a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
@@ -34,7 +34,6 @@
 #include "JSBlob.h"
 #include "JSDOMBinding.h"
 #include "JSDOMConstructor.h"
-#include "JSDOMConvert.h"
 #include "JSDOMIterator.h"
 #include "JSDOMPromise.h"
 #include "JSDOMStringList.h"
@@ -92,11 +91,6 @@
 
 namespace WebCore {
 
-template<typename T> Optional<T> parse(ExecState&, JSValue);
-template<typename T> const char* expectedEnumerationValues();
-
-JSString* jsStringWithCache(ExecState*, TestObj::EnumType);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::EnumType enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -113,10 +107,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::EnumType> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::EnumType value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::EnumType> parse<TestObj::EnumType>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -143,13 +133,11 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::EnumType>()
+template<> const char* expectedEnumerationValues<TestObj::EnumType>()
 {
     return "\"\", \"enumValue1\", \"EnumValue2\", \"EnumValue3\"";
 }
 
-JSString* jsStringWithCache(ExecState*, TestObj::Optional);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::Optional enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -166,10 +154,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::Optional> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::Optional value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::Optional> parse<TestObj::Optional>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -196,13 +180,11 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::Optional>()
+template<> const char* expectedEnumerationValues<TestObj::Optional>()
 {
     return "\"\", \"OptionalValue1\", \"OptionalValue2\", \"OptionalValue3\"";
 }
 
-JSString* jsStringWithCache(ExecState*, AlternateEnumName);
-
 JSString* jsStringWithCache(ExecState* state, AlternateEnumName enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -215,10 +197,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<AlternateEnumName> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, AlternateEnumName value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<AlternateEnumName> parse<AlternateEnumName>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -241,15 +219,13 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<AlternateEnumName>()
+template<> const char* expectedEnumerationValues<AlternateEnumName>()
 {
     return "\"enumValue1\", \"EnumValue2\"";
 }
 
 #if ENABLE(Condition1)
 
-JSString* jsStringWithCache(ExecState*, TestObj::EnumA);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::EnumA enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -260,10 +236,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::EnumA> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::EnumA value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::EnumA> parse<TestObj::EnumA>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -284,7 +256,7 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::EnumA>()
+template<> const char* expectedEnumerationValues<TestObj::EnumA>()
 {
     return "\"A\"";
 }
@@ -293,8 +265,6 @@
 
 #if ENABLE(Condition1) && ENABLE(Condition2)
 
-JSString* jsStringWithCache(ExecState*, TestObj::EnumB);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::EnumB enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -305,10 +275,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::EnumB> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::EnumB value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::EnumB> parse<TestObj::EnumB>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -329,7 +295,7 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::EnumB>()
+template<> const char* expectedEnumerationValues<TestObj::EnumB>()
 {
     return "\"B\"";
 }
@@ -338,8 +304,6 @@
 
 #if ENABLE(Condition1) || ENABLE(Condition2)
 
-JSString* jsStringWithCache(ExecState*, TestObj::EnumC);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::EnumC enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -350,10 +314,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::EnumC> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::EnumC value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::EnumC> parse<TestObj::EnumC>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -374,15 +334,13 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::EnumC>()
+template<> const char* expectedEnumerationValues<TestObj::EnumC>()
 {
     return "\"C\"";
 }
 
 #endif
 
-JSString* jsStringWithCache(ExecState*, TestObj::Kind);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::Kind enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -395,10 +353,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::Kind> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::Kind value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::Kind> parse<TestObj::Kind>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -421,13 +375,11 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::Kind>()
+template<> const char* expectedEnumerationValues<TestObj::Kind>()
 {
     return "\"quick\", \"dead\"";
 }
 
-JSString* jsStringWithCache(ExecState*, TestObj::Size);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::Size enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -440,10 +392,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::Size> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::Size value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::Size> parse<TestObj::Size>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -466,13 +414,11 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::Size>()
+template<> const char* expectedEnumerationValues<TestObj::Size>()
 {
     return "\"small\", \"much-much-larger\"";
 }
 
-JSString* jsStringWithCache(ExecState*, TestObj::Confidence);
-
 JSString* jsStringWithCache(ExecState* state, TestObj::Confidence enumerationValue)
 {
     static NeverDestroyed<const String> values[] = {
@@ -485,10 +431,6 @@
     return jsStringWithCache(state, values[static_cast<size_t>(enumerationValue)]);
 }
 
-template<> struct JSValueTraits<TestObj::Confidence> {
-    static JSString* arrayJSValue(ExecState* state, JSDOMGlobalObject*, TestObj::Confidence value) { return jsStringWithCache(state, value); }
-};
-
 template<> Optional<TestObj::Confidence> parse<TestObj::Confidence>(ExecState& state, JSValue value)
 {
     auto stringValue = value.toWTFString(&state);
@@ -511,7 +453,7 @@
     return result.value();
 }
 
-template<> inline const char* expectedEnumerationValues<TestObj::Confidence>()
+template<> const char* expectedEnumerationValues<TestObj::Confidence>()
 {
     return "\"high\", \"kinda-low\"";
 }
diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h
index 91d7ea9..0791139 100644
--- a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h
+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h
@@ -20,6 +20,7 @@
 
 #pragma once
 
+#include "JSDOMConvert.h"
 #include "JSDOMWrapper.h"
 #include "TestObj.h"
 #include <wtf/NeverDestroyed.h>
@@ -104,5 +105,119 @@
 template<> struct JSDOMWrapperConverterTraits<TestObj> {
     using WrapperClass = JSTestObj;
 };
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::EnumType);
+
+template<> struct JSValueTraits<TestObj::EnumType> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::EnumType value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::EnumType> parse<TestObj::EnumType>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::EnumType convert<TestObj::EnumType>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::EnumType>();
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::Optional);
+
+template<> struct JSValueTraits<TestObj::Optional> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::Optional value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::Optional> parse<TestObj::Optional>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::Optional convert<TestObj::Optional>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::Optional>();
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, AlternateEnumName);
+
+template<> struct JSValueTraits<AlternateEnumName> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, AlternateEnumName value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<AlternateEnumName> parse<AlternateEnumName>(JSC::ExecState&, JSC::JSValue);
+template<> AlternateEnumName convert<AlternateEnumName>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<AlternateEnumName>();
+
+#if ENABLE(Condition1)
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::EnumA);
+
+template<> struct JSValueTraits<TestObj::EnumA> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::EnumA value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::EnumA> parse<TestObj::EnumA>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::EnumA convert<TestObj::EnumA>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::EnumA>();
+
+#endif
+
+#if ENABLE(Condition1) && ENABLE(Condition2)
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::EnumB);
+
+template<> struct JSValueTraits<TestObj::EnumB> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::EnumB value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::EnumB> parse<TestObj::EnumB>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::EnumB convert<TestObj::EnumB>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::EnumB>();
+
+#endif
+
+#if ENABLE(Condition1) || ENABLE(Condition2)
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::EnumC);
+
+template<> struct JSValueTraits<TestObj::EnumC> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::EnumC value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::EnumC> parse<TestObj::EnumC>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::EnumC convert<TestObj::EnumC>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::EnumC>();
+
+#endif
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::Kind);
+
+template<> struct JSValueTraits<TestObj::Kind> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::Kind value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::Kind> parse<TestObj::Kind>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::Kind convert<TestObj::Kind>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::Kind>();
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::Size);
+
+template<> struct JSValueTraits<TestObj::Size> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::Size value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::Size> parse<TestObj::Size>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::Size convert<TestObj::Size>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::Size>();
+
+JSC::JSString* jsStringWithCache(JSC::ExecState*, TestObj::Confidence);
+
+template<> struct JSValueTraits<TestObj::Confidence> {
+    static JSC::JSString* arrayJSValue(JSC::ExecState* state, JSDOMGlobalObject*, TestObj::Confidence value) { return jsStringWithCache(state, value); }
+};
+
+template<> Optional<TestObj::Confidence> parse<TestObj::Confidence>(JSC::ExecState&, JSC::JSValue);
+template<> TestObj::Confidence convert<TestObj::Confidence>(JSC::ExecState&, JSC::JSValue);
+template<> const char* expectedEnumerationValues<TestObj::Confidence>();
+
+template<> Optional<TestObj::Dictionary> convertDictionary<TestObj::Dictionary>(JSC::ExecState&, JSC::JSValue);
+
+template<> Optional<TestObj::DictionaryThatShouldNotTolerateNull> convertDictionary<TestObj::DictionaryThatShouldNotTolerateNull>(JSC::ExecState&, JSC::JSValue);
+
+template<> Optional<TestObj::DictionaryThatShouldTolerateNull> convertDictionary<TestObj::DictionaryThatShouldTolerateNull>(JSC::ExecState&, JSC::JSValue);
+
+template<> Optional<AlternateDictionaryName> convertDictionary<AlternateDictionaryName>(JSC::ExecState&, JSC::JSValue);
+
+template<> Optional<TestObj::ParentDictionary> convertDictionary<TestObj::ParentDictionary>(JSC::ExecState&, JSC::JSValue);
+
+template<> Optional<TestObj::ChildDictionary> convertDictionary<TestObj::ChildDictionary>(JSC::ExecState&, JSC::JSValue);
+
 
 } // namespace WebCore