Fix matching of methods named *_get_type()
authorMatthew Booth <mbooth@redhat.com>
Tue, 6 Mar 2012 14:57:01 +0000 (11:57 -0300)
committerJohan Dahlin <jdahlin@litl.com>
Tue, 6 Mar 2012 14:57:22 +0000 (11:57 -0300)
The code which heuristically turned functions into class methods would always
ignore any function called *_get_type or *_get_gtype. However, the code which
looked for GI metadata functions to execute them was much more comprehensive,
checking not just the name, but also that it had no parameters and that it
returned a GType.

This change abstracts the more comprehensive check into the Function class, and
uses the same check in both places.

https://bugzilla.gnome.org/show_bug.cgi?id=671218

.gitignore
giscanner/ast.py
giscanner/gdumpparser.py
giscanner/maintransformer.py
tests/scanner/GetType-1.0-expected.gir [new file with mode: 0644]
tests/scanner/Makefile.am
tests/scanner/gettype.c [new file with mode: 0644]
tests/scanner/gettype.h [new file with mode: 0644]

index 7ecec39eba98eed655b829737917e97670699b47..1d4ae8a7a3f723ec0024cb7bd3b22fc91d5d28df 100644 (file)
@@ -70,6 +70,7 @@ tests/repository/gitypelibtest
 tests/scanner/Annotation-1.0.gir
 tests/scanner/Bar-1.0.gir
 tests/scanner/Foo-1.0.gir
+tests/scanner/GetType-1.0.gir
 tests/scanner/GtkFrob-1.0.gir
 tests/scanner/Headeronly-1.0.gir
 tests/scanner/Regress-1.0.gir
index 6df356dd72dc7e983a26b81a70bf682c67ef2070..9e9d7c37ad833eaaf699a014820f689dff150bcc 100644 (file)
@@ -21,6 +21,8 @@
 
 import copy
 
+from . import message
+
 from .message import Position
 from .odict import odict
 from .utils import to_underscores
@@ -589,6 +591,25 @@ class Function(Callable):
         clone.parameters = self.parameters[:]
         return clone
 
+    def is_type_meta_function(self):
+        # Named correctly
+        if not (self.name.endswith('_get_type') or
+                self.name.endswith('_get_gtype')):
+                return False
+
+        # Doesn't have any parameters
+        if self.parameters:
+            return False
+
+        # Returns GType
+        rettype = self.retval.type
+        if (not rettype.is_equiv(TYPE_GTYPE) and
+           rettype.target_giname != 'Gtk.Type'):
+            message.warn("function '%s' returns '%r', not a GType" %
+                         (self.name, rettype))
+            return False
+
+        return True
 
 class ErrorQuarkFunction(Function):
 
index c0c4ef61d038b7c1492932516a893b595952ce0b..c0b13f4aa05e4fd3005f81774cd16432ced626a6 100644 (file)
@@ -188,18 +188,12 @@ blob containing data gleaned from GObject's primitive introspection."""
         if func.symbol == 'g_variant_get_gtype':
             # We handle variants internally, see _initparse_gobject_record
             return True
-        if func.parameters:
-            return False
-        # GType *_get_type(void)
-        rettype = func.retval.type
-        if not (rettype.is_equiv(ast.TYPE_GTYPE)
-                or rettype.target_giname == 'Gtk.Type'):
-            message.warn("function returns '%r', not a GType" % (
-                func.retval.type, ))
-            return False
 
-        self._get_type_functions.append(func.symbol)
-        return True
+        if func.is_type_meta_function():
+            self._get_type_functions.append(func.symbol)
+            return True
+
+        return False
 
     def _initparse_error_quark_function(self, func):
         if (func.retval.type.ctype != 'GQuark'):
index 3a35b0e709e8030fa487c851d31c0eddb17c0931..7d274b34656650f29ced84c24ee46d55f5c5c3d8 100644 (file)
@@ -955,10 +955,11 @@ _split_uscored_by_type(text_buffer_try_new) -> (ast.Class(TextBuffer), 'try_new'
     def _pair_function(self, func):
         """Check to see whether a toplevel function should be a
 method or constructor of some type."""
-        if (func.symbol.endswith('_get_type')
-            or func.symbol.endswith('_get_gtype')
-            or func.symbol.startswith('_')):
+
+        # Ignore internal symbols and type metadata functions
+        if func.symbol.startswith('_') or func.is_type_meta_function():
             return
+
         (ns, subsymbol) = self._transformer.split_csymbol(func.symbol)
         assert ns == self._namespace
         if self._is_constructor(func, subsymbol):
diff --git a/tests/scanner/GetType-1.0-expected.gir b/tests/scanner/GetType-1.0-expected.gir
new file mode 100644 (file)
index 0000000..3b1dd19
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<!-- This file was automatically generated from C sources - DO NOT EDIT!
+To affect the contents of this file, edit the original C definitions,
+and/or use gtk-doc annotations.  -->
+<repository version="1.2"
+            xmlns="http://www.gtk.org/introspection/core/1.0"
+            xmlns:c="http://www.gtk.org/introspection/c/1.0"
+            xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
+  <include name="GLib" version="2.0"/>
+  <include name="GObject" version="2.0"/>
+  <package name="gobject-2.0"/>
+  <c:include name="gettype.h"/>
+  <namespace name="GetType"
+             version="1.0"
+             shared-library="libgettype.so"
+             c:identifier-prefixes="GetType"
+             c:symbol-prefixes="gettype">
+    <class name="Object"
+           c:symbol-prefix="object"
+           c:type="GetTypeObject"
+           parent="GObject.Object"
+           glib:type-name="GetTypeObject"
+           glib:get-type="gettype_object_get_type"
+           glib:type-struct="ObjectClass">
+      <constructor name="new" c:identifier="gettype_object_new">
+        <return-value transfer-ownership="full">
+          <type name="Object" c:type="GetTypeObject*"/>
+        </return-value>
+      </constructor>
+      <function name="nonmeta2_get_type"
+                c:identifier="gettype_object_nonmeta2_get_type">
+        <doc xml:whitespace="preserve">This shouldn't be scanned as a *_get_type function because it doesn't return
+a GType. It will generate a warning.</doc>
+        <return-value transfer-ownership="none">
+          <doc xml:whitespace="preserve">true</doc>
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+      </function>
+      <function name="nonmeta_get_gtype"
+                c:identifier="gettype_object_nonmeta_get_gtype">
+        <doc xml:whitespace="preserve">This shouldn't be scanned as a *_get_type function because it doesn't return
+a GType. It will generate a warning.</doc>
+        <return-value transfer-ownership="none">
+          <doc xml:whitespace="preserve">true</doc>
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+      </function>
+      <method name="nonmeta1_get_type"
+              c:identifier="gettype_object_nonmeta1_get_type">
+        <doc xml:whitespace="preserve">This shouldn't be scanned as a *_get_type function because it takes
+arguments.</doc>
+        <return-value transfer-ownership="none">
+          <doc xml:whitespace="preserve">0</doc>
+          <type name="GType" c:type="GType"/>
+        </return-value>
+      </method>
+      <field name="parent_instance">
+        <type name="GObject.Object" c:type="GObject"/>
+      </field>
+    </class>
+    <record name="ObjectClass"
+            c:type="GetTypeObjectClass"
+            glib:is-gtype-struct-for="Object">
+      <field name="parent_class">
+        <type name="GObject.ObjectClass" c:type="GObjectClass"/>
+      </field>
+    </record>
+  </namespace>
+</repository>
index d2bed5acd76bcafc0fa91eaeae47905a5d5e0940..0e5ddb533939bc3678c6f168ac8899268d07061a 100644 (file)
@@ -1,14 +1,15 @@
 include $(top_srcdir)/common.mk
 include $(top_srcdir)/Makefile.introspection
 
-INTROSPECTION_SCANNER_ARGS += --warn-all --warn-error -I.
+INTROSPECTION_SCANNER_ARGS += --warn-all
 
 check_LTLIBRARIES = \
        libannotation.la \
        libtestinherit.la \
        libfoo.la \
        libutility.la \
-       libgtkfrob.la
+       libgtkfrob.la \
+       libgettype.la
 if HAVE_CAIRO
 check_LTLIBRARIES += libregress.la
 endif
@@ -28,6 +29,7 @@ libutility_la_SOURCES = $(srcdir)/utility.c $(srcdir)/utility.h
 libgtkfrob_la_SOURCES = $(srcdir)/gtkfrob.c $(srcdir)/gtkfrob.h
 libregress_la_SOURCES = $(srcdir)/regress.c $(srcdir)/regress.h
 libregress_la_LIBADD = $(GIO_LIBS) $(CAIRO_LIBS)
+libgettype_la_SOURCES = $(srcdir)/gettype.c $(srcdir)/gettype.h
 
 testsdir = $(datadir)/gobject-introspection-1.0/tests
 tests_DATA = $(libregress_la_SOURCES)
@@ -53,7 +55,7 @@ Regress-1.0.gir: $(top_builddir)/Gio-2.0.gir libregress.la
 Regress_1_0_gir_LIBS = libregress.la
 Regress_1_0_gir_INCLUDES = cairo-1.0 Gio-2.0
 Regress_1_0_gir_FILES = $(libregress_la_SOURCES)
-Regress_1_0_gir_SCANNERFLAGS = --c-include="regress.h"
+Regress_1_0_gir_SCANNERFLAGS = --c-include="regress.h" --warn-error
 if HAVE_CAIRO
 GIRS += Regress-1.0.gir
 endif
@@ -63,7 +65,7 @@ Annotation_1_0_gir_PACKAGES = gobject-2.0
 Annotation_1_0_gir_LIBS = libannotation.la
 Annotation_1_0_gir_INCLUDES = GObject-2.0 Utility-1.0
 Annotation_1_0_gir_FILES = $(libannotation_la_SOURCES)
-Annotation_1_0_gir_SCANNERFLAGS = --c-include="annotation.h"
+Annotation_1_0_gir_SCANNERFLAGS = --c-include="annotation.h" --warn-error
 GIRS += Annotation-1.0.gir
 
 TestInherit-1.0.gir: Utility-1.0.gir libtestinherit.la
@@ -71,7 +73,7 @@ TestInherit_1_0_gir_PACKAGES = gobject-2.0
 TestInherit_1_0_gir_LIBS = libtestinherit.la
 TestInherit_1_0_gir_INCLUDES = GObject-2.0 Utility-1.0
 TestInherit_1_0_gir_FILES = $(libtestinherit_la_SOURCES)
-TestInherit_1_0_gir_SCANNERFLAGS = --c-include="drawable.h"
+TestInherit_1_0_gir_SCANNERFLAGS = --c-include="drawable.h" --warn-error
 GIRS += TestInherit-1.0.gir
 
 Foo-1.0.gir: Utility-1.0.gir libfoo.la
@@ -79,7 +81,7 @@ Foo_1_0_gir_PACKAGES = gobject-2.0
 Foo_1_0_gir_LIBS = libfoo.la
 Foo_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 Utility-1.0
 Foo_1_0_gir_FILES = $(srcdir)/foo.h $(srcdir)/foo.c
-Foo_1_0_gir_SCANNERFLAGS = --c-include="foo.h"
+Foo_1_0_gir_SCANNERFLAGS = --c-include="foo.h" --warn-error
 GIRS += Foo-1.0.gir
 
 Utility-1.0.gir: libutility.la
@@ -87,7 +89,7 @@ Utility_1_0_gir_PACKAGES = gobject-2.0
 Utility_1_0_gir_LIBS = libutility.la
 Utility_1_0_gir_INCLUDES = GObject-2.0
 Utility_1_0_gir_FILES = $(libutility_la_SOURCES)
-Utility_1_0_gir_SCANNERFLAGS = --c-include="utility.h"
+Utility_1_0_gir_SCANNERFLAGS = --c-include="utility.h" --warn-error
 GIRS += Utility-1.0.gir
 
 # This one tests different --namespace and --strip-prefix
@@ -96,9 +98,19 @@ GtkFrob_1_0_gir_PACKAGES = gobject-2.0
 GtkFrob_1_0_gir_LIBS = libgtkfrob.la
 GtkFrob_1_0_gir_INCLUDES = GObject-2.0
 GtkFrob_1_0_gir_FILES = $(libgtkfrob_la_SOURCES)
-GtkFrob_1_0_gir_SCANNERFLAGS = --identifier-prefix=Gtk --symbol-prefix=gtk_frob
+GtkFrob_1_0_gir_SCANNERFLAGS = --identifier-prefix=Gtk --symbol-prefix=gtk_frob --warn-error
 GIRS += GtkFrob-1.0.gir
 
+# This tests that functions called _get_type are only matched if they have no
+# arguments and return GType
+GetType-1.0.gir: libgettype.la
+GetType_1_0_gir_PACKAGES = gobject-2.0
+GetType_1_0_gir_LIBS = libgettype.la
+GetType_1_0_gir_INCLUDES = GObject-2.0
+GetType_1_0_gir_FILES = $(libgettype_la_SOURCES)
+GetType_1_0_gir_SCANNERFLAGS = --c-include="gettype.h" --identifier-prefix=GetType --symbol-prefix=gettype
+GIRS += GetType-1.0.gir
+
 if !OS_WIN32
 check_PROGRAMS = barapp
 
diff --git a/tests/scanner/gettype.c b/tests/scanner/gettype.c
new file mode 100644 (file)
index 0000000..cd81673
--- /dev/null
@@ -0,0 +1,62 @@
+#include "gettype.h"
+
+G_DEFINE_TYPE(GetTypeObject, gettype_object, G_TYPE_OBJECT);
+
+static void
+gettype_object_class_init (GetTypeObjectClass *klass)
+{
+}
+
+static void
+gettype_object_init (GetTypeObject *object)
+{
+}
+
+GetTypeObject *
+gettype_object_new (void)
+{
+  return g_object_new (GETTYPE_TYPE_OBJECT, NULL);
+}
+
+/**
+ * gettype_object_nonmeta1_get_type:
+ * @obj: self
+ *
+ * This shouldn't be scanned as a *_get_type function because it takes
+ * arguments.
+ *
+ * Returns: 0
+ */
+GType
+gettype_object_nonmeta1_get_type (GetTypeObject *obj)
+{
+    return 0;
+}
+
+/**
+ * gettype_object_nonmeta2_get_type:
+ *
+ * This shouldn't be scanned as a *_get_type function because it doesn't return
+ * a GType. It will generate a warning.
+ *
+ * Returns: true
+ */
+gboolean
+gettype_object_nonmeta2_get_type (void)
+{
+    return TRUE;
+}
+
+/**
+ * gettype_object_nonmeta_get_gtype:
+ *
+ * This shouldn't be scanned as a *_get_type function because it doesn't return
+ * a GType. It will generate a warning.
+ *
+ * Returns: true
+ */
+gboolean
+gettype_object_nonmeta_get_gtype (void)
+{
+    return TRUE;
+}
diff --git a/tests/scanner/gettype.h b/tests/scanner/gettype.h
new file mode 100644 (file)
index 0000000..755f091
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __GETTYPE_OBJECT_H__
+#define __GETTYPE_OBJECT_H__
+
+#include <glib-object.h>
+
+#define GETTYPE_TYPE_OBJECT            (gettype_object_get_type ())
+#define GETTYPE_OBJECT(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), GETTYPE_TYPE_OBJECT, GetTypeObject))
+#define GETTYPE_IS_OBJECT(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), GETTYPE_TYPE_OBJECT))
+
+typedef struct _GetTypeObject           GetTypeObject;
+typedef struct _GetTypeObjectClass      GetTypeObjectClass;
+struct _GetTypeObject
+{
+  GObject parent_instance;
+};
+
+struct _GetTypeObjectClass
+{
+  GObjectClass parent_class;
+};
+
+GType           gettype_object_get_type          (void) G_GNUC_CONST;
+GetTypeObject*  gettype_object_new               (void);
+
+GType           gettype_object_nonmeta1_get_type (GetTypeObject *obj);
+gboolean        gettype_object_nonmeta2_get_type (void);
+gboolean        gettype_object_nonmeta_get_gtype (void);
+
+#endif /* __GETTYPE_OBJECT_H__ */