Eobj: Add checks to ensure consistent method rosulotion order.

SVN revision: 70321
This commit is contained in:
Tom Hacohen 2012-04-19 08:52:15 +00:00
parent 7713059d6d
commit 5bfbd5f9d1
2 changed files with 127 additions and 3 deletions

View File

@ -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. */

View File

@ -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);
}