[glib] GObject: fix property override type checks
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GObject: fix property override type checks
- Date: Wed, 21 Dec 2011 01:01:39 +0000 (UTC)
commit 5fb7a8e127bde6465a5b9e22b299ca2e439e702c
Author: Ryan Lortie <desrt desrt ca>
Date: Tue Dec 20 18:26:14 2011 -0500
GObject: fix property override type checks
The property override typecheck was meant to enforce the type on the
overriding property being exactly equal to the type on the interface
property. Instead, g_type_is_a() was incorrectly used.
We could try to enforce equality, but if a property is read-only then it
should be possible for the implementation to type the property with any
subtype of the type specified on the interface (because returning a more
specific type will still satisfy the interface). Likewise, if the
property is write-only then it should be possible for the implementation
to type the property with any supertype.
We implement the check this way.
https://bugzilla.gnome.org/show_bug.cgi?id=666616
gobject/gobject.c | 73 ++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 58 insertions(+), 15 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index eabd2fe..e92990c 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -1373,22 +1373,65 @@ object_interface_check_properties (gpointer func_data,
continue;
}
- /* The implementation paramspec must have a less restrictive
- * type than the interface parameter spec for set() and a
- * more restrictive type for get(). We just require equality,
- * rather than doing something more complicated checking
- * the READABLE and WRITABLE flags. We also simplify here
- * by only checking the value type, not the G_PARAM_SPEC_TYPE.
+ /* If the property on the interface is readable then we are
+ * effectively advertising that reading the property will return a
+ * value of a specific type. All implementations of the interface
+ * need to return items of this type -- but may be more
+ * restrictive. For example, it is legal to have:
+ *
+ * GtkWidget *get_item();
+ *
+ * that is implemented by a function that always returns a
+ * GtkEntry. In short: readability implies that the
+ * implementation value type must be equal or more restrictive.
+ *
+ * Similarly, if the property on the interface is writable then
+ * must be able to accept the property being set to any value of
+ * that type, including subclasses. In this case, we may also be
+ * less restrictive. For example, it is legal to have:
+ *
+ * set_item (GtkEntry *);
+ *
+ * that is implemented by a function that will actually work with
+ * any GtkWidget. In short: writability implies that the
+ * implementation value type must be equal or less restrictive.
+ *
+ * In the case that the property is both readable and writable
+ * then the only way that both of the above can be satisfied is
+ * with a type that is exactly equal.
*/
- if (!g_type_is_a (pspecs[n]->value_type, class_pspec->value_type))
- g_critical ("Property '%s' on class '%s' has type '%s' "
- "which is different from the type '%s', "
- "of the property on interface '%s'\n",
- pspecs[n]->name,
- g_type_name (G_OBJECT_CLASS_TYPE (class)),
- g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
- g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])),
- g_type_name (iface_type));
+ switch (pspecs[n]->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE))
+ {
+ case G_PARAM_READABLE | G_PARAM_WRITABLE:
+ /* class pspec value type must have exact equality with interface */
+ if (pspecs[n]->value_type != class_pspec->value_type)
+ g_critical ("Read/writable property '%s' on class '%s' has type '%s' which is not exactly equal to the "
+ "type '%s' of the property on the interface '%s'\n", pspecs[n]->name,
+ g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), g_type_name (iface_type));
+ break;
+
+ case G_PARAM_READABLE:
+ /* class pspec value type equal or more restrictive than interface */
+ if (!g_type_is_a (class_pspec->value_type, pspecs[n]->value_type))
+ g_critical ("Read-only property '%s' on class '%s' has type '%s' which is not equal to or more "
+ "restrictive than the type '%s' of the property on the interface '%s'\n", pspecs[n]->name,
+ g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), g_type_name (iface_type));
+ break;
+
+ case G_PARAM_WRITABLE:
+ /* class pspec value type equal or less restrictive than interface */
+ if (!g_type_is_a (pspecs[n]->value_type, class_pspec->value_type))
+ g_critical ("Write-only property '%s' on class '%s' has type '%s' which is not equal to or less "
+ "restrictive than the type '%s' of the property on the interface '%s' \n", pspecs[n]->name,
+ g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
+ g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])), g_type_name (iface_type));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
#define SUBSET(a,b,mask) (((a) & ~(b) & (mask)) == 0)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]