#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "eo_lexer.h" #include "eolian_priv.h" static Eina_Bool _check_cycle(Eina_Hash *chash, const Eolian_Object *obj) { /* need to check this for classes, typedecls, vars (toplevel objects) */ if (eina_hash_find(chash, &obj)) return EINA_TRUE; eina_hash_add(chash, &obj, obj); return EINA_FALSE; } static void _add_dep(Eina_Hash *depset, const Eolian_Unit *dep) { if (!eina_hash_find(depset, &dep)) eina_hash_add(depset, &dep, dep); } static void _check_type(const Eolian_Type *tp, Eina_Hash *depset, Eina_Hash *chash) { if (tp->base_type) _check_type(tp->base_type, depset, chash); if (tp->next_type) { const Eolian_Type *ntp = tp->next_type; for (; ntp; ntp = ntp->next_type) _check_type(ntp, depset, chash); } /* also covers EOLIAN_TYPE_CLASS */ if (tp->tdecl) _add_dep(depset, ((const Eolian_Object *)tp->tdecl)->unit); } static void _check_expr_cb(const Eolian_Object *obj, void *data) { Eina_Hash *depset = data; switch (obj->type) { case EOLIAN_OBJECT_TYPEDECL: case EOLIAN_OBJECT_CONSTANT: _add_dep(depset, obj->unit); default: break; } } static void _check_expr(const Eolian_Expression *expr, Eina_Hash *depset) { database_expr_eval(expr->base.unit, (Eolian_Expression *)expr, EOLIAN_MASK_ALL, _check_expr_cb, depset); } static void _check_param(const Eolian_Function_Parameter *arg, Eina_Hash *depset, Eina_Hash *chash) { if (arg->type) _check_type(arg->type, depset, chash); if (arg->value) _check_expr(arg->value, depset); } static void _check_function(const Eolian_Function *f, Eina_Hash *depset, Eina_Hash *chash) { if (f->get_ret_type) _check_type(f->get_ret_type, depset, chash); if (f->set_ret_type) _check_type(f->set_ret_type, depset, chash); if (f->get_ret_val) _check_expr(f->get_ret_val, depset); if (f->set_ret_val) _check_expr(f->set_ret_val, depset); Eina_List *l; const Eolian_Function_Parameter *arg; if ((f->type == EOLIAN_METHOD) || (f->type == EOLIAN_FUNCTION_POINTER)) { EINA_LIST_FOREACH(f->params, l, arg) _check_param(arg, depset, chash); } else { EINA_LIST_FOREACH(f->prop_values, l, arg) _check_param(arg, depset, chash); EINA_LIST_FOREACH(f->prop_values_get, l, arg) _check_param(arg, depset, chash); EINA_LIST_FOREACH(f->prop_values_set, l, arg) _check_param(arg, depset, chash); EINA_LIST_FOREACH(f->prop_keys, l, arg) _check_param(arg, depset, chash); EINA_LIST_FOREACH(f->prop_keys_get, l, arg) _check_param(arg, depset, chash); EINA_LIST_FOREACH(f->prop_keys_set, l, arg) _check_param(arg, depset, chash); } } static void _check_class(const Eolian_Class *cl, Eina_Hash *depset, Eina_Hash *chash) { if (_check_cycle(chash, &cl->base)) return; _add_dep(depset, cl->base.unit); const Eolian_Class *icl = cl->parent; if (icl) _add_dep(depset, icl->base.unit); Eina_Iterator *itr = eina_list_iterator_new(cl->extends); EINA_ITERATOR_FOREACH(itr, icl) _add_dep(depset, icl->base.unit); eina_iterator_free(itr); itr = eina_list_iterator_new(cl->requires); EINA_ITERATOR_FOREACH(itr, icl) _add_dep(depset, icl->base.unit); eina_iterator_free(itr); const Eolian_Function *fid; itr = eina_list_iterator_new(cl->properties); EINA_ITERATOR_FOREACH(itr, fid) _check_function(fid, depset, chash); eina_iterator_free(itr); itr = eina_list_iterator_new(cl->methods); EINA_ITERATOR_FOREACH(itr, fid) _check_function(fid, depset, chash); eina_iterator_free(itr); const Eolian_Event *ev; itr = eina_list_iterator_new(cl->events); EINA_ITERATOR_FOREACH(itr, ev) { if (ev->type) _check_type(ev->type, depset, chash); } eina_iterator_free(itr); const Eolian_Part *part; itr = eina_list_iterator_new(cl->parts); EINA_ITERATOR_FOREACH(itr, part) _add_dep(depset, part->klass->base.unit); eina_iterator_free(itr); } static void _check_typedecl(const Eolian_Typedecl *tp, Eina_Hash *depset, Eina_Hash *chash) { if (_check_cycle(chash, &tp->base)) return; _add_dep(depset, tp->base.unit); if (tp->base_type) _check_type(tp->base_type, depset, chash); if (tp->field_list) { Eina_List *l; void *data; EINA_LIST_FOREACH(tp->field_list, l, data) { switch (tp->type) { case EOLIAN_TYPEDECL_STRUCT: _check_type(((const Eolian_Struct_Type_Field *)data)->type, depset, chash); break; case EOLIAN_TYPEDECL_ENUM: _check_expr(((const Eolian_Enum_Type_Field *)data)->value, depset); break; default: break; } } } if (tp->function_pointer) _check_function(tp->function_pointer, depset, chash); } static void _check_constant(const Eolian_Constant *v, Eina_Hash *depset, Eina_Hash *chash) { if (_check_cycle(chash, &v->base)) return; _add_dep(depset, v->base.unit); _check_type(v->base_type, depset, chash); if (v->value) _check_expr(v->value, depset); } static Eina_Bool _check_unit(const Eolian_Unit *unit) { Eina_Bool ret = EINA_TRUE; Eina_Hash *depset = eina_hash_pointer_new(NULL); /* collect all real dependencies of the unit */ Eina_Hash *chash = eina_hash_pointer_new(NULL); Eina_Iterator *itr = eolian_unit_objects_get(unit); const Eolian_Object *obj; EINA_ITERATOR_FOREACH(itr, obj) { /* skip stuff merged in from children */ if (obj->unit != unit) continue; switch (obj->type) { case EOLIAN_OBJECT_CLASS: _check_class((const Eolian_Class *)obj, depset, chash); break; case EOLIAN_OBJECT_TYPEDECL: _check_typedecl((const Eolian_Typedecl *)obj, depset, chash); break; case EOLIAN_OBJECT_CONSTANT: _check_constant((const Eolian_Constant *)obj, depset, chash); break; default: continue; } } eina_hash_free(chash); /* check collected deps against children units */ Eina_Iterator *citr = eolian_unit_children_get(unit); const Eolian_Unit *cunit; EINA_ITERATOR_FOREACH(citr, cunit) { if (!eina_hash_find(depset, &cunit)) { eolian_state_log(unit->state, "%s: unused dependency %s", unit->file, cunit->file); ret = EINA_FALSE; } } eina_iterator_free(citr); eina_hash_free(depset); return ret; } static Eina_Bool _check_namespaces(const Eolian_Unit *src) { Eina_Bool ret = EINA_TRUE; Eina_Iterator *itr = eina_hash_iterator_data_new(src->objects); const Eolian_Object *obj; EINA_ITERATOR_FOREACH(itr, obj) { char const *dot = strrchr(obj->name, '.'); if (!dot) continue; Eina_Stringshare *ssr = eina_stringshare_add_length(obj->name, dot - obj->name); const Eolian_Object *cobj = eina_hash_find(src->objects, ssr); eina_stringshare_del(ssr); if (cobj) { eolian_state_log_obj(src->state, obj, "the namespace of object '%s' conflicts with %s:%d:%d", obj->name, cobj->file, cobj->line, cobj->column); ret = EINA_FALSE; } } eina_iterator_free(itr); return ret; } Eina_Bool database_check(const Eolian_State *state) { Eina_Bool ret = EINA_TRUE; /* check for extra dependencies */ Eina_Iterator *itr = eolian_state_units_get(state); const Eolian_Unit *unit; EINA_ITERATOR_FOREACH(itr, unit) { if (!_check_unit(unit)) ret = EINA_FALSE; } eina_iterator_free(itr); /* namespace checks */ if (!_check_namespaces(&state->main.unit)) ret = EINA_FALSE; return ret; }