forked from enlightenment/efl
Eobj: Add checks to ensure consistent method rosulotion order.
SVN revision: 70321
This commit is contained in:
parent
7713059d6d
commit
5bfbd5f9d1
|
@ -443,25 +443,60 @@ _eobj_class_base_op_init(Eobj_Class *klass)
|
|||
static Eina_List *
|
||||
_eobj_class_mro_add(Eina_List *mro, const Eobj_Class *klass)
|
||||
{
|
||||
Eina_List *extn_pos = NULL;
|
||||
Eina_Bool check_consistency = !mro;
|
||||
if (!klass)
|
||||
return mro;
|
||||
|
||||
mro = eina_list_append(mro, klass);
|
||||
|
||||
/* Recursively add extenions. */
|
||||
{
|
||||
Eobj_Extension_Node *extn;
|
||||
EINA_INLIST_FOREACH(klass->extensions, extn)
|
||||
{
|
||||
mro = _eobj_class_mro_add(mro, extn->klass);
|
||||
if (!mro)
|
||||
return NULL;
|
||||
|
||||
if (check_consistency)
|
||||
{
|
||||
extn_pos = eina_list_append(extn_pos, eina_list_last(mro));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we can create a consistent mro. We only do it for the class
|
||||
* we are working on (i.e no parents). */
|
||||
if (check_consistency)
|
||||
{
|
||||
Eobj_Extension_Node *extn;
|
||||
|
||||
Eina_List *itr = extn_pos;
|
||||
EINA_INLIST_FOREACH(klass->extensions, extn)
|
||||
{
|
||||
/* Get the first one after the extension. */
|
||||
Eina_List *extn_list = eina_list_next(eina_list_data_get(itr));
|
||||
|
||||
/* If we found the extension again. */
|
||||
if (eina_list_data_find_list(extn_list, extn->klass))
|
||||
{
|
||||
eina_list_free(mro);
|
||||
ERR("Cannot create a consistent method resolution order for class '%s' because of '%s'.", klass->desc->name, extn->klass->desc->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
itr = eina_list_next(itr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mro = _eobj_class_mro_add(mro, klass->parent);
|
||||
|
||||
return mro;
|
||||
}
|
||||
|
||||
static void
|
||||
static Eina_Bool
|
||||
_eobj_class_mro_init(Eobj_Class *klass)
|
||||
{
|
||||
Eina_List *mro = NULL;
|
||||
|
@ -469,6 +504,10 @@ _eobj_class_mro_init(Eobj_Class *klass)
|
|||
DBG("Started creating MRO for class '%s'", klass->desc->name);
|
||||
mro = _eobj_class_mro_add(mro, klass);
|
||||
|
||||
if (!mro)
|
||||
return EINA_FALSE;
|
||||
|
||||
/* Remove duplicates and make them the right order. */
|
||||
{
|
||||
Eina_List *itr1, *itr2, *itr2n;
|
||||
|
||||
|
@ -511,6 +550,8 @@ _eobj_class_mro_init(Eobj_Class *klass)
|
|||
}
|
||||
|
||||
DBG("Finished creating MRO for class '%s'", klass->desc->name);
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -523,8 +564,6 @@ _eobj_class_constructor(Eobj_Class *klass)
|
|||
|
||||
if (klass->desc->class_constructor)
|
||||
klass->desc->class_constructor(klass);
|
||||
|
||||
_eobj_class_mro_init(klass);
|
||||
}
|
||||
|
||||
EAPI void
|
||||
|
@ -713,6 +752,11 @@ eobj_class_new(const Eobj_Class_Description *desc, const Eobj_Class *parent, ...
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!_eobj_class_mro_init(klass))
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
klass->class_id = ++_eobj_classes_last_id;
|
||||
{
|
||||
/* FIXME: Handle errors. */
|
||||
|
|
|
@ -159,8 +159,88 @@ START_TEST(eobj_inherit_errors)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(eobj_inconsistent_mro)
|
||||
{
|
||||
eobj_init();
|
||||
|
||||
const Eobj_Class *klass;
|
||||
const Eobj_Class *klass_mixin;
|
||||
const Eobj_Class *klass_mixin2;
|
||||
const Eobj_Class *klass_mixin3;
|
||||
|
||||
static const Eobj_Class_Description class_desc_simple = {
|
||||
"Simple",
|
||||
EOBJ_CLASS_TYPE_REGULAR,
|
||||
EOBJ_CLASS_DESCRIPTION_OPS(NULL, NULL, 0),
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const Eobj_Class_Description class_desc_mixin = {
|
||||
"Mixin",
|
||||
EOBJ_CLASS_TYPE_MIXIN,
|
||||
EOBJ_CLASS_DESCRIPTION_OPS(NULL, NULL, 0),
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const Eobj_Class_Description class_desc_mixin2 = {
|
||||
"Mixin2",
|
||||
EOBJ_CLASS_TYPE_MIXIN,
|
||||
EOBJ_CLASS_DESCRIPTION_OPS(NULL, NULL, 0),
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const Eobj_Class_Description class_desc_mixin3 = {
|
||||
"Mixin3",
|
||||
EOBJ_CLASS_TYPE_MIXIN,
|
||||
EOBJ_CLASS_DESCRIPTION_OPS(NULL, NULL, 0),
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
klass_mixin = eobj_class_new(&class_desc_mixin, NULL, NULL);
|
||||
fail_if(!klass_mixin);
|
||||
|
||||
klass_mixin2 = eobj_class_new(&class_desc_mixin2, klass_mixin, NULL);
|
||||
fail_if(!klass_mixin2);
|
||||
|
||||
klass_mixin3 = eobj_class_new(&class_desc_mixin3, klass_mixin, NULL);
|
||||
fail_if(!klass_mixin3);
|
||||
|
||||
klass = eobj_class_new(&class_desc_simple, EOBJ_BASE_CLASS, klass_mixin, klass_mixin2, NULL);
|
||||
fail_if(klass);
|
||||
|
||||
klass = eobj_class_new(&class_desc_simple, EOBJ_BASE_CLASS, klass_mixin2, klass_mixin, NULL);
|
||||
fail_if(!klass);
|
||||
|
||||
klass = eobj_class_new(&class_desc_simple, EOBJ_BASE_CLASS, klass_mixin2, klass_mixin3, NULL);
|
||||
fail_if(!klass);
|
||||
|
||||
eobj_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void eobj_test_class_errors(TCase *tc)
|
||||
{
|
||||
tcase_add_test(tc, eobj_incomplete_desc);
|
||||
tcase_add_test(tc, eobj_inherit_errors);
|
||||
tcase_add_test(tc, eobj_inconsistent_mro);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue