csharp: cleanup concrete class
authorYeongjong Lee <yj34.lee@samsung.com>
Wed, 22 Jan 2020 22:30:13 +0000 (07:30 +0900)
committerJongmin Lee <jm105.lee@samsung.com>
Mon, 27 Jan 2020 21:06:49 +0000 (06:06 +0900)
Summary:
Concrete class is only used to call static member of NativeMethod. they don't
need any inheritance and implementation of c functions.

Depends on D9893

Test Plan: ninja test

Reviewers: lauromoura, felipealmeida

Subscribers: Jaehyun_Cho, woohyun, segfaultxavi, cedric, #reviewers, #committers

Tags: #efl

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

src/bin/eolian_mono/eolian/mono/events.hh
src/bin/eolian_mono/eolian/mono/klass.hh
src/bin/eolian_mono/eolian/mono/name_helpers.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.c
src/tests/efl_mono/dummy_test_object.eo

index 7405f8c..b6cb4aa 100644 (file)
@@ -131,7 +131,7 @@ struct unpack_event_args_visitor
    }
    bool operator()(grammar::attributes::klass_name const& cls) const
    {
-      return as_generator("(Efl.Eo.Globals.CreateWrapperFor(info) as " + name_helpers::klass_full_concrete_name(cls) + ")").generate(sink, attributes::unused, *context);
+      return as_generator("(Efl.Eo.Globals.CreateWrapperFor(info) as " + name_helpers::klass_full_interface_name(cls) + ")").generate(sink, attributes::unused, *context);
    }
    bool operator()(attributes::complex_type_def const& types) const
    {
index 32586c9..cdca63c 100644 (file)
@@ -197,98 +197,9 @@ struct klass
          auto concrete_cxt = context_add_tag(class_context{class_context::concrete,
                                              name_helpers::klass_full_concrete_or_interface_name(cls)},
                                              context);
-         auto concrete_name = name_helpers::klass_concrete_name(cls);
-         auto interface_name = name_helpers::klass_interface_name(cls);
 
-         // We can't make these internal yet as they have methods that are used by
-         // other classes that implement the interface.
-         if(!as_generator
-            (
-             documentation(1)
-             << scope_tab << "public sealed " << (is_partial ? "partial ":"") << "class " << concrete_name << " :\n"
-             << scope_tab(2) << (root ? "Efl.Eo.EoWrapper" : "") << (klass_full_concrete_or_interface_name % "")
-             << ",\n" << scope_tab(2) << interface_name
-             << *(",\n" << scope_tab(2) << name_helpers::klass_full_concrete_or_interface_name) << "\n"
-             << scope_tab << "{\n"
-            ).generate(sink, std::make_tuple(cls, inherit_classes, inherit_interfaces), concrete_cxt))
-              return false;
-
-         if (!generate_fields(sink, cls, concrete_cxt))
-           return false;
-
-         if (!as_generator
-            (
-             scope_tab(2) << "/// <summary>Subclasses should override this constructor if they are expected to be instantiated from native code.\n"
-             << scope_tab(2) << "/// Do not call this constructor directly.</summary>\n"
-             << scope_tab(2) << "/// <param name=\"ch\">Tag struct storing the native handle of the object being constructed.</param>\n"
-             << scope_tab(2) << "private " << concrete_name << "(ConstructingHandle ch) : base(ch)\n"
-             << scope_tab(2) << "{\n"
-             << scope_tab(2) << "}\n\n"
-            )
-            .generate(sink, attributes::unused, concrete_cxt))
-           return false;
-
-         if (!as_generator
-            (
-             scope_tab(2) << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(concrete_cxt).actual_library_name(cls.filename)
-             << ")] internal static extern System.IntPtr\n"
-             << scope_tab(2) << scope_tab << name_helpers::klass_get_name(cls) << "();\n\n"
-             << scope_tab(2) << "/// <summary>Initializes a new instance of the <see cref=\"" << interface_name << "\"/> class.\n"
-             << scope_tab(2) << "/// Internal usage: This is used when interacting with C code and should not be used directly.</summary>\n"
-             << scope_tab(2) << "/// <param name=\"wh\">The native pointer to be wrapped.</param>\n"
-             << scope_tab(2) << "private " << concrete_name << "(Efl.Eo.WrappingHandle wh) : base(wh)\n"
-             << scope_tab(2) << "{\n"
-             << scope_tab(2) << "}\n\n"
-            )
-            .generate(sink, attributes::unused, concrete_cxt))
-           return false;
-
-         if (!generate_events(sink, cls, concrete_cxt))
-             return false;
-
-         if (!as_generator(lit("#pragma warning disable CS0628\n")).generate(sink, attributes::unused, concrete_cxt))
-            return false;
-
-         // Parts
-         if(!as_generator(*(part_definition))
-            .generate(sink, cls.parts, concrete_cxt)) return false;
-
-         // Concrete function definitions
-         auto implemented_methods = helpers::get_all_implementable_methods(cls, concrete_cxt);
-         if(!as_generator(*(function_definition))
-            .generate(sink, implemented_methods, concrete_cxt)) return false;
-
-         // Async wrappers
-         if(!as_generator(*(async_function_definition)).generate(sink, implemented_methods, concrete_cxt))
-           return false;
-
-         // Property wrappers
-         if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, cls.properties, concrete_cxt))
-           return false;
-
-         for (auto&& klass : helpers::non_implemented_interfaces(cls, concrete_cxt))
-           {
-              attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
-              if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, c.properties, concrete_cxt))
-                return false;
-           }
-
-         if (!as_generator(lit("#pragma warning restore CS0628\n")).generate(sink, attributes::unused, concrete_cxt))
-            return false;
-
-         // Copied from nativeinherit class, used when setting up providers.
-         if(!as_generator(
-              scope_tab(2) << "private static IntPtr GetEflClassStatic()\n"
-              << scope_tab(2) << "{\n"
-              << scope_tab(2) << scope_tab << "return " << name_helpers::klass_get_full_name(cls) << "();\n"
-              << scope_tab(2) << "}\n\n"
-           ).generate(sink, attributes::unused, concrete_cxt))
-           return false;
-
-         if(!generate_native_inherit_class(sink, cls, change_indentation(indent.inc(), concrete_cxt)))
+         if(!generate_native_inherit_class(sink, cls, change_indentation(indent, concrete_cxt)))
            return true;
-
-         if(!as_generator(scope_tab << "}\n").generate(sink, attributes::unused, concrete_cxt)) return false;
        }
 
      // Inheritable class
@@ -431,6 +342,7 @@ struct klass
          auto inherit_name = name_helpers::klass_inherit_name(cls);
          auto implementable_methods = helpers::get_all_registerable_methods(cls, context);
          bool root = !helpers::has_regular_ancestor(cls);
+         bool is_concrete = context_find_tag<class_context>(context).current_wrapper_kind == class_context::concrete;
          auto const& indent = current_indentation(inative_cxt).inc();
          std::string klass_since;
 
@@ -451,11 +363,23 @@ struct klass
              << klass_since
              << indent << "/// </summary>\n"
              << indent << "[EditorBrowsable(EditorBrowsableState.Never)]\n"
-             << indent << "internal new class " << native_inherit_name << " : " << (root ? "Efl.Eo.EoWrapper.NativeMethods" : base_name) << "\n"
+             << indent << "internal " << (is_concrete ? "" : "new ") << "class " << native_inherit_name << " : " << (root ? "Efl.Eo.EoWrapper.NativeMethods" : base_name) << "\n"
              << indent << "{\n"
             ).generate(sink, attributes::unused, inative_cxt))
            return false;
 
+         if(is_concrete)
+           {
+              if (!as_generator
+                 (
+                  scope_tab(2) << "[System.Runtime.InteropServices.DllImport(" << context_find_tag<library_context>(context).actual_library_name(cls.filename)
+                  << ")] internal static extern System.IntPtr\n"
+                  << scope_tab(2) << scope_tab << name_helpers::klass_get_name(cls) << "();\n"
+                 )
+                 .generate(sink, attributes::unused, inative_cxt))
+                return false;
+           }
+
          if(implementable_methods.size() >= 1)
            {
               if(!as_generator(
@@ -506,7 +430,7 @@ struct klass
            ).generate(sink, attributes::unused, inative_cxt))
              return false;
 
-         if (!root || context_find_tag<class_context>(context).current_wrapper_kind != class_context::concrete)
+         if (!root || !is_concrete)
            if(!as_generator(indent << scope_tab << scope_tab << "descs.AddRange(base.GetEoOps(type, false));\n").generate(sink, attributes::unused, inative_cxt))
              return false;
 
index f036059..6aa7f61 100644 (file)
@@ -404,9 +404,7 @@ struct klass_full_interface_name_generator
 template<typename T>
 inline std::string klass_concrete_name(T const& klass)
 {
-   return utils::remove_all(klass.eolian_name, '_') + ((klass.type == attributes::class_type::mixin
-           || klass.type == attributes::class_type::interface_)
-                                                       ? "Concrete" : "");
+   return utils::remove_all(klass.eolian_name, '_');
 }
 
 template<typename  T>
@@ -472,14 +470,19 @@ inline std::string klass_inherit_name(T const& klass)
 }
 
 template<typename T>
-inline std::string klass_native_inherit_name(EINA_UNUSED T const& klass)
+inline std::string klass_native_inherit_name(T const& klass)
 {
-  return "NativeMethods";
+  return ((klass.type == attributes::class_type::mixin
+           || klass.type == attributes::class_type::interface_) ? klass_interface_name(klass) : "") + "NativeMethods";
 }
 
 template<typename T>
 inline std::string klass_full_native_inherit_name(T const& klass)
 {
+  if(klass.type == attributes::class_type::mixin
+     || klass.type == attributes::class_type::interface_)
+    return join_namespaces(klass.namespaces, '.', managed_namespace) + klass_native_inherit_name(klass);
+
   return klass_full_concrete_name(klass) + "." + klass_native_inherit_name(klass);
 }
 
@@ -492,6 +495,10 @@ inline std::string klass_get_name(T const& clsname)
 template<typename T>
 inline std::string klass_get_full_name(T const& clsname)
 {
+  if(clsname.type == attributes::class_type::mixin
+     || clsname.type == attributes::class_type::interface_)
+    return klass_get_name(clsname);
+
   return klass_full_concrete_name(clsname) + "." + klass_get_name(clsname);
 }
 
index 176b551..1f4152a 100644 (file)
@@ -190,11 +190,10 @@ struct to_external_field_convert_generator
       if (klass)
         {
            auto interface_name = name_helpers::klass_full_interface_name(*klass);
-           auto concrete_name = name_helpers::klass_full_concrete_name(*klass);
            if (!as_generator(
                  "\n"
                  << indent << scope_tab << scope_tab << "_external_struct." << string
-                 << " = (" << concrete_name << ") Efl.Eo.Globals.CreateWrapperFor(_internal_struct." << string << ");\n"
+                 << " = (" << interface_name << ") Efl.Eo.Globals.CreateWrapperFor(_internal_struct." << string << ");\n"
                  ).generate(sink, std::make_tuple(field_name, field_name), context))
              return false;
         }
index 192469a..a07153e 100644 (file)
@@ -1003,22 +1003,6 @@ internal static class TraitFunctions
 
     private static IDictionary<System.Type, object> register = new Dictionary<System.Type, object>();
 
-    private static System.Type AsEflInstantiableType(System.Type type)
-    {
-        if (!IsEflObject(type))
-        {
-            return null;
-        }
-
-        if (type.IsInterface)
-        {
-            string fullName = type.FullName + "Concrete";
-            return type.Assembly.GetType(fullName); // That was our best guess...
-        }
-
-        return type; // Not interface, so it should be a concrete.
-    }
-
     public static object RegisterTypeTraits<T>()
     {
         Eina.Log.Debug($"Finding TypeTraits for {typeof(T).Name}");
@@ -1026,14 +1010,6 @@ internal static class TraitFunctions
         var type = typeof(T);
         if (IsEflObject(type))
         {
-            System.Type concrete = AsEflInstantiableType(type);
-            if (concrete == null || !type.IsAssignableFrom(concrete))
-            {
-                throw new Exception("Failed to get a suitable concrete class for this type.");
-            }
-
-            // 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 780735f..ceae250 100644 (file)
@@ -1221,14 +1221,12 @@ internal static class ClassRegister
 
         if (objectType.IsInterface)
         {
-            // Try to get the *Concrete class
-            var assembly = objectType.Assembly;
-            objectType = assembly.GetType(objectType.FullName + "Concrete");
-
-            if (objectType == null)
-            {
+            // Try to get the *NativeMethods class
+            var nativeMethods = (Efl.Eo.NativeClass)System.Attribute.GetCustomAttributes(objectType)?.FirstOrDefault(attr => attr is Efl.Eo.NativeClass);
+            if (nativeMethods == null)
                 return IntPtr.Zero;
-            }
+
+            return nativeMethods.GetEflClass();
         }
 
         var method = objectType.GetMethod("GetEflClassStatic",
index 70e9d29..8d00155 100644 (file)
@@ -385,6 +385,16 @@ class TestEoMultipleChildClasses
 
 class TestCsharpProperties
 {
+
+    private class MyObject : Dummy.TestObject
+    {
+        public MyObject(Efl.Object parent = null) : base(parent)
+        {
+        }
+        private MyObject(ConstructingHandle ch) : base(ch)
+        {
+        }
+    }
     public static void test_csharp_properties()
     {
         var obj = new Dummy.TestObject();
@@ -428,6 +438,28 @@ class TestCsharpProperties
         iface.Dispose();
     }
 
+    public static void test_iface_value_property()
+    {
+        var obj = new Dummy.TestObject();
+        var prop = new MyObject();
+
+        obj.IfaceValueProp = prop;
+        Test.AssertEquals(obj.IfaceValueProp, prop);
+
+        obj.Dispose();
+        prop.Dispose();
+    }
+
+    public static void test_iface_value_from_c()
+    {
+        var obj = new Dummy.TestObject();
+
+        obj.SetIfaceKlassProp(typeof(MyObject));
+        Test.AssertEquals(obj.IfaceValueFromC.GetType(), typeof(MyObject));
+
+        obj.Dispose();
+    }
+
     public static void test_csharp_multi_valued_prop()
     {
         var obj = new Dummy.TestObject();
index b87aff1..687737a 100644 (file)
@@ -38,6 +38,8 @@ typedef struct Dummy_Test_Object_Data
   int prop1;
   int prop2;
   Eo *hidden_object;
+  Dummy_Test_Iface *iface_value_prop;
+  Efl_Class *iface_klass;
 
   // Containers passed to C# as iterator/accessors
   Eina_Array *out_array;
@@ -4784,6 +4786,26 @@ Eo *_dummy_test_object_hidden_object_get(EINA_UNUSED const Eo *obj, Dummy_Test_O
     return pd->hidden_object;
 }
 
+Dummy_Test_Iface *_dummy_test_object_iface_value_prop_get(EINA_UNUSED const Eo *obj, Dummy_Test_Object_Data *pd)
+{
+    return pd->iface_value_prop;
+}
+
+void _dummy_test_object_iface_value_prop_set(EINA_UNUSED Eo *obj, Dummy_Test_Object_Data *pd, Dummy_Test_Iface *prop)
+{
+    pd->iface_value_prop = prop;
+}
+
+void _dummy_test_object_iface_klass_prop_set(EINA_UNUSED Eo *obj, Dummy_Test_Object_Data *pd, Efl_Class *klass)
+{
+    pd->iface_klass = klass;
+}
+
+Dummy_Test_Iface *_dummy_test_object_iface_value_from_c_get(const Eo *obj, Dummy_Test_Object_Data *pd)
+{
+    return efl_add(pd->iface_klass, (Eo*)obj);
+}
+
 // Inherit
 int _dummy_inherit_helper_receive_dummy_and_call_int_out(Dummy_Test_Object *x)
 {
index cf2ae7c..ee24e5e 100644 (file)
@@ -1664,6 +1664,23 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface {
             obj: Efl.Object;
          }
       }
+      @property iface_value_prop {
+         values {
+            prop: Dummy.Test_Iface;
+         }
+      }
+      @property iface_klass_prop {
+         set {}
+         values {
+            klass: Efl.Class;
+         }
+      }
+      @property iface_value_from_c {
+         get {}
+         values {
+            prop: Dummy.Test_Iface;
+         }
+      }
    }
    implements {
       Efl.Object.constructor;