c011d40445aca901b419204fe37ac1ae6ba73c3f
[WebKit-https.git] / Source / WebCore / bindings / scripts / CodeGenerator.pm
1 #
2 # WebKit IDL parser
3 #
4 # Copyright (C) 2005 Nikolas Zimmermann <wildfox@kde.org>
5 # Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
6 # Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
7 # Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
8 # Copyright (C) Research In Motion Limited 2010. All rights reserved.
9 #
10 # This library is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU Library General Public
12 # License as published by the Free Software Foundation; either
13 # version 2 of the License, or (at your option) any later version.
14 #
15 # This library is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 # Library General Public License for more details.
19 #
20 # You should have received a copy of the GNU Library General Public License
21 # along with this library; see the file COPYING.LIB.  If not, write to
22 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 # Boston, MA 02110-1301, USA.
24 #
25
26 package CodeGenerator;
27
28 use strict;
29
30 use File::Find;
31
32 my $useDocument = "";
33 my $useGenerator = "";
34 my $useOutputDir = "";
35 my $useOutputHeadersDir = "";
36 my $useDirectories = "";
37 my $useLayerOnTop = 0;
38 my $preprocessor;
39 my $writeDependencies = 0;
40 my $defines = "";
41 my $targetIdlFilePath = "";
42
43 my $codeGenerator = 0;
44
45 my $verbose = 0;
46
47 my %numericTypeHash = ("int" => 1, "short" => 1, "long" => 1, "long long" => 1,
48                        "unsigned int" => 1, "unsigned short" => 1,
49                        "unsigned long" => 1, "unsigned long long" => 1,
50                        "float" => 1, "double" => 1);
51
52 my %primitiveTypeHash = ( "boolean" => 1, "void" => 1, "Date" => 1);
53
54 my %stringTypeHash = ("DOMString" => 1, "AtomicString" => 1);
55
56 my %nonPointerTypeHash = ("DOMTimeStamp" => 1, "CompareHow" => 1);
57
58 my %svgAnimatedTypeHash = ("SVGAnimatedAngle" => 1, "SVGAnimatedBoolean" => 1,
59                            "SVGAnimatedEnumeration" => 1, "SVGAnimatedInteger" => 1,
60                            "SVGAnimatedLength" => 1, "SVGAnimatedLengthList" => 1,
61                            "SVGAnimatedNumber" => 1, "SVGAnimatedNumberList" => 1,
62                            "SVGAnimatedPreserveAspectRatio" => 1,
63                            "SVGAnimatedRect" => 1, "SVGAnimatedString" => 1,
64                            "SVGAnimatedTransformList" => 1);
65
66 my %svgAttributesInHTMLHash = ("class" => 1, "id" => 1, "onabort" => 1, "onclick" => 1,
67                                "onerror" => 1, "onload" => 1, "onmousedown" => 1,
68                                "onmousemove" => 1, "onmouseout" => 1, "onmouseover" => 1,
69                                "onmouseup" => 1, "onresize" => 1, "onscroll" => 1,
70                                "onunload" => 1);
71
72 my %svgTypeNeedingTearOff = (
73     "SVGAngle" => "SVGPropertyTearOff<SVGAngle>",
74     "SVGLength" => "SVGPropertyTearOff<SVGLength>",
75     "SVGLengthList" => "SVGListPropertyTearOff<SVGLengthList>",
76     "SVGMatrix" => "SVGPropertyTearOff<SVGMatrix>",
77     "SVGNumber" => "SVGPropertyTearOff<float>",
78     "SVGNumberList" => "SVGListPropertyTearOff<SVGNumberList>",
79     "SVGPathSegList" => "SVGPathSegListPropertyTearOff",
80     "SVGPoint" => "SVGPropertyTearOff<FloatPoint>",
81     "SVGPointList" => "SVGListPropertyTearOff<SVGPointList>",
82     "SVGPreserveAspectRatio" => "SVGPropertyTearOff<SVGPreserveAspectRatio>",
83     "SVGRect" => "SVGPropertyTearOff<FloatRect>",
84     "SVGStringList" => "SVGStaticListPropertyTearOff<SVGStringList>",
85     "SVGTransform" => "SVGPropertyTearOff<SVGTransform>",
86     "SVGTransformList" => "SVGTransformListPropertyTearOff"
87 );
88
89 my %svgTypeWithWritablePropertiesNeedingTearOff = (
90     "SVGPoint" => 1,
91     "SVGMatrix" => 1
92 );
93
94 # Cache of IDL file pathnames.
95 my $idlFiles;
96
97 # Default constructor
98 sub new
99 {
100     my $object = shift;
101     my $reference = { };
102
103     $useDirectories = shift;
104     $useGenerator = shift;
105     $useOutputDir = shift;
106     $useOutputHeadersDir = shift;
107     $useLayerOnTop = shift;
108     $preprocessor = shift;
109     $writeDependencies = shift;
110     $verbose = shift;
111     $targetIdlFilePath = shift;
112
113     bless($reference, $object);
114     return $reference;
115 }
116
117 sub StripModule($)
118 {
119     my $object = shift;
120     my $name = shift;
121     $name =~ s/[a-zA-Z0-9]*:://;
122     return $name;
123 }
124
125 sub ProcessDocument
126 {
127     my $object = shift;
128     $useDocument = shift;
129     $defines = shift;
130
131     my $ifaceName = "CodeGenerator" . $useGenerator;
132     require $ifaceName . ".pm";
133
134     # Dynamically load external code generation perl module
135     $codeGenerator = $ifaceName->new($object, $useOutputDir, $useOutputHeadersDir, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose, $targetIdlFilePath);
136     unless (defined($codeGenerator)) {
137         my $classes = $useDocument->classes;
138         foreach my $class (@$classes) {
139             print "Skipping $useGenerator code generation for IDL interface \"" . $class->name . "\".\n" if $verbose;
140         }
141         return;
142     }
143
144     # Start the actual code generation!
145     $codeGenerator->GenerateModule($useDocument, $defines);
146
147     my $classes = $useDocument->classes;
148     foreach my $class (@$classes) {
149         print "Generating $useGenerator bindings code for IDL interface \"" . $class->name . "\"...\n" if $verbose;
150         $codeGenerator->GenerateInterface($class, $defines);
151     }
152 }
153
154 sub FileNamePrefix
155 {
156     my $object = shift;
157
158     my $ifaceName = "CodeGenerator" . $useGenerator;
159     require $ifaceName . ".pm";
160
161     # Dynamically load external code generation perl module
162     $codeGenerator = $ifaceName->new($object, $useOutputDir, $useOutputHeadersDir, $useLayerOnTop, $preprocessor, $writeDependencies, $verbose);
163     return $codeGenerator->FileNamePrefix();
164 }
165
166 sub UpdateFile
167 {
168     my $object = shift;
169     my $fileName = shift;
170     my $contents = shift;
171
172     open FH, "> $fileName" or die "Couldn't open $fileName: $!\n";
173     print FH $contents;
174     close FH;
175 }
176
177 sub ForAllParents
178 {
179     my $object = shift;
180     my $dataNode = shift;
181     my $beforeRecursion = shift;
182     my $afterRecursion = shift;
183     my $parentsOnly = shift;
184
185     my $recurse;
186     $recurse = sub {
187         my $interface = shift;
188
189         for (@{$interface->parents}) {
190             my $interfaceName = $object->StripModule($_);
191             my $parentInterface = $object->ParseInterface($interfaceName, $parentsOnly);
192
193             if ($beforeRecursion) {
194                 &$beforeRecursion($parentInterface) eq 'prune' and next;
195             }
196             &$recurse($parentInterface);
197             &$afterRecursion($parentInterface) if $afterRecursion;
198         }
199     };
200
201     &$recurse($dataNode);
202 }
203
204 sub AddMethodsConstantsAndAttributesFromParentClasses
205 {
206     # Add to $dataNode all of its inherited interface members, except for those
207     # inherited through $dataNode's first listed parent.  If an array reference
208     # is passed in as $parents, the names of all ancestor interfaces visited
209     # will be appended to the array.  If $collectDirectParents is true, then
210     # even the names of $dataNode's first listed parent and its ancestors will
211     # be appended to $parents.
212
213     my $object = shift;
214     my $dataNode = shift;
215     my $parents = shift;
216     my $collectDirectParents = shift;
217
218     my $first = 1;
219
220     $object->ForAllParents($dataNode, sub {
221         my $interface = shift;
222
223         if ($first) {
224             # Ignore first parent class, already handled by the generation itself.
225             $first = 0;
226
227             if ($collectDirectParents) {
228                 # Just collect the names of the direct ancestor interfaces,
229                 # if necessary.
230                 push(@$parents, $interface->name);
231                 $object->ForAllParents($interface, sub {
232                     my $interface = shift;
233                     push(@$parents, $interface->name);
234                 }, undef, 1);
235             }
236
237             # Prune the recursion here.
238             return 'prune';
239         }
240
241         # Collect the name of this additional parent.
242         push(@$parents, $interface->name) if $parents;
243
244         print "  |  |>  -> Inheriting "
245             . @{$interface->constants} . " constants, "
246             . @{$interface->functions} . " functions, "
247             . @{$interface->attributes} . " attributes...\n  |  |>\n" if $verbose;
248
249         # Add this parent's members to $dataNode.
250         push(@{$dataNode->constants}, @{$interface->constants});
251         push(@{$dataNode->functions}, @{$interface->functions});
252         push(@{$dataNode->attributes}, @{$interface->attributes});
253     });
254 }
255
256 sub FindSuperMethod
257 {
258     my ($object, $dataNode, $functionName) = @_;
259     my $indexer;
260     $object->ForAllParents($dataNode, undef, sub {
261         my $interface = shift;
262         foreach my $function (@{$interface->functions}) {
263             if ($function->signature->name eq $functionName) {
264                 $indexer = $function->signature;
265                 return 'prune';
266             }
267         }
268     });
269     return $indexer;
270 }
271
272 sub IDLFileForInterface
273 {
274     my $object = shift;
275     my $interfaceName = shift;
276
277     unless ($idlFiles) {
278         my $sourceRoot = $ENV{SOURCE_ROOT};
279         my @directories = map { $_ = "$sourceRoot/$_" if $sourceRoot && -d "$sourceRoot/$_"; $_ } @$useDirectories;
280
281         $idlFiles = { };
282
283         my $wanted = sub {
284             $idlFiles->{$1} = $File::Find::name if /^([A-Z].*)\.idl$/;
285             $File::Find::prune = 1 if /^\../;
286         };
287         find($wanted, @directories);
288     }
289
290     return $idlFiles->{$interfaceName};
291 }
292
293 sub ParseInterface
294 {
295     my $object = shift;
296     my $interfaceName = shift;
297     my $parentsOnly = shift;
298
299     return undef if $interfaceName eq 'Object';
300
301     # Step #1: Find the IDL file associated with 'interface'
302     my $filename = $object->IDLFileForInterface($interfaceName)
303         or die("Could NOT find IDL file for interface \"$interfaceName\"!\n");
304
305     print "  |  |>  Parsing parent IDL \"$filename\" for interface \"$interfaceName\"\n" if $verbose;
306
307     # Step #2: Parse the found IDL file (in quiet mode).
308     my $parser = IDLParser->new(1);
309     my $document = $parser->Parse($filename, $defines, $preprocessor, $parentsOnly);
310
311     foreach my $interface (@{$document->classes}) {
312         return $interface if $interface->name eq $interfaceName;
313     }
314
315     die("Could NOT find interface definition for $interfaceName in $filename");
316 }
317
318 # Helpers for all CodeGenerator***.pm modules
319
320 sub SkipIncludeHeader
321 {
322     my $object = shift;
323     my $type = shift;
324
325     return 1 if $primitiveTypeHash{$type};
326     return 1 if $numericTypeHash{$type};
327     return 1 if $type eq "String";
328
329     # Special case: SVGPoint.h / SVGNumber.h do not exist.
330     return 1 if $type eq "SVGPoint" or $type eq "SVGNumber";
331     return 0;
332 }
333
334 sub IsArrayType
335 {
336     my $object = shift;
337     my $type = shift;
338     # FIXME: Add proper support for T[], T[]?, sequence<T>.
339     return $type =~ m/\[\]$/;
340 }
341
342 sub IsConstructorTemplate
343 {
344     my $object = shift;
345     my $dataNode = shift;
346     my $template = shift;
347
348     return $dataNode->extendedAttributes->{"ConstructorTemplate"} && $dataNode->extendedAttributes->{"ConstructorTemplate"} eq $template;
349 }
350
351 sub IsPrimitiveType
352 {
353     my $object = shift;
354     my $type = shift;
355
356     return 1 if $primitiveTypeHash{$type};
357     return 1 if $numericTypeHash{$type};
358     return 0;
359 }
360
361 sub IsStringType
362 {
363     my $object = shift;
364     my $type = shift;
365
366     return 1 if $stringTypeHash{$type};
367     return 0;
368 }
369
370 sub IsNonPointerType
371 {
372     my $object = shift;
373     my $type = shift;
374
375     return 1 if $nonPointerTypeHash{$type} or $primitiveTypeHash{$type} or $numericTypeHash{$type};
376     return 0;
377 }
378
379 sub IsSVGTypeNeedingTearOff
380 {
381     my $object = shift;
382     my $type = shift;
383
384     return 1 if exists $svgTypeNeedingTearOff{$type};
385     return 0;
386 }
387
388 sub IsSVGTypeWithWritablePropertiesNeedingTearOff
389 {
390     my $object = shift;
391     my $type = shift;
392
393     return 1 if $svgTypeWithWritablePropertiesNeedingTearOff{$type};
394     return 0;
395 }
396
397 sub IsTypedArrayType
398 {
399     my $object = shift;
400     my $type = shift;
401     return 1 if (($type eq "ArrayBuffer") or ($type eq "ArrayBufferView"));
402     return 1 if (($type eq "Uint8Array") or ($type eq "Uint8ClampedArray") or ($type eq "Uint16Array") or ($type eq "Uint32Array"));
403     return 1 if (($type eq "Int8Array") or ($type eq "Int16Array") or ($type eq "Int32Array"));
404     return 1 if (($type eq "Float32Array") or ($type eq "Float64Array"));
405     return 0;
406 }
407
408 sub GetSVGTypeNeedingTearOff
409 {
410     my $object = shift;
411     my $type = shift;
412
413     return $svgTypeNeedingTearOff{$type} if exists $svgTypeNeedingTearOff{$type};
414     return undef;
415 }
416
417 sub GetSVGWrappedTypeNeedingTearOff
418 {
419     my $object = shift;
420     my $type = shift;
421
422     my $svgTypeNeedingTearOff = $object->GetSVGTypeNeedingTearOff($type);
423     return $svgTypeNeedingTearOff if not $svgTypeNeedingTearOff;
424
425     if ($svgTypeNeedingTearOff =~ /SVGPropertyTearOff/) {
426         $svgTypeNeedingTearOff =~ s/SVGPropertyTearOff<//;
427     } elsif ($svgTypeNeedingTearOff =~ /SVGListPropertyTearOff/) {
428         $svgTypeNeedingTearOff =~ s/SVGListPropertyTearOff<//;
429     } elsif ($svgTypeNeedingTearOff =~ /SVGStaticListPropertyTearOff/) {
430         $svgTypeNeedingTearOff =~ s/SVGStaticListPropertyTearOff<//;
431     }  elsif ($svgTypeNeedingTearOff =~ /SVGTransformListPropertyTearOff/) {
432         $svgTypeNeedingTearOff =~ s/SVGTransformListPropertyTearOff<//;
433     } 
434
435     $svgTypeNeedingTearOff =~ s/>//;
436     return $svgTypeNeedingTearOff;
437 }
438
439 sub IsSVGAnimatedType
440 {
441     my $object = shift;
442     my $type = shift;
443
444     return 1 if $svgAnimatedTypeHash{$type};
445     return 0;
446 }
447
448 sub GetSequenceType
449 {
450     my $object = shift;
451     my $type = shift;
452
453     return $1 if $type =~ /^sequence<([\w\d_\s]+)>.*/;
454     return "";
455 }
456
457 sub GetArrayType
458 {
459     my $object = shift;
460     my $type = shift;
461
462     return $1 if $type =~ /^([\w\d_\s]+)\[\]/;
463     return "";
464 }
465
466 sub AssertNotSequenceType
467 {
468     my $object = shift;
469     my $type = shift;
470     die "Sequences must not be used as the type of an attribute, constant or exception field." if $object->GetSequenceType($type);
471 }
472
473 # Uppercase the first letter while respecting WebKit style guidelines.
474 # E.g., xmlEncoding becomes XMLEncoding, but xmlllang becomes Xmllang.
475 sub WK_ucfirst
476 {
477     my ($object, $param) = @_;
478     my $ret = ucfirst($param);
479     $ret =~ s/Xml/XML/ if $ret =~ /^Xml[^a-z]/;
480
481     return $ret;
482 }
483
484 # Lowercase the first letter while respecting WebKit style guidelines.
485 # URL becomes url, but SetURL becomes setURL.
486 sub WK_lcfirst
487 {
488     my ($object, $param) = @_;
489     my $ret = lcfirst($param);
490     $ret =~ s/hTML/html/ if $ret =~ /^hTML/;
491     $ret =~ s/uRL/url/ if $ret =~ /^uRL/;
492     $ret =~ s/jS/js/ if $ret =~ /^jS/;
493     $ret =~ s/xML/xml/ if $ret =~ /^xML/;
494     $ret =~ s/xSLT/xslt/ if $ret =~ /^xSLT/;
495
496     # For HTML5 FileSystem API Flags attributes.
497     # (create is widely used to instantiate an object and must be avoided.)
498     $ret =~ s/^create/isCreate/ if $ret =~ /^create$/;
499     $ret =~ s/^exclusive/isExclusive/ if $ret =~ /^exclusive$/;
500
501     return $ret;
502 }
503
504 # Return the C++ namespace that a given attribute name string is defined in.
505 sub NamespaceForAttributeName
506 {
507     my ($object, $interfaceName, $attributeName) = @_;
508     return "SVGNames" if $interfaceName =~ /^SVG/ && !$svgAttributesInHTMLHash{$attributeName};
509     return "HTMLNames";
510 }
511
512 # Identifies overloaded functions and for each function adds an array with
513 # links to its respective overloads (including itself).
514 sub LinkOverloadedFunctions
515 {
516     my ($object, $dataNode) = @_;
517
518     my %nameToFunctionsMap = ();
519     foreach my $function (@{$dataNode->functions}) {
520         my $name = $function->signature->name;
521         $nameToFunctionsMap{$name} = [] if !exists $nameToFunctionsMap{$name};
522         push(@{$nameToFunctionsMap{$name}}, $function);
523         $function->{overloads} = $nameToFunctionsMap{$name};
524         $function->{overloadIndex} = @{$nameToFunctionsMap{$name}};
525     }
526 }
527
528 sub AttributeNameForGetterAndSetter
529 {
530     my ($generator, $attribute) = @_;
531
532     my $attributeName = $attribute->signature->name;
533     if ($attribute->signature->extendedAttributes->{"ImplementedAs"}) {
534         $attributeName = $attribute->signature->extendedAttributes->{"ImplementedAs"};
535     }
536     my $attributeType = $generator->StripModule($attribute->signature->type);
537
538     # Avoid clash with C++ keyword.
539     $attributeName = "_operator" if $attributeName eq "operator";
540
541     # SVGAElement defines a non-virtual "String& target() const" method which clashes with "virtual String target() const" in Element.
542     # To solve this issue the SVGAElement method was renamed to "svgTarget", take care of that when calling this method.
543     $attributeName = "svgTarget" if $attributeName eq "target" and $attributeType eq "SVGAnimatedString";
544
545     # SVG animated types need to use a special attribute name.
546     # The rest of the special casing for SVG animated types is handled in the language-specific code generators.
547     $attributeName .= "Animated" if $generator->IsSVGAnimatedType($attributeType);
548
549     return $attributeName;
550 }
551
552 sub ContentAttributeName
553 {
554     my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
555
556     my $contentAttributeName = $attribute->signature->extendedAttributes->{"Reflect"};
557     return undef if !$contentAttributeName;
558
559     $contentAttributeName = lc $generator->AttributeNameForGetterAndSetter($attribute) if $contentAttributeName eq "VALUE_IS_MISSING";
560
561     my $namespace = $generator->NamespaceForAttributeName($interfaceName, $contentAttributeName);
562
563     $implIncludes->{"${namespace}.h"} = 1;
564     return "WebCore::${namespace}::${contentAttributeName}Attr";
565 }
566
567 sub GetterExpression
568 {
569     my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
570
571     my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute);
572
573     if (!$contentAttributeName) {
574         return ($generator->WK_lcfirst($generator->AttributeNameForGetterAndSetter($attribute)));
575     }
576
577     my $functionName;
578     if ($attribute->signature->extendedAttributes->{"URL"}) {
579         $functionName = "getURLAttribute";
580     } elsif ($attribute->signature->type eq "boolean") {
581         $functionName = "hasAttribute";
582     } elsif ($attribute->signature->type eq "long") {
583         $functionName = "getIntegralAttribute";
584     } elsif ($attribute->signature->type eq "unsigned long") {
585         $functionName = "getUnsignedIntegralAttribute";
586     } else {
587         $functionName = "getAttribute";
588     }
589
590     return ($functionName, $contentAttributeName);
591 }
592
593 sub SetterExpression
594 {
595     my ($generator, $implIncludes, $interfaceName, $attribute) = @_;
596
597     my $contentAttributeName = $generator->ContentAttributeName($implIncludes, $interfaceName, $attribute);
598
599     if (!$contentAttributeName) {
600         return ("set" . $generator->WK_ucfirst($generator->AttributeNameForGetterAndSetter($attribute)));
601     }
602
603     my $functionName;
604     if ($attribute->signature->type eq "boolean") {
605         $functionName = "setBooleanAttribute";
606     } elsif ($attribute->signature->type eq "long") {
607         $functionName = "setIntegralAttribute";
608     } elsif ($attribute->signature->type eq "unsigned long") {
609         $functionName = "setUnsignedIntegralAttribute";
610     } else {
611         $functionName = "setAttribute";
612     }
613
614     return ($functionName, $contentAttributeName);
615 }
616
617 sub GenerateConditionalString
618 {
619     my $generator = shift;
620     my $node = shift;
621
622     my $conditional = $node->extendedAttributes->{"Conditional"};
623     if ($conditional) {
624         return $generator->GenerateConditionalStringFromAttributeValue($conditional);
625     } else {
626         return "";
627     }
628 }
629
630 sub GenerateConditionalStringFromAttributeValue
631 {
632     my $generator = shift;
633     my $conditional = shift;
634
635     my $operator = ($conditional =~ /&/ ? '&' : ($conditional =~ /\|/ ? '|' : ''));
636     if ($operator) {
637         # Avoid duplicated conditions.
638         my %conditions;
639         map { $conditions{$_} = 1 } split('\\' . $operator, $conditional);
640         return "ENABLE(" . join(") $operator$operator ENABLE(", sort keys %conditions) . ")";
641     } else {
642         return "ENABLE(" . $conditional . ")";
643     }
644 }
645
646 sub GenerateCompileTimeCheckForEnumsIfNeeded
647 {
648     my ($generator, $dataNode) = @_;
649     my $interfaceName = $dataNode->name;
650     my @checks = ();
651     # If necessary, check that all constants are available as enums with the same value.
652     if (!$dataNode->extendedAttributes->{"DoNotCheckConstants"} && @{$dataNode->constants}) {
653         push(@checks, "\n");
654         foreach my $constant (@{$dataNode->constants}) {
655             my $reflect = $constant->extendedAttributes->{"Reflect"};
656             my $name = $reflect ? $reflect : $constant->name;
657             my $value = $constant->value;
658             my $conditional = $constant->extendedAttributes->{"Conditional"};
659
660             if ($conditional) {
661                 my $conditionalString = $generator->GenerateConditionalStringFromAttributeValue($conditional);
662                 push(@checks, "#if ${conditionalString}\n");
663             }
664
665             if ($constant->extendedAttributes->{"ImplementedBy"}) {
666                 push(@checks, "COMPILE_ASSERT($value == " . $constant->extendedAttributes->{"ImplementedBy"} . "::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n");
667             } else {
668                 push(@checks, "COMPILE_ASSERT($value == ${interfaceName}::$name, ${interfaceName}Enum${name}IsWrongUseDoNotCheckConstants);\n");
669             }
670
671             if ($conditional) {
672                 push(@checks, "#endif\n");
673             }
674         }
675         push(@checks, "\n");
676     }
677     return @checks;
678 }
679
680 sub ExtendedAttributeContains
681 {
682     my $object = shift;
683     my $callWith = shift;
684     return 0 unless $callWith;
685     my $keyword = shift;
686
687     my @callWithKeywords = split /\s*\|\s*/, $callWith;
688     return grep { $_ eq $keyword } @callWithKeywords;
689 }
690
691 # FIXME: This is backwards. We currently name the interface and the IDL files with the implementation name. We
692 # should use the real interface name in the IDL files and then use ImplementedAs to map this to the implementation name.
693 sub GetVisibleInterfaceName
694 {
695     my $object = shift;
696     my $dataNode = shift;
697     my $interfaceName = $dataNode->extendedAttributes->{"InterfaceName"};
698     return $interfaceName ? $interfaceName : $dataNode->name;
699 }
700
701 sub IsStrictSubtype
702 {
703     my $object = shift;
704     my $dataNode = shift;
705     my $interfaceName = shift;
706     my $found = 0;
707
708     $object->ForAllParents($dataNode, sub {
709         my $interface = shift;
710         if ($object->StripModule($interface->name) eq $interfaceName) {
711             $found = 1;
712         }
713         return "prune" if $found;
714     }, 0, 1);
715
716     return $found;
717 }
718
719 1;