diff --git a/docs/website/generator-errors.md b/docs/website/generator-errors.md index c6835ccf5e..0b95a9f08e 100644 --- a/docs/website/generator-errors.md +++ b/docs/website/generator-errors.md @@ -174,6 +174,8 @@ This usually indicates a bug in Xamarin.iOS/Xamarin.Mac; please [file a bug repo ### BI1061: The attribute '{attribute}' found on '{member}' is not a valid binding attribute. Please remove this attribute. +### BI1062: The member '*' contains ref/out parameters and must not be decorated with [Async]. + # BI11xx: warnings @@ -210,6 +212,8 @@ This usually indicates a bug in Xamarin.iOS/Xamarin.Mac; please [file a bug repo ### BI1116: The parameter '*' in the delegate '*' does not have a [CCallback] or [BlockCallback] attribute. Defaulting to [CCallback]. Declare a custom delegate instead of using System.Action / System.Func and add the attribute on the corresponding parameter. +### BI1117: The member '*' is decorated with [Static] and its container class * is decorated with [Category] this leads to hard to use code. Please inline * into * class. + diff --git a/src/generator.cs b/src/generator.cs index 2e17a3cfab..90de5013e4 100644 --- a/src/generator.cs +++ b/src/generator.cs @@ -4110,7 +4110,7 @@ public partial class Generator : IMemberGatherer { var hasStaticAtt = AttributeManager.HasAttribute (mi); if (category_type != null && hasStaticAtt && !minfo.ignore_category_static_warnings) { var baseTypeAtt = AttributeManager.GetCustomAttribute (minfo.type); - ErrorHelper.Show (new BindingException (1117, "The {0} member is decorated with [Static] and its container class {1} is decorated with [Category] this leads to hard to use code. Please inline {0} into {2} class.", mi.Name, type.FullName, baseTypeAtt?.BaseType.FullName)); + ErrorHelper.Show (new BindingException (1117, "The member '{0}' is decorated with [Static] and its container class {1} is decorated with [Category] this leads to hard to use code. Please inline {0} into {2} class.", mi.Name, type.FullName, baseTypeAtt?.BaseType.FullName)); } indent++; @@ -4885,6 +4885,21 @@ public partial class Generator : IMemberGatherer { var mi = original_minfo.method; var minfo = new AsyncMethodInfo (this, original_minfo.type, mi, original_minfo.category_extension_type, original_minfo.is_extension_method); var is_void = mi.ReturnType == TypeManager.System_Void; + + // Print a error if any of the method parameters or handler parameters is ref/out, it should not be asyncified. + if (minfo.async_initial_params != null) { + foreach (var param in minfo.async_initial_params) { + if (param.ParameterType.IsByRef) { + throw new BindingException (1062, true, $"The member '{original_minfo.type.Name}.{mi.Name}' contains ref/out parameters and must not be decorated with [Async]."); + } + } + } + foreach (var param in minfo.async_completion_params) { + if (param.ParameterType.IsByRef) { + throw new BindingException (1062, true, $"The member '{original_minfo.type.Name}.{mi.Name}' contains ref/out parameters and must not be decorated with [Async]."); + } + } + PrintMethodAttributes (minfo); PrintAsyncHeader (minfo, asyncKind); diff --git a/tests/generator/ErrorTests.cs b/tests/generator/ErrorTests.cs index 5c5d3a1208..227bf8df78 100644 --- a/tests/generator/ErrorTests.cs +++ b/tests/generator/ErrorTests.cs @@ -221,7 +221,7 @@ namespace Bug52570Tests { } }"); bgen.AssertExecute ("build"); - bgen.AssertWarning (1117, "The SomeMethod member is decorated with [Static] and its container class Bug52570Tests.FooObject_Extensions is decorated with [Category] this leads to hard to use code. Please inline SomeMethod into Bug52570Tests.FooObject class."); + bgen.AssertWarning (1117, "The member 'SomeMethod' is decorated with [Static] and its container class Bug52570Tests.FooObject_Extensions is decorated with [Category] this leads to hard to use code. Please inline SomeMethod into Bug52570Tests.FooObject class."); } [Test] @@ -445,12 +445,112 @@ namespace Bug57094 { bgen.AssertError (1014, "Unsupported type for Fields: byte[] for 'Bug57094.FooObject SomeField'."); } + [Test] + public void BI1062_NoAsyncMethodRefHandlerTest () + { + var bgen = new BGenTool (); + bgen.Profile = Profile.iOS; + bgen.CreateTemporaryBinding (@" +using System; +using Foundation; + +namespace BI1062Tests { + + delegate void MyHandler (ref bool staaph, NSError error); + + [BaseType (typeof (NSObject))] + interface FooObject { + + [Async] + [Export (""fooMethod:"")] + void FooMethod (MyHandler handler); + } +}"); + bgen.AssertExecuteError ("build"); + bgen.AssertError (1062, "The member 'FooObject.FooMethod' contains ref/out parameters and must not be decorated with [Async]."); + } + + [Test] + public void BI1062_NoAsyncMethodOutHandlerTest () + { + var bgen = new BGenTool (); + bgen.Profile = Profile.iOS; + bgen.CreateTemporaryBinding (@" +using System; +using Foundation; + +namespace BI1062Tests { + + delegate void MyHandler (out bool staaph, NSError error); + + [BaseType (typeof (NSObject))] + interface FooObject { + + [Async] + [Export (""fooMethod:"")] + void FooMethod (MyHandler handler); + } +}"); + bgen.AssertExecuteError ("build"); + bgen.AssertError (1062, "The member 'FooObject.FooMethod' contains ref/out parameters and must not be decorated with [Async]."); + } + + [Test] + public void BI1062_NoAsyncMethodOutParameterTest () + { + var bgen = new BGenTool (); + bgen.Profile = Profile.iOS; + bgen.CreateTemporaryBinding (@" +using System; +using Foundation; + +namespace BI1062Tests { + + delegate void MyHandler (bool staaph, NSError error); + + [BaseType (typeof (NSObject))] + interface FooObject { + + [Async] + [Export (""fooMethod:completion:"")] + void FooMethod (out NSObject obj, MyHandler handler); + } +}"); + bgen.AssertExecuteError ("build"); + bgen.AssertError (1062, "The member 'FooObject.FooMethod' contains ref/out parameters and must not be decorated with [Async]."); + } + + [Test] + public void BI1062_NoAsyncMethodRefParameterTest () + { + var bgen = new BGenTool (); + bgen.Profile = Profile.iOS; + bgen.CreateTemporaryBinding (@" +using System; +using Foundation; + +namespace BI1062Tests { + + delegate void MyHandler (bool staaph, NSError error); + + [BaseType (typeof (NSObject))] + interface FooObject { + + [Async] + [Export (""fooMethod:completion:"")] + void FooMethod (ref NSObject obj, Action handler); + } +}"); + bgen.AssertExecuteError ("build"); + bgen.AssertError (1062, "The member 'FooObject.FooMethod' contains ref/out parameters and must not be decorated with [Async]."); + } + [Test] [TestCase (Profile.iOS)] [TestCase (Profile.macClassic)] public void WarnAsError (Profile profile) { - const string message = "The SomeMethod member is decorated with [Static] and its container class warnaserrorTests.FooObject_Extensions is decorated with [Category] this leads to hard to use code. Please inline SomeMethod into warnaserrorTests.FooObject class."; + const string message = "The member 'SomeMethod' is decorated with [Static] and its container class warnaserrorTests.FooObject_Extensions is decorated with [Category] this leads to hard to use code. Please inline SomeMethod into warnaserrorTests.FooObject class."; { // Enabled var bgen = new BGenTool (); @@ -500,7 +600,7 @@ namespace Bug57094 { [TestCase (Profile.macClassic)] public void NoWarn (Profile profile) { - const string message = "The SomeMethod member is decorated with [Static] and its container class nowarnTests.FooObject_Extensions is decorated with [Category] this leads to hard to use code. Please inline SomeMethod into nowarnTests.FooObject class."; + const string message = "The member 'SomeMethod' is decorated with [Static] and its container class nowarnTests.FooObject_Extensions is decorated with [Category] this leads to hard to use code. Please inline SomeMethod into nowarnTests.FooObject class."; { // Enabled var bgen = new BGenTool ();