[generator] Disallow the use of [Async] when the signature contains ref/out parameters, fixes bug 58792. (#3059)
When a method signature contains any ref/out parameters it is a hint that this method is not a candidate to be used with [Async] we now error BI1062 in the generator. The reason of an error instead of a warning is that we currently generate not compilable code when ref/out is used on the method signature or in the signature of the delegate (completion handler), it is very unlikely we are breaking someone now that we emit an error instead of broken code. * Fix Anchor and Clarify the addition of BI1117 Warning into docs/website/generator-errors.md BI1117 Warning documentation was missing from docs/website/generator-errors.md so I added it.
This commit is contained in:
Родитель
ddf9d63078
Коммит
f8d7c54a0f
|
@ -174,6 +174,8 @@ This usually indicates a bug in Xamarin.iOS/Xamarin.Mac; please [file a bug repo
|
|||
|
||||
### <a name='BI1061'/>BI1061: The attribute '{attribute}' found on '{member}' is not a valid binding attribute. Please remove this attribute.
|
||||
|
||||
### <a name='BI1062'/>BI1062: The member '*' contains ref/out parameters and must not be decorated with [Async].
|
||||
|
||||
# BI11xx: warnings
|
||||
|
||||
<!-- 11xx: warnings -->
|
||||
|
@ -210,6 +212,8 @@ This usually indicates a bug in Xamarin.iOS/Xamarin.Mac; please [file a bug repo
|
|||
|
||||
### <a name='BI1116'/>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.
|
||||
|
||||
### <a name='BI1117'/>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.
|
||||
|
||||
<!-- 2xxx: reserved -->
|
||||
<!-- 3xxx: reserved -->
|
||||
<!-- 4xxx: reserved -->
|
||||
|
|
|
@ -4110,7 +4110,7 @@ public partial class Generator : IMemberGatherer {
|
|||
var hasStaticAtt = AttributeManager.HasAttribute<StaticAttribute> (mi);
|
||||
if (category_type != null && hasStaticAtt && !minfo.ignore_category_static_warnings) {
|
||||
var baseTypeAtt = AttributeManager.GetCustomAttribute<BaseTypeAttribute> (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);
|
||||
|
|
|
@ -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<bool, NSError> 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 ();
|
||||
|
|
Загрузка…
Ссылка в новой задаче