From 5424cdbd810042ba59e71bec6b8d91cb6a2c3e9c Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Wed, 7 Dec 2016 13:55:13 +0000 Subject: [PATCH] Eo: Fix efl_isa() sometimes returning wrong results with extensions This fixes an issue where efl_isa() wouldn't work for extensions or ancestors of extensions of a class. Example: Class A implements interface F2 F2 inherits from interface F1 obj is of class A Before this patch efl_isa(obj, F1) would return false, now it returns true as expected. This is just one example, there is a whole array of variations to this issue that are now fixed. Thanks to Gustavo for reminding me of this. @fix --- src/lib/eo/eo.c | 45 +++++++++++++------------ src/tests/eo/interface/interface_main.c | 3 ++ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index c4c6a5f0b7..20cf56d25d 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -228,14 +228,14 @@ _eo_op_class_get(Efl_Object_Op op) } static inline Eina_Bool -_vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass, Efl_Object_Op op, Eo_Op_Func_Type func) +_vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass, Efl_Object_Op op, Eo_Op_Func_Type func, Eina_Bool allow_same_override) { op_type_funcs *fsrc; size_t idx1 = DICH_CHAIN1(op); Dich_Chain1 *chain1 = &vtable->chain[idx1]; _vtable_chain_write_prepare(chain1); fsrc = &chain1->chain2->funcs[DICH_CHAIN_LAST(op)]; - if (fsrc->src == klass) + if (!allow_same_override && (fsrc->src == klass)) { const _Efl_Class *op_kls = _eo_op_class_get(op); ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.", @@ -746,7 +746,7 @@ _eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Cla DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc)); - if (!_vtable_func_set(vtable, klass, op, op_desc->func)) + if (!_vtable_func_set(vtable, klass, op, op_desc->func, EINA_FALSE)) return EINA_FALSE; last_api_func = op_desc->api_func; @@ -1224,6 +1224,25 @@ _eo_class_isa_func(Eo *eo_id EINA_UNUSED, void *class_data EINA_UNUSED) /* Do nonthing. */ } +static void +_eo_class_isa_recursive_set(_Efl_Class *klass, const _Efl_Class *cur) +{ + const _Efl_Class **extn_itr; + + _vtable_func_set(&klass->vtable, klass, cur->base_id + cur->ops_count, + _eo_class_isa_func, EINA_TRUE); + + for (extn_itr = cur->extensions ; *extn_itr ; extn_itr++) + { + _eo_class_isa_recursive_set(klass, *extn_itr); + } + + if (cur->parent) + { + _eo_class_isa_recursive_set(klass, cur->parent); + } +} + static inline void _eo_classes_release(void) { @@ -1509,25 +1528,7 @@ efl_class_new(const Efl_Class_Description *desc, const Efl_Class *parent_id, ... /* Mark which classes we implement */ if (klass->vtable.size) { - const _Efl_Class **extn_itr; - - for (extn_itr = klass->extensions ; *extn_itr ; extn_itr++) - { - const _Efl_Class *extn = *extn_itr; - /* Set it in the dich. */ - _vtable_func_set(&klass->vtable, klass, extn->base_id + - extn->ops_count, _eo_class_isa_func); - } - - _vtable_func_set(&klass->vtable, klass, klass->base_id + klass->ops_count, - _eo_class_isa_func); - - if (klass->parent) - { - _vtable_func_set(&klass->vtable, klass, - klass->parent->base_id + klass->parent->ops_count, - _eo_class_isa_func); - } + _eo_class_isa_recursive_set(klass, klass); } _eo_class_constructor(klass); diff --git a/src/tests/eo/interface/interface_main.c b/src/tests/eo/interface/interface_main.c index e9e145bd75..8f07bb29e6 100644 --- a/src/tests/eo/interface/interface_main.c +++ b/src/tests/eo/interface/interface_main.c @@ -35,6 +35,9 @@ main(int argc, char *argv[]) sum = interface2_ab_sum_get2(obj); fail_if(sum != a + b + 1); + fail_if(!efl_isa(obj, INTERFACE_CLASS)); + fail_if(!efl_isa(obj, INTERFACE2_CLASS)); + efl_unref(obj); efl_object_shutdown(); return 0;