summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLauro Moura <lauromoura@expertisesolutions.com.br>2019-09-10 19:30:46 -0300
committerLauro Moura <lauromoura@expertisesolutions.com.br>2019-09-10 19:30:47 -0300
commitdfb856158c8ea37d9caa170a6794447ec18ecdd9 (patch)
tree7d9130fac1c8d4a46341192feb965d842279f2fc
parentd1890f5eca0b439c902999716ed0a49634e848a1 (diff)
csharp: Skip non-public members from interfaces
Summary: Eolian allows non-public members in interfaces and mixins (usually @protected). As both kinds are converted to C# interfaces, this causes problem as non-public members are forbidden in C# interfaces. This commit changes eolian_mono by removing those members from the C# interfaces. If a generated class implements the interface, the method is generated as if it were a protected member of the class directly. For mixed properties like `Efl.Io.Reader.CanRead { get; set @protected; }`, the interface has only the public getter and the the implementing class has both the public getter and the protected setter. With this, C# devs won't be able to directly implement protected Eo methods from interfaces. (But this really does not make sense from the C# point of view). ref T7494 Reviewers: segfaultxavi, felipealmeida, YOhoho Reviewed By: YOhoho Subscribers: cedric, brunobelo, Jaehyun_Cho, #reviewers, woohyun, #committers Tags: #efl Maniphest Tasks: T7494 Differential Revision: https://phab.enlightenment.org/D9800
-rw-r--r--src/bin/eolian_mono/eolian/mono/async_function_definition.hh3
-rw-r--r--src/bin/eolian_mono/eolian/mono/blacklist.hh12
-rw-r--r--src/bin/eolian_mono/eolian/mono/documentation.hh21
-rw-r--r--src/bin/eolian_mono/eolian/mono/function_declaration.hh4
-rw-r--r--src/bin/eolian_mono/eolian/mono/function_definition.hh42
-rw-r--r--src/bin/eolian_mono/eolian/mono/function_helpers.hh7
-rw-r--r--src/bin/eolian_mono/eolian/mono/function_registration.hh5
-rw-r--r--src/bin/eolian_mono/eolian/mono/helpers.hh33
-rw-r--r--src/bin/eolian_mono/eolian/mono/klass.hh20
-rw-r--r--src/bindings/mono/efl_mono/Bind.cs10
-rw-r--r--src/lib/eolian_cxx/grammar/klass_def.hpp20
-rw-r--r--src/tests/efl_mono/Eo.cs74
-rw-r--r--src/tests/efl_mono/dummy_interfaces.c2
-rw-r--r--src/tests/efl_mono/dummy_test_iface.eo31
-rw-r--r--src/tests/efl_mono/dummy_test_object.c12
-rw-r--r--src/tests/efl_mono/dummy_test_object.eo2
16 files changed, 262 insertions, 36 deletions
diff --git a/src/bin/eolian_mono/eolian/mono/async_function_definition.hh b/src/bin/eolian_mono/eolian/mono/async_function_definition.hh
index b3ab6d4102..a6907a2a95 100644
--- a/src/bin/eolian_mono/eolian/mono/async_function_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/async_function_definition.hh
@@ -52,6 +52,9 @@ struct async_function_declaration_generator
52 return true; 52 return true;
53 if (!f.return_type.original_type.visit(is_future{})) 53 if (!f.return_type.original_type.visit(is_future{}))
54 return true; 54 return true;
55 // C# interfaces can't have non-public members
56 if(f.scope != attributes::member_scope::scope_public)
57 return true;
55 58
56 if (!as_generator( 59 if (!as_generator(
57 scope_tab << "/// <summary>Async wrapper for <see cref=\"" << name_helpers::managed_method_name(f) << "\" />.</summary>\n" 60 scope_tab << "/// <summary>Async wrapper for <see cref=\"" << name_helpers::managed_method_name(f) << "\" />.</summary>\n"
diff --git a/src/bin/eolian_mono/eolian/mono/blacklist.hh b/src/bin/eolian_mono/eolian/mono/blacklist.hh
index 5099013396..c46f2f4de7 100644
--- a/src/bin/eolian_mono/eolian/mono/blacklist.hh
+++ b/src/bin/eolian_mono/eolian/mono/blacklist.hh
@@ -64,6 +64,18 @@ inline bool is_function_blacklisted(attributes::function_def const& func, Contex
64 return is_function_blacklisted(c_name); 64 return is_function_blacklisted(c_name);
65} 65}
66 66
67inline bool is_non_public_interface_member(attributes::function_def const& func, attributes::klass_def const&current_klass)
68{
69 if (current_klass.type == attributes::class_type::interface_
70 || current_klass.type == attributes::class_type::mixin)
71 {
72 if (func.scope != attributes::member_scope::scope_public)
73 return true;
74 }
75
76 return false;
77}
78
67 79
68// Blacklist structs that require some kind of manual binding. 80// Blacklist structs that require some kind of manual binding.
69inline bool is_struct_blacklisted(std::string const& full_name) 81inline bool is_struct_blacklisted(std::string const& full_name)
diff --git a/src/bin/eolian_mono/eolian/mono/documentation.hh b/src/bin/eolian_mono/eolian/mono/documentation.hh
index 588d0b68fa..6cf57fd342 100644
--- a/src/bin/eolian_mono/eolian/mono/documentation.hh
+++ b/src/bin/eolian_mono/eolian/mono/documentation.hh
@@ -73,6 +73,25 @@ struct documentation_generator
73 // Klass is needed to check the property naming rulles 73 // Klass is needed to check the property naming rulles
74 attributes::klass_def klass_d((const ::Eolian_Class *)klass, eolian_object_unit_get(klass)); 74 attributes::klass_def klass_d((const ::Eolian_Class *)klass, eolian_object_unit_get(klass));
75 75
76 // Comment the block below to enable @see reference conversion for non-public interface members.
77 // As they are not generated, this causes a doc warning that fails the build, but can be useful to track
78 // public methods referencing protected stuff.
79 if (ftype != EOLIAN_PROPERTY)
80 {
81 bool is_func_public = ::eolian_function_scope_get(function, ftype) == EOLIAN_SCOPE_PUBLIC;
82
83 if (helpers::is_managed_interface(klass_d) && !is_func_public)
84 return "";
85 }
86 else
87 {
88 bool is_get_public = ::eolian_function_scope_get(function, EOLIAN_PROP_GET) == EOLIAN_SCOPE_PUBLIC;
89 bool is_set_public = ::eolian_function_scope_get(function, EOLIAN_PROP_SET) == EOLIAN_SCOPE_PUBLIC;
90
91 if (helpers::is_managed_interface(klass_d) && !(is_get_public || is_set_public))
92 return "";
93 }
94
76 switch(ftype) 95 switch(ftype)
77 { 96 {
78 case ::EOLIAN_METHOD: 97 case ::EOLIAN_METHOD:
@@ -112,6 +131,8 @@ struct documentation_generator
112 131
113 static std::string function_conversion(attributes::function_def const& func) 132 static std::string function_conversion(attributes::function_def const& func)
114 { 133 {
134 // This function is called only from the constructor reference conversion, so it does not
135 // need to check whether this function non-public in a interface returning an empty reference (yet).
115 std::string name = name_helpers::klass_full_concrete_or_interface_name(func.klass); 136 std::string name = name_helpers::klass_full_concrete_or_interface_name(func.klass);
116 switch (func.type) 137 switch (func.type)
117 { 138 {
diff --git a/src/bin/eolian_mono/eolian/mono/function_declaration.hh b/src/bin/eolian_mono/eolian/mono/function_declaration.hh
index baad0bb33d..4532746be2 100644
--- a/src/bin/eolian_mono/eolian/mono/function_declaration.hh
+++ b/src/bin/eolian_mono/eolian/mono/function_declaration.hh
@@ -23,6 +23,10 @@ struct function_declaration_generator
23 if(blacklist::is_function_blacklisted(f, context) || f.is_static) 23 if(blacklist::is_function_blacklisted(f, context) || f.is_static)
24 return true; 24 return true;
25 25
26 // C# interfaces can't have non-public members
27 if(f.scope != attributes::member_scope::scope_public)
28 return true;
29
26 if(!as_generator(documentation).generate(sink, f, context)) 30 if(!as_generator(documentation).generate(sink, f, context))
27 return false; 31 return false;
28 32
diff --git a/src/bin/eolian_mono/eolian/mono/function_definition.hh b/src/bin/eolian_mono/eolian/mono/function_definition.hh
index 81e2ad81ef..51da954d44 100644
--- a/src/bin/eolian_mono/eolian/mono/function_definition.hh
+++ b/src/bin/eolian_mono/eolian/mono/function_definition.hh
@@ -81,6 +81,10 @@ struct native_function_definition_generator
81 .generate(sink, std::make_tuple(f.c_name, f.c_name, f.c_name, f.c_name), context)) 81 .generate(sink, std::make_tuple(f.c_name, f.c_name, f.c_name, f.c_name), context))
82 return false; 82 return false;
83 83
84 // We do not generate the wrapper to be called from C for non public interface member directly.
85 if (blacklist::is_non_public_interface_member(f, *klass))
86 return true;
87
84 // Actual method implementation to be called from C. 88 // Actual method implementation to be called from C.
85 std::string return_type; 89 std::string return_type;
86 if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context)) 90 if(!as_generator(eolian_mono::type(true)).generate(std::back_inserter(return_type), f.return_type, context))
@@ -303,12 +307,12 @@ struct property_wrapper_definition_generator
303 if (blacklist::is_property_blacklisted(property, *implementing_klass, context)) 307 if (blacklist::is_property_blacklisted(property, *implementing_klass, context))
304 return true; 308 return true;
305 309
306 bool interface = context_find_tag<class_context>(context).current_wrapper_kind == class_context::interface; 310 bool is_interface = context_find_tag<class_context>(context).current_wrapper_kind == class_context::interface;
307 bool is_static = (property.getter.is_engaged() && property.getter->is_static) 311 bool is_static = (property.getter.is_engaged() && property.getter->is_static)
308 || (property.setter.is_engaged() && property.setter->is_static); 312 || (property.setter.is_engaged() && property.setter->is_static);
309 313
310 314
311 if (interface && is_static) 315 if (is_interface && is_static)
312 return true; 316 return true;
313 317
314 auto get_params = property.getter.is_engaged() ? property.getter->parameters.size() : 0; 318 auto get_params = property.getter.is_engaged() ? property.getter->parameters.size() : 0;
@@ -389,19 +393,21 @@ struct property_wrapper_definition_generator
389 393
390 std::string scope = "public "; 394 std::string scope = "public ";
391 std::string get_scope = property.getter.is_engaged() ? eolian_mono::function_scope_get(*property.getter) : ""; 395 std::string get_scope = property.getter.is_engaged() ? eolian_mono::function_scope_get(*property.getter) : "";
396 bool is_get_public = get_scope == "public ";
392 std::string set_scope = property.setter.is_engaged() ? eolian_mono::function_scope_get(*property.setter) : ""; 397 std::string set_scope = property.setter.is_engaged() ? eolian_mono::function_scope_get(*property.setter) : "";
393 if (interface) 398 bool is_set_public = set_scope == "public ";
399
400 // No need to generate this wrapper as no accessor is public.
401 if (is_interface && (!is_get_public && !is_set_public))
402 return true;
403
404 // C# interface members are declared automatically as public
405 if (is_interface)
394 { 406 {
395 scope = ""; 407 scope = "";
396 get_scope = ""; 408 get_scope = "";
397 set_scope = ""; 409 set_scope = "";
398 } 410 }
399 else if ((property.klass.type == attributes::class_type::mixin) ||
400 (property.klass.type == attributes::class_type::interface_))
401 {
402 get_scope = "";
403 set_scope = "";
404 }
405 else if ((get_scope != "") && (get_scope == set_scope)) 411 else if ((get_scope != "") && (get_scope == set_scope))
406 { 412 {
407 scope = get_scope; 413 scope = get_scope;
@@ -439,11 +445,12 @@ struct property_wrapper_definition_generator
439 return false; 445 return false;
440 } 446 }
441 447
442 if (property.getter.is_engaged() && interface) 448 if (property.getter.is_engaged() && is_interface)
443 { 449 {
444 if (!as_generator(scope_tab << scope_tab << set_scope << "get;\n" 450 if (is_get_public)
445 ).generate(sink, attributes::unused, context)) 451 if (!as_generator(scope_tab << scope_tab << set_scope << "get;\n"
446 return false; 452 ).generate(sink, attributes::unused, context))
453 return false;
447 } 454 }
448 else if (property.getter.is_engaged() && get_params == 0/*parameters.size() == 1 && property.getter.is_engaged()*/) 455 else if (property.getter.is_engaged() && get_params == 0/*parameters.size() == 1 && property.getter.is_engaged()*/)
449 { 456 {
@@ -483,11 +490,12 @@ struct property_wrapper_definition_generator
483 // return false; 490 // return false;
484 // } 491 // }
485 492
486 if (property.setter.is_engaged() && interface) 493 if (property.setter.is_engaged() && is_interface)
487 { 494 {
488 if (!as_generator(scope_tab << scope_tab << set_scope << "set;\n" 495 if (is_set_public)
489 ).generate(sink, attributes::unused, context)) 496 if (!as_generator(scope_tab << scope_tab << set_scope << "set;\n"
490 return false; 497 ).generate(sink, attributes::unused, context))
498 return false;
491 } 499 }
492 else if (parameters.size() == 1 && property.setter.is_engaged()) 500 else if (parameters.size() == 1 && property.setter.is_engaged())
493 { 501 {
diff --git a/src/bin/eolian_mono/eolian/mono/function_helpers.hh b/src/bin/eolian_mono/eolian/mono/function_helpers.hh
index 0ea25da536..5f7cf67877 100644
--- a/src/bin/eolian_mono/eolian/mono/function_helpers.hh
+++ b/src/bin/eolian_mono/eolian/mono/function_helpers.hh
@@ -165,10 +165,6 @@ function_definition_epilogue_generator const as_generator(function_definition_ep
165 165
166inline std::string function_scope_get(attributes::function_def const& f) 166inline std::string function_scope_get(attributes::function_def const& f)
167{ 167{
168 if ((f.klass.type == attributes::class_type::mixin) ||
169 (f.klass.type == attributes::class_type::interface_))
170 return "public ";
171
172 switch (f.scope) 168 switch (f.scope)
173 { 169 {
174 case attributes::member_scope::scope_public: 170 case attributes::member_scope::scope_public:
@@ -178,7 +174,8 @@ inline std::string function_scope_get(attributes::function_def const& f)
178 case attributes::member_scope::scope_protected: 174 case attributes::member_scope::scope_protected:
179 return "protected "; 175 return "protected ";
180 case attributes::member_scope::scope_unknown: 176 case attributes::member_scope::scope_unknown:
181 return " "; 177 // This should trigger a compilation error
178 return "unkown_scope ";
182 } 179 }
183 return " "; 180 return " ";
184} 181}
diff --git a/src/bin/eolian_mono/eolian/mono/function_registration.hh b/src/bin/eolian_mono/eolian/mono/function_registration.hh
index b490808b9a..e258ce7cff 100644
--- a/src/bin/eolian_mono/eolian/mono/function_registration.hh
+++ b/src/bin/eolian_mono/eolian/mono/function_registration.hh
@@ -35,6 +35,11 @@ struct function_registration_generator
35 if(blacklist::is_function_blacklisted(f, context) || f.is_static) // Static methods aren't overrideable 35 if(blacklist::is_function_blacklisted(f, context) || f.is_static) // Static methods aren't overrideable
36 return true; 36 return true;
37 37
38 // We do not generate registration wrappers for non public interface/mixin members in their concrete classes.
39 // They go in the first concrete/abstract implementation.
40 if(blacklist::is_non_public_interface_member(f, *klass))
41 return true;
42
38 if(!as_generator( 43 if(!as_generator(
39 indent << "if (" << f.c_name << "_static_delegate == null)\n" 44 indent << "if (" << f.c_name << "_static_delegate == null)\n"
40 << indent << "{\n" 45 << indent << "{\n"
diff --git a/src/bin/eolian_mono/eolian/mono/helpers.hh b/src/bin/eolian_mono/eolian/mono/helpers.hh
index a7c27c4809..291e5234ff 100644
--- a/src/bin/eolian_mono/eolian/mono/helpers.hh
+++ b/src/bin/eolian_mono/eolian/mono/helpers.hh
@@ -233,6 +233,39 @@ std::vector<attributes::function_def> get_all_implementable_methods(attributes::
233 return ret; 233 return ret;
234} 234}
235 235
236template<typename Klass>
237inline bool is_managed_interface(Klass const& klass)
238{
239 return klass.type == attributes::class_type::interface_
240 || klass.type == attributes::class_type::mixin;
241}
242
243
244/*
245 * Gets all methods that this class should register (i.e. that comes from it and non-public interface methods
246 * that this class is the first one implementing)
247 */
248template<typename Context>
249std::vector<attributes::function_def> get_all_registerable_methods(attributes::klass_def const& cls, Context const& context)
250{
251 std::vector<attributes::function_def> ret;
252
253 auto implementable_methods = get_all_implementable_methods(cls, context);
254
255 std::copy_if(implementable_methods.cbegin(), implementable_methods.cend(), std::back_inserter(ret)
256 , [&cls](attributes::function_def const & func) {
257
258 if (cls == func.klass)
259 return true;
260
261 if (!is_managed_interface(func.klass) || func.scope != attributes::member_scope::scope_public)
262 return true;
263 return false;
264 });
265
266 return ret;
267}
268
236/* 269/*
237 * Checks whether the given is unique going up the inheritance tree from leaf_klass 270 * Checks whether the given is unique going up the inheritance tree from leaf_klass
238 */ 271 */
diff --git a/src/bin/eolian_mono/eolian/mono/klass.hh b/src/bin/eolian_mono/eolian/mono/klass.hh
index 81d1070aab..80ac37c141 100644
--- a/src/bin/eolian_mono/eolian/mono/klass.hh
+++ b/src/bin/eolian_mono/eolian/mono/klass.hh
@@ -31,18 +31,6 @@
31 31
32namespace eolian_mono { 32namespace eolian_mono {
33 33
34/* Get the actual number of functions of a class, checking for blacklisted ones */
35template<typename Context>
36static std::size_t
37get_implementable_function_count(grammar::attributes::klass_def const& cls, Context context)
38{
39 auto methods = helpers::get_all_implementable_methods(cls, context);
40 return std::count_if(methods.cbegin(), methods.cend(), [&context](grammar::attributes::function_def const& func)
41 {
42 return !blacklist::is_function_blacklisted(func, context) && !func.is_static;
43 });
44}
45
46template<typename Context> 34template<typename Context>
47static bool 35static bool
48is_inherit_context(Context const& context) 36is_inherit_context(Context const& context)
@@ -239,6 +227,9 @@ struct klass
239 if (!generate_events(sink, cls, concrete_cxt)) 227 if (!generate_events(sink, cls, concrete_cxt))
240 return false; 228 return false;
241 229
230 if (!as_generator(lit("#pragma warning disable CS0628\n")).generate(sink, attributes::unused, concrete_cxt))
231 return false;
232
242 // Parts 233 // Parts
243 if(!as_generator(*(part_definition)) 234 if(!as_generator(*(part_definition))
244 .generate(sink, cls.parts, concrete_cxt)) return false; 235 .generate(sink, cls.parts, concrete_cxt)) return false;
@@ -263,6 +254,9 @@ struct klass
263 return false; 254 return false;
264 } 255 }
265 256
257 if (!as_generator(lit("#pragma warning restore CS0628\n")).generate(sink, attributes::unused, concrete_cxt))
258 return false;
259
266 // Copied from nativeinherit class, used when setting up providers. 260 // Copied from nativeinherit class, used when setting up providers.
267 if(!as_generator( 261 if(!as_generator(
268 scope_tab << "private static IntPtr GetEflClassStatic()\n" 262 scope_tab << "private static IntPtr GetEflClassStatic()\n"
@@ -398,7 +392,7 @@ struct klass
398 context); 392 context);
399 auto native_inherit_name = name_helpers::klass_native_inherit_name(cls); 393 auto native_inherit_name = name_helpers::klass_native_inherit_name(cls);
400 auto inherit_name = name_helpers::klass_inherit_name(cls); 394 auto inherit_name = name_helpers::klass_inherit_name(cls);
401 auto implementable_methods = cls.functions; 395 auto implementable_methods = helpers::get_all_registerable_methods(cls, context);
402 bool root = !helpers::has_regular_ancestor(cls); 396 bool root = !helpers::has_regular_ancestor(cls);
403 auto const& indent = current_indentation(inative_cxt); 397 auto const& indent = current_indentation(inative_cxt);
404 398
diff --git a/src/bindings/mono/efl_mono/Bind.cs b/src/bindings/mono/efl_mono/Bind.cs
index d82d0c1f49..1d29c25d42 100644
--- a/src/bindings/mono/efl_mono/Bind.cs
+++ b/src/bindings/mono/efl_mono/Bind.cs
@@ -3,6 +3,7 @@
3using System; 3using System;
4using System.Runtime.InteropServices; 4using System.Runtime.InteropServices;
5using System.Collections.Generic; 5using System.Collections.Generic;
6using System.Reflection;
6using System.Linq; 7using System.Linq;
7using System.ComponentModel; 8using System.ComponentModel;
8 9
@@ -47,8 +48,15 @@ public class BindableProperty<T>
47 throw new InvalidOperationException($"Failed to cast binder {binder} to IPart"); 48 throw new InvalidOperationException($"Failed to cast binder {binder} to IPart");
48 } 49 }
49 50
50 var partBinder = partHolder.GetPart(this.partName) as Efl.Ui.IPropertyBind; 51 // We rely on reflection as GetPart is protected and not generated in IPart.
52 var partMethod = partHolder.GetType().GetMethod("GetPart", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
51 53
54 if (partMethod == null)
55 {
56 throw new InvalidOperationException($"Failed to get 'GetPart' method on property binder");
57 }
58
59 var partBinder = partMethod.Invoke(partHolder, new System.Object[] { this.partName }) as Efl.Ui.IPropertyBind;
52 if (partBinder != null) 60 if (partBinder != null)
53 { 61 {
54 return partBinder.PropertyBind(this.propertyName, modelProperty); 62 return partBinder.PropertyBind(this.propertyName, modelProperty);
diff --git a/src/lib/eolian_cxx/grammar/klass_def.hpp b/src/lib/eolian_cxx/grammar/klass_def.hpp
index 108be02f79..683bb000a4 100644
--- a/src/lib/eolian_cxx/grammar/klass_def.hpp
+++ b/src/lib/eolian_cxx/grammar/klass_def.hpp
@@ -1277,6 +1277,26 @@ struct klass_def
1277 || lhs.parts < rhs.parts; 1277 || lhs.parts < rhs.parts;
1278 } 1278 }
1279 1279
1280 friend inline bool operator==(klass_def const& lhs, klass_name const& rhs)
1281 {
1282 return lhs.namespaces == rhs.namespaces
1283 && lhs.eolian_name == rhs.eolian_name
1284 && lhs.type == rhs.type;
1285 }
1286 friend inline bool operator==(klass_name const& lhs, klass_def const& rhs)
1287 {
1288 return rhs == lhs;
1289 }
1290 friend inline bool operator!=(klass_def const& lhs, klass_name const& rhs)
1291 {
1292 return !(lhs == rhs);
1293 }
1294 friend inline bool operator!=(klass_name const& lhs, klass_def const& rhs)
1295 {
1296 return !(rhs == lhs);
1297 }
1298
1299
1280 klass_def(std::string eolian_name, std::string cxx_name, std::string filename 1300 klass_def(std::string eolian_name, std::string cxx_name, std::string filename
1281 , documentation_def documentation 1301 , documentation_def documentation
1282 , std::vector<std::string> namespaces 1302 , std::vector<std::string> namespaces
diff --git a/src/tests/efl_mono/Eo.cs b/src/tests/efl_mono/Eo.cs
index 56813b3f87..efb1faa306 100644
--- a/src/tests/efl_mono/Eo.cs
+++ b/src/tests/efl_mono/Eo.cs
@@ -1,6 +1,7 @@
1using System; 1using System;
2using System.Linq; 2using System.Linq;
3using System.Collections.Generic; 3using System.Collections.Generic;
4using System.Reflection;
4 5
5namespace TestSuite 6namespace TestSuite
6{ 7{
@@ -533,4 +534,77 @@ class TestObjectDeletion
533 } 534 }
534} 535}
535 536
537class TestProtectedInterfaceMembers
538{
539
540 private class MyObject : Dummy.TestObject
541 {
542 public MyObject(Efl.Object parent = null) : base(parent)
543 {
544 }
545
546 protected override int MethodProtected(int x)
547 {
548 return x * x;
549 }
550 }
551
552 public static void test_protected_interface_in_generated_class_called_from_c()
553 {
554 var obj = new Dummy.TestObject();
555 Test.AssertEquals(obj.CallMethodProtected(42), -42);
556 }
557
558 public static void test_protected_interface_in_inherited_class_called_from_c()
559 {
560 var obj = new MyObject();
561 Test.AssertEquals(obj.CallMethodProtected(42), 42 * 42);
562 }
563
564 public static void test_interface_skipped_protected()
565 {
566 var type = typeof(Dummy.ITestIface);
567 var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
568
569 // Fully protected property
570 Test.AssertNull(methods.SingleOrDefault(m => m.Name == "GetProtectedProp"));
571 Test.AssertNull(methods.SingleOrDefault(m => m.Name == "SetProtectedProp"));
572
573 // Partially protected property
574 Test.AssertNotNull(methods.SingleOrDefault(m => m.Name == "GetPublicGetterPrivateSetter"));
575 Test.AssertNull(methods.SingleOrDefault(m => m.Name == "SetPublicGetterPrivateSetter"));
576
577 var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
578 Test.AssertNull(properties.SingleOrDefault(m => m.Name == "ProtectedProp"));
579 Test.AssertNotNull(properties.SingleOrDefault(m => m.Name == "PublicGetterPrivateSetter"));
580 }
581
582 public static void test_interface_skipped_protected_in_implementation()
583 {
584 var type = typeof(Dummy.TestObject);
585
586 // Fully protected property
587 var protected_methods = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(m => m.IsFamily);
588 Test.AssertNotNull(protected_methods.SingleOrDefault(m => m.Name == "GetProtectedProp"));
589 Test.AssertNotNull(protected_methods.SingleOrDefault(m => m.Name == "SetProtectedProp"));
590
591 // Partially protected property
592 var public_methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance);
593 Test.AssertNotNull(public_methods.SingleOrDefault(m => m.Name == "GetPublicGetterPrivateSetter"));
594 Test.AssertNotNull(protected_methods.SingleOrDefault(m => m.Name == "SetPublicGetterPrivateSetter"));
595
596 var protected_properties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
597 var prop = protected_properties.SingleOrDefault(m => m.Name == "ProtectedProp");
598 Test.AssertNotNull(prop);
599 Test.Assert(prop.GetMethod.IsFamily);
600 Test.Assert(prop.SetMethod.IsFamily);
601
602 var public_properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
603 prop = public_properties.SingleOrDefault(m => m.Name == "PublicGetterPrivateSetter");
604 Test.AssertNotNull(prop);
605 Test.Assert(prop.GetMethod.IsPublic);
606 Test.Assert(prop.SetMethod.IsFamily);
607 }
608}
609
536} 610}
diff --git a/src/tests/efl_mono/dummy_interfaces.c b/src/tests/efl_mono/dummy_interfaces.c
index f4b3ca5948..c60ec59f0a 100644
--- a/src/tests/efl_mono/dummy_interfaces.c
+++ b/src/tests/efl_mono/dummy_interfaces.c
@@ -1,4 +1,6 @@
1// Include file for interfaces .eo.c files 1// Include file for interfaces .eo.c files
2#define DUMMY_TEST_IFACE_PROTECTED
3
2#include "libefl_mono_native_test.h" 4#include "libefl_mono_native_test.h"
3 5
4#include "dummy_test_iface.eo.c" 6#include "dummy_test_iface.eo.c"
diff --git a/src/tests/efl_mono/dummy_test_iface.eo b/src/tests/efl_mono/dummy_test_iface.eo
index 3ab37f5407..068b1352bd 100644
--- a/src/tests/efl_mono/dummy_test_iface.eo
+++ b/src/tests/efl_mono/dummy_test_iface.eo
@@ -10,6 +10,37 @@ interface Dummy.Test_Iface
10 data: int; 10 data: int;
11 } 11 }
12 } 12 }
13
14 method_protected @protected @const {
15 params {
16 @in x: int;
17 }
18 return: int;
19 }
20
21 call_method_protected @const {
22 params {
23 @in x: int;
24 }
25 return: int;
26 }
27
28 @property protected_prop @protected {
29 get {}
30 set {}
31 values {
32 data: int;
33 }
34 }
35
36 @property public_getter_private_setter {
37 get {}
38 set @protected {}
39 values {
40 data: int;
41 }
42 }
43
13 } 44 }
14 events { 45 events {
15 nonconflicted: void; 46 nonconflicted: void;
diff --git a/src/tests/efl_mono/dummy_test_object.c b/src/tests/efl_mono/dummy_test_object.c
index 6c32f80ca1..a880dc40c6 100644
--- a/src/tests/efl_mono/dummy_test_object.c
+++ b/src/tests/efl_mono/dummy_test_object.c
@@ -1,4 +1,6 @@
1 1
2#define DUMMY_TEST_IFACE_PROTECTED
3
2#include "libefl_mono_native_test.h" 4#include "libefl_mono_native_test.h"
3 5
4typedef struct Dummy_Test_Object_Data 6typedef struct Dummy_Test_Object_Data
@@ -4704,6 +4706,16 @@ const Eina_Value_Type *_dummy_test_object_mirror_value_type(EINA_UNUSED const Eo
4704 return type; 4706 return type;
4705} 4707}
4706 4708
4709int _dummy_test_object_dummy_test_iface_method_protected(EINA_UNUSED const Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd, int x)
4710{
4711 return -x;
4712}
4713
4714int _dummy_test_object_dummy_test_iface_call_method_protected(const Eo *obj, EINA_UNUSED Dummy_Test_Object_Data *pd, int x)
4715{
4716 return dummy_test_iface_method_protected(obj, x);
4717}
4718
4707// Inherit 4719// Inherit
4708int _dummy_inherit_helper_receive_dummy_and_call_int_out(Dummy_Test_Object *x) 4720int _dummy_inherit_helper_receive_dummy_and_call_int_out(Dummy_Test_Object *x)
4709{ 4721{
diff --git a/src/tests/efl_mono/dummy_test_object.eo b/src/tests/efl_mono/dummy_test_object.eo
index 2fa2c32c55..676b68a421 100644
--- a/src/tests/efl_mono/dummy_test_object.eo
+++ b/src/tests/efl_mono/dummy_test_object.eo
@@ -1653,6 +1653,8 @@ class Dummy.Test_Object extends Efl.Object implements Dummy.Test_Iface {
1653 Efl.Object.provider_find; 1653 Efl.Object.provider_find;
1654 Dummy.Test_Iface.emit_nonconflicted; 1654 Dummy.Test_Iface.emit_nonconflicted;
1655 Dummy.Test_Iface.iface_prop { get; set; } 1655 Dummy.Test_Iface.iface_prop { get; set; }
1656 Dummy.Test_Iface.method_protected;
1657 Dummy.Test_Iface.call_method_protected;
1656 } 1658 }
1657 events { 1659 events {
1658 evt,with,string @hot: const(string); 1660 evt,with,string @hot: const(string);