[registrar] Fix verification of generic parameters to accept unrelated generic types. Fixes #6687. (#6850)

* [registrar] Fix verification of generic parameters to accept unrelated generic types. Fixes #6687.

When we export generic classes to Objective-C, we verify that any generic
parameters are constrained so that we know how to handle them.

Example:

    class MyObj<T> : NSObject where T: NSObject
    {
        [Export ("foo:")]
        public void Foo (T obj);
    }

in this case we verify that the parameter T is constrained to NSObject, so
that we can treat the argument like an NSObject.

The problem was when the function contained a generic type which was not
related to T:

    class MyObj<T> : NSObject where T: NSObject
    {
        [Export ("foo:")]
        public void Foo (Action<int> obj);
    }

in which case the same logic would kick in and reject the Action<int> type
since it's not related to NSObject (no generic arguments could be found, and
the default response was 'not valid').

So I've changed the default response for generic types that are unrelated to
the generic parameter we're verifying to accept such types.

Fixes https://github.com/xamarin/xamarin-macios/issues/6687.

* No need to use a UIViewController as the super class, NSObject works just fine for this test.

Fixes the test build on macOS.
This commit is contained in:
Rolf Bjarne Kvinge 2019-08-27 06:41:17 -07:00 коммит произвёл GitHub
Родитель fac23dc599
Коммит 73ce0f8882
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 55 добавлений и 14 удалений

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

@ -503,20 +503,7 @@ namespace Registrar {
return rv;
}
if (type.IsGenericType) {
var rv = true;
var args = type.GetGenericArguments ();
var constrs = new Type [args.Length];
for (int i = 0; i < args.Length; i++) {
Type constr;
rv &= VerifyIsConstrainedToNSObject (args [i], out constr);
constrs [i] = constr;
}
constrained_type = type.GetGenericTypeDefinition ().MakeGenericType (constrs);
return rv;
}
return false;
return true;
}
protected override Exception CreateException (int code, Exception innerException, MethodBase method, string message, params object[] args)

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

@ -254,6 +254,9 @@ namespace MonoTouch.ObjCRuntime
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_int_int_int (IntPtr receiver, IntPtr selector, int p1, ref int p2, out int p3);
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_IntPtr_IntPtr_BlockLiteral (IntPtr receiver, IntPtr selector, IntPtr p1, IntPtr p2, ref BlockLiteral p3);
}
}

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

@ -35,6 +35,7 @@ using CoreLocation;
#if !__TVOS__
using Contacts;
#endif
using WebKit;
#else
using MonoTouch;
using MonoTouch.AddressBook;
@ -5246,6 +5247,44 @@ namespace MonoTouchFixtures.ObjCRuntime {
}
}
#if !__WATCHOS__ && !__TVOS__ // No WebKit on watchOS/tvOS
[Test]
public void GenericClassWithUnrelatedGenericDelegate ()
{
using (var obj = new GenericWebNavigationThingie<NSObject> ()) {
var handler_called = false;
Action<WKNavigationActionPolicy> handler = new Action<WKNavigationActionPolicy> ((v) => {
handler_called = true;
});
var block = new BlockLiteral ();
var tramp = new DActionArity1V3 (SDActionArity1V3.Invoke);
if (Runtime.DynamicRegistrationSupported) {
block.SetupBlock (tramp, handler);
Messaging.void_objc_msgSend_IntPtr_IntPtr_BlockLiteral (obj.Handle, Selector.GetHandle ("webView:decidePolicyForNavigationAction:decisionHandler:"), IntPtr.Zero, IntPtr.Zero, ref block);
block.CleanupBlock ();
Assert.IsTrue (handler_called, "Handler called");
} else {
Assert.Throws<RuntimeException> (() => block.SetupBlock (tramp, handler));
}
}
}
[UnmanagedFunctionPointerAttribute (CallingConvention.Cdecl)]
internal delegate void DActionArity1V3 (IntPtr block, nint value);
static internal class SDActionArity1V3 {
static internal readonly DActionArity1V3 Handler = Invoke;
[MonoPInvokeCallback (typeof (DActionArity1V3))]
public static unsafe void Invoke (IntPtr block, nint value)
{
var del = BlockLiteral.GetTarget<Action<WKNavigationActionPolicy>> (block);
if (del != null)
del ((WKNavigationActionPolicy) (long) value);
}
}
#endif // !__WATCHOS__ && !__TVOS__
}
#if !__WATCHOS__
@ -5382,6 +5421,18 @@ namespace MonoTouchFixtures.ObjCRuntime {
public class SomeConsumer : NSObject, ISomeDelegate
{
}
#if !__WATCHOS__ && !__TVOS__ // No WebKit on watchOS/tvOS
[Preserve]
public class GenericWebNavigationThingie<WebViewModel> : NSObject, IWKNavigationDelegate {
[Export ("webView:decidePolicyForNavigationAction:decisionHandler:")]
public void DecidePolicy (WKWebView webView, WKNavigationAction navigationAction, Action<WKNavigationActionPolicy> decisionHandler)
{
decisionHandler (WKNavigationActionPolicy.Allow);
}
}
#endif
#if !__WATCHOS__ // no MetalKit on watchOS
// These classes implement Metal* protocols, so that the generated registrar code includes the corresponding Metal* headers.
// https://github.com/xamarin/xamarin-macios/issues/4422