Bug 780970 - Add [infallible] attribute for XPIDL attributes. r=khuey
authorJustin Lebar <justin.lebar@gmail.com>
Wed, 22 Aug 2012 18:27:04 -0700
changeset 105137 6c7efe05324138b63abb38ed31f32d1000312026
parent 105136 08f91bc1bd99976883cd79c8be9fe68edc660287
child 105138 bd0bf4b676dabbe74111442391e93ea21d641279
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewerskhuey
bugs780970
milestone17.0a1
Bug 780970 - Add [infallible] attribute for XPIDL attributes. r=khuey
xpcom/idl-parser/header.py
xpcom/idl-parser/xpidl.py
--- a/xpcom/idl-parser/header.py
+++ b/xpcom/idl-parser/header.py
@@ -133,16 +133,21 @@ include = """
 #include "%(basename)s.h"
 #endif
 """
 
 jspubtd_include = """
 #include "jspubtd.h"
 """
 
+infallible_includes = """
+#include "mozilla/Assertions.h"
+#include "mozilla/Util.h"
+"""
+
 header_end = """/* For IDL files that don't want to include root IDL files. */
 #ifndef NS_NO_VTABLE
 #define NS_NO_VTABLE
 #endif
 """
 
 footer = """
 #endif /* __gen_%(basename)s_h__ */
@@ -165,16 +170,23 @@ def print_header(idl, fd, filename):
         if not foundinc:
             foundinc = True
             fd.write('\n')
         fd.write(include % {'basename': idl_basename(inc.filename)})
 
     if idl.needsJSTypes():
         fd.write(jspubtd_include)
 
+    # Include some extra files if any attributes are infallible.
+    for iface in [p for p in idl.productions if p.kind == 'interface']:
+        for attr in [m for m in iface.members if isinstance(m, xpidl.Attribute)]:
+            if attr.infallible:
+                fd.write(infallible_includes)
+                break
+
     fd.write('\n')
     fd.write(header_end)
 
     for p in idl.productions:
         if p.kind == 'include': continue
         if p.kind == 'cdata':
             fd.write(p.data)
             continue
@@ -275,16 +287,26 @@ example_tmpl = """%(returntype)s %(implc
 }
 """
 
 iface_template_epilog = """/* End of implementation class template. */
 #endif
 
 """
 
+attr_infallible_tmpl = """\
+  inline %(realtype)s%(nativename)s(%(args)s)
+  {
+    %(realtype)sresult;
+    mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    return result;
+  }
+"""
+
 def write_interface(iface, fd):
     if iface.namemap is None:
         raise Exception("Interface was not resolved.")
 
     def write_const_decls(g):
         fd.write("  enum {\n")
         enums = []
         for c in g:
@@ -305,16 +327,23 @@ def write_interface(iface, fd):
         fd.write("  %s = 0;\n\n" % methodAsNative(m))
                                                                            
     def write_attr_decl(a):
         printComments(fd, a.doccomments, '  ')
 
         fd.write("  /* %s */\n" % a.toIDL());
 
         fd.write("  %s = 0;\n" % attributeAsNative(a, True))
+        if a.infallible:
+            fd.write(attr_infallible_tmpl %
+                     {'realtype': a.realtype.nativeType('in'),
+                      'nativename': attributeNativeName(a, getter=True),
+                      'args': '' if not a.implicit_jscontext else 'JSContext* cx',
+                      'argnames': '' if not a.implicit_jscontext else 'cx, '})
+
         if not a.readonly:
             fd.write("  %s = 0;\n" % attributeAsNative(a, False))
         fd.write("\n")
 
     defname = iface.name.upper()
     if iface.name[0:2] == 'ns':
         defname = 'NS_' + defname[2:]
 
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -710,16 +710,17 @@ class Attribute(object):
     readonly = False
     implicit_jscontext = False
     nostdcall = False
     binaryname = None
     null = None
     undefined = None
     deprecated = False
     nullable = False
+    infallible = False
     defvalue = None
 
     def __init__(self, type, name, attlist, readonly, nullable, defvalue, location, doccomments):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.readonly = readonly
         self.nullable = nullable
@@ -765,16 +766,18 @@ class Attribute(object):
                 elif name == 'notxpcom':
                     self.notxpcom = True
                 elif name == 'implicit_jscontext':
                     self.implicit_jscontext = True
                 elif name == 'deprecated':
                     self.deprecated = True
                 elif name == 'nostdcall':
                     self.nostdcall = True
+                elif name == 'infallible':
+                    self.infallible = True
                 else:
                     raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = iface.idl.getName(self.type, self.location)
         if (self.null is not None and
             getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
@@ -783,16 +786,25 @@ class Attribute(object):
         if (self.undefined is not None and
             getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Undefined' attribute can only be used on DOMString",
                            self.location)
         if (self.nullable and
             getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("Nullable types (T?) is supported only for DOMString",
                            self.location)
+        if self.infallible and not self.realtype.kind == 'builtin':
+            raise IDLError('[infallible] only works on builtin types '
+                           '(numbers, bool, and raw char types)',
+                           self.location)
+        if self.infallible and not iface.attributes.builtinclass:
+            raise IDLError('[infallible] attributes are only allowed on '
+                           '[builtinclass] interfaces',
+                           self.location)
+
 
     def toIDL(self):
         attribs = attlistToIDL(self.attlist)
         readonly = self.readonly and 'readonly ' or ''
         return "%s%sattribute %s %s;" % (attribs, readonly, self.type, self.name)
         
     def isScriptable(self):
         if not self.iface.attributes.scriptable: return False