forked from enlightenment/efl
308 lines
8.1 KiB
C
308 lines
8.1 KiB
C
#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;
|
|
}
|