Bug 1359269 - Part 10: Make it a hard error to apply TreatNullAs on non-types; r=bzbarsky
authorManish Goregaokar <manishearth@gmail.com>
Sat, 02 Mar 2019 04:22:05 +0000
changeset 519963 759c00e21197485574c8cba2447397d0d6e20486
parent 519962 b26067ba0f78f974cf069124abc711b74996d9d7
child 519964 4166cae81546f54accae807413f806d20bf30920
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs1359269
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1359269 - Part 10: Make it a hard error to apply TreatNullAs on non-types; r=bzbarsky Depends on D20060 Differential Revision: https://phabricator.services.mozilla.com/D20061
dom/bindings/Codegen.py
dom/bindings/GenerateCSS2PropertiesWebIDL.py
dom/bindings/parser/WebIDL.py
dom/chrome-webidl/InspectorUtils.webidl
dom/imptests/html/dom/test_interfaces.html
dom/webidl/CSSStyleDeclaration.webidl
dom/webidl/CharacterData.webidl
dom/webidl/Element.webidl
dom/webidl/HTMLDocument.webidl
dom/webidl/HTMLFontElement.webidl
dom/webidl/HTMLFrameElement.webidl
dom/webidl/HTMLIFrameElement.webidl
dom/webidl/HTMLImageElement.webidl
dom/webidl/HTMLObjectElement.webidl
dom/webidl/HTMLTableCellElement.webidl
dom/webidl/HTMLTableElement.webidl
dom/webidl/HTMLTableRowElement.webidl
dom/webidl/MediaList.webidl
dom/webidl/ShadowRoot.webidl
dom/webidl/Window.webidl
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4565,17 +4565,16 @@ def recordKeyDeclType(recordType):
 # and holdertype we end up using, because it needs to be able to return the code
 # that will convert those to the actual return value of the callback function.
 def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
                                 isDefinitelyObject=False,
                                 isMember=False,
                                 isOptional=False,
                                 invalidEnumValueFatal=True,
                                 defaultValue=None,
-                                treatNullAs="Default",
                                 isNullOrUndefined=False,
                                 exceptionCode=None,
                                 lenientFloatCode=None,
                                 allowTreatNonCallableAsNull=False,
                                 isCallbackReturnValue=False,
                                 sourceDescription="value",
                                 nestingLevel=""):
     """
@@ -4645,18 +4644,16 @@ def getJSToNativeConversionInfo(type, de
     # Also, we should not have a defaultValue if we know we're an object
     assert not isDefinitelyObject or defaultValue is None
 
     # And we can't both be an object and be null or undefined
     assert not isDefinitelyObject or not isNullOrUndefined
 
     isClamp = type.clamp
     isEnforceRange = type.enforceRange
-    if type.treatNullAsEmpty:
-        treatNullAs = "EmptyString"
 
     # If exceptionCode is not set, we'll just rethrow the exception we got.
     # Note that we can't just set failureCode to exceptionCode, because setting
     # failureCode will prevent pending exceptions from being set in cases when
     # they really should be!
     if exceptionCode is None:
         exceptionCode = "return false;\n"
 
@@ -5786,16 +5783,20 @@ def getJSToNativeConversionInfo(type, de
         }
         if type.nullable():
             # For nullable strings null becomes a null string.
             treatNullAs = "Null"
             # For nullable strings undefined also becomes a null string.
             undefinedBehavior = "eNull"
         else:
             undefinedBehavior = "eStringify"
+            if type.treatNullAsEmpty:
+                treatNullAs = "EmptyString"
+            else:
+                treatNullAs = "Default"
         nullBehavior = treatAs[treatNullAs]
 
         def getConversionCode(varName):
             normalizeCode = ""
             if type.isUSVString():
                 normalizeCode = "NormalizeUSVString(%s);\n" % varName
 
             conversionCode = fill("""
@@ -6441,17 +6442,16 @@ class CGArgumentConverter(CGThing):
     def define(self):
         typeConversion = getJSToNativeConversionInfo(
             self.argument.type,
             self.descriptorProvider,
             isOptional=(self.argcAndIndex is not None and
                         not self.argument.variadic),
             invalidEnumValueFatal=self.invalidEnumValueFatal,
             defaultValue=self.argument.defaultValue,
-            treatNullAs=self.argument.treatNullAs,
             lenientFloatCode=self.lenientFloatCode,
             isMember="Variadic" if self.argument.variadic else False,
             allowTreatNonCallableAsNull=self.argument.allowTreatNonCallableAsNull(),
             sourceDescription=self.argDescription)
 
         if not self.argument.variadic:
             return instantiateJSToNativeConversion(
                 typeConversion,
@@ -8607,22 +8607,16 @@ class FakeArgument():
     setters look like method calls or for special operations.
     """
     def __init__(self, type, interfaceMember, name="arg", allowTreatNonCallableAsNull=False):
         self.type = type
         self.optional = False
         self.variadic = False
         self.defaultValue = None
         self._allowTreatNonCallableAsNull = allowTreatNonCallableAsNull
-        # For FakeArguments generated by maplike/setlike convenience functions,
-        # we won't have an interfaceMember to pass in.
-        if interfaceMember:
-            self.treatNullAs = interfaceMember.treatNullAs
-        else:
-            self.treatNullAs = "Default"
 
         self.identifier = FakeIdentifier(name)
 
     def allowTreatNonCallableAsNull(self):
         return self._allowTreatNonCallableAsNull
 
     def canHaveMissingValue(self):
         return False
@@ -11314,17 +11308,16 @@ class CGProxySpecialOperation(CGPerSigna
                                     len(arguments), resultVar=resultVar,
                                     objectName="proxy")
 
         if operation.isSetter():
             # arguments[0] is the index or name of the item that we're setting.
             argument = arguments[1]
             info = getJSToNativeConversionInfo(
                 argument.type, descriptor,
-                treatNullAs=argument.treatNullAs,
                 sourceDescription=("value being assigned to %s setter" %
                                    descriptor.interface.identifier.name))
             if argumentHandleValue is None:
                 argumentHandleValue = "desc.value()"
             rootedValue = fill(
                 """
                 JS::Rooted<JS::Value> rootedValue(cx, ${argumentHandleValue});
                 """,
@@ -16362,17 +16355,16 @@ class CGCallbackInterface(CGCallback):
             methods.append(initIdsClassMethod(idlist,
                                               iface.identifier.name + "Atoms"))
         CGCallback.__init__(self, iface, descriptor, "CallbackInterface",
                             methods, getters=getters, setters=setters)
 
 
 class FakeMember():
     def __init__(self, name=None):
-        self.treatNullAs = "Default"
         if name is not None:
             self.identifier = FakeIdentifier(name)
 
     def isStatic(self):
         return False
 
     def isAttr(self):
         return False
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -6,27 +6,27 @@ import sys
 import string
 import argparse
 import runpy
 
 # Generates a line of WebIDL with the given spelling of the property name
 # (whether camelCase, _underscorePrefixed, etc.) and the given array of
 # extended attributes.
 def generateLine(propName, extendedAttrs):
-    return "  [%s] attribute DOMString %s;\n" % (", ".join(extendedAttrs),
+    return "  [%s] attribute [TreatNullAs=EmptyString] DOMString %s;\n" % (", ".join(extendedAttrs),
                                                  propName)
 def generate(output, idlFilename, dataFile):
     propList = runpy.run_path(dataFile)["data"]
     props = ""
     for p in propList:
         if "Internal" in p.flags:
             continue
         # Unfortunately, even some of the getters here are fallible
         # (e.g. on nsComputedDOMStyle).
-        extendedAttrs = ["CEReactions", "Throws", "TreatNullAs=EmptyString",
+        extendedAttrs = ["CEReactions", "Throws",
                          "SetterNeedsSubjectPrincipal=NonSystem"]
         if p.pref is not "":
             extendedAttrs.append('Pref="%s"' % p.pref)
 
         prop = p.method
 
         # webkit properties get a camelcase "webkitFoo" accessor
         # as well as a capitalized "WebkitFoo" alias (added here).
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -415,58 +415,21 @@ class IDLObjectWithIdentifier(IDLObject)
 
         assert isinstance(identifier, IDLUnresolvedIdentifier)
 
         self.identifier = identifier
 
         if parentScope:
             self.resolve(parentScope)
 
-        self.treatNullAs = "Default"
-
     def resolve(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         assert isinstance(self.identifier, IDLUnresolvedIdentifier)
         self.identifier.resolve(parentScope, self)
 
-    def checkForStringHandlingExtendedAttributes(self, attrs,
-                                                 isDictionaryMember=False,
-                                                 isOptional=False):
-        """
-        A helper function to deal with TreatNullAs.  Returns the list
-        of attrs it didn't handle itself.
-        """
-        assert isinstance(self, IDLArgument) or isinstance(self, IDLAttribute)
-        unhandledAttrs = list()
-        for attr in attrs:
-            if not attr.hasValue():
-                unhandledAttrs.append(attr)
-                continue
-
-            identifier = attr.identifier()
-            value = attr.value()
-            if identifier == "TreatNullAs":
-                if not self.type.isDOMString() or self.type.nullable():
-                    raise WebIDLError("[TreatNullAs] is only allowed on "
-                                      "arguments or attributes whose type is "
-                                      "DOMString",
-                                      [self.location])
-                if isDictionaryMember:
-                    raise WebIDLError("[TreatNullAs] is not allowed for "
-                                      "dictionary members", [self.location])
-                if value != 'EmptyString':
-                    raise WebIDLError("[TreatNullAs] must take the identifier "
-                                      "'EmptyString', not '%s'" % value,
-                                      [self.location])
-                self.treatNullAs = value
-            else:
-                unhandledAttrs.append(attr)
-
-        return unhandledAttrs
-
 
 class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
     def __init__(self, location, parentScope, identifier):
         assert isinstance(identifier, IDLUnresolvedIdentifier)
 
         IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier)
         IDLScope.__init__(self, location, parentScope, self.identifier)
 
@@ -3556,16 +3519,20 @@ class IDLValue(IDLObject):
             return IDLValue(self.location, type, self.value)
         elif self.type.isString() and type.isUSVString():
             # Allow USVStrings to use default value just like
             # DOMString.  No coercion is required in this case as Codegen.py
             # treats USVString just like DOMString, but with an
             # extra normalization step.
             assert self.type.isDOMString()
             return self
+        elif self.type.isDOMString() and type.treatNullAsEmpty:
+            # TreatNullAsEmpty is a different type for resolution reasons,
+            # however once you have a value it doesn't matter
+            return self
         elif self.type.isString() and type.isByteString():
             # Allow ByteStrings to use a default value like DOMString.
             # No coercion is required as Codegen.py will handle the
             # extra steps. We want to make sure that our string contains
             # only valid characters, so we check that here.
             valid_ascii_lit = " " + string.ascii_letters + string.digits + string.punctuation
             for idx, c in enumerate(self.value):
                 if c not in valid_ascii_lit:
@@ -4233,17 +4200,17 @@ class IDLAttribute(IDLInterfaceMember):
         if not self.type.isComplete():
             t = self.type.complete(scope)
 
             assert not isinstance(t, IDLUnresolvedType)
             assert not isinstance(t, IDLTypedefType)
             assert not isinstance(t.name, IDLUnresolvedIdentifier)
             self.type = t
 
-        if self.readonly and (self.type.clamp or self.type.enforceRange):
+        if self.readonly and (self.type.clamp or self.type.enforceRange or self.type.treatNullAsEmpty):
             raise WebIDLError("A readonly attribute cannot be [Clamp] or [EnforceRange]",
                               [self.location])
         if self.type.isDictionary() and not self.getExtendedAttribute("Cached"):
             raise WebIDLError("An attribute cannot be of a dictionary type",
                               [self.location])
         if self.type.isSequence() and not self.getExtendedAttribute("Cached"):
             raise WebIDLError("A non-cached attribute cannot be of a sequence "
                               "type", [self.location])
@@ -4560,20 +4527,16 @@ class IDLAttribute(IDLInterfaceMember):
                               [attr.location])
         IDLInterfaceMember.handleExtendedAttribute(self, attr)
 
     def resolve(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         self.type.resolveType(parentScope)
         IDLObjectWithIdentifier.resolve(self, parentScope)
 
-    def addExtendedAttributes(self, attrs):
-        attrs = self.checkForStringHandlingExtendedAttributes(attrs)
-        IDLInterfaceMember.addExtendedAttributes(self, attrs)
-
     def hasLenientThis(self):
         return self.lenientThis
 
     def isMaplikeOrSetlikeAttr(self):
         """
         True if this attribute was generated from an interface with
         maplike/setlike (e.g. this is the size attribute for
         maplike/setlike)
@@ -4602,23 +4565,20 @@ class IDLArgument(IDLObjectWithIdentifie
         self._allowTreatNonCallableAsNull = False
         self._extendedAttrDict = {}
         self.allowTypeAttributes = allowTypeAttributes
 
         assert not variadic or optional
         assert not variadic or not defaultValue
 
     def addExtendedAttributes(self, attrs):
-        attrs = self.checkForStringHandlingExtendedAttributes(
-            attrs,
-            isDictionaryMember=self.dictionaryMember,
-            isOptional=self.optional)
         for attribute in attrs:
             identifier = attribute.identifier()
-            if self.allowTypeAttributes and (identifier == "EnforceRange" or identifier == "Clamp"):
+            if self.allowTypeAttributes and (identifier == "EnforceRange" or identifier == "Clamp" or
+                                             identifier == "TreatNullAs"):
                 self.type = self.type.withExtendedAttributes([attribute])
             elif identifier == "TreatNonCallableAsNull":
                 self._allowTreatNonCallableAsNull = True
             elif (self.dictionaryMember and
                   (identifier == "ChromeOnly" or identifier == "Func")):
                 if not self.optional:
                     raise WebIDLError("[%s] must not be used on a required "
                                       "dictionary member" % identifier,
@@ -4661,16 +4621,18 @@ class IDLArgument(IDLObjectWithIdentifie
             assert (self.defaultValue is None or
                     isinstance(self.defaultValue, IDLNullValue))
             # optional 'any' values always have a default value
             if self.optional and not self.defaultValue and not self.variadic:
                 # Set the default value to undefined, for simplicity, so the
                 # codegen doesn't have to special-case this.
                 self.defaultValue = IDLUndefinedValue(self.location)
 
+        if self.dictionaryMember and self.type.treatNullAsEmpty:
+            raise WebIDLError("Dictionary members cannot be [TreatNullAs]", [self.location])
         # Now do the coercing thing; this needs to happen after the
         # above creation of a default value.
         if self.defaultValue:
             self.defaultValue = self.defaultValue.coerceToType(self.type,
                                                                self.location)
             assert self.defaultValue
 
     def allowTreatNonCallableAsNull(self):
--- a/dom/chrome-webidl/InspectorUtils.webidl
+++ b/dom/chrome-webidl/InspectorUtils.webidl
@@ -10,31 +10,31 @@
  * See InspectorUtils.h for documentation on these methods.
  */
 [Func="nsContentUtils::IsCallerChromeOrFuzzingEnabled"]
 namespace InspectorUtils {
   // documentOnly tells whether user and UA sheets should get included.
   sequence<StyleSheet> getAllStyleSheets(Document document, optional boolean documentOnly = false);
   sequence<CSSStyleRule> getCSSStyleRules(
     Element element,
-    [TreatNullAs=EmptyString] optional DOMString pseudo = "");
+    optional [TreatNullAs=EmptyString] DOMString pseudo = "");
   unsigned long getRuleLine(CSSRule rule);
   unsigned long getRuleColumn(CSSRule rule);
   unsigned long getRelativeRuleLine(CSSRule rule);
   boolean hasRulesModifiedByCSSOM(CSSStyleSheet sheet);
   unsigned long getSelectorCount(CSSStyleRule rule);
   [Throws] DOMString getSelectorText(CSSStyleRule rule,
                                      unsigned long selectorIndex);
   [Throws] unsigned long long getSpecificity(CSSStyleRule rule,
                                              unsigned long selectorIndex);
   [Throws] boolean selectorMatchesElement(
       Element element,
       CSSStyleRule rule,
       unsigned long selectorIndex,
-      [TreatNullAs=EmptyString] optional DOMString pseudo = "");
+      optional [TreatNullAs=EmptyString] DOMString pseudo = "");
   boolean isInheritedProperty(DOMString property);
   sequence<DOMString> getCSSPropertyNames(optional PropertyNamesOptions options);
   sequence<PropertyPref> getCSSPropertyPrefs();
   [Throws] sequence<DOMString> getCSSValuesForProperty(DOMString property);
   [Throws] DOMString rgbToColorName(octet r, octet g, octet b);
   InspectorRGBATuple? colorToRGBA(DOMString colorString);
   boolean isValidCSSColor(DOMString colorString);
   [Throws] sequence<DOMString> getSubpropertiesForCSSProperty(DOMString property);
--- a/dom/imptests/html/dom/test_interfaces.html
+++ b/dom/imptests/html/dom/test_interfaces.html
@@ -272,17 +272,17 @@ interface Attr {
            attribute DOMString value;
 
   readonly attribute DOMString name;
   readonly attribute DOMString? namespaceURI;
   readonly attribute DOMString? prefix;
 };
 
 interface CharacterData : Node {
-  [TreatNullAs=EmptyString] attribute DOMString data;
+  attribute [TreatNullAs=EmptyString] DOMString data;
   readonly attribute unsigned long length;
   DOMString substringData(unsigned long offset, unsigned long count);
   void appendData(DOMString data);
   void insertData(unsigned long offset, DOMString data);
   void deleteData(unsigned long offset, unsigned long count);
   void replaceData(unsigned long offset, unsigned long count, DOMString data);
 };
 
--- a/dom/webidl/CSSStyleDeclaration.webidl
+++ b/dom/webidl/CSSStyleDeclaration.webidl
@@ -19,14 +19,14 @@ interface CSSStyleDeclaration {
 
   [Throws, ChromeOnly]
   sequence<DOMString> getCSSImageURLs(DOMString property);
 
   [Throws]
   DOMString getPropertyValue(DOMString property);
   DOMString getPropertyPriority(DOMString property);
   [CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
-  void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = "");
+  void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, optional [TreatNullAs=EmptyString] DOMString priority = "");
   [CEReactions, Throws]
   DOMString removeProperty(DOMString property);
 
   readonly attribute CSSRule? parentRule;
 };
--- a/dom/webidl/CharacterData.webidl
+++ b/dom/webidl/CharacterData.webidl
@@ -6,18 +6,18 @@
  * The origin of this IDL file is
  * http://dom.spec.whatwg.org/#characterdata
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 interface CharacterData : Node {
-  [TreatNullAs=EmptyString, Pure, SetterThrows]
-  attribute DOMString data;
+  [Pure, SetterThrows]
+  attribute [TreatNullAs=EmptyString] DOMString data;
   [Pure]
   readonly attribute unsigned long length;
   [Throws]
   DOMString substringData(unsigned long offset, unsigned long count);
   [Throws]
   void appendData(DOMString data);
   [Throws]
   void insertData(unsigned long offset, DOMString data);
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -199,20 +199,20 @@ partial interface Element {
   [ChromeOnly] readonly attribute long scrollTopMin;
                readonly attribute long scrollTopMax;
   [ChromeOnly] readonly attribute long scrollLeftMin;
                readonly attribute long scrollLeftMax;
 };
 
 // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
 partial interface Element {
-  [CEReactions, SetterNeedsSubjectPrincipal=NonSystem, Pure, SetterThrows, GetterCanOOM, TreatNullAs=EmptyString]
-  attribute DOMString innerHTML;
-  [CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString]
-  attribute DOMString outerHTML;
+  [CEReactions, SetterNeedsSubjectPrincipal=NonSystem, Pure, SetterThrows, GetterCanOOM]
+  attribute [TreatNullAs=EmptyString] DOMString innerHTML;
+  [CEReactions, Pure, SetterThrows]
+  attribute [TreatNullAs=EmptyString] DOMString outerHTML;
   [CEReactions, Throws]
   void insertAdjacentHTML(DOMString position, DOMString text);
 };
 
 // http://www.w3.org/TR/selectors-api/#interface-definitions
 partial interface Element {
   [Throws, Pure]
   Element?  querySelector(DOMString selectors);
--- a/dom/webidl/HTMLDocument.webidl
+++ b/dom/webidl/HTMLDocument.webidl
@@ -37,21 +37,21 @@ interface HTMLDocument : Document {
   boolean queryCommandIndeterm(DOMString commandId);
   [Throws]
   boolean queryCommandState(DOMString commandId);
   [NeedsCallerType]
   boolean queryCommandSupported(DOMString commandId);
   [Throws]
   DOMString queryCommandValue(DOMString commandId);
 
-  [CEReactions, TreatNullAs=EmptyString] attribute DOMString fgColor;
-  [CEReactions, TreatNullAs=EmptyString] attribute DOMString linkColor;
-  [CEReactions, TreatNullAs=EmptyString] attribute DOMString vlinkColor;
-  [CEReactions, TreatNullAs=EmptyString] attribute DOMString alinkColor;
-  [CEReactions, TreatNullAs=EmptyString] attribute DOMString bgColor;
+  [CEReactions] attribute [TreatNullAs=EmptyString] DOMString fgColor;
+  [CEReactions] attribute [TreatNullAs=EmptyString] DOMString linkColor;
+  [CEReactions] attribute [TreatNullAs=EmptyString] DOMString vlinkColor;
+  [CEReactions] attribute [TreatNullAs=EmptyString] DOMString alinkColor;
+  [CEReactions] attribute [TreatNullAs=EmptyString] DOMString bgColor;
 
   void clear();
 
   readonly attribute HTMLAllCollection all;
 
   // @deprecated These are old Netscape 4 methods. Do not use,
   //             the implementation is no-op.
   // XXXbz do we actually need these anymore?
--- a/dom/webidl/HTMLFontElement.webidl
+++ b/dom/webidl/HTMLFontElement.webidl
@@ -8,12 +8,12 @@
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 [HTMLConstructor]
 interface HTMLFontElement : HTMLElement {
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows] attribute DOMString color;
+  [CEReactions, SetterThrows] attribute [TreatNullAs=EmptyString] DOMString color;
   [CEReactions, SetterThrows]                          attribute DOMString face;
   [CEReactions, SetterThrows]                          attribute DOMString size;
 };
--- a/dom/webidl/HTMLFrameElement.webidl
+++ b/dom/webidl/HTMLFrameElement.webidl
@@ -24,15 +24,15 @@ interface HTMLFrameElement : HTMLElement
            [CEReactions, SetterThrows]
            attribute DOMString longDesc;
            [CEReactions, SetterThrows]
            attribute boolean noResize;
   [NeedsSubjectPrincipal]
   readonly attribute Document? contentDocument;
   readonly attribute WindowProxy? contentWindow;
 
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-  attribute DOMString marginHeight;
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-  attribute DOMString marginWidth;
+  [CEReactions, SetterThrows]
+  attribute [TreatNullAs=EmptyString] DOMString marginHeight;
+  [CEReactions, SetterThrows]
+  attribute [TreatNullAs=EmptyString] DOMString marginWidth;
 };
 
 HTMLFrameElement implements MozFrameLoaderOwner;
--- a/dom/webidl/HTMLIFrameElement.webidl
+++ b/dom/webidl/HTMLIFrameElement.webidl
@@ -44,20 +44,20 @@ partial interface HTMLIFrameElement {
            attribute DOMString align;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString scrolling;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString frameBorder;
   [CEReactions, SetterThrows, Pure]
            attribute DOMString longDesc;
 
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows, Pure]
-           attribute DOMString marginHeight;
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows, Pure]
-           attribute DOMString marginWidth;
+  [CEReactions, SetterThrows, Pure]
+           attribute [TreatNullAs=EmptyString] DOMString marginHeight;
+  [CEReactions, SetterThrows, Pure]
+           attribute [TreatNullAs=EmptyString] DOMString marginWidth;
 };
 
 partial interface HTMLIFrameElement {
   // GetSVGDocument
   [NeedsSubjectPrincipal]
   Document? getSVGDocument();
 };
 
--- a/dom/webidl/HTMLImageElement.webidl
+++ b/dom/webidl/HTMLImageElement.webidl
@@ -52,17 +52,17 @@ partial interface HTMLImageElement {
            attribute DOMString align;
            [CEReactions, SetterThrows]
            attribute unsigned long hspace;
            [CEReactions, SetterThrows]
            attribute unsigned long vspace;
            [CEReactions, SetterThrows]
            attribute DOMString longDesc;
 
-  [CEReactions, TreatNullAs=EmptyString,SetterThrows] attribute DOMString border;
+  [CEReactions, SetterThrows] attribute [TreatNullAs=EmptyString] DOMString border;
 };
 
 // [Update me: not in whatwg spec yet]
 // http://picture.responsiveimages.org/#the-img-element
 partial interface HTMLImageElement {
            [CEReactions, SetterThrows]
            attribute DOMString sizes;
   readonly attribute DOMString currentSrc;
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -63,18 +63,18 @@ partial interface HTMLObjectElement {
            attribute DOMString standby;
   [CEReactions, Pure, SetterThrows]
            attribute unsigned long vspace;
   [CEReactions, Pure, SetterThrows]
            attribute DOMString codeBase;
   [CEReactions, Pure, SetterThrows]
            attribute DOMString codeType;
 
-  [CEReactions, TreatNullAs=EmptyString, Pure, SetterThrows]
-           attribute DOMString border;
+  [CEReactions, Pure, SetterThrows]
+           attribute [TreatNullAs=EmptyString] DOMString border;
 };
 
 partial interface HTMLObjectElement {
   // GetSVGDocument
   [NeedsSubjectPrincipal]
   Document? getSVGDocument();
 };
 
--- a/dom/webidl/HTMLTableCellElement.webidl
+++ b/dom/webidl/HTMLTableCellElement.webidl
@@ -43,11 +43,11 @@ partial interface HTMLTableCellElement {
            attribute DOMString ch;
            [CEReactions, SetterThrows]
            attribute DOMString chOff;
            [CEReactions, SetterThrows]
            attribute boolean noWrap;
            [CEReactions, SetterThrows]
            attribute DOMString vAlign;
 
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-           attribute DOMString bgColor;
+           [CEReactions, SetterThrows]
+           attribute [TreatNullAs=EmptyString] DOMString bgColor;
 };
--- a/dom/webidl/HTMLTableElement.webidl
+++ b/dom/webidl/HTMLTableElement.webidl
@@ -48,15 +48,15 @@ partial interface HTMLTableElement {
            attribute DOMString frame;
            [CEReactions, SetterThrows]
            attribute DOMString rules;
            [CEReactions, SetterThrows]
            attribute DOMString summary;
            [CEReactions, SetterThrows]
            attribute DOMString width;
 
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-           attribute DOMString bgColor;
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-           attribute DOMString cellPadding;
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-           attribute DOMString cellSpacing;
+  [CEReactions, SetterThrows]
+           attribute [TreatNullAs=EmptyString] DOMString bgColor;
+  [CEReactions, SetterThrows]
+           attribute [TreatNullAs=EmptyString] DOMString cellPadding;
+  [CEReactions, SetterThrows]
+           attribute [TreatNullAs=EmptyString] DOMString cellSpacing;
 };
--- a/dom/webidl/HTMLTableRowElement.webidl
+++ b/dom/webidl/HTMLTableRowElement.webidl
@@ -27,11 +27,11 @@ partial interface HTMLTableRowElement {
            attribute DOMString align;
            [CEReactions, SetterThrows]
            attribute DOMString ch;
            [CEReactions, SetterThrows]
            attribute DOMString chOff;
            [CEReactions, SetterThrows]
            attribute DOMString vAlign;
 
-  [CEReactions, TreatNullAs=EmptyString, SetterThrows]
-           attribute DOMString bgColor;
+  [CEReactions, SetterThrows]
+           attribute [TreatNullAs=EmptyString] DOMString bgColor;
 };
--- a/dom/webidl/MediaList.webidl
+++ b/dom/webidl/MediaList.webidl
@@ -8,18 +8,17 @@
 interface MediaList {
   // Bug 824857: no support for stringifier attributes yet.
   //   [TreatNullAs=EmptyString]
   // stringifier attribute DOMString        mediaText;
 
   // Bug 824857 should remove this.
   stringifier;
 
-  [TreatNullAs=EmptyString]
-           attribute DOMString        mediaText;
+           attribute [TreatNullAs=EmptyString] DOMString        mediaText;
 
   readonly attribute unsigned long    length;
   getter DOMString?  item(unsigned long index);
   [Throws]
   void               deleteMedium(DOMString oldMedium);
   [Throws]
   void               appendMedium(DOMString newMedium);
 };
--- a/dom/webidl/ShadowRoot.webidl
+++ b/dom/webidl/ShadowRoot.webidl
@@ -23,18 +23,18 @@ interface ShadowRoot : DocumentFragment
   readonly attribute ShadowRootMode mode;
   readonly attribute Element host;
 
   // [deprecated] Shadow DOM v0
   Element? getElementById(DOMString elementId);
   HTMLCollection getElementsByTagName(DOMString localName);
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);
-  [CEReactions, SetterThrows, TreatNullAs=EmptyString]
-  attribute DOMString innerHTML;
+  [CEReactions, SetterThrows]
+  attribute [TreatNullAs=EmptyString] DOMString innerHTML;
 
   // When JS invokes importNode or createElement, the binding code needs to
   // create a reflector, and so invoking those methods directly on the content
   // document would cause the reflector to be created in the content scope,
   // at which point it would be difficult to move into the UA Widget scope.
   // As such, these methods allow UA widget code to simultaneously create nodes
   // and associate them with the UA widget tree, so that the reflectors get
   // created in the right scope.
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -58,17 +58,17 @@ typedef OfflineResourceList ApplicationC
   [Replaceable, CrossOriginReadable] readonly attribute unsigned long length;
   //[Unforgeable, Throws, CrossOriginReadable] readonly attribute WindowProxy top;
   [Unforgeable, Throws, CrossOriginReadable] readonly attribute WindowProxy? top;
   [Throws, CrossOriginReadable] attribute any opener;
   //[Throws] readonly attribute WindowProxy parent;
   [Replaceable, Throws, CrossOriginReadable] readonly attribute WindowProxy? parent;
   [Throws, NeedsSubjectPrincipal] readonly attribute Element? frameElement;
   //[Throws] WindowProxy? open(optional USVString url = "about:blank", optional DOMString target = "_blank", [TreatNullAs=EmptyString] optional DOMString features = "");
-  [Throws] WindowProxy? open(optional DOMString url = "", optional DOMString target = "", [TreatNullAs=EmptyString] optional DOMString features = "");
+  [Throws] WindowProxy? open(optional DOMString url = "", optional DOMString target = "", optional [TreatNullAs=EmptyString] DOMString features = "");
   getter object (DOMString name);
 
   // the user agent
   readonly attribute Navigator navigator;
 #ifdef HAVE_SIDEBAR
   [Replaceable, Throws] readonly attribute External external;
 #endif
   [Throws, Pref="browser.cache.offline.enable", Func="nsGlobalWindowInner::OfflineCacheAllowedForContext"] readonly attribute ApplicationCache applicationCache;