edje: Improve error report with efl_part misuse

This improves a rare error message when a function is called on an
efl_part() that does not implement it. Example: calling a swallow
function on a non-swallow part.

This isn't entirely fool-proof but should already help quite a bit.

This also changes how the efl_part proxies are stored: the variable
is not reset to NULL every time we use it, instead we check it in
the del intercept.

Note: _part_reuse_error() can not be enabled inside
_internal_proxy_get because there are valid use cases such as:

  func1(efl_part(obj, part), func2(efl_part(obj, part), ...), ...)

Here we use two efl_part() at the same time, on the same object,
but we haven't entered "func1" yet when we are reaching the second
call to efl_part(). This is completely valid and there is pretty
much no way to detect this.

I think I will improve this later with a core function on
Efl.Object like "debug_string".

Ref T5584
This commit is contained in:
Jean-Philippe Andre 2017-06-22 09:05:41 +09:00
parent 5a98f78ce8
commit 56a74238d1
7 changed files with 131 additions and 53 deletions

View File

@ -2,9 +2,55 @@
#include "edje_part_helper.h"
#define MY_CLASS EFL_CANVAS_LAYOUT_INTERNAL_CLASS
PROXY_IMPLEMENTATION(other, INTERNAL, EINA_FALSE)
PROXY_IMPLEMENTATION(other, MY_CLASS, EINA_FALSE)
#undef PROXY_IMPLEMENTATION
void
_part_reuse_error(Efl_Canvas_Layout_Internal_Data *pd)
{
const char *typestr = "UNKNOWN";
Edje *ed;
// TODO: Enable full debug only for eo_debug?
// Don't trust pd->ed as it may be invalid now.
ed = efl_data_scope_safe_get(pd->obj, EDJE_OBJECT_CLASS);
if (!ed)
{
ERR("A previous misuse of efl_part has been detected. Handles returned "
"by efl_part() are valid for a single function call. Did you call "
"a non implemented function? obj: %p has been deleted!", pd->obj);
return;
}
switch (pd->rp->part->type)
{
case EDJE_PART_TYPE_RECTANGLE: typestr = "RECTANGLE"; break;
case EDJE_PART_TYPE_TEXT: typestr = "TEXT"; break;
case EDJE_PART_TYPE_IMAGE: typestr = "IMAGE"; break;
case EDJE_PART_TYPE_SWALLOW: typestr = "SWALLOW"; break;
case EDJE_PART_TYPE_TEXTBLOCK: typestr = "TEXTBLOCK"; break;
case EDJE_PART_TYPE_GRADIENT: typestr = "GRADIENT"; break;
case EDJE_PART_TYPE_GROUP: typestr = "GROUP"; break;
case EDJE_PART_TYPE_BOX: typestr = "BOX"; break;
case EDJE_PART_TYPE_TABLE: typestr = "TABLE"; break;
case EDJE_PART_TYPE_EXTERNAL: typestr = "EXTERNAL"; break;
case EDJE_PART_TYPE_PROXY: typestr = "PROXY"; break;
case EDJE_PART_TYPE_SPACER: typestr = "SPACER"; break;
case EDJE_PART_TYPE_MESH_NODE: typestr = "MESH_NODE"; break;
case EDJE_PART_TYPE_LIGHT: typestr = "LIGHT"; break;
case EDJE_PART_TYPE_CAMERA: typestr = "CAMERA"; break;
case EDJE_PART_TYPE_SNAPSHOT: typestr = "SNAPSHOT"; break;
case EDJE_PART_TYPE_VECTOR: typestr = "VECTOR"; break;
default: break;
}
ERR("A previous misuse of efl_part has been detected. Handles returned "
"by efl_part() are valid for a single function call. Did you call "
"a non implemented function? obj: %p group: '%s' part: '%s' type: %s%s",
pd->obj, ed->group, pd->part, typestr,
ed->delete_me ? ". This object is already deleted." : "");
}
PROXY_INIT(box)
PROXY_INIT(table)
PROXY_INIT(swallow)
@ -24,20 +70,25 @@ _edje_internal_proxy_shutdown(void)
}
void
_edje_real_part_set(Eo *obj, void *ed, void *rp, const char *part)
_edje_real_part_set(Eo *obj, Edje *ed, Edje_Real_Part *rp, const char *part)
{
PROXY_DATA_GET(obj, pd);
Efl_Canvas_Layout_Internal_Data *pd;
pd = efl_data_scope_get(obj, EFL_CANVAS_LAYOUT_INTERNAL_CLASS);
pd->obj = ed->obj;
pd->ed = ed;
pd->rp = rp;
pd->part = part;
pd->temp = 1;
efl_parent_set(obj, pd->ed->obj);
pd->in_call = 0;
efl_parent_set(obj, ed->obj);
}
EOLIAN static Efl_Object *
_efl_canvas_layout_internal_efl_object_finalize(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd)
{
EINA_SAFETY_ON_FALSE_RETURN_VAL(pd->rp && pd->ed && pd->part, NULL);
// Do not use RETURN_VAL() here!
return efl_finalize(efl_super(obj, MY_CLASS));
}
@ -45,6 +96,7 @@ EOLIAN void
_efl_canvas_layout_internal_efl_gfx_geometry_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, int *x, int *y, int *w, int *h)
{
Edje_Real_Part *rp = pd->rp;
PROXY_CALL_BEGIN(pd);
_edje_recalc_do(pd->ed);
if (!rp)
@ -53,6 +105,7 @@ _efl_canvas_layout_internal_efl_gfx_geometry_get(Eo *obj, Efl_Canvas_Layout_Inte
if (y) *y = 0;
if (w) *w = 0;
if (h) *h = 0;
RETURN_VOID;
}
if (x) *x = rp->x;
@ -66,8 +119,10 @@ EOLIAN static void
_efl_canvas_layout_internal_state_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, const char **name, double *val)
{
const char *str;
PROXY_CALL_BEGIN(pd);
if (!name && !val) return;
if (!name && !val)
RETURN_VOID;
str = _edje_object_part_state_get(pd->ed, pd->part, val);
if (name) *name = str;
RETURN_VOID;
@ -76,66 +131,77 @@ _efl_canvas_layout_internal_state_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_value_set(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double dx, double dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_value_set(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_value_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double *dx, double *dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_value_get(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_size_set(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double dw, double dh)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_size_set(pd->ed, pd->part, dw, dh));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_size_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double *dw, double *dh)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_size_get(pd->ed, pd->part, dw, dh));
}
EOLIAN static Efl_Ui_Drag_Dir
_efl_canvas_layout_internal_efl_ui_drag_drag_dir_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_dir_get(pd->ed, pd->part));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_step_set(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double dx, double dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_step_set(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_step_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double *dx, double *dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_step_get(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_step_move(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double dx, double dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_step(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_page_set(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double dx, double dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_page_set(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_page_get(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double *dx, double *dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_page_get(pd->ed, pd->part, dx, dy));
}
EOLIAN static Eina_Bool
_efl_canvas_layout_internal_efl_ui_drag_drag_page_move(Eo *obj, Efl_Canvas_Layout_Internal_Data *pd, double dx, double dy)
{
PROXY_CALL_BEGIN(pd);
RETURN_VAL(_edje_object_part_drag_page(pd->ed, pd->part, dx, dy));
}

View File

@ -5,7 +5,7 @@
#include "../evas/canvas/evas_box.eo.h"
PROXY_IMPLEMENTATION(box, INTERNAL_BOX, EINA_FALSE)
PROXY_IMPLEMENTATION(box, MY_CLASS, EINA_FALSE)
#undef PROXY_IMPLEMENTATION
typedef struct _Part_Item_Iterator Part_Item_Iterator;

View File

@ -5,7 +5,7 @@
static void _external_compose(Eo *obj, Edje *ed, const char *part);
PROXY_IMPLEMENTATION(external, EXTERNAL, EINA_TRUE, _external_compose(proxy, ed, rp->part->name))
PROXY_IMPLEMENTATION(external, MY_CLASS, EINA_TRUE, _external_compose(proxy, ed, rp->part->name))
#undef PROXY_IMPLEMENTATION
static void

View File

@ -8,7 +8,8 @@ struct _Efl_Canvas_Layout_Internal_Data
Edje *ed;
Edje_Real_Part *rp;
const char *part;
unsigned char temp;
Eo *obj;
unsigned char temp, in_call;
};
struct _Part_Item_Iterator
@ -19,26 +20,53 @@ struct _Part_Item_Iterator
Eo *object;
};
void _part_reuse_error(Efl_Canvas_Layout_Internal_Data *pd);
#define PROXY_CALL_BEGIN(pd) do { pd->in_call = 1; } while (0)
#define PROXY_CALL_END(pd) do { pd->in_call = 0; } while (0)
#define PROXY_REF(obj, pd) do { if (!(pd->temp++)) efl_ref(obj); } while(0)
#define PROXY_UNREF(obj, pd) do { if (pd->temp) { if (!(--pd->temp)) efl_del(obj); } } while(0)
#define RETURN_VAL(a) do { typeof(a) _ret = a; PROXY_UNREF(obj, pd); return _ret; } while(0)
#define RETURN_VOID do { PROXY_UNREF(obj, pd); return; } while(0)
#define RETURN_VAL(a) do { typeof(a) _ret = a; PROXY_CALL_END(pd); PROXY_UNREF(obj, pd); return _ret; } while(0)
#define RETURN_VOID do { PROXY_CALL_END(pd); PROXY_UNREF(obj, pd); return; } while(0)
#define PROXY_CALL(a) ({ PROXY_REF(obj, pd); a; })
#define PROXY_STATIC_VAR(type) _##type##_proxy
#ifndef PROXY_ADD_EXTRA_OP
# define PROXY_ADD_EXTRA_OP
#endif
void _edje_real_part_set(Eo *obj, void *ed, void *rp, const char *part);
void _edje_real_part_set(Eo *obj, Edje *ed, Edje_Real_Part *rp, const char *part);
static inline void
_part_proxy_del_cb(Eo *proxy, Eo **static_var)
{
if (*static_var)
{
// FIXME: Enable debug checks only in debug mode
Efl_Canvas_Layout_Internal_Data *pd = efl_data_scope_get
(*static_var, EFL_CANVAS_LAYOUT_INTERNAL_CLASS);
if (pd && pd->temp && !pd->in_call)
_part_reuse_error(pd);
if (*static_var != proxy)
efl_del_intercept_set(*static_var, NULL);
}
if (efl_parent_get(proxy))
{
efl_ref(proxy);
efl_parent_set(proxy, NULL);
}
efl_reuse(proxy);
*static_var = proxy;
}
/* ugly macros to avoid code duplication */
#define PROXY_RESET(type) \
do { if (_ ## type ## _proxy) \
do { if (PROXY_STATIC_VAR(type)) \
{ \
efl_del_intercept_set(_ ## type ## _proxy, NULL); \
efl_del(_ ## type ## _proxy); \
_ ## type ## _proxy = NULL; \
efl_del_intercept_set(PROXY_STATIC_VAR(type), NULL); \
efl_del(PROXY_STATIC_VAR(type)); \
PROXY_STATIC_VAR(type) = NULL; \
} } while (0)
#define PROXY_INIT(type) \
@ -46,27 +74,16 @@ void \
_ ## type ## _shutdown(void); \
#define PROXY_DATA_GET(obj, pd) \
Efl_Canvas_Layout_Internal_Data *pd = efl_data_scope_get(obj, EFL_CANVAS_LAYOUT_INTERNAL_CLASS)
Efl_Canvas_Layout_Internal_Data *pd = efl_data_scope_get(obj, EFL_CANVAS_LAYOUT_INTERNAL_CLASS); \
PROXY_CALL_BEGIN(pd)
#define PROXY_IMPLEMENTATION(type, TYPE, no_del_cb, ...) \
static Eo * _ ## type ## _proxy = NULL; \
#define PROXY_IMPLEMENTATION(type, KLASS, no_del_cb, ...) \
static Eo * PROXY_STATIC_VAR(type) = NULL; \
\
static void \
_ ## type ## _del_cb(Eo *proxy) \
{ \
if (_ ## type ## _proxy) \
{ \
efl_del_intercept_set(proxy, NULL); \
efl_del(proxy); \
return; \
} \
if (efl_parent_get(proxy)) \
{ \
efl_ref(proxy); \
efl_parent_set(proxy, NULL); \
} \
efl_reuse(proxy); \
_ ## type ## _proxy = proxy; \
_part_proxy_del_cb(proxy, &(PROXY_STATIC_VAR(type))); \
} \
\
void \
@ -81,32 +98,27 @@ _edje_ ## type ## _internal_proxy_get(Edje_Object *obj EINA_UNUSED, Edje *ed, Ed
Efl_Canvas_Layout_Internal_Data *pd; \
Eo *proxy; \
\
pd = efl_data_scope_get(_ ## type ## _proxy, EFL_CANVAS_LAYOUT_INTERNAL_CLASS); \
pd = PROXY_STATIC_VAR(type) ? efl_data_scope_get(PROXY_STATIC_VAR(type), EFL_CANVAS_LAYOUT_INTERNAL_CLASS) : NULL; \
if (!pd) \
{ \
if (_ ## type ## _proxy) \
{ \
ERR("Found invalid handle for efl_part. Reset."); \
_ ## type ## _proxy = NULL; \
} \
proxy = efl_add(EFL_CANVAS_LAYOUT_##TYPE##_CLASS, ed->obj, \
_edje_real_part_set(efl_added, ed, rp, rp->part->name)); \
__VA_ARGS__; \
if (!no_del_cb) efl_del_intercept_set(proxy, _ ## type ## _del_cb); \
return proxy; \
if (PROXY_STATIC_VAR(type)) \
ERR("Found invalid handle for efl_part. Reset."); \
PROXY_STATIC_VAR(type) = efl_add(KLASS, ed->obj, _edje_real_part_set(efl_added, ed, rp, rp->part->name)); \
goto end ; \
} \
\
if (EINA_UNLIKELY(pd->temp)) \
{ \
/* warn about misuse, since non-implemented functions may trigger this \
* misuse by accident. */ \
ERR("Misuse of efl_part detected. Handles returned by efl_part() are " \
"valid for a single function call! Did you call a non implemented " \
"function?"); \
/* if (!pd->in_call) _part_reuse_error(pd); */ \
PROXY_STATIC_VAR(type) = efl_add(KLASS, ed->obj, _edje_real_part_set(efl_added, ed, rp, rp->part->name)); \
} \
proxy = _ ## type ## _proxy; \
_ ## type ## _proxy = NULL; \
_edje_real_part_set(proxy, ed, rp, rp->part->name); \
else \
{ \
_edje_real_part_set(PROXY_STATIC_VAR(type), ed, rp, rp->part->name); \
} \
\
end: \
proxy = PROXY_STATIC_VAR(type); \
__VA_ARGS__; \
if (!no_del_cb) efl_del_intercept_set(proxy, _ ## type ## _del_cb); \
return proxy; \

View File

@ -3,7 +3,7 @@
#include "efl_canvas_layout_internal_swallow.eo.h"
#define MY_CLASS EFL_CANVAS_LAYOUT_INTERNAL_SWALLOW_CLASS
PROXY_IMPLEMENTATION(swallow, INTERNAL_SWALLOW, EINA_FALSE)
PROXY_IMPLEMENTATION(swallow, MY_CLASS, EINA_FALSE)
#undef PROXY_IMPLEMENTATION
/* Swallow parts */

View File

@ -5,7 +5,7 @@
#include "../evas/canvas/evas_table.eo.h"
PROXY_IMPLEMENTATION(table, INTERNAL_TABLE, EINA_FALSE)
PROXY_IMPLEMENTATION(table, MY_CLASS, EINA_FALSE)
#undef PROXY_IMPLEMENTATION
typedef struct _Part_Item_Iterator Part_Item_Iterator;

View File

@ -3,7 +3,7 @@
#include "efl_canvas_layout_internal_text.eo.h"
#define MY_CLASS EFL_CANVAS_LAYOUT_INTERNAL_TEXT_CLASS
PROXY_IMPLEMENTATION(text, INTERNAL_TEXT, EINA_FALSE)
PROXY_IMPLEMENTATION(text, MY_CLASS, EINA_FALSE)
#undef PROXY_IMPLEMENTATION
EOLIAN static void