Bug 836816 - WebIDL parser should enforce spec restrictions on dictionary member types. r=bzbarsky
authorPranav Ravichandran <prp.1111@gmail.com>
Wed, 27 Feb 2013 09:55:56 -0500
changeset 133560 95d500777957227364701ae252e0ce9202046483
parent 133559 c87c6b23794ead3fa0da02225d3c835b2736cc6a
child 133561 f118eb2326f7a80806d137bf760de63cb7da800e
push idunknown
push userunknown
push dateunknown
reviewersbzbarsky
bugs836816
milestone22.0a1
Bug 836816 - WebIDL parser should enforce spec restrictions on dictionary member types. r=bzbarsky
dom/bindings/parser/WebIDL.py
dom/bindings/parser/tests/test_dictionary.py
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -1018,17 +1018,75 @@ class IDLDictionary(IDLObjectWithScope):
         for inheritedMember in inheritedMembers:
             for member in self.members:
                 if member.identifier.name == inheritedMember.identifier.name:
                     raise WebIDLError("Dictionary %s has two members with name %s" %
                                       (self.identifier.name, member.identifier.name),
                                       [member.location, inheritedMember.location])
 
     def validate(self):
-        pass
+        def typeContainsDictionary(memberType, dictionary):
+            """
+            Returns a tuple whose:
+
+                - First element is a Boolean value indicating whether
+                  memberType contains dictionary.
+
+                - Second element is:
+                    A list of locations that leads from the type that was passed in
+                    the memberType argument, to the dictionary being validated,
+                    if the boolean value in the first element is True.
+
+                    None, if the boolean value in the first element is False.
+            """
+
+            if memberType.nullable() or \
+               memberType.isArray() or \
+               memberType.isSequence():
+                return typeContainsDictionary(memberType.inner, dictionary)
+
+            if memberType.isDictionary():
+                if memberType.inner == dictionary:
+                    return (True, [memberType.location])
+
+                (contains, locations) = dictionaryContainsDictionary(memberType.inner, \
+                                                                     dictionary)
+                if contains:
+                    return (True, [memberType.location] + locations)
+
+            if memberType.isUnion():
+                for member in memberType.flatMemberTypes:
+                    (contains, locations) = typeContainsDictionary(member, dictionary)
+                    if contains:
+                        return (True, locations)
+
+            return (False, None)
+
+        def dictionaryContainsDictionary(dictMember, dictionary):
+            for member in dictMember.members:
+                (contains, locations) = typeContainsDictionary(member.type, dictionary)
+                if contains:
+                    return (True, [member.location] + locations)
+
+            if dictMember.parent:
+                if dictMember.parent == dictionary:
+                    return (True, [dictMember.location])
+                else:
+                    (contains, locations) = dictionaryContainsDictionary(dictMember.parent, dictionary)
+                    if contains:
+                        return (True, [dictMember.location] + locations)
+
+            return (False, None)
+
+        for member in self.members:
+            (contains, locations) = typeContainsDictionary(member.type, self)
+            if contains:
+                raise WebIDLError("Dictionary %s has member with itself as type." %
+                                  self.identifier.name,
+                                  [member.location] + locations)
 
     def addExtendedAttributes(self, attrs):
         assert len(attrs) == 0
 
     def _getDependentObjects(self):
         deps = set(self.members)
         if (self.parent):
             deps.add(self.parent)
--- a/dom/bindings/parser/tests/test_dictionary.py
+++ b/dom/bindings/parser/tests/test_dictionary.py
@@ -291,8 +291,137 @@ def WebIDLTest(parser, harness):
         dictionary A {
         };
         interface X {
           void doFoo(optional (A or DOMString) arg);
         };
     """)
     results = parser.finish()
     harness.ok(True, "Union arg containing a dictionary should actually parse")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo {
+              Foo foo;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be its Dictionary.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo3 : Foo {
+              short d;
+            };
+
+            dictionary Foo2 : Foo3 {
+              boolean c;
+            };
+
+            dictionary Foo1 : Foo2 {
+              long a;
+            };
+
+            dictionary Foo {
+              Foo1 b;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be a Dictionary that "
+                      "inherits from its Dictionary.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo {
+              (Foo or DOMString)[]? b;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be a Nullable type "
+                      "whose inner type includes its Dictionary.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo {
+              (DOMString or Foo) b;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be a Union type, one of "
+                      "whose member types includes its Dictionary.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo {
+              sequence<sequence<sequence<Foo>>> c;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be a Sequence type "
+                      "whose element type includes its Dictionary.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo {
+              (DOMString or Foo)[] d;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be an Array type "
+                      "whose element type includes its Dictionary.")
+
+    parser = parser.reset()
+    threw = False
+    try:
+        parser.parse("""
+            dictionary Foo {
+              Foo1 b;
+            };
+
+            dictionary Foo3 {
+              Foo d;
+            };
+
+            dictionary Foo2 : Foo3 {
+              short c;
+            };
+
+            dictionary Foo1 : Foo2 {
+              long a;
+            };
+        """)
+        results = parser.finish()
+    except:
+        threw = True
+
+    harness.ok(threw, "Member type must not be a Dictionary, one of whose "
+                      "members or inherited members has a type that includes "
+                      "its Dictionary.")