When we're searching for metadata for marshalling blocks, we must search the entire interface hierarchy for protocols that implement optional members. Fixes https://github.com/xamarin/xamarin-macios/issues/6493.
This commit is contained in:
Родитель
f80e6b4032
Коммит
a7f4c7011e
|
@ -135,6 +135,7 @@ namespace Registrar {
|
|||
public CategoryAttribute CategoryAttribute;
|
||||
public TType Type;
|
||||
public ObjCType BaseType;
|
||||
// This only contains the leaf protocols implemented by this type.
|
||||
public ObjCType [] Protocols;
|
||||
public string [] AdoptedProtocols;
|
||||
public bool IsModel;
|
||||
|
@ -159,6 +160,44 @@ namespace Registrar {
|
|||
|
||||
public bool IsCategory { get { return CategoryAttribute != null; } }
|
||||
|
||||
#if MTOUCH || MMP
|
||||
HashSet<ObjCType> all_protocols;
|
||||
// This contains all protocols in the type hierarchy.
|
||||
// Given a type T that implements a protocol with super protocols:
|
||||
// class T : NSObject, IProtocol2 {}
|
||||
// [Protocol]
|
||||
// interface IP1 {}
|
||||
// [Protocol]
|
||||
// interface IP2 : IP1 {}
|
||||
// This property will contain both IP1 and IP2. The Protocols property only contains IP2.
|
||||
public IEnumerable<ObjCType> AllProtocols {
|
||||
get {
|
||||
if (Protocols == null || Protocols.Length == 0)
|
||||
return null;
|
||||
|
||||
if (all_protocols == null) {
|
||||
var queue = new Queue<ObjCType> (Protocols);
|
||||
var rv = new HashSet<ObjCType> ();
|
||||
while (queue.Count > 0) {
|
||||
var type = queue.Dequeue ();
|
||||
if (rv.Add (type)) {
|
||||
foreach (var iface in type.Type.Resolve ().Interfaces) {
|
||||
if (!Registrar.Types.TryGetValue (iface.InterfaceType, out var superIface)) {
|
||||
// This is not an interface that corresponds to a protocol.
|
||||
continue;
|
||||
}
|
||||
queue.Enqueue (superIface);
|
||||
}
|
||||
}
|
||||
}
|
||||
all_protocols = rv;
|
||||
}
|
||||
|
||||
return all_protocols;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public void VerifyRegisterAttribute (ref List<Exception> exceptions)
|
||||
{
|
||||
if (RegisterAttribute == null)
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#if XAMCORE_2_0
|
||||
using Foundation;
|
||||
#if MONOMAC
|
||||
|
@ -66,5 +69,140 @@ namespace MonoTouchFixtures.Foundation {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !__WATCHOS__
|
||||
[Test]
|
||||
public void RegistrarTest ()
|
||||
{
|
||||
Exception ex = null;
|
||||
var done = new ManualResetEvent (false);
|
||||
var success = false;
|
||||
|
||||
Task.Run (async () => {
|
||||
try {
|
||||
var config = NSUrlSessionConfiguration.DefaultSessionConfiguration;
|
||||
config.WeakProtocolClasses = NSArray.FromNSObjects (new Class (typeof (CustomUrlProtocol)));
|
||||
var session = NSUrlSession.FromConfiguration (config);
|
||||
var custom_url = new NSUrl ("foo://server");
|
||||
using (var task = await session.CreateDownloadTaskAsync (custom_url)) {
|
||||
success = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
done.Set ();
|
||||
}
|
||||
});
|
||||
|
||||
Assert.IsTrue (TestRuntime.RunAsync (DateTime.Now.AddSeconds (10), () => { }, () => done.WaitOne (0)), "Timed out");
|
||||
Assert.IsNull (ex, "Exception");
|
||||
Assert.IsTrue (custom_url_protocol_instance.Called_DidCompleteWithError, "DidCompleteWithError");
|
||||
// if DidReceiveChallenge is called or not seems to vary between test runs, so we can't assert it.
|
||||
//Assert.IsFalse (custom_url_protocol_instance.Called_DidReceiveChallenge, "DidReceiveChallenge");
|
||||
Assert.IsTrue (custom_url_protocol_instance.Called_DidReceiveData, "DidReceiveData");
|
||||
Assert.IsTrue (custom_url_protocol_instance.Called_DidReceiveResponse, "DidReceiveResponse");
|
||||
Assert.IsTrue (custom_url_protocol_instance.Called_StartLoading, "StartLoading");
|
||||
Assert.IsTrue (custom_url_protocol_instance.Called_StopLoading, "StopLoading");
|
||||
Assert.IsTrue (custom_url_protocol_instance.Called_WillPerformHttpRedirection, "WillPerformHttpRedirection");
|
||||
|
||||
Assert.IsTrue (CustomUrlProtocol.Called_CanInitWithRequest, "CanInitWithRequest");
|
||||
Assert.IsTrue (CustomUrlProtocol.Called_GetCanonicalRequest, "GetCanonicalRequest");
|
||||
|
||||
Assert.IsTrue (success, "Success");
|
||||
}
|
||||
|
||||
static CustomUrlProtocol custom_url_protocol_instance;
|
||||
|
||||
public class CustomUrlProtocol : NSUrlProtocol, INSUrlSessionDelegate, INSUrlSessionTaskDelegate, INSUrlSessionDataDelegate {
|
||||
[Export ("canInitWithRequest:")]
|
||||
public static new bool CanInitWithRequest (NSUrlRequest request)
|
||||
{
|
||||
Called_CanInitWithRequest = true;
|
||||
return true;
|
||||
}
|
||||
public static bool Called_CanInitWithRequest;
|
||||
|
||||
[Export ("canonicalRequestForRequest:")]
|
||||
public static new NSUrlRequest GetCanonicalRequest (NSUrlRequest request)
|
||||
{
|
||||
Called_GetCanonicalRequest = true;
|
||||
return request;
|
||||
}
|
||||
public static bool Called_GetCanonicalRequest;
|
||||
|
||||
[Export ("initWithRequest:cachedResponse:client:")]
|
||||
public CustomUrlProtocol (NSUrlRequest request, NSCachedUrlResponse cachedResponse, INSUrlProtocolClient client)
|
||||
: base (request, cachedResponse, client)
|
||||
{
|
||||
custom_url_protocol_instance = this;
|
||||
}
|
||||
|
||||
[Export ("startLoading")]
|
||||
public override void StartLoading ()
|
||||
{
|
||||
Called_StartLoading = true;
|
||||
var config = NSUrlSession.SharedSession.Configuration;
|
||||
var session = NSUrlSession.FromConfiguration (config, this, new NSOperationQueue ());
|
||||
|
||||
var task = session.CreateDataTask (new NSUrlRequest (new NSUrl ("https://microsoft.com")));
|
||||
task.Resume ();
|
||||
}
|
||||
public bool Called_StartLoading;
|
||||
|
||||
[Export ("stopLoading")]
|
||||
public override void StopLoading ()
|
||||
{
|
||||
Called_StopLoading = true;
|
||||
}
|
||||
public bool Called_StopLoading;
|
||||
|
||||
//NSURLSessionTaskDelegate
|
||||
[Export ("URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:")]
|
||||
public virtual void WillPerformHttpRedirection (NSUrlSession session, NSUrlSessionTask task, NSHttpUrlResponse response, NSUrlRequest newRequest, Action<NSUrlRequest> completionHandler)
|
||||
{
|
||||
Called_WillPerformHttpRedirection = true;
|
||||
completionHandler (newRequest);
|
||||
}
|
||||
public bool Called_WillPerformHttpRedirection;
|
||||
|
||||
[Export ("URLSession:task:didReceiveChallenge:completionHandler:")]
|
||||
public virtual void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
|
||||
{
|
||||
Called_DidReceiveChallenge = true;
|
||||
completionHandler (NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null);
|
||||
}
|
||||
public bool Called_DidReceiveChallenge;
|
||||
|
||||
//NSURLSessionDataDelegate
|
||||
[Export ("URLSession:dataTask:didReceiveResponse:completionHandler:")]
|
||||
public virtual void DidReceiveResponse (NSUrlSession session, NSUrlSessionDataTask dataTask, NSUrlResponse response, Action<NSUrlSessionResponseDisposition> completionHandler)
|
||||
{
|
||||
Called_DidReceiveResponse = true;
|
||||
completionHandler (NSUrlSessionResponseDisposition.Allow);
|
||||
this.Client.ReceivedResponse (this, response, NSUrlCacheStoragePolicy.Allowed);
|
||||
}
|
||||
public bool Called_DidReceiveResponse;
|
||||
|
||||
[Export ("URLSession:dataTask:didReceiveData:")]
|
||||
public virtual void DidReceiveData (NSUrlSession session, NSUrlSessionDataTask dataTask, NSData data)
|
||||
{
|
||||
Called_DidReceiveData = true;
|
||||
this.Client.DataLoaded (this, data);
|
||||
}
|
||||
public bool Called_DidReceiveData;
|
||||
|
||||
[Export ("URLSession:task:didCompleteWithError:")]
|
||||
public virtual void DidCompleteWithError (NSUrlSession session, NSUrlSessionTask task, NSError error)
|
||||
{
|
||||
Called_DidCompleteWithError = true;
|
||||
if (error != null) {
|
||||
this.Client.FailedWithError (this, error);
|
||||
} else {
|
||||
this.Client.FinishedLoading (this);
|
||||
}
|
||||
}
|
||||
public bool Called_DidCompleteWithError;
|
||||
}
|
||||
#endif // !__WATCHOS__
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4137,10 +4137,11 @@ namespace Registrar {
|
|||
}
|
||||
|
||||
// Might be an implementation of an optional protocol member.
|
||||
if (obj_method.DeclaringType.Protocols != null) {
|
||||
var allProtocols = obj_method.DeclaringType.AllProtocols;
|
||||
if (allProtocols != null) {
|
||||
string selector = null;
|
||||
|
||||
foreach (var proto in obj_method.DeclaringType.Protocols) {
|
||||
foreach (var proto in allProtocols) {
|
||||
// We store the DelegateProxy type in the ProtocolMemberAttribute, so check those.
|
||||
if (selector == null)
|
||||
selector = obj_method.Selector ?? string.Empty;
|
||||
|
@ -4183,10 +4184,11 @@ namespace Registrar {
|
|||
}
|
||||
|
||||
// Might be an implementation of an optional protocol member.
|
||||
if (obj_method.DeclaringType.Protocols != null) {
|
||||
var allProtocols = obj_method.DeclaringType.AllProtocols;
|
||||
if (allProtocols != null) {
|
||||
string selector = null;
|
||||
|
||||
foreach (var proto in obj_method.DeclaringType.Protocols) {
|
||||
foreach (var proto in allProtocols) {
|
||||
// We store the BlockProxy type in the ProtocolMemberAttribute, so check those.
|
||||
// We may run into binding assemblies built with earlier versions of the generator,
|
||||
// which means we can't rely on finding the BlockProxy attribute in the ProtocolMemberAttribute.
|
||||
|
|
Загрузка…
Ссылка в новой задаче