mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-05 02:36:19 +01:00
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
This commit is contained in:
parent
ab0da3c282
commit
5fb7a8e127
@ -1373,22 +1373,65 @@ object_interface_check_properties (gpointer func_data,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The implementation paramspec must have a less restrictive
|
/* If the property on the interface is readable then we are
|
||||||
* type than the interface parameter spec for set() and a
|
* effectively advertising that reading the property will return a
|
||||||
* more restrictive type for get(). We just require equality,
|
* value of a specific type. All implementations of the interface
|
||||||
* rather than doing something more complicated checking
|
* need to return items of this type -- but may be more
|
||||||
* the READABLE and WRITABLE flags. We also simplify here
|
* restrictive. For example, it is legal to have:
|
||||||
* by only checking the value type, not the G_PARAM_SPEC_TYPE.
|
*
|
||||||
|
* 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))
|
switch (pspecs[n]->flags & (G_PARAM_READABLE | G_PARAM_WRITABLE))
|
||||||
g_critical ("Property '%s' on class '%s' has type '%s' "
|
{
|
||||||
"which is different from the type '%s', "
|
case G_PARAM_READABLE | G_PARAM_WRITABLE:
|
||||||
"of the property on interface '%s'\n",
|
/* class pspec value type must have exact equality with interface */
|
||||||
pspecs[n]->name,
|
if (pspecs[n]->value_type != class_pspec->value_type)
|
||||||
g_type_name (G_OBJECT_CLASS_TYPE (class)),
|
g_critical ("Read/writable property '%s' on class '%s' has type '%s' which is not exactly equal to the "
|
||||||
g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
|
"type '%s' of the property on the interface '%s'\n", pspecs[n]->name,
|
||||||
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspecs[n])),
|
g_type_name (G_OBJECT_CLASS_TYPE (class)), g_type_name (G_PARAM_SPEC_VALUE_TYPE (class_pspec)),
|
||||||
g_type_name (iface_type));
|
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)
|
#define SUBSET(a,b,mask) (((a) & ~(b) & (mask)) == 0)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user