eo: Add debug_name read-only property to ease debugging
authorJean-Philippe Andre <jp.andre@samsung.com>
Fri, 14 Jul 2017 06:57:36 +0000 (15:57 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Fri, 4 Aug 2017 01:24:03 +0000 (10:24 +0900)
This will include the following information, by default:
 - class name
 - whether the class is an override
 - eo id (pointer)
 - refcount
 - name if one was set (Efl.Object property)

This also supports classes, which is why it's an EAPI in eo.c
and not only a method of Efl.Object

This can be overriden by subclasses using the empty method
Efl.Object.debug_name_override.get

If the function is overriden, then the returned string is used
as is and so it is left to the subclass to include all the
necessary information (as above). This can easily be achieved
by calling efl_debug_name_get(efl_super()) and then concatenating
the strings.

Think of this function as something like Java's toString(), but
only for debugging (i.e. a string class should not just return
its string value).

@feature

src/lib/eo/Eo.h
src/lib/eo/efl_object.eo
src/lib/eo/eo.c
src/lib/eo/eo_base_class.c
src/lib/eo/eo_ptr_indirection.h

index 44610e4..16617e9 100644 (file)
@@ -691,6 +691,23 @@ EAPI Eina_Bool efl_isa(const Eo *obj, const Efl_Class *klass);
 EAPI const char *efl_class_name_get(const Efl_Class *klass);
 
 /**
+ * @brief Gets a debug name for this object
+ * @param obj_id The object (or class)
+ * @return A name to use in logs and for other debugging purposes
+ *
+ * Note that subclasses can override Efl.Object "debug_name_override" to
+ * provide more meaningful debug strings. The standard format includes the
+ * class name, the object ID (this @p obj_id), the reference count and
+ * optionally the object name (as defined by Efl.Object.name).
+ *
+ * This might return a temporary string, as created by eina_slstr, which means
+ * that a main loop should probably be running.
+ *
+ * @since 1.21
+ */
+EAPI const char *efl_debug_name_get(const Eo *obj_id);
+
+/**
  * @}
  */
 
index 3318875..31861a6 100644 (file)
@@ -81,6 +81,16 @@ abstract Efl.Object ()
            comment: string @nullable; [[The comment]]
          }
       }
+      @property debug_name_override {
+         [[ A read-only name for this object used for debugging.
+
+            @since 1.21
+         ]]
+         get {}
+         values {
+            name: string; [[A name including class name and object name.]]
+         }
+      }
       @property event_global_freeze_count @class {
          get {
             [[Return freeze events of object.
index 50ddddd..72db1dd 100644 (file)
@@ -2476,6 +2476,67 @@ err:
    return EINA_FALSE;
 }
 
+EAPI const char *
+efl_debug_name_get(const Eo *obj_id)
+{
+   const char *override = "";
+   const char *name, *clsname, *ret;
+
+   if (!obj_id) return "(null)";
+
+   if (_eo_is_a_class(obj_id))
+     {
+        const char *clstype;
+
+        EO_CLASS_POINTER(obj_id, klass);
+        if (!klass || !klass->desc)
+          return eina_slstr_printf("Invalid_Class_ID(invalid)@%p", obj_id);
+
+        switch (klass->desc->type)
+          {
+           case EFL_CLASS_TYPE_REGULAR: clstype = "regular"; break;
+           case EFL_CLASS_TYPE_REGULAR_NO_INSTANT: clstype = "abstract"; break;
+           case EFL_CLASS_TYPE_INTERFACE: clstype = "interface"; break;
+           case EFL_CLASS_TYPE_MIXIN: clstype = "mixin"; break;
+           default: clstype = "invalid"; break;
+          }
+
+        return eina_slstr_printf("%s(%s)@%p", klass->desc->name, clstype, obj_id);
+     }
+
+   EO_OBJ_POINTER(obj_id, obj);
+   if (!obj) return eina_slstr_printf("Invalid_Object_ID@%p", obj_id);
+
+   if (!obj->cur_klass)
+     {
+        ret = efl_debug_name_override_get(obj_id);
+        if (ret) goto end;
+     }
+   else
+     {
+        if (obj->super)
+          ret = efl_debug_name_override_get(efl_super(obj_id, (Efl_Class *) obj->cur_klass->header.id));
+        else
+          ret = efl_debug_name_override_get(efl_cast(obj_id, (Efl_Class *) obj->cur_klass->header.id));
+        obj->super = EINA_FALSE;
+        obj->cur_klass = NULL;
+        if (ret) goto end;
+     }
+
+   name = efl_name_get(obj_id);
+   clsname = obj->klass->desc->name;
+   if (_obj_is_override(obj)) override = "(override)";
+
+   if (name)
+     ret = eina_slstr_printf("%s%s@%p[%d]:'%s'", clsname, override, obj_id, (int) obj->refcount, name);
+   else
+     ret = eina_slstr_printf("%s%s@%p[%d]", clsname, override, obj_id, (int) obj->refcount);
+
+end:
+   EO_OBJ_DONE(obj_id);
+   return ret;
+}
+
 EAPI int
 efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_Array_Item *b)
 {
index 6d05aed..ceea226 100644 (file)
@@ -572,6 +572,12 @@ _efl_object_comment_get(Eo *obj EINA_UNUSED, Efl_Object_Data *pd)
    return pd->ext->comment;
 }
 
+EOLIAN static const char *
+_efl_object_debug_name_override_get(Eo *obj_id EINA_UNUSED, Efl_Object_Data *pd EINA_UNUSED)
+{
+   return NULL;
+}
+
 EOLIAN static void
 _efl_object_del(const Eo *obj, Efl_Object_Data *pd EINA_UNUSED)
 {
index c0aaff8..9cde5ba 100644 (file)
@@ -69,7 +69,7 @@ void _eo_pointer_error(const Eo *obj_id, const char *func_name, const char *file
 #define EO_CLASS_POINTER(klass_id, klass)   \
    _Efl_Class *klass; \
    do { \
-      klass = _eo_class_pointer_get(klass_id, __FUNCTION__, __FILE__, __LINE__); \
+      klass = _eo_class_pointer_get(klass_id); \
    } while (0)
 
 #define EO_CLASS_POINTER_PROXY(klass_id, klass)   \