[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:
Alex Soto 2017-12-18 08:21:23 -06:00 коммит произвёл Sebastien Pouliot
Родитель ddf9d63078
Коммит f8d7c54a0f
3 изменённых файлов: 123 добавлений и 4 удалений

Просмотреть файл

@ -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 ();