commit 25f0d6399a01169608e35e38a820428706d63eec
Author: Colin Walters <walters@verbum.org>
Date:   Sun Nov 16 16:22:53 2008 -0500

    Parse static methods

diff --git a/docs/typelib-format.txt b/docs/typelib-format.txt
index fa76393..71ff8d5 100644
--- a/docs/typelib-format.txt
+++ b/docs/typelib-format.txt
@@ -302,7 +302,7 @@ arguments:
           An array of ArgBlob for the arguments of the function.
 
 
-FunctionBlob (16 bytes)
+FunctionBlob (20 bytes)
 
 struct FunctionBlob 
 {
@@ -313,12 +313,14 @@ struct FunctionBlob
   guint   is_getter      : 1;
   guint   is_constructor : 1;
   guint   wraps_vfunc    : 1;
-  guint   reserved       : 1;
+  guint   throws         : 1;
   guint   index          :10;
 
   guint32 name;
   guint32 c_name;
   guint32 signature;
+  guint   is_static      : 1;
+  guint   reserved       : 31;
 }
 
 c_name:   The symbol which can be used to obtain the function pointer with 
@@ -352,6 +354,10 @@ signature:
           Offset of the SignatureBlob describing the parameter types and the 
           return value type.
 
+is_static
+          The function is a "static method"; in other words it's a pure
+	  function whose name is conceptually scoped to the object.
+
 
 CallbackBlob (12 bytes)
 
diff --git a/girepository/ginfo.c b/girepository/ginfo.c
index a3813d6..a66a4e0 100644
--- a/girepository/ginfo.c
+++ b/girepository/ginfo.c
@@ -478,7 +478,7 @@ g_function_info_get_flags (GIFunctionInfo *info)
   flags = 0;
 
   /* Make sure we don't flag Constructors as methods */
-  if (base->container != NULL && !blob->constructor)
+  if (!blob->constructor && !blob->is_static)
     flags = flags | GI_FUNCTION_IS_METHOD;
     
   if (blob->constructor)
diff --git a/girepository/girmodule.c b/girepository/girmodule.c
index 1b26f3d..be41a1e 100644
--- a/girepository/girmodule.c
+++ b/girepository/girmodule.c
@@ -209,7 +209,7 @@ g_ir_module_build_typelib (GIrModule  *module,
                              : 0);
   header->directory = ALIGN_VALUE (header_size, 4);
   header->entry_blob_size = 12;
-  header->function_blob_size = 16;
+  header->function_blob_size = sizeof (FunctionBlob);
   header->callback_blob_size = 12;
   header->signal_blob_size = 12;
   header->vfunc_blob_size = 16;
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 9c5cf5b..04a36e5 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -415,7 +415,7 @@ g_ir_node_get_size (GIrNode *node)
       break;
 
     case G_IR_NODE_FUNCTION:
-      size = 16; 
+      size = sizeof (FunctionBlob);
       break;
 
     case G_IR_NODE_PARAM:
@@ -1576,11 +1576,12 @@ g_ir_node_build_typelib (GIrNode    *node,
 	signature = *offset2;
 	n = g_list_length (function->parameters);
 
-	*offset += 16;
+	*offset += sizeof (FunctionBlob);
 	*offset2 += 8 + n * 12;
 
 	blob->blob_type = BLOB_TYPE_FUNCTION;
 	blob->deprecated = function->deprecated;
+	blob->is_static = !function->is_method;
 	blob->setter = function->is_setter;
 	blob->getter = function->is_getter;
 	blob->constructor = function->is_constructor;
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 48e3119..e6d59b4 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -674,10 +674,12 @@ start_function (GMarkupParseContext *context,
 	       strcmp (element_name, "callback") == 0);
       break;
     case STATE_CLASS:
+      found = strcmp (element_name, "function") == 0;
+	/* fallthrough */
     case STATE_BOXED:
     case STATE_STRUCT:
     case STATE_UNION:
-      found = strcmp (element_name, "constructor") == 0;
+      found = (found || strcmp (element_name, "constructor") == 0);
       /* fallthrough */
     case STATE_INTERFACE:
       found = (found ||
diff --git a/girepository/gtypelib.c b/girepository/gtypelib.c
index 8472195..3cf73ec 100644
--- a/girepository/gtypelib.c
+++ b/girepository/gtypelib.c
@@ -159,7 +159,7 @@ g_typelib_check_sanity (void)
   CHECK_SIZE (ArgBlob, 12);
   CHECK_SIZE (SignatureBlob, 8);
   CHECK_SIZE (CommonBlob, 8);
-  CHECK_SIZE (FunctionBlob, 16);
+  CHECK_SIZE (FunctionBlob, 20);
   CHECK_SIZE (InterfaceTypeBlob, 4);
   CHECK_SIZE (ArrayTypeBlob, 8);
   CHECK_SIZE (ParamTypeBlob, 4);
@@ -307,7 +307,7 @@ validate_header (ValidateContext  *ctx,
     }
 
   if (header->entry_blob_size != 12 ||
-      header->function_blob_size != 16 ||
+      header->function_blob_size != 20 ||
       header->callback_blob_size != 12 ||
       header->signal_blob_size != 12 ||
       header->vfunc_blob_size != 16 ||
@@ -723,7 +723,7 @@ validate_function_blob (ValidateContext *ctx,
       g_set_error (error,
 		   G_TYPELIB_ERROR,
 		   G_TYPELIB_ERROR_INVALID_BLOB,
-		   "Wrong blob type");
+		   "Wrong blob type %d, expected function", blob->blob_type);
       return FALSE;
     }
 
diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h
index 1b2b893..2cc304f 100644
--- a/girepository/gtypelib.h
+++ b/girepository/gtypelib.h
@@ -172,10 +172,17 @@ typedef struct
   guint16 wraps_vfunc : 1;
   guint16 throws      : 1;
   guint16 index       :10;
+  /* Note the bits above need to match CommonBlob
+   * and are thus exhausted, extend things using
+   * the reserved block below. */
 
   guint32 name;
   guint32 symbol;
   guint32 signature;
+
+  guint16 is_static   : 1;
+  guint16 reserved    : 15;
+  guint16 reserved2   : 16;
 } FunctionBlob;
 
 typedef struct 
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 41587bc..1a90911 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -366,6 +366,7 @@ class Class(Node):
         self.parent = parent
         self.is_abstract = is_abstract
         self.methods = []
+        self.static_methods = []
         self.interfaces = []
         self.constructors = []
         self.properties = []
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index a5c50d9..23d3a92 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -121,6 +121,9 @@ class GIRWriter(XMLWriter):
     def _write_method(self, method):
         self._write_function(method, tag_name='method')
 
+    def _write_static_method(self, method):
+        self._write_function(method, tag_name='function')
+
     def _write_constructor(self, method):
         self._write_function(method, tag_name='constructor')
 
@@ -260,6 +263,8 @@ class GIRWriter(XMLWriter):
             if isinstance(node, Class):
                 for method in node.constructors:
                     self._write_constructor(method)
+                for method in node.static_methods:
+                    self._write_static_method(method)
             for method in node.methods:
                 self._write_method(method)
             for prop in node.properties:
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 2edab36..088c163 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -328,6 +328,27 @@ class GLibTransformer(object):
         except KeyError, e:
             return False
 
+    def _parse_static_method(self, func):
+        components = func.symbol.split('_')
+        if len(components) < 2:
+            return None
+        target_klass = None
+        prefix_components = None
+        methname = None
+        for i in xrange(1, len(components)-1):
+            prefix_components = '_'.join(components[0:-i])
+            methname = '_'.join(components[-i:])
+            target_klass = self._uscore_type_names.get(prefix_components)
+            if target_klass and isinstance(target_klass, GLibObject):
+                break
+            target_klass = None
+        if not target_klass:
+            return None
+        self._remove_attribute(func.name)
+        func.name = methname
+        target_klass.static_methods.append(func)
+        return func
+
     def _parse_method(self, func):
         if not func.parameters:
             return False
@@ -377,19 +398,6 @@ class GLibTransformer(object):
                 return None
             prefix = func.symbol[:new_idx]
 
-        klass = None
-
-        def valid_matching_klass(tclass):
-            if tclass is None:
-                return False
-            elif isinstance(klass, (GLibEnum, GLibFlags)):
-                return False
-            elif not isinstance(tclass, (GLibObject, GLibBoxed,
-                                          GLibInterface)):
-                return False
-            else:
-                return True
-
         klass = self._uscore_type_names.get(prefix)
         if klass is None:
             #print "NOTE: No valid matching class for likely "+\
@@ -675,13 +683,14 @@ class GLibTransformer(object):
             self._resolve_alias(node)
 
     def _resolve_function_toplevel(self, func):
-        newfunc = self._parse_constructor(func)
-        if not newfunc:
-            newfunc = self._parse_method(func)
-            if not newfunc:
-                self._resolve_function(func)
+        for parser in [self._parse_constructor,
+                       self._parse_method,
+                       self._parse_static_method]:
+            newfunc = parser(func)
+            if newfunc:
+                self._resolve_function(newfunc)
                 return
-        self._resolve_function(newfunc)
+        self._resolve_function(func)
 
     def _pair_boxed_type(self, boxed):
         name = self._transformer.remove_prefix(boxed.type_name)
@@ -743,6 +752,7 @@ class GLibTransformer(object):
                                     for x in node.interfaces])
         self._resolve_constructors(node.constructors)
         self._resolve_methods(node.methods)
+        self._resolve_methods(node.static_methods)
         self._resolve_properties(node.properties, node)
         self._resolve_signals(node.signals)
         for field in node.fields:
diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir
index 21d70c5..9db4c29 100644
--- a/tests/scanner/foo-1.0-expected.gir
+++ b/tests/scanner/foo-1.0-expected.gir
@@ -87,6 +87,11 @@
           <type name="Object" c:type="FooObject*"/>
         </return-value>
       </constructor>
+      <function name="static_meth" c:identifier="foo_object_static_meth">
+        <return-value transfer-ownership="none">
+          <type name="int" c:type="int"/>
+        </return-value>
+      </function>
       <method name="external_type" c:identifier="foo_object_external_type">
         <return-value transfer-ownership="full">
           <type name="utility.Object" c:type="UtilityObject*"/>
diff --git a/tests/scanner/foo-1.0-expected.tgir b/tests/scanner/foo-1.0-expected.tgir
index 2591fdf..d44f118 100644
--- a/tests/scanner/foo-1.0-expected.tgir
+++ b/tests/scanner/foo-1.0-expected.tgir
@@ -36,6 +36,11 @@
           <type name="Object"/>
         </return-value>
       </constructor>
+      <function name="static_meth" c:identifier="foo_object_static_meth">
+        <return-value transfer-ownership="none">
+          <type name="int"/>
+        </return-value>
+      </function>
       <method name="external_type" c:identifier="foo_object_external_type">
         <return-value transfer-ownership="full">
           <type name="utility.Object"/>
diff --git a/tests/scanner/foo.h b/tests/scanner/foo.h
index c7da0a4..fd9d359 100644
--- a/tests/scanner/foo.h
+++ b/tests/scanner/foo.h
@@ -91,6 +91,8 @@ char *                foo_object_dup_name          (FooObject *object);
 
 void                  foo_object_handle_glyph      (FooObject *object, UtilityGlyph glyph);
 
+int                   foo_object_static_meth       ();
+
 struct _FooSubobject
 {
   FooObject parent_instance;
