From 0881d1524b6d3996a29b68820690f97821116585 Mon Sep 17 00:00:00 2001 From: Lauro Moura Date: Thu, 21 Mar 2019 14:38:45 -0300 Subject: [PATCH] efl-csharp: Add back I prefix for interfaces. 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 --- src/bin/eolian_mono/eolian/mono/blacklist.hh | 18 ++++++- .../eolian_mono/eolian/mono/documentation.hh | 25 +++++++++- .../eolian/mono/function_definition.hh | 20 +++++++- src/bin/eolian_mono/eolian/mono/klass.hh | 10 ++-- .../eolian_mono/eolian/mono/name_helpers.hh | 29 ++++++++--- .../eolian/mono/part_definition.hh | 2 +- src/bindings/mono/eo_mono/iwrapper.cs | 25 ++++++++++ src/tests/efl_mono/Eo.cs | 49 +++++++++++++++++-- src/tests/efl_mono/Inheritance.cs | 2 +- src/tests/efl_mono/TestUtils.cs | 10 ++++ src/tests/efl_mono/dummy_test_object.eo | 11 +++++ src/tests/efl_mono/libefl_mono_native_test.c | 12 +++++ 12 files changed, 191 insertions(+), 22 deletions(-) diff --git a/src/bin/eolian_mono/eolian/mono/blacklist.hh b/src/bin/eolian_mono/eolian/mono/blacklist.hh index 2b9d8ad4bf..77be1c0da8 100644 --- a/src/bin/eolian_mono/eolian/mono/blacklist.hh +++ b/src/bin/eolian_mono/eolian/mono/blacklist.hh @@ -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 @@ -132,6 +132,22 @@ inline bool is_property_blacklisted(attributes::property_def const& property, Co return is_property_blacklisted(name); } +template +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 inline bool is_class_blacklisted(attributes::klass_def const& cls, Context context) { diff --git a/src/bin/eolian_mono/eolian/mono/documentation.hh b/src/bin/eolian_mono/eolian/mono/documentation.hh index 6d9399bb3a..1d65bcb076 100644 --- a/src/bin/eolian_mono/eolian/mono/documentation.hh +++ b/src/bin/eolian_mono/eolian/mono/documentation.hh @@ -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 tag. break; + case ::EOLIAN_OBJECT_CLASS: + ref = object_ref_conversion(data); + break; default: ref = name_helpers::managed_namespace(::eolian_object_name_get(data)); break; diff --git a/src/bin/eolian_mono/eolian/mono/function_definition.hh b/src/bin/eolian_mono/eolian/mono/function_definition.hh index 67dfcc0ce4..465a8fee71 100644 --- a/src/bin/eolian_mono/eolian/mono/function_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/function_definition.hh @@ -219,7 +219,7 @@ struct property_wrapper_definition_generator template 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(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 {}; +template <> +struct attributes_needed< ::eolian_mono::property_wrapper_definition_parameterized> : std::integral_constant {}; } } } } diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh index 71228edb8f..20045de39b 100644 --- a/src/bin/eolian_mono/eolian/mono/klass.hh +++ b/src/bin/eolian_mono/eolian/mono/klass.hh @@ -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; } diff --git a/src/bin/eolian_mono/eolian/mono/name_helpers.hh b/src/bin/eolian_mono/eolian/mono/name_helpers.hh index 074fd4f7ed..698976446e 100644 --- a/src/bin/eolian_mono/eolian/mono/name_helpers.hh +++ b/src/bin/eolian_mono/eolian/mono/name_helpers.hh @@ -278,7 +278,11 @@ struct klass_interface_name_generator template 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 @@ -306,10 +310,23 @@ struct klass_full_interface_name_generator template 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 +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"; } diff --git a/src/bin/eolian_mono/eolian/mono/part_definition.hh b/src/bin/eolian_mono/eolian/mono/part_definition.hh index 2a8d2e1b00..7894086f95 100644 --- a/src/bin/eolian_mono/eolian/mono/part_definition.hh +++ b/src/bin/eolian_mono/eolian/mono/part_definition.hh @@ -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" diff --git a/src/bindings/mono/eo_mono/iwrapper.cs b/src/bindings/mono/eo_mono/iwrapper.cs index 13f82cf090..3120dbbbf7 100644 --- a/src/bindings/mono/eo_mono/iwrapper.cs +++ b/src/bindings/mono/eo_mono/iwrapper.cs @@ -12,6 +12,21 @@ using EoG = Efl.Eo.Globals; namespace Efl { namespace Eo { public class Globals { + + /// Represents the type of the native Efl_Class. + public enum EflClassType { + /// Regular EFL classes. + Regular = 0, + /// Non-instantiable efl classes (i.e. Abstracts). + RegularNoInstant, + /// Interface types. + Interface, + /// Mixins types. + Mixin, + /// Invalid class type. + Invalid + } + [return: MarshalAs(UnmanagedType.U1)] public delegate bool efl_object_init_delegate(); public static FunctionWrapper 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) diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs index 95f9b7e1d8..578ad10790 100644 --- a/src/tests/efl_mono/Eo.cs +++ b/src/tests/efl_mono/Eo.cs @@ -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"); + } } diff --git a/src/tests/efl_mono/Inheritance.cs b/src/tests/efl_mono/Inheritance.cs index 344c6da71f..befdd3a7b4 100644 --- a/src/tests/efl_mono/Inheritance.cs +++ b/src/tests/efl_mono/Inheritance.cs @@ -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) { diff --git a/src/tests/efl_mono/TestUtils.cs b/src/tests/efl_mono/TestUtils.cs index 615a8f3c6d..e7daf0559d 100644 --- a/src/tests/efl_mono/TestUtils.cs +++ b/src/tests/efl_mono/TestUtils.cs @@ -186,6 +186,16 @@ public static class Test if (reference != null) throw new AssertionException($"Assertion failed: {file}:{line} ({member}) {msg}"); } + + /// Asserts if the given reference is not null. + 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}"); + } } diff --git a/src/tests/efl_mono/dummy_test_object.eo b/src/tests/efl_mono/dummy_test_object.eo index ed63eaee64..5475c81c3c 100644 --- a/src/tests/efl_mono/dummy_test_object.eo +++ b/src/tests/efl_mono/dummy_test_object.eo @@ -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; diff --git a/src/tests/efl_mono/libefl_mono_native_test.c b/src/tests/efl_mono/libefl_mono_native_test.c index 7e3bffe111..7b4dd1a77f 100644 --- a/src/tests/efl_mono/libefl_mono_native_test.c +++ b/src/tests/efl_mono/libefl_mono_native_test.c @@ -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 *