csharp: Make classes abstract and rework casting
authorLauro Moura <lauromoura@expertisesolutions.com.br>
Fri, 5 Apr 2019 22:53:37 +0000 (19:53 -0300)
committerWonki Kim <wonki_.kim@samsung.com>
Mon, 8 Apr 2019 01:50:03 +0000 (10:50 +0900)
Summary:
Abstract Eo classes are now proper C# abstract classes.

As a side effect, returning Eo instances from native code was reworked
to return instances of their actual Eo classes instead of previous
behavior of returning a generic Efl.Object and using static_cast.

Instead of `var window = Efl.Ui.Win.static_cast(widget.GetParent());`
Use `var window = widget.GetParent() as Efl.Ui.Win;`

Another side effect was that `efl_constructor` was removed from the list
of supported `Efl.Object` overrides. It is invoked inside
`efl_add_internal_start`, before the bindings makes the association of
the newly created EoId with the C# instance that created it, making the
managed delegate meaningless. C# users then can use regular C#
constructors to initialize fields.

Also changed to set the private data of C#-inherited classes before the
call to constructing methods (aka constructor parameters) so C# classes
can override them correctly.

Fixes T7778
Fixes T7757

Reviewers: vitor.sousa, felipealmeida, segfaultxavi

Reviewed By: vitor.sousa, segfaultxavi

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Maniphest Tasks: T7778, T7757, T7702

Differential Revision: https://phab.enlightenment.org/D8550

src/bin/eolian_mono/eolian/mono/blacklist.hh
src/bin/eolian_mono/eolian/mono/events.hh
src/bin/eolian_mono/eolian/mono/function_definition.hh
src/bin/eolian_mono/eolian/mono/klass.hh
src/bin/eolian_mono/eolian/mono/part_definition.hh
src/bin/eolian_mono/eolian/mono/struct_definition.hh
src/bindings/mono/eina_mono/eina_container_common.cs
src/bindings/mono/eo_mono/iwrapper.cs
src/tests/efl_mono/Eo.cs
src/tests/efl_mono/dummy_test_object.eo
src/tests/efl_mono/libefl_mono_native_test.c

index df94b6a..02cda67 100644 (file)
@@ -16,6 +16,7 @@ inline bool is_function_blacklisted(std::string const& c_name)
 {
   return
     c_name == "efl_event_callback_array_priority_add"
+    || c_name == "efl_constructor"
     || c_name == "efl_player_position_get"
     || c_name == "efl_ui_widget_focus_set"
     || c_name == "efl_ui_widget_focus_get"
index f688602..ea042fb 100644 (file)
@@ -73,7 +73,7 @@ struct unpack_event_args_visitor
    }
    bool operator()(grammar::attributes::klass_name const& cls) const
    {
-      return as_generator("new " + name_helpers::klass_full_concrete_name(cls) + "(evt.Info)").generate(sink, attributes::unused, *context);
+      return as_generator("(Efl.Eo.Globals.CreateWrapperFor(evt.Info) as " + name_helpers::klass_full_concrete_name(cls) + ")").generate(sink, attributes::unused, *context);
    }
    bool operator()(attributes::complex_type_def const&) const
    {
index 0d6eff6..3abf82f 100644 (file)
@@ -103,7 +103,7 @@ struct native_function_definition_generator
         /****/
         << scope_tab << scope_tab << "Eina.Log.Debug(\"function " << string << " was called\");\n"
         /****/
-        << scope_tab << scope_tab << "Efl.Eo.IWrapper wrapper = Efl.Eo.Globals.data_get(pd);\n"
+        << scope_tab << scope_tab << "Efl.Eo.IWrapper wrapper = Efl.Eo.Globals.PrivateDataGet(pd);\n"
         << scope_tab << scope_tab << "if(wrapper != null) {\n"
         << scope_tab << scope_tab << scope_tab << eolian_mono::native_function_definition_preamble()
         << scope_tab << scope_tab << scope_tab << "try {\n"
index 20045de..2f0bc62 100644 (file)
 namespace eolian_mono {
 
 template <typename OutputIterator, typename Context>
-static bool generate_static_cast_method(OutputIterator sink, grammar::attributes::klass_def const& cls, Context const &context)
-{
-   return as_generator(
-       scope_tab << "///<summary>Casts obj into an instance of this type.</summary>\n"
-       << scope_tab << "public " << (helpers::has_regular_ancestor(cls) ? "new " : "") <<"static " << name_helpers::klass_concrete_name(cls) << " static_cast(Efl.Object obj)\n"
-       << scope_tab << "{\n"
-       << scope_tab << scope_tab << "if (obj == null)\n"
-       << scope_tab << scope_tab << scope_tab << "throw new System.ArgumentNullException(\"obj\");\n"
-       << scope_tab << scope_tab << "return new " << name_helpers::klass_concrete_name(cls) << "(obj.NativeHandle);\n"
-       << scope_tab << "}\n"
-       ).generate(sink, nullptr, context);
-}
-
-template <typename OutputIterator, typename Context>
 static bool generate_equals_method(OutputIterator sink, Context const &context)
 {
    return as_generator(
@@ -110,7 +96,7 @@ struct klass
          suffix = "CLASS";
          break;
        case attributes::class_type::abstract_:
-         class_type = "class";
+         class_type = "abstract class";
          suffix = "CLASS";
          break;
        case attributes::class_type::mixin:
@@ -207,7 +193,7 @@ struct klass
                     });
 
      // Concrete class for interfaces, mixins, etc.
-     if(class_type != "class")
+     if(class_type != "class" && class_type != "abstract class")
        {
          auto concrete_cxt = context_add_tag(class_context{class_context::concrete}, context);
          auto concrete_name = name_helpers::klass_concrete_name(cls);
@@ -234,7 +220,7 @@ struct klass
              << ")] internal static extern System.IntPtr\n"
              << scope_tab << scope_tab << name_helpers::klass_get_name(cls) << "();\n"
              << scope_tab << "///<summary>Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>\n"
-             << scope_tab << "public " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
+             << scope_tab << "private " << concrete_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
              << scope_tab << "{\n"
              << scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
              << scope_tab << scope_tab << "RegisterEventProxies();\n"
@@ -246,9 +232,6 @@ struct klass
          if (!generate_dispose_methods(sink, cls, concrete_cxt))
            return false;
 
-         if (!generate_static_cast_method(sink, cls, concrete_cxt))
-           return false;
-
          if (!generate_equals_method(sink, concrete_cxt))
            return false;
 
@@ -296,7 +279,7 @@ struct klass
        }
 
      // Inheritable class
-     if(class_type == "class")
+     if(class_type == "class" || class_type == "abstract class")
        {
         auto inherit_cxt = context_add_tag(class_context{class_context::inherit}, context);
 
@@ -327,9 +310,6 @@ struct klass
          if (!generate_dispose_methods(sink, cls, inherit_cxt))
            return false;
 
-         if (!generate_static_cast_method(sink, cls, inherit_cxt))
-           return false;
-
          if (!generate_equals_method(sink, inherit_cxt))
            return false;
 
@@ -430,7 +410,7 @@ struct klass
               << scope_tab << "}\n"
            ).generate(sink, attributes::unused, inative_cxt))
            return false;
-         
+
          // Native method definitions
          if(!as_generator(*(native_function_definition(cls)))
             .generate(sink, helpers::get_all_implementable_methods(cls), inative_cxt)) return false;
@@ -534,7 +514,7 @@ struct klass
                      << scope_tab << scope_tab << "FinishInstantiation();\n"
                      << scope_tab << "}\n"
                      << scope_tab << "///<summary>Internal usage: Constructs an instance from a native pointer. This is used when interacting with C code and should not be used directly.</summary>\n"
-                     << scope_tab << "public " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
+                     << scope_tab << "protected " << inherit_name << "(System.IntPtr raw)" << (root ? "" : " : base(raw)") << "\n"
                      << scope_tab << "{\n"
                      << scope_tab << scope_tab << (root ? "handle = raw;\n" : "")
                      << scope_tab << scope_tab << "RegisterEventProxies();\n"
@@ -542,6 +522,23 @@ struct klass
                  ).generate(sink, std::make_tuple(constructors, constructors, constructors), context))
          return false;
 
+     // Some abstract classes (like Efl.App) have a simple regular class that is used to instantiate them
+     // in a controlled manner. These fake-private classes can be returned from C and we use a similarly-named
+     // private class to be able to instantiate them when they get to the C# world.
+     if (cls.type == attributes::class_type::abstract_)
+     {
+         if (!as_generator(
+                scope_tab << "[Efl.Eo.PrivateNativeClass]\n"
+                << scope_tab << "private class " << inherit_name << "Realized : " << inherit_name << "\n"
+                << scope_tab << "{\n"
+                << scope_tab << scope_tab << "private " << inherit_name << "Realized(IntPtr ptr) : base(ptr)\n"
+                << scope_tab << scope_tab << "{\n"
+                << scope_tab << scope_tab << "}\n"
+                << scope_tab << "}\n"
+            ).generate(sink, attributes::unused, context))
+           return false;
+     }
+
      // Internal constructors
      if (!root)
      {
@@ -564,13 +561,14 @@ struct klass
              << scope_tab << scope_tab << "}\n"
              << scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_start(actual_klass, parent);\n"
              << scope_tab << scope_tab << "RegisterEventProxies();\n"
+             << scope_tab << scope_tab << "if (inherited)\n"
+             << scope_tab << scope_tab << "{\n"
+             << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.PrivateDataSet(this);\n"
+             << scope_tab << scope_tab << "}\n"
              << scope_tab << "}\n"
 
              << scope_tab << "protected void FinishInstantiation()\n"
              << scope_tab << "{\n"
-             << scope_tab << scope_tab << "if (inherited) {\n"
-             << scope_tab << scope_tab << scope_tab << "Efl.Eo.Globals.data_set(this);\n"
-             << scope_tab << scope_tab << "}\n"
              << scope_tab << scope_tab << "handle = Efl.Eo.Globals.instantiate_end(handle);\n"
              << scope_tab << scope_tab << "Eina.Error.RaiseIfUnhandledException();\n"
              << scope_tab << "}\n"
index 7894086..06cdf15 100644 (file)
@@ -27,8 +27,7 @@ struct part_definition_generator
                        << scope_tab << "{\n"
                        << scope_tab << scope_tab << "get\n"
                        << scope_tab << scope_tab << "{\n"
-                       << scope_tab << scope_tab << scope_tab << "Efl.Object obj = Efl.IPartNativeInherit.efl_part_get_ptr.Value.Delegate(NativeHandle, \"" << part.name << "\");\n"
-                       << scope_tab << scope_tab << scope_tab << "return " << part_klass_name << ".static_cast(obj);\n"
+                       << scope_tab << scope_tab << scope_tab << "return Efl.IPartNativeInherit.efl_part_get_ptr.Value.Delegate(NativeHandle, \"" << part.name << "\") as " << part_klass_name << ";\n"
                        << scope_tab << scope_tab << "}\n"
                        << scope_tab << "}\n"
             ).generate(sink, part.documentation, context);
index 35f7725..c059dd9 100644 (file)
@@ -159,10 +159,8 @@ struct to_external_field_convert_generator
            if (!as_generator(
                  "\n"
                  << indent << scope_tab << scope_tab << "_external_struct." << string
-                 << " = (" << concrete_name << ") System.Activator.CreateInstance(typeof("
-                 << concrete_name << "), new System.Object[] {_internal_struct." << string << "});\n"
-                 << indent << scope_tab << scope_tab << "Efl.Eo.Globals.efl_ref(_internal_struct." << string << ");\n")
-               .generate(sink, std::make_tuple(field_name, field_name, field_name), context))
+                 << " = (" << concrete_name << ") Efl.Eo.Globals.CreateWrapperFor(_internal_struct." << string << ");\n"
+                 ).generate(sink, std::make_tuple(field_name, field_name), context))
              return false;
         }
       else if (field.type.c_type == "Eina_Binbuf *" || field.type.c_type == "const Eina_Binbuf *")
index 73a3a0f..9695c09 100644 (file)
@@ -4,6 +4,7 @@ using System;
 using System.Linq;
 using System.Runtime.InteropServices;
 using System.Collections.Generic;
+using System.Reflection;
 
 using Eina.Callbacks;
 using static Eina.HashNativeFunctions;
@@ -196,13 +197,6 @@ public class StringElementTraits : IBaseElementTraits<string>
 
 public class EflObjectElementTraits<T> : IBaseElementTraits<T>
 {
-    private System.Type concreteType = null;
-
-    public EflObjectElementTraits(System.Type concrete)
-    {
-        concreteType = concrete;
-    }
-
     public IntPtr ManagedToNativeAlloc(T man)
     {
         IntPtr h = ((Efl.Eo.IWrapper)man).NativeHandle;
@@ -290,7 +284,7 @@ public class EflObjectElementTraits<T> : IBaseElementTraits<T>
             return default(T);
         }
 
-        return (T)Activator.CreateInstance(concreteType, Efl.Eo.Globals.efl_ref(nat));
+        return (T) Efl.Eo.Globals.CreateWrapperFor(nat, shouldIncRef: true);
     }
 
     public T NativeToManagedRef(IntPtr nat)
@@ -762,7 +756,9 @@ public static class TraitFunctions
                 throw new Exception("Failed to get a suitable concrete class for this type.");
             }
 
-            traits = new EflObjectElementTraits<T>(concrete);
+            // No need to pass concrete as the traits class will use reflection to get the actually most
+            // derived type returned.
+            traits = new EflObjectElementTraits<T>();
         }
         else if (IsString(type))
         {
index 43835aa..3600cde 100644 (file)
@@ -4,6 +4,7 @@ using System;
 using System.Runtime.InteropServices;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Reflection;
 using System.Threading;
 
 using static Eina.NativeCustomExportFunctions;
@@ -289,7 +290,7 @@ public class Globals
         return ifaces_lst;
     }
 
-    private static Efl.Eo.NativeClass get_native_class(System.Type type)
+    private static Efl.Eo.NativeClass GetNativeClass(System.Type type)
     {
         var attrs = System.Attribute.GetCustomAttributes(type);
         foreach (var attr in attrs)
@@ -306,7 +307,7 @@ public class Globals
     public static byte class_initializer_call(IntPtr klass, System.Type type)
     {
         Eina.Log.Debug($"called with 0x{klass.ToInt64():x} {type}");
-        Efl.Eo.NativeClass nativeClass = get_native_class(type.BaseType);
+        Efl.Eo.NativeClass nativeClass = GetNativeClass(type.BaseType);
 
         if (nativeClass != null)
         {
@@ -320,7 +321,7 @@ public class Globals
             {
                 if (!System.Array.Exists(base_interfaces, element => element == iface))
                 {
-                    var nc = get_native_class(iface);
+                    var nc = GetNativeClass(iface);
                     if (nc != null)
                     {
                         var moredescs = nc.GetEoOps(type);
@@ -442,7 +443,7 @@ public class Globals
         return eo;
     }
 
-    public static void data_set(Efl.Eo.IWrapper obj)
+    public static void PrivateDataSet(Efl.Eo.IWrapper obj)
     {
         Eina.Log.Debug($"Calling data_scope_get with obj {obj.NativeHandle.ToInt64():x} and klass {obj.NativeClass.ToInt64():x}");
         IntPtr pd = Efl.Eo.Globals.efl_data_scope_get(obj.NativeHandle, obj.NativeClass);
@@ -454,7 +455,7 @@ public class Globals
         }
     }
 
-    public static Efl.Eo.IWrapper data_get(IntPtr pd)
+    public static Efl.Eo.IWrapper PrivateDataGet(IntPtr pd)
     {
         EolianPD epd = (EolianPD)Marshal.PtrToStructure(pd, typeof(EolianPD));
         if (epd.pointer != IntPtr.Zero)
@@ -542,6 +543,80 @@ public class Globals
 
         return tcs.Task;
     }
+
+    /// <summary>Returns whether the given type was generated by eolian-mono</summary>
+    /// <param name="managedType">The type to check.</param>
+    /// <returns>True if generated by eolian-mono. False otherwise.</returns>
+    private static bool IsGeneratedClass(System.Type managedType)
+    {
+        return GetNativeClass(managedType) != null;
+    }
+
+    /// <summary>Creates a new wrapper for the given Eo id.
+    ///
+    /// <para>If the Eo was created from a non-generated class (i.e. C#-pure class), it returns
+    /// the C# instance handle stored in the Eo's private data.</para>
+    ///
+    /// <para>For generated-class Eo instance, we use reflection to get the correct C# type to re-wrap
+    /// it.</para>
+    /// </summary>
+    ///
+    /// <param name="handle">The Eo id to be wrapped.</param>
+    /// <param name="shouldIncRef">Whether we should increase the refcount of the Eo instance.</param>
+    /// <returns>The C# wrapper for this instance.</returns>
+    public static Efl.Eo.IWrapper CreateWrapperFor(System.IntPtr handle, bool shouldIncRef=true)
+    {
+        IntPtr eoKlass = efl_class_get(handle);
+
+        if (eoKlass == IntPtr.Zero)
+        {
+            throw new InvalidOperationException($"Can't get Eo class for object handle 0x{handle.ToInt64():x}");
+        }
+
+        var managedType = ClassRegister.GetManagedType(eoKlass);
+
+        if (managedType == null)
+        {
+            IntPtr nativeName = efl_class_name_get(eoKlass);
+            var name = Eina.StringConversion.NativeUtf8ToManagedString(nativeName);
+
+            throw new InvalidOperationException($"Can't get Managed class for object handle 0x{handle.ToInt64():x} with native class [{name}]");
+        }
+
+        // Pure C# classes that inherit from generated classes store their C# instance in their
+        // Eo private data field.
+        if (!IsGeneratedClass(managedType))
+        {
+            Efl.Eo.IWrapper instance = null;
+            IntPtr pd = efl_data_scope_get(handle, eoKlass);
+
+            if (pd != IntPtr.Zero)
+            {
+                instance = PrivateDataGet(pd);
+            }
+
+            return instance;
+        }
+
+        System.Reflection.ConstructorInfo constructor = null;
+
+        try
+        {
+            var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
+            constructor = managedType.GetConstructor(flags, null, new Type[1] { typeof(System.IntPtr) }, null);
+        }
+        catch (InvalidOperationException)
+        {
+            throw new InvalidOperationException($"Can't get constructor for type {managedType}");
+        }
+
+        var ret = constructor.Invoke(new object[1] { handle }) as Efl.Eo.IWrapper;
+
+        if (ret != null && shouldIncRef)
+            Efl.Eo.Globals.efl_ref(handle);
+
+        return ret;
+    }
 } // Globals
 
 public static class Config
@@ -560,7 +635,7 @@ public static class Config
 [System.AttributeUsage(System.AttributeTargets.Class |
                        System.AttributeTargets.Interface,
                        AllowMultiple = false,
-                       Inherited = true)
+                       Inherited = false)
 ]
 public abstract class NativeClass : System.Attribute
 {
@@ -568,6 +643,22 @@ public abstract class NativeClass : System.Attribute
     public abstract System.Collections.Generic.List<Efl_Op_Description> GetEoOps(System.Type type);
 }
 
+/// <summary>Attribute for private native classes.
+///
+/// <para>For internal usage by generated code only.</para></summary>
+public class PrivateNativeClass : NativeClass
+{
+    public override IntPtr GetEflClass()
+    {
+        return IntPtr.Zero;
+    }
+
+    public override System.Collections.Generic.List<Efl_Op_Description> GetEoOps(System.Type type)
+    {
+        return null;
+    }
+}
+
 public interface IWrapper
 {
     /// <summary>Pointer to internal Eo instance.</summary>
@@ -605,6 +696,16 @@ public static class ClassRegister
 
         var klass_type = Efl.Eo.Globals.efl_class_type_get(klass);
 
+        // Check if this is an internal implementation of an abstract class
+        var abstract_impl_suffix = "Realized";
+        if (name.EndsWith(abstract_impl_suffix))
+        {
+            name = name.Substring(0, name.Length - abstract_impl_suffix.Length);
+            var lastDot = name.LastIndexOf(".");
+            var klassName = name.Substring(lastDot + 1);
+            name += "+" + klassName + abstract_impl_suffix; // '+' is the separator for nested classes
+        }
+
         // When converting to managed, interfaces and mixins gets the 'I' prefix.
         if (klass_type == Efl.Eo.Globals.EflClassType.Interface || klass_type == Efl.Eo.Globals.EflClassType.Mixin)
         {
@@ -795,6 +896,12 @@ public class MarshalTest<T, U> : ICustomMarshaler
     public IntPtr MarshalManagedToNative(object ManagedObj)
     {
         Eina.Log.Debug("MarshalTest.MarshallManagedToNative");
+
+        if (ManagedObj == null)
+        {
+            return IntPtr.Zero;
+        }
+
         var r = ((IWrapper)ManagedObj).NativeHandle;
         if (typeof(U) == typeof(OwnTag))
         {
@@ -806,14 +913,7 @@ public class MarshalTest<T, U> : ICustomMarshaler
 
     public object MarshalNativeToManaged(IntPtr pNativeData)
     {
-        Eina.Log.Debug("MarshalTest.MarshalNativeToManaged");
-        if (typeof(U) != typeof(OwnTag))
-        {
-            Efl.Eo.Globals.efl_ref(pNativeData);
-        }
-
-        return Activator.CreateInstance(typeof(T), new System.Object[] {pNativeData});
-        //return null;
+        return Efl.Eo.Globals.CreateWrapperFor(pNativeData, shouldIncRef : typeof(U) != typeof(OwnTag));
     }
 }
 
index 578ad10..f4e3f5d 100644 (file)
@@ -131,7 +131,7 @@ class TestEoParent
 
         Test.AssertEquals(parent, child.GetParent());
 
-        var parent_retrieved = Dummy.TestObject.static_cast(child.GetParent());
+        var parent_retrieved = child.GetParent() as Dummy.TestObject;
         Test.AssertEquals(parent, parent_retrieved);
     }
 
@@ -142,7 +142,7 @@ class TestEoParent
 
         Test.AssertEquals(parent, child.GetParent());
 
-        Dummy.Numberwrapper parent_retrieved = Dummy.Numberwrapper.static_cast(child.GetParent());
+        Dummy.Numberwrapper parent_retrieved = child.GetParent() as Dummy.Numberwrapper;
         Test.AssertEquals(parent, parent_retrieved);
     }
 
@@ -160,7 +160,7 @@ class TestEoParent
 
         Test.AssertEquals(parent, child.GetParent());
 
-        var parent_from_cast = Dummy.TestObject.static_cast(child.GetParent());
+        var parent_from_cast = child.GetParent() as Derived;
         Test.AssertEquals(parent, parent_from_cast);
     }
 }
@@ -430,7 +430,7 @@ class TestInterfaceConcrete
     public static void test_iface_concrete_methods()
     {
         var obj = new Dummy.TestObject();
-        Dummy.ITestIface iface = Dummy.ITestIfaceConcrete.static_cast(obj);
+        Dummy.ITestIface iface = obj.ReturnIface();
 
         iface.IfaceProp = 1970;
         Test.AssertEquals(iface.IfaceProp, 1970);
@@ -443,7 +443,7 @@ class TestProvider
     {
         // Tests only the direction C# -> C
         var obj = new Dummy.TestObject();
-        Dummy.Numberwrapper provider = Dummy.Numberwrapper.static_cast(obj.FindProvider(typeof(Dummy.Numberwrapper)));
+        Dummy.Numberwrapper provider = obj.FindProvider(typeof(Dummy.Numberwrapper)) as Dummy.Numberwrapper;
         Test.AssertEquals(provider.GetType(), typeof(Dummy.Numberwrapper));
         Test.AssertEquals(provider.GetNumber(), 1999);
     }
index 5475c81..eabb6cd 100644 (file)
@@ -111,6 +111,10 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface {
          return: Dummy.Test_Object;
       }
 
+      return_iface {
+         return: Dummy.Test_Iface;
+      }
+
       int_out {
          params {
             @in x: int;
index 7b4dd1a..8575eba 100644 (file)
 # endif
 #endif
 
+#include "dummy_test_iface.eo.h"
+#include "dummy_inherit_iface.eo.h"
 #include "dummy_numberwrapper.eo.h"
 #include "dummy_test_object.eo.h"
 #include "dummy_child.eo.h"
-#include "dummy_test_iface.eo.h"
-#include "dummy_inherit_iface.eo.h"
 #include "dummy_inherit_helper.eo.h"
 #include "dummy_part_holder.eo.h"
 
@@ -172,6 +172,11 @@ Efl_Object *_dummy_test_object_return_null_object(Eo *obj EINA_UNUSED, EINA_UNUS
   return NULL;
 }
 
+Dummy_Test_Iface *_dummy_test_object_return_iface(Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd)
+{
+  return obj;
+}
+
 void _dummy_test_object_int_out(EINA_UNUSED Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd, int x, int *y)
 {
     *y = -x;