From b191379d1db3b90ae8c0150117035b4c5d318f2b Mon Sep 17 00:00:00 2001 From: Daniel Zaoui Date: Tue, 17 Mar 2015 13:11:41 +0200 Subject: [PATCH] Eolian: add API to determine if a function is implemented. This is needed in Erigo to determine if a virtual pure function can be invoked via eo_do, as we don't want error messages to be displayed in case of a non implementation in the Eo object. This function works with non virtual functions too. Tests have been provided. @feature --- src/lib/eolian/Eolian.h | 13 ++++++ src/lib/eolian/database_function_api.c | 63 ++++++++++++++++++++++++++ src/tests/eolian/eolian_parsing.c | 12 +++++ 3 files changed, 88 insertions(+) diff --git a/src/lib/eolian/Eolian.h b/src/lib/eolian/Eolian.h index bb13a31cee..d231782c81 100644 --- a/src/lib/eolian/Eolian.h +++ b/src/lib/eolian/Eolian.h @@ -1107,6 +1107,19 @@ EAPI Eina_Bool eolian_function_object_is_const(const Eolian_Function *function_i */ EAPI const Eolian_Class *eolian_function_class_get(const Eolian_Function *function_id); +/* + * @brief Determine if a function is implemented in the inheritance of the given class + * + * @param[in] function_id id of the function + * @param[in] func_type type requested + * @param[in] klass the top class to begin with + * @return EINA_TRUE if found, EINA_FALSE otherwise + * + * @ingroup Eolian + */ +EAPI Eina_Bool eolian_function_is_implemented(const Eolian_Function *function_id, + Eolian_Function_Type func_type, const Eolian_Class *klass); + /* * @brief Get full string of an overriding function (implement). * diff --git a/src/lib/eolian/database_function_api.c b/src/lib/eolian/database_function_api.c index 69b96686d6..fbe1e1cb46 100644 --- a/src/lib/eolian/database_function_api.c +++ b/src/lib/eolian/database_function_api.c @@ -263,3 +263,66 @@ eolian_function_is_c_only(const Eolian_Function *fid) EINA_SAFETY_ON_NULL_RETURN_VAL(fid, EINA_FALSE); return fid->is_c_only; } + +EAPI Eina_Bool eolian_function_is_implemented( + const Eolian_Function *function_id, Eolian_Function_Type func_type, + const Eolian_Class *klass) +{ + Eina_Iterator *impl_itr = NULL; + Eolian_Function_Type found_type = EOLIAN_UNRESOLVED; + Eina_Bool found = EINA_TRUE; + if (!function_id || !klass) return EINA_FALSE; + Eina_List *list = eina_list_append(NULL, klass), *list2, *itr; + EINA_LIST_FOREACH(list, itr, klass) + { + const char *inherit_name; + const Eolian_Implement *impl; + if (eolian_class_type_get(klass) == EOLIAN_CLASS_INTERFACE) continue; + impl_itr = eolian_class_implements_get(klass); + EINA_ITERATOR_FOREACH(impl_itr, impl) + { + if (eolian_implement_is_virtual(impl)) continue; + Eolian_Function_Type impl_type = EOLIAN_UNRESOLVED; + const Eolian_Function *impl_func = eolian_implement_function_get(impl, &impl_type); + if (impl_func == function_id) + { + /* The type matches the requested or is not important for the caller */ + if (func_type == EOLIAN_UNRESOLVED || impl_type == func_type) goto end; + if (impl_type == EOLIAN_METHOD) continue; + /* In case we search for a property type */ + if (impl_type == EOLIAN_PROPERTY && + (func_type == EOLIAN_PROP_GET || func_type == EOLIAN_PROP_SET)) + goto end; + /* Property may be splitted on multiple implements */ + if (func_type == EOLIAN_PROPERTY) + { + if (found_type == EOLIAN_UNRESOLVED) found_type = impl_type; + if ((found_type == EOLIAN_PROP_SET && impl_type == EOLIAN_PROP_GET) || + (found_type == EOLIAN_PROP_GET && impl_type == EOLIAN_PROP_SET)) + goto end; + } + } + } + eina_iterator_free(impl_itr); + impl_itr = NULL; + + Eina_Iterator *inherits_itr = eolian_class_inherits_get(klass); + EINA_ITERATOR_FOREACH(inherits_itr, inherit_name) + { + const Eolian_Class *inherit = eolian_class_get_by_name(inherit_name); + /* Avoid duplicates. */ + if (!eina_list_data_find(list, inherit)) + { + list2 = eina_list_append(list, inherit); + } + } + eina_iterator_free(inherits_itr); + } + (void) list2; + found = EINA_FALSE; +end: + if (impl_itr) eina_iterator_free(impl_itr); + eina_list_free(list); + return found; +} + diff --git a/src/tests/eolian/eolian_parsing.c b/src/tests/eolian/eolian_parsing.c index 3c623e175b..f61434635c 100644 --- a/src/tests/eolian/eolian_parsing.c +++ b/src/tests/eolian/eolian_parsing.c @@ -155,15 +155,27 @@ START_TEST(eolian_override) /* Base ctor */ fail_if(!(fid = eolian_class_function_get_by_name(base, "constructor", EOLIAN_UNRESOLVED))); fail_if(!eolian_function_is_virtual_pure(fid, EOLIAN_UNRESOLVED)); + fail_if(!eolian_function_is_implemented(fid, EOLIAN_UNRESOLVED, class)); + fail_if(!eolian_function_is_implemented(fid, EOLIAN_METHOD, class)); + fail_if(eolian_function_is_implemented(fid, EOLIAN_PROP_GET, class)); /* Property */ fail_if(!(fid = eolian_class_function_get_by_name(class, "a", EOLIAN_PROPERTY))); fail_if(!eolian_function_is_virtual_pure(fid, EOLIAN_PROP_SET)); fail_if(eolian_function_is_virtual_pure(fid, EOLIAN_PROP_GET)); + fail_if(eolian_function_is_implemented(fid, EOLIAN_PROP_SET, class)); + fail_if(!eolian_function_is_implemented(fid, EOLIAN_PROP_GET, class)); + fail_if(eolian_function_is_implemented(fid, EOLIAN_PROPERTY, class)); /* Method */ fail_if(!(fid = eolian_class_function_get_by_name(class, "foo", EOLIAN_METHOD))); fail_if(!eolian_function_is_virtual_pure(fid, EOLIAN_METHOD)); + fail_if(eolian_function_is_implemented(fid, EOLIAN_UNRESOLVED, class)); + fail_if(eolian_function_is_implemented(fid, EOLIAN_UNRESOLVED, base)); + + fail_if(!(fid = eolian_class_function_get_by_name(base, "z", EOLIAN_PROPERTY))); + fail_if(!eolian_function_is_implemented(fid, EOLIAN_PROPERTY, class)); + fail_if(!eolian_function_is_implemented(fid, EOLIAN_PROP_SET, class)); /* Implements */ fail_if(!(iter = eolian_class_implements_get(class)));