efl-csharp: Add back I prefix for interfaces.
authorLauro Moura <lauromoura@expertisesolutions.com.br>
Thu, 21 Mar 2019 17:38:45 +0000 (14:38 -0300)
committerYeongjong Lee <yj34.lee@samsung.com>
Tue, 2 Apr 2019 03:45:17 +0000 (12:45 +0900)
Summary:
Conforming to C# coding conventions.

For properties, now we only generate a wrapper if its name does not
clash with the name of the class that would be implementing it.

Fixes T7751

Reviewers: vitor.sousa, felipealmeida, segfaultxavi

Reviewed By: vitor.sousa, segfaultxavi

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Maniphest Tasks: T7751

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

12 files changed:
src/bin/eolian_mono/eolian/mono/blacklist.hh
src/bin/eolian_mono/eolian/mono/documentation.hh
src/bin/eolian_mono/eolian/mono/function_definition.hh
src/bin/eolian_mono/eolian/mono/klass.hh
src/bin/eolian_mono/eolian/mono/name_helpers.hh
src/bin/eolian_mono/eolian/mono/part_definition.hh
src/bindings/mono/eo_mono/iwrapper.cs
src/tests/efl_mono/Eo.cs
src/tests/efl_mono/Inheritance.cs
src/tests/efl_mono/TestUtils.cs
src/tests/efl_mono/dummy_test_object.eo
src/tests/efl_mono/libefl_mono_native_test.c

index 2b9d8ad..77be1c0 100644 (file)
@@ -115,7 +115,7 @@ inline bool is_property_blacklisted(std::string const& name)
 {
     return name == "Efl.Input.Key.Key"
         || name == "Efl.Input.Hold.Hold"
-        || name == "Efl.Text.Text";
+        || name == "Efl.IText.Text";
 }
 
 template<typename Context>
@@ -133,6 +133,22 @@ inline bool is_property_blacklisted(attributes::property_def const& property, Co
 }
 
 template<typename Context>
+inline bool is_property_blacklisted(attributes::property_def const& property,
+                                    attributes::klass_def const& implementing_class,
+                                    Context context)
+{
+   std::string property_name = name_helpers::property_managed_name(property);
+   std::string klass_name = name_helpers::klass_concrete_or_interface_name(implementing_class);
+
+   // This property wrapper is invalidated as it would clash with the implementing
+   // class constructor. CS
+   if (property_name == klass_name)
+     return true;
+
+   return is_property_blacklisted(property, context);
+}
+
+template<typename Context>
 inline bool is_class_blacklisted(attributes::klass_def const& cls, Context context)
 {
    auto options = efl::eolian::grammar::context_find_tag<options_context>(context);
index 6d9399b..1d65bcb 100644 (file)
@@ -37,6 +37,24 @@ struct documentation_generator
       return n;
    }
 
+   // Gets the eolian ref for the given class, prepending I for interfaces.
+   static std::string object_ref_conversion(const Eolian_Object *cls)
+   {
+      auto klass_type = ::eolian_class_type_get((const Eolian_Class *)cls);
+      auto full_eolian_name = name_helpers::managed_namespace(::eolian_object_name_get(cls));
+      if (klass_type == EOLIAN_CLASS_MIXIN || klass_type == EOLIAN_CLASS_INTERFACE)
+        {
+           size_t pos = full_eolian_name.rfind(".");
+           if (pos == std::string::npos)
+             pos = 0;
+           else
+             pos++;
+           full_eolian_name.insert(pos, "I");
+        }
+      return full_eolian_name;
+   }
+
+
    // Turns a function name from EO convention to EFL# convention.
    // The name_tail parameter is the last 4 chars of the original string, which
    // could be ".set" or ".get" and in this case they are ignored by Eolian.
@@ -45,7 +63,7 @@ struct documentation_generator
    {
       ::Eolian_Function_Type ftype = ::eolian_function_type_get(function);
       const char* eo_name = ::eolian_function_name_get(function);
-      std::string name = name_helpers::managed_namespace(::eolian_object_name_get(klass));
+      std::string name = object_ref_conversion(klass);
       switch(ftype)
       {
          case ::EOLIAN_METHOD:
@@ -123,7 +141,7 @@ struct documentation_generator
            if (blacklist::is_struct_blacklisted(ref)) return "";
            break;
          case ::EOLIAN_OBJECT_EVENT:
-           ref = name_helpers::managed_namespace(::eolian_object_name_get(data));
+           ref = object_ref_conversion(data);
            ref += ".";
            ref += name_helpers::managed_event_name(::eolian_object_name_get(data2));
            break;
@@ -151,6 +169,9 @@ struct documentation_generator
            // If the reference cannot be resolved, just return an empty string and
            // it won't be converted into a <see> tag.
            break;
+         case ::EOLIAN_OBJECT_CLASS:
+           ref = object_ref_conversion(data);
+           break;
          default:
            ref = name_helpers::managed_namespace(::eolian_object_name_get(data));
            break;
index 67dfcc0..465a8fe 100644 (file)
@@ -219,7 +219,7 @@ struct property_wrapper_definition_generator
    template<typename OutputIterator, typename Context>
    bool generate(OutputIterator sink, attributes::property_def const& property, Context context) const
    {
-      if (blacklist::is_property_blacklisted(property, context))
+      if (blacklist::is_property_blacklisted(property, *implementing_klass, context))
         return true;
 
       bool interface = context_find_tag<class_context>(context).current_wrapper_kind == class_context::interface;
@@ -281,7 +281,19 @@ struct property_wrapper_definition_generator
 
       return true;
    }
+   attributes::klass_def const* implementing_klass;
+};
+struct property_wrapper_definition_parameterized
+{
+  property_wrapper_definition_generator operator()(attributes::klass_def const& klass) const
+  {
+     return {&klass};
+  }
 } const property_wrapper_definition;
+property_wrapper_definition_generator as_generator(property_wrapper_definition_parameterized)
+{
+   return {};
+}
 
 }
 
@@ -294,6 +306,8 @@ struct is_eager_generator< ::eolian_mono::native_function_definition_generator>
 template <>
 struct is_eager_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
 template <>
+struct is_eager_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {};
+template <>
 struct is_generator< ::eolian_mono::function_definition_generator> : std::true_type {};
 template <>
 struct is_generator< ::eolian_mono::native_function_definition_generator> : std::true_type {};
@@ -301,6 +315,8 @@ template <>
 struct is_generator< ::eolian_mono::function_definition_parameterized> : std::true_type {};
 template <>
 struct is_generator< ::eolian_mono::property_wrapper_definition_generator> : std::true_type {};
+template <>
+struct is_generator< ::eolian_mono::property_wrapper_definition_parameterized> : std::true_type {};
 
 namespace type_traits {
 template <>
@@ -314,6 +330,8 @@ struct attributes_needed< ::eolian_mono::native_function_definition_generator> :
 
 template <>
 struct attributes_needed< ::eolian_mono::property_wrapper_definition_generator> : std::integral_constant<int, 1> {};
+template <>
+struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant<int, 1> {};
 }
       
 } } }
index 71228ed..20045de 100644 (file)
@@ -177,7 +177,7 @@ struct klass
             ).generate(sink, p, iface_cxt))
            return false;
 
-       if (!as_generator(*(property_wrapper_definition)).generate(sink, cls.properties, iface_cxt))
+       if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, cls.properties, iface_cxt))
          return false;
 
        // End of interface declaration
@@ -272,13 +272,13 @@ struct klass
            return false;
 
          // Property wrappers
-         if (!as_generator(*(property_wrapper_definition)).generate(sink, cls.properties, concrete_cxt))
+         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)).generate(sink, c.properties, concrete_cxt))
+              if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, c.properties, concrete_cxt))
                 return false;
            }
 
@@ -353,13 +353,13 @@ struct klass
            return false;
 
          // Property wrappers
-         if (!as_generator(*(property_wrapper_definition)).generate(sink, cls.properties, inherit_cxt))
+         if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, cls.properties, inherit_cxt))
            return false;
 
          for (auto&& klass : helpers::non_implemented_interfaces(cls, inherit_cxt))
            {
               attributes::klass_def c(get_klass(klass, cls.unit), cls.unit);
-              if (!as_generator(*(property_wrapper_definition)).generate(sink, c.properties, inherit_cxt))
+              if (!as_generator(*(property_wrapper_definition(cls))).generate(sink, c.properties, inherit_cxt))
                 return false;
            }
 
index 074fd4f..6989764 100644 (file)
@@ -278,7 +278,11 @@ struct klass_interface_name_generator
   template <typename T>
   std::string operator()(T const& klass) const
   {
-    return utils::remove_all(klass.eolian_name, '_');
+    std::string name = utils::remove_all(klass.eolian_name, '_');
+    if (klass.type == attributes::class_type::mixin || klass.type == attributes::class_type::interface_)
+      return "I" + name;
+    else
+      return name;
   }
 
   template <typename OutputIterator, typename Attr, typename Context>
@@ -306,10 +310,23 @@ struct klass_full_interface_name_generator
 template<typename T>
 inline std::string klass_concrete_name(T const& klass)
 {
-  std::string name = utils::remove_all(klass.eolian_name, '_');
-  if (klass.type == attributes::class_type::regular || klass.type == attributes::class_type::abstract_)
-    return name;
-  return name + "Concrete";
+  if (klass.type == attributes::class_type::mixin || klass.type == attributes::class_type::interface_)
+    return klass_interface_name(klass) + "Concrete";
+
+  return utils::remove_all(klass.eolian_name, '_');
+}
+
+template<typename  T>
+inline std::string klass_concrete_or_interface_name(T const& klass)
+{
+    switch(klass.type)
+    {
+    case attributes::class_type::abstract_:
+    case attributes::class_type::regular:
+      return klass_concrete_name(klass);
+    default:
+      return klass_interface_name(klass);
+    }
 }
 
 struct klass_full_concrete_name_generator
@@ -408,7 +425,7 @@ inline std::string managed_event_name(std::string const& name)
 inline std::string managed_event_args_short_name(attributes::event_def const& evt)
 {
    std::string ret;
-     ret = klass_interface_name(evt.klass);
+     ret = klass_concrete_or_interface_name(evt.klass);
    return ret + name_helpers::managed_event_name(evt.name) + "_Args";
 }
 
index 2a8d2e1..7894086 100644 (file)
@@ -27,7 +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.PartNativeInherit.efl_part_get_ptr.Value.Delegate(NativeHandle, \"" << part.name << "\");\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 << "}\n"
                        << scope_tab << "}\n"
index 13f82cf..3120dbb 100644 (file)
@@ -12,6 +12,21 @@ using EoG = Efl.Eo.Globals;
 namespace Efl { namespace Eo {
 
 public class Globals {
+
+    /// <summary>Represents the type of the native Efl_Class.</summary>
+    public enum EflClassType {
+        /// <summary>Regular EFL classes.</summary>
+        Regular = 0,
+        /// <summary>Non-instantiable efl classes (i.e. Abstracts).</summary>
+        RegularNoInstant,
+        /// <summary>Interface types.</summary>
+        Interface,
+        /// <summary>Mixins types.</summary>
+        Mixin,
+        /// <summary>Invalid class type.</summary>
+        Invalid
+    }
+
     [return: MarshalAs(UnmanagedType.U1)]
     public delegate bool efl_object_init_delegate();
     public static FunctionWrapper<efl_object_init_delegate> efl_object_init_ptr =
@@ -155,6 +170,7 @@ public class Globals {
     [DllImport(efl.Libs.Eo)] public static extern IntPtr efl_super(IntPtr obj, IntPtr klass);
     public delegate  IntPtr efl_class_get_delegate(IntPtr obj);
     [DllImport(efl.Libs.Eo)] public static extern IntPtr efl_class_get(IntPtr obj);
+    [DllImport(efl.Libs.Eo)] public static extern EflClassType efl_class_type_get(IntPtr klass);
     public delegate  IntPtr dlerror_delegate();
     [DllImport(efl.Libs.Evil)] public static extern IntPtr dlerror();
 
@@ -542,6 +558,15 @@ public static class ClassRegister
         string name = Eina.StringConversion.NativeUtf8ToManagedString(namePtr)
                       .Replace("_", ""); // Convert Efl C name to C# name
 
+        var klass_type = Efl.Eo.Globals.efl_class_type_get(klass);
+
+        // 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)
+        {
+            var pos = name.LastIndexOf(".");
+            name = name.Insert(pos + 1, "I"); // -1 if not found, inserts at 0 normally
+        }
+
         var curr_asm = typeof(IWrapper).Assembly;
         t = curr_asm.GetType(name);
         if (t == null)
index 95f9b7e..578ad10 100644 (file)
@@ -1,5 +1,6 @@
 using System;
 using System.Linq;
+using System.Collections.Generic;
 
 namespace TestSuite
 {
@@ -327,7 +328,7 @@ class TestCsharpProperties
     public static void test_iface_property()
     {
         int val = -33;
-        Dummy.TestIface iface = new Dummy.TestObject();
+        Dummy.ITestIface iface = new Dummy.TestObject();
         iface.IfaceProp = val;
         Test.AssertEquals(val, iface.IfaceProp);
     }
@@ -429,7 +430,7 @@ class TestInterfaceConcrete
     public static void test_iface_concrete_methods()
     {
         var obj = new Dummy.TestObject();
-        Dummy.TestIface iface = Dummy.TestIfaceConcrete.static_cast(obj);
+        Dummy.ITestIface iface = Dummy.ITestIfaceConcrete.static_cast(obj);
 
         iface.IfaceProp = 1970;
         Test.AssertEquals(iface.IfaceProp, 1970);
@@ -447,11 +448,49 @@ class TestProvider
         Test.AssertEquals(provider.GetNumber(), 1999);
     }
 
+    private class ProviderHolder : Dummy.TestObject
+    {
+        private Dummy.TestObject provider;
+        public string ProviderName
+        {
+            get
+            {
+                return "MyProvider";
+            }
+        }
+
+        public ProviderHolder() : base(null)
+        {
+            this.provider = new Dummy.TestObject(this);
+            this.provider.Name = this.ProviderName;
+            this.provider.IfaceProp = 1997;
+        }
+
+        public override Efl.Object FindProvider(System.Type type)
+        {
+            Console.WriteLine("Called FindProvider");
+            if (type == typeof(Dummy.ITestIface))
+            {
+                return this.provider;
+            }
+            else
+            {
+                return null;
+            }
+        }
+    }
+
     public static void test_find_provider_iface()
     {
-        var obj = new Dummy.TestObject();
-        Dummy.TestIface provider = Dummy.TestIfaceConcrete.static_cast(obj.FindProvider(typeof(Dummy.TestIface)));
-        Test.AssertEquals(provider.GetIfaceProp(), 1997);
+        var obj = new ProviderHolder();
+
+        var provider = obj.CallFindProvider(typeof(Efl.Object));
+        Test.AssertNull(provider, msg : "Unkonw provider must be null");
+
+        provider = obj.CallFindProviderForIface();
+        Test.AssertNotNull(provider, msg : "Provider of ITestIFace must not be null");
+        Test.AssertEquals(provider.Name, obj.ProviderName, "Provider name does not match expected");
+
     }
 }
 
index 344c6da..befdd3a 100644 (file)
@@ -20,7 +20,7 @@ class TestInheritance
         }
     }
 
-    internal class Inherit2 : Dummy.TestObject, Dummy.InheritIface
+    internal class Inherit2 : Dummy.TestObject, Dummy.IInheritIface
     {
         override public void IntOut (int x, out int y)
         {
index 615a8f3..e7daf05 100644 (file)
@@ -186,6 +186,16 @@ public static class Test
         if (reference != null)
             throw new AssertionException($"Assertion failed: {file}:{line} ({member}) {msg}");
     }
+
+    /// <summary> Asserts if the given reference is not null.</summary>
+    public static void AssertNotNull(object reference, String msg = "Reference is null",
+                              [CallerLineNumber] int line = 0,
+                              [CallerFilePath] string file = null,
+                              [CallerMemberName] string member = null)
+    {
+        if (reference == null)
+            throw new AssertionException($"Assertion failed: {file}:{line} ({member}) {msg}");
+    }
 }
 
 
index ed63eae..5475c81 100644 (file)
@@ -1388,6 +1388,17 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface {
       get_setter_only {
          return: int;
       }
+
+      call_find_provider {
+         params {
+            @in type: const(Efl.Class);
+         }
+         return: Efl.Object;
+      }
+
+      call_find_provider_for_iface {
+         return: Efl.Object;
+      }
    }
    implements {
       class.constructor;
index 7e3bffe..7b4dd1a 100644 (file)
@@ -3929,6 +3929,18 @@ Eo * _dummy_test_object_efl_object_provider_find(EINA_UNUSED const Eo *obj, Dumm
     return efl_provider_find(efl_super(obj, DUMMY_TEST_OBJECT_CLASS), klass);
 }
 
+Efl_Object *_dummy_test_object_call_find_provider(Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd, const Efl_Class *type)
+{
+    printf("CALLING FIND PROVIDER FROM C");
+    return efl_provider_find(obj, type);
+}
+
+Efl_Object *_dummy_test_object_call_find_provider_for_iface(Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd)
+{
+    printf("CALLING FIND PROVIDER FROM C");
+    return efl_provider_find(obj, DUMMY_TEST_IFACE_INTERFACE);
+}
+
 /// Dummy.Child
 
 static Efl_Object *