Merge remote-tracking branch 'origin/master' into mono-2018-06

This commit is contained in:
Rolf Bjarne Kvinge 2018-09-06 16:37:37 +02:00
Родитель a285ec72bc bd32b74347
Коммит 28347f9167
30 изменённых файлов: 769 добавлений и 123 удалений

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

@ -378,6 +378,20 @@ will be shown.
Reference: https://github.com/xamarin/xamarin-macios/issues/4072 Reference: https://github.com/xamarin/xamarin-macios/issues/4072
### <a name="MM4176"/>MM4176: Unable to locate the delegate to block conversion type for the return value of the method {method}.
This is a warning indicating that the static registrar couldn't find the type
used to convert a delegate to an Objective-C block. An attempt will be made at
runtime to find the method, but it will likely fail as well (with an MM8009
exception).
One possible reason for this warning is when manually writing bindings for API
that uses blocks. It's recommended to use a binding project to bind
Objective-C code, in particular when it involves blocks, since it's quite
complicated to get it right when doing it manually.
If this is not the case, please file a bug at [https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=Xamarin.Mac) with a test case.
# MM5xxx: GCC and toolchain # MM5xxx: GCC and toolchain
## MM51xx: compilation ## MM51xx: compilation

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

@ -1787,6 +1787,20 @@ will be shown.
Reference: https://github.com/xamarin/xamarin-macios/issues/4072 Reference: https://github.com/xamarin/xamarin-macios/issues/4072
### <a name="MT4176"/>MT4176: Unable to locate the delegate to block conversion type for the return value of the method {method}.
This is a warning indicating that the static registrar couldn't find the type
used to convert a delegate to an Objective-C block. An attempt will be made at
runtime to find the method, but it will likely fail as well (with an MT8009
exception).
One possible reason for this warning is when manually writing bindings for API
that uses blocks. It's recommended to use a binding project to bind
Objective-C code, in particular when it involves blocks, since it's quite
complicated to get it right when doing it manually.
If this is not the case, please file a bug at [https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS) with a test case.
# MT5xxx: GCC and toolchain error messages # MT5xxx: GCC and toolchain error messages
### MT51xx: Compilation ### MT51xx: Compilation

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

@ -21,7 +21,10 @@
<_DebugFileExt Condition="'$(_DebugFileExt)' == ''">.mdb</_DebugFileExt> <_DebugFileExt Condition="'$(_DebugFileExt)' == ''">.mdb</_DebugFileExt>
</PropertyGroup> </PropertyGroup>
<Import Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets')" <Import Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')"
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets" />
<Import Condition="!$(MSBuildAllProjects.Contains('Microsoft.FSharp.Targets')) and Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets')"
Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets" /> Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets" />
<Import Condition="!$(MSBuildAllProjects.Contains('Microsoft.FSharp.Targets')) and Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')" <Import Condition="!$(MSBuildAllProjects.Contains('Microsoft.FSharp.Targets')) and Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')"

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

@ -69,7 +69,8 @@
new XDelegate ("id", "IntPtr", "xamarin_create_delegate_proxy", new XDelegate ("id", "IntPtr", "xamarin_create_delegate_proxy",
"MonoObject *", "IntPtr", "method", "MonoObject *", "IntPtr", "method",
"MonoObject *", "IntPtr", "block", "MonoObject *", "IntPtr", "block",
"const char *", "IntPtr", "signature" "const char *", "IntPtr", "signature",
"unsigned int", "uint", "token_ref"
) { ) {
WrappedManagedFunction = "CreateDelegateProxy", WrappedManagedFunction = "CreateDelegateProxy",
OnlyDynamicUsage = false, OnlyDynamicUsage = false,

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

@ -2187,10 +2187,10 @@ xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref,
} }
id id
xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature, guint32 *exception_gchandle) xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature, guint32 token_ref, guint32 *exception_gchandle)
{ {
// COOP: accesses managed memory: unsafe mode. // COOP: accesses managed memory: unsafe mode.
return delegates.create_delegate_proxy ((MonoObject *) mono_method_get_object (mono_domain_get (), method, NULL), delegate, signature, exception_gchandle); return delegates.create_delegate_proxy ((MonoObject *) mono_method_get_object (mono_domain_get (), method, NULL), delegate, signature, token_ref, exception_gchandle);
} }
void void

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

@ -60,7 +60,7 @@ xamarin_marshal_return_value (MonoType *mtype, const char *type, MonoObject *ret
case _C_PTR: { case _C_PTR: {
MonoClass *klass = mono_class_from_mono_type (mtype); MonoClass *klass = mono_class_from_mono_type (mtype);
if (mono_class_is_delegate (klass)) { if (mono_class_is_delegate (klass)) {
return xamarin_get_block_for_delegate (method, retval, NULL, exception_gchandle); return xamarin_get_block_for_delegate (method, retval, NULL, INVALID_TOKEN_REF, exception_gchandle);
} else { } else {
return *(void **) mono_object_unbox (retval); return *(void **) mono_object_unbox (retval);
} }

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

@ -176,7 +176,7 @@ MonoType * xamarin_get_parameter_type (MonoMethod *managed_method, int index);
MonoObject * xamarin_get_nsobject_with_type_for_ptr (id self, bool owns, MonoType* type, SEL selector, MonoMethod *managed_method, guint32 *exception_gchandle); MonoObject * xamarin_get_nsobject_with_type_for_ptr (id self, bool owns, MonoType* type, SEL selector, MonoMethod *managed_method, guint32 *exception_gchandle);
MonoObject * xamarin_get_nsobject_with_type_for_ptr_created (id self, bool owns, MonoType *type, int32_t *created, SEL selector, MonoMethod *managed_method, guint32 *exception_gchandle); MonoObject * xamarin_get_nsobject_with_type_for_ptr_created (id self, bool owns, MonoType *type, int32_t *created, SEL selector, MonoMethod *managed_method, guint32 *exception_gchandle);
int * xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref, int par, void *nativeBlock, guint32 *exception_gchandle); int * xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref, int par, void *nativeBlock, guint32 *exception_gchandle);
id xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature /* NULL allowed, but requires the dynamic registrar at runtime to compute */, guint32 *exception_gchandle); id xamarin_get_block_for_delegate (MonoMethod *method, MonoObject *delegate, const char *signature /* NULL allowed, but requires the dynamic registrar at runtime to compute */, guint32 token_ref /* INVALID_TOKEN_REF allowed, but requires the dynamic registrar at runtime */, guint32 *exception_gchandle);
id xamarin_get_nsobject_handle (MonoObject *obj); id xamarin_get_nsobject_handle (MonoObject *obj);
void xamarin_set_nsobject_handle (MonoObject *obj, id handle); void xamarin_set_nsobject_handle (MonoObject *obj, id handle);
uint8_t xamarin_get_nsobject_flags (MonoObject *obj); uint8_t xamarin_get_nsobject_flags (MonoObject *obj);

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

@ -59,6 +59,7 @@ namespace Foundation {
public string Name { get; set; } public string Name { get; set; }
public string Selector { get; set; } public string Selector { get; set; }
public Type ReturnType { get; set; } public Type ReturnType { get; set; }
public Type ReturnTypeDelegateProxy { get; set; }
public Type[] ParameterType { get; set; } public Type[] ParameterType { get; set; }
public bool[] ParameterByRef { get; set; } public bool[] ParameterByRef { get; set; }
public Type[] ParameterBlockProxy { get; set; } public Type[] ParameterBlockProxy { get; set; }

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

@ -168,11 +168,7 @@ $(IOS_BUILD_DIR)/reference/System.Drawing.dll: $(IOS_SYSTEM_DRAWING_SOURCES) mon
$(IOS_SYSTEM_DRAWING_SOURCES) $(IOS_SYSTEM_DRAWING_SOURCES)
$(IOS_BUILD_DIR)/reference/Xamarin.iOS.dll: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.dll | $(IOS_BUILD_DIR)/reference $(IOS_BUILD_DIR)/reference/Xamarin.iOS.dll: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.dll | $(IOS_BUILD_DIR)/reference
@# Don't strip, btouch-native needs to execute code from Xamarin.iOS, $(Q_GEN) mono-cil-strip $< $@
@# and that'll break if we strip out the code from the reference assembly.
@# Note that there is only btouch-native executable for both 32 and 64 bits.
@#$(Q_GEN) mono-cil-strip $< $@
$(Q) cp $< $@
$(IOS_BUILD_DIR)/reference/Xamarin.iOS.pdb: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.pdb | $(IOS_BUILD_DIR)/reference $(IOS_BUILD_DIR)/reference/Xamarin.iOS.pdb: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.pdb | $(IOS_BUILD_DIR)/reference
$(Q) cp $< $@ $(Q) cp $< $@
@ -753,11 +749,7 @@ $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS%dll $(WATCH_BUILD_DIR)/watch-32/Xama
$(WATCHOS_SOURCES) @$(WATCH_BUILD_DIR)/watch/generated_sources $(WATCHOS_SOURCES) @$(WATCH_BUILD_DIR)/watch/generated_sources
$(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.dll: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.dll | $(WATCH_BUILD_DIR)/reference $(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.dll: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.dll | $(WATCH_BUILD_DIR)/reference
@# Don't strip, bwatch needs to execute code from Xamarin.WatchOS (attributes), $(Q_GEN) mono-cil-strip $< $@
@# and that'll break if we strip out the code from the reference assembly.
@# Note that there is only bwatch executable for both 32 and 64 bits.
@#$(Q_GEN) mono-cil-strip $< $@
$(Q) cp $< $@
$(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.pdb: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.pdb | $(WATCH_BUILD_DIR)/reference $(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.pdb: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.pdb | $(WATCH_BUILD_DIR)/reference
$(Q) cp $< $@ $(Q) cp $< $@
@ -966,10 +958,7 @@ $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS%dll $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVO
$(TVOS_SOURCES) @$(TVOS_BUILD_DIR)/tvos/generated_sources $(TVOS_SOURCES) @$(TVOS_BUILD_DIR)/tvos/generated_sources
$(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(TVOS_BUILD_DIR)/reference $(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(TVOS_BUILD_DIR)/reference
@# Don't strip, btv needs to execute code from Xamarin.TVOS (attributes), $(Q_GEN) mono-cil-strip $< $@
@# and that'll break if we strip out the code from the reference assembly.
@#$(Q_GEN) mono-cil-strip $< $@
$(Q) cp $< $@
$(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(TVOS_BUILD_DIR)/reference $(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(TVOS_BUILD_DIR)/reference
$(Q) cp $< $@ $(Q) cp $< $@
@ -1060,8 +1049,8 @@ TVOS_TARGETS += \
$(PROJECT_DIR)/MonoTouch.NUnitLite.tvos.csproj \ $(PROJECT_DIR)/MonoTouch.NUnitLite.tvos.csproj \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/Xamarin.TVOS.dll \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/Xamarin.TVOS.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/Xamarin.TVOS.pdb \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/Xamarin.TVOS.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.dll \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.pdb \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/System.Net.Http.dll \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/System.Net.Http.dll \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/System.Net.Http.pdb \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/System.Net.Http.pdb \
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/OpenTK-1.0.dll \ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/OpenTK-1.0.dll \
@ -1088,10 +1077,10 @@ $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/mono/Xamarin.TVOS/%.config: $(TVOS_BUILD_D
$(Q) install -m 0644 $< $@ $(Q) install -m 0644 $< $@
# the actual architecture-specific versions # the actual architecture-specific versions
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.dll: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.dll | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits
$(Q) install -m 0755 $< $@ $(Q) install -m 0755 $< $@
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits
$(Q) install -m 0644 $< $@ $(Q) install -m 0644 $< $@
$(TVOS_TARGETS_DIRS): $(TVOS_TARGETS_DIRS):

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

@ -247,8 +247,50 @@ namespace ObjCRuntime {
return descriptor->copy_helper == ((BlockDescriptor *) literal->block_descriptor)->copy_helper; return descriptor->copy_helper == ((BlockDescriptor *) literal->block_descriptor)->copy_helper;
} }
[BindingImpl (BindingImplOptions.Optimizable)] static Type GetDelegateProxyType (MethodInfo minfo, uint token_ref, out MethodInfo baseMethod)
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, string signature) {
// A mirror of this method is also implemented in StaticRegistrar:GetDelegateProxyType
// If this method is changed, that method will probably have to be updated too (tests!!!)
baseMethod = null;
if (token_ref != Runtime.INVALID_TOKEN_REF)
return (Type) Class.ResolveTokenReference (token_ref, 0x02000000 /* TypeDef */);
baseMethod = minfo.GetBaseDefinition ();
var delegateProxies = baseMethod.ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false);
if (delegateProxies.Length > 0)
return ((DelegateProxyAttribute) delegateProxies [0]).DelegateType;
// We might be implementing a protocol, find any DelegateProxy attributes on the corresponding interface as well.
string selector = null;
foreach (var iface in minfo.DeclaringType.GetInterfaces ()) {
if (!iface.IsDefined (typeof (ProtocolAttribute), false))
continue;
var map = minfo.DeclaringType.GetInterfaceMap (iface);
for (int i = 0; i < map.TargetMethods.Length; i++) {
if (map.TargetMethods [i] == minfo) {
delegateProxies = map.InterfaceMethods [i].ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false);
if (delegateProxies.Length > 0)
return ((DelegateProxyAttribute) delegateProxies [0]).DelegateType;
}
}
// It might be an optional method/property, in which case we need to check any ProtocolMember attributes
if (selector == null)
selector = Runtime.GetExportAttribute (minfo)?.Selector ?? string.Empty;
if (!string.IsNullOrEmpty (selector)) {
var attrib = Runtime.GetProtocolMemberAttribute (iface, selector, minfo);
if (attrib?.ReturnTypeDelegateProxy != null)
return attrib.ReturnTypeDelegateProxy;
}
}
throw ErrorHelper.CreateError (8011, "Unable to locate the delegate to block conversion attribute ([DelegateProxy]) for the return value for the method {0}.{1}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
}
[BindingImpl(BindingImplOptions.Optimizable)]
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, uint token_ref, string signature)
{ {
if (@delegate == null) if (@delegate == null)
return IntPtr.Zero; return IntPtr.Zero;
@ -256,26 +298,22 @@ namespace ObjCRuntime {
if (!(@delegate is Delegate)) if (!(@delegate is Delegate))
throw ErrorHelper.CreateError (8016, "Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com.", minfo.DeclaringType.FullName, minfo.Name, @delegate.GetType ().FullName); throw ErrorHelper.CreateError (8016, "Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com.", minfo.DeclaringType.FullName, minfo.Name, @delegate.GetType ().FullName);
var baseMethod = minfo.GetBaseDefinition (); Type delegateProxyType = GetDelegateProxyType (minfo, token_ref, out var baseMethod);
if (baseMethod == null)
var delegateProxies = baseMethod.ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false); baseMethod = minfo; // 'baseMethod' is only used in error messages, and if it's null, we just use the closest alternative we have (minfo).
if (delegateProxies.Length == 0) if (delegateProxyType == null)
throw ErrorHelper.CreateError (8011, "Unable to locate the delegate to block conversion attribute ([DelegateProxy]) for the return value for the method {0}.{1}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
var delegateProxy = (DelegateProxyAttribute) delegateProxies [0];
if (delegateProxy.DelegateType == null)
throw ErrorHelper.CreateError (8012, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name); throw ErrorHelper.CreateError (8012, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
var delegateProxyField = delegateProxy.DelegateType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static); var delegateProxyField = delegateProxyType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static);
if (delegateProxyField == null) if (delegateProxyField == null)
throw ErrorHelper.CreateError (8013, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType ({2}) specifies a type without a 'Handler' field. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName); throw ErrorHelper.CreateError (8013, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType ({2}) specifies a type without a 'Handler' field. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxyType.FullName);
var handlerDelegate = delegateProxyField.GetValue (null); var handlerDelegate = delegateProxyField.GetValue (null);
if (handlerDelegate == null) if (handlerDelegate == null)
throw ErrorHelper.CreateError (8014, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName); throw ErrorHelper.CreateError (8014, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxyType.FullName);
if (!(handlerDelegate is Delegate)) if (!(handlerDelegate is Delegate))
throw ErrorHelper.CreateError (8015, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName, handlerDelegate.GetType ().FullName); throw ErrorHelper.CreateError (8015, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxyType.FullName, handlerDelegate.GetType ().FullName);
// We now have the information we need to create the block. // We now have the information we need to create the block.
// Note that we must create a heap-allocated block, so we // Note that we must create a heap-allocated block, so we

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

@ -32,6 +32,7 @@ using ProductException=MonoMac.RuntimeException;
using ObjCRuntime; using ObjCRuntime;
#endif #endif
#else #else
using System.Linq;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
#endif #endif
@ -297,6 +298,26 @@ namespace ObjCRuntime {
Show (new ProductException (code, false, innerException, message, args)); Show (new ProductException (code, false, innerException, message, args));
} }
#if MMP || MTOUCH
// Shows any warnings, and if there are any errors, throws an AggregateException.
public static void ThrowIfErrors (IList<Exception> exceptions)
{
if (exceptions?.Any () != true)
return;
// Separate warnings from errors
var grouped = exceptions.GroupBy ((v) => (v as ProductException)?.Error == false);
var warnings = grouped.SingleOrDefault ((v) => v.Key);
if (warnings?.Any () == true)
Show (warnings);
var errors = grouped.SingleOrDefault ((v) => !v.Key);
if (errors?.Any () == true)
throw new AggregateException (errors);
}
#endif
public static void Show (IEnumerable<Exception> list) public static void Show (IEnumerable<Exception> list)
{ {
List<Exception> exceptions = new List<Exception> (); List<Exception> exceptions = new List<Exception> ();

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

@ -447,9 +447,9 @@ namespace ObjCRuntime {
return ObjectWrapper.Convert (CreateBlockProxy ((MethodInfo) ObjectWrapper.Convert (method), block)); return ObjectWrapper.Convert (CreateBlockProxy ((MethodInfo) ObjectWrapper.Convert (method), block));
} }
static IntPtr CreateDelegateProxy (IntPtr method, IntPtr @delegate, IntPtr signature) static IntPtr CreateDelegateProxy (IntPtr method, IntPtr @delegate, IntPtr signature, uint token_ref)
{ {
return BlockLiteral.GetBlockForDelegate ((MethodInfo) ObjectWrapper.Convert (method), ObjectWrapper.Convert (@delegate), Marshal.PtrToStringAuto (signature)); return BlockLiteral.GetBlockForDelegate ((MethodInfo) ObjectWrapper.Convert (method), ObjectWrapper.Convert (@delegate), token_ref, Marshal.PtrToStringAuto (signature));
} }
static unsafe Assembly GetEntryAssembly () static unsafe Assembly GetEntryAssembly ()
@ -776,6 +776,48 @@ namespace ObjCRuntime {
return null; return null;
} }
internal static ProtocolMemberAttribute GetProtocolMemberAttribute (Type type, string selector, MethodInfo method)
{
var memberAttributes = type.GetCustomAttributes<ProtocolMemberAttribute> ();
if (memberAttributes == null)
return null;
foreach (var attrib in memberAttributes) {
if (attrib.IsStatic != method.IsStatic)
continue;
if (attrib.Selector != selector)
continue;
if (!attrib.IsProperty) {
var methodParameters = method.GetParameters ();
if ((attrib.ParameterType?.Length ?? 0) != methodParameters.Length)
continue;
var notApplicable = false;
for (int i = 0; i < methodParameters.Length; i++) {
var paramType = methodParameters [i].ParameterType;
var isByRef = paramType.IsByRef;
if (isByRef)
paramType = paramType.GetElementType ();
if (isByRef != attrib.ParameterByRef [i]) {
notApplicable = true;
break;
}
if (paramType != attrib.ParameterType [i]) {
notApplicable = true;
break;
}
}
if (notApplicable)
continue;
}
return attrib;
}
return null;
}
// //
// Returns a MethodInfo that represents the method that can be used to turn // Returns a MethodInfo that represents the method that can be used to turn
// a the block in the given method at the given parameter into a strongly typed // a the block in the given method at the given parameter into a strongly typed
@ -824,39 +866,11 @@ namespace ObjCRuntime {
// We may run into binding assemblies built with earlier versions of the generator, // 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. // which means we can't rely on finding the BlockProxy attribute in the ProtocolMemberAttribute.
if (selector == null) if (selector == null)
selector = method.GetCustomAttribute<ExportAttribute> ()?.Selector ?? string.Empty; selector = GetExportAttribute (method)?.Selector ?? string.Empty;
if (!string.IsNullOrEmpty (selector)) { if (!string.IsNullOrEmpty (selector)) {
var memberAttributes = iface.GetCustomAttributes<ProtocolMemberAttribute> (); var attrib = GetProtocolMemberAttribute (iface, selector, method);
foreach (var attrib in memberAttributes) { if (attrib != null && attrib.ParameterBlockProxy.Length > parameter && attrib.ParameterBlockProxy [parameter] != null)
if (attrib.ParameterBlockProxy == null || attrib.ParameterBlockProxy.Length <= parameter || attrib.ParameterBlockProxy [parameter] == null)
continue; // no need to check anything if what we want isn't there
if (attrib.Selector != selector)
continue;
if (attrib.IsStatic != method.IsStatic)
continue;
var methodParameters = method.GetParameters ();
if (attrib.ParameterType.Length != methodParameters.Length)
continue;
var notApplicable = false;
for (int i = 0; i < methodParameters.Length; i++) {
var paramType = methodParameters [i].ParameterType;
var isByRef = paramType.IsByRef;
if (isByRef)
paramType = paramType.GetElementType ();
if (isByRef != attrib.ParameterByRef [i]) {
notApplicable = true;
break;
}
if (paramType != attrib.ParameterType [i]) {
notApplicable = true;
break;
}
}
if (notApplicable)
continue;
return attrib.ParameterBlockProxy [parameter].GetMethod ("Create"); return attrib.ParameterBlockProxy [parameter].GetMethod ("Create");
}
} }
// Might be an implementation of an optional protocol member. // Might be an implementation of an optional protocol member.
@ -1010,6 +1024,31 @@ namespace ObjCRuntime {
} }
} }
internal static PropertyInfo FindPropertyInfo (MethodInfo accessor)
{
if (!accessor.IsSpecialName)
return null;
foreach (var pi in accessor.DeclaringType.GetProperties ()) {
if (pi.GetGetMethod () == accessor)
return pi;
if (pi.GetSetMethod () == accessor)
return pi;
}
return null;
}
internal static ExportAttribute GetExportAttribute (MethodInfo method)
{
var attrib = method.GetCustomAttribute<ExportAttribute> ();
if (attrib == null) {
var pinfo = FindPropertyInfo (method);
if (pinfo != null)
attrib = pinfo.GetCustomAttribute<ExportAttribute> ();
}
return attrib;
}
static NSObject IgnoreConstructionError (IntPtr ptr, IntPtr klass, Type type) static NSObject IgnoreConstructionError (IntPtr ptr, IntPtr klass, Type type)
{ {

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

@ -4778,6 +4778,7 @@ public partial class Generator : IMemberGatherer {
sel = ba.Selector; sel = ba.Selector;
} }
PrintBlockProxy (pi.PropertyType);
PrintAttributes (pi, platform:true); PrintAttributes (pi, platform:true);
if (not_implemented_attr == null && (!minfo.is_sealed || !minfo.is_wrapper)) if (not_implemented_attr == null && (!minfo.is_sealed || !minfo.is_wrapper))
@ -5101,6 +5102,15 @@ public partial class Generator : IMemberGatherer {
} }
} }
void PrintBlockProxy (Type type)
{
type = GetCorrectGenericType (type);
if (type.IsSubclassOf (TypeManager.System_Delegate)) {
var ti = MakeTrampoline (type);
print ("[param: BlockProxy (typeof ({0}.Trampolines.{1}))]", ns.CoreObjCRuntime, ti.NativeInvokerName);
}
}
void PrintExport (MemberInformation minfo) void PrintExport (MemberInformation minfo)
{ {
if (minfo.is_export) if (minfo.is_export)
@ -5418,8 +5428,14 @@ public partial class Generator : IMemberGatherer {
sb.Append (", IsStatic = ").Append (AttributeManager.HasAttribute<StaticAttribute> (mi) ? "true" : "false"); sb.Append (", IsStatic = ").Append (AttributeManager.HasAttribute<StaticAttribute> (mi) ? "true" : "false");
sb.Append (", Name = \"").Append (mi.Name).Append ("\""); sb.Append (", Name = \"").Append (mi.Name).Append ("\"");
sb.Append (", Selector = \"").Append (attrib.Selector).Append ("\""); sb.Append (", Selector = \"").Append (attrib.Selector).Append ("\"");
if (mi.ReturnType != TypeManager.System_Void) if (mi.ReturnType != TypeManager.System_Void) {
sb.Append (", ReturnType = typeof (").Append (RenderType (GetCorrectGenericType (mi.ReturnType))).Append(")"); var retType = GetCorrectGenericType (mi.ReturnType);
sb.Append (", ReturnType = typeof (").Append (RenderType (retType)).Append (")");
if (retType.IsSubclassOf (TypeManager.System_Delegate)) {
var ti = MakeTrampoline (retType);
sb.Append ($", ReturnTypeDelegateProxy = typeof ({ns.CoreObjCRuntime}.Trampolines.{ti.StaticName})");
}
}
var parameters = mi.GetParameters (); var parameters = mi.GetParameters ();
if (parameters != null && parameters.Length > 0) { if (parameters != null && parameters.Length > 0) {
sb.Append (", ParameterType = new Type [] { "); sb.Append (", ParameterType = new Type [] { ");
@ -5489,6 +5505,15 @@ public partial class Generator : IMemberGatherer {
sb.Append (", SetterSelector = \"").Append (ba != null ? ba.Selector : ea.Selector).Append ("\""); sb.Append (", SetterSelector = \"").Append (ba != null ? ba.Selector : ea.Selector).Append ("\"");
} }
sb.Append (", ArgumentSemantic = ArgumentSemantic.").Append (attrib.ArgumentSemantic); sb.Append (", ArgumentSemantic = ArgumentSemantic.").Append (attrib.ArgumentSemantic);
// Check for block/delegate proxies
var propType = GetCorrectGenericType (pi.PropertyType);
if (propType.IsSubclassOf (TypeManager.System_Delegate)) {
var ti = MakeTrampoline (propType);
if (pi.SetMethod != null)
sb.Append ($", ParameterBlockProxy = new Type [] {{ typeof ({ns.CoreObjCRuntime}.Trampolines.{ti.NativeInvokerName}) }}");
if (pi.GetMethod != null)
sb.Append ($", ReturnTypeDelegateProxy = typeof ({ns.CoreObjCRuntime}.Trampolines.{ti.StaticName})");
}
sb.Append (")]"); sb.Append (")]");
print (sb.ToString ()); print (sb.ToString ());
} }
@ -5565,6 +5590,7 @@ public partial class Generator : IMemberGatherer {
} }
if (pi.CanWrite) { if (pi.CanWrite) {
var setMethod = pi.GetSetMethod (); var setMethod = pi.GetSetMethod ();
PrintBlockProxy (pi.PropertyType);
PrintAttributes (setMethod, notImplemented:true); PrintAttributes (setMethod, notImplemented:true);
if (!AttributeManager.HasAttribute<NotImplementedAttribute> (setMethod)) if (!AttributeManager.HasAttribute<NotImplementedAttribute> (setMethod))
PrintExport (minfo, GetSetterExportAttribute (pi)); PrintExport (minfo, GetSetterExportAttribute (pi));

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

@ -28,6 +28,7 @@
<MtouchLink>None</MtouchLink> <MtouchLink>None</MtouchLink>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<MtouchArch>i386, x86_64</MtouchArch> <MtouchArch>i386, x86_64</MtouchArch>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -39,6 +40,7 @@
<MtouchLink>None</MtouchLink> <MtouchLink>None</MtouchLink>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<MtouchArch>i386, x86_64</MtouchArch> <MtouchArch>i386, x86_64</MtouchArch>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
@ -52,6 +54,7 @@
<MtouchDebug>True</MtouchDebug> <MtouchDebug>True</MtouchDebug>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<MtouchArch>ARMv7, ARM64</MtouchArch> <MtouchArch>ARMv7, ARM64</MtouchArch>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug32|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug32|iPhone' ">
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
@ -65,6 +68,7 @@
<MtouchDebug>True</MtouchDebug> <MtouchDebug>True</MtouchDebug>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<MtouchArch>ARMv7</MtouchArch> <MtouchArch>ARMv7</MtouchArch>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug64|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug64|iPhone' ">
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
@ -78,6 +82,7 @@
<MtouchDebug>True</MtouchDebug> <MtouchDebug>True</MtouchDebug>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<MtouchArch>ARM64</MtouchArch> <MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -91,6 +96,7 @@
<DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5;NET_2_1;MOBILE;MONOTOUCH;FULL_AOT_RUNTIME;DISABLE_CAS_USE;$(DefineConstants)</DefineConstants> <DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5;NET_2_1;MOBILE;MONOTOUCH;FULL_AOT_RUNTIME;DISABLE_CAS_USE;$(DefineConstants)</DefineConstants>
<MtouchArch>ARMv7, ARM64</MtouchArch> <MtouchArch>ARMv7, ARM64</MtouchArch>
<MtouchUseLlvm>true</MtouchUseLlvm> <MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release32|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release32|iPhone' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -104,6 +110,7 @@
<DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5;NET_2_1;MOBILE;MONOTOUCH;FULL_AOT_RUNTIME;DISABLE_CAS_USE;$(DefineConstants)</DefineConstants> <DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5;NET_2_1;MOBILE;MONOTOUCH;FULL_AOT_RUNTIME;DISABLE_CAS_USE;$(DefineConstants)</DefineConstants>
<MtouchArch>ARMv7</MtouchArch> <MtouchArch>ARMv7</MtouchArch>
<MtouchUseLlvm>true</MtouchUseLlvm> <MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release64|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release64|iPhone' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -117,6 +124,7 @@
<DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5;NET_2_1;MOBILE;MONOTOUCH;FULL_AOT_RUNTIME;DISABLE_CAS_USE;$(DefineConstants)</DefineConstants> <DefineConstants>NET_1_1;NET_2_0;NET_3_0;NET_3_5;NET_4_0;NET_4_5;NET_2_1;MOBILE;MONOTOUCH;FULL_AOT_RUNTIME;DISABLE_CAS_USE;$(DefineConstants)</DefineConstants>
<MtouchArch>ARM64</MtouchArch> <MtouchArch>ARM64</MtouchArch>
<MtouchUseLlvm>true</MtouchUseLlvm> <MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release-bitcode|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release-bitcode|iPhone' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -131,6 +139,7 @@
<MtouchArch>ARMv7, ARM64</MtouchArch> <MtouchArch>ARMv7, ARM64</MtouchArch>
<MtouchExtraArgs>--bitcode:full</MtouchExtraArgs> <MtouchExtraArgs>--bitcode:full</MtouchExtraArgs>
<MtouchUseLlvm>true</MtouchUseLlvm> <MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />

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

@ -289,6 +289,22 @@ namespace Bindings.Test {
[Static] [Static]
[Export ("optionalStaticCallback:")] [Export ("optionalStaticCallback:")]
void OptionalStaticCallback (Action<int> completionHandler); void OptionalStaticCallback (Action<int> completionHandler);
[Abstract]
[Export ("requiredReturnValue")]
Action<int> RequiredReturnValue ();
[Abstract]
[Static]
[Export ("requiredStaticReturnValue")]
Action<int> RequiredStaticReturnValue ();
[Export ("optionalReturnValue")]
Action<int> OptionalReturnValue ();
[Static]
[Export ("optionalStaticReturnValue")]
Action<int> OptionalStaticReturnValue ();
} }
interface IObjCProtocolBlockTest { } interface IObjCProtocolBlockTest { }
@ -339,6 +355,23 @@ namespace Bindings.Test {
[Static] [Static]
[Export ("freedBlockCount")] [Export ("freedBlockCount")]
int FreedBlockCount { get; } int FreedBlockCount { get; }
[Static]
[Export ("calledBlockCount")]
int CalledBlockCount { get; }
[Static]
[Export ("callProtocolWithBlockProperties:required:instance:")]
void CallProtocolWithBlockProperties (IProtocolWithBlockProperties obj, bool required, bool instance);
[Static]
[Export ("callProtocolWithBlockReturnValue:required:instance:")]
void CallProtocolWithBlockReturnValue (IObjCProtocolBlockTest obj, bool required, bool instance);
[Static]
[Export ("setProtocolWithBlockProperties:required:instance:")]
void SetProtocolWithBlockProperties (IProtocolWithBlockProperties obj, bool required, bool instance);
} }
delegate void InnerBlock (int magic_number); delegate void InnerBlock (int magic_number);
@ -350,6 +383,28 @@ namespace Bindings.Test {
[Export ("evilCallback")] [Export ("evilCallback")]
Action<int> EvilCallback { get; set; } Action<int> EvilCallback { get; set; }
} }
delegate void SimpleCallback ();
[BaseType (typeof (NSObject))]
[Protocol]
interface ProtocolWithBlockProperties {
[Abstract]
[Export ("myRequiredProperty")]
SimpleCallback MyRequiredProperty { get; set; }
[Export ("myOptionalProperty")]
SimpleCallback MyOptionalProperty { get; set; }
[Static]
[Abstract]
[Export ("myRequiredStaticProperty")]
SimpleCallback MyRequiredStaticProperty { get; set; }
[Static]
[Export ("myOptionalStaticProperty")]
SimpleCallback MyOptionalStaticProperty { get; set; }
}
interface IProtocolWithBlockProperties { }
} }

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

@ -65,6 +65,37 @@ namespace Xamarin.BindingTests
{ {
completionHandler (42); completionHandler (42);
} }
public Action<int> RequiredReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalReturnValue")]
public Action<int> OptionalReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("requiredStaticReturnValue")]
public static Action<int> RequiredStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalStaticReturnValue")]
public static Action<int> OptionalStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
} }
class BlockCallbackClassExplicit : NSObject, IObjCProtocolBlockTest class BlockCallbackClassExplicit : NSObject, IObjCProtocolBlockTest
@ -92,6 +123,38 @@ namespace Xamarin.BindingTests
{ {
completionHandler (42); completionHandler (42);
} }
// Explicitly implemented interface member
Action<int> IObjCProtocolBlockTest.RequiredReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalReturnValue")]
public Action<int> OptionalReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("requiredStaticReturnValue")]
public static Action<int> RequiredStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
[Export ("optionalStaticReturnValue")]
public static Action<int> OptionalStaticReturnValue ()
{
return new Action<int> ((v) => {
Assert.AreEqual (42, v, "RequiredReturnValue");
});
}
} }
public class BlockCallbackTester : ObjCBlockTester public class BlockCallbackTester : ObjCBlockTester
@ -101,5 +164,86 @@ namespace Xamarin.BindingTests
completionHandler (42); completionHandler (42);
} }
} }
public class PropertyBlock : NSObject, IProtocolWithBlockProperties {
[Export ("myOptionalProperty")]
public SimpleCallback MyOptionalProperty { get; set; }
public SimpleCallback MyRequiredProperty { get; set; }
[Export ("myOptionalStaticProperty")]
public static SimpleCallback MyOptionalStaticProperty { get; set; }
[Export ("myRequiredStaticProperty")]
public static SimpleCallback MyRequiredStaticProperty { get; set; }
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void ProtocolWithBlockProperties (bool required, bool instance)
{
using (var pb = new PropertyBlock ()) {
var callbackCalled = false;
SimpleCallback action = () => {
callbackCalled = true;
};
if (required) {
if (instance) {
pb.MyRequiredProperty = action;
} else {
PropertyBlock.MyRequiredStaticProperty = action;
}
} else {
if (instance) {
pb.MyOptionalProperty = action;
} else {
PropertyBlock.MyOptionalStaticProperty = action;
}
}
ObjCBlockTester.CallProtocolWithBlockProperties (pb, required, instance);
Assert.IsTrue (callbackCalled, "Callback");
}
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void ProtocolWithNativeBlockProperties (bool required, bool instance)
{
using (var pb = new PropertyBlock ()) {
var calledCounter = ObjCBlockTester.CalledBlockCount;
ObjCBlockTester.SetProtocolWithBlockProperties (pb, required, instance);
if (required) {
if (instance) {
pb.MyRequiredProperty ();
} else {
PropertyBlock.MyRequiredStaticProperty ();
}
} else {
if (instance) {
pb.MyOptionalProperty ();
} else {
PropertyBlock.MyOptionalStaticProperty ();
}
}
Assert.AreEqual (calledCounter + 1, ObjCBlockTester.CalledBlockCount, "Blocks called");
}
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void ProtocolWithReturnValues (bool required, bool instance)
{
using (var pb = new BlockCallbackClass ()) {
ObjCBlockTester.CallProtocolWithBlockReturnValue (pb, required, instance);
}
}
} }
} }

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

@ -59,6 +59,11 @@ namespace Xamarin.Tests
[Test] [Test]
public void MainThreadDeallocationTest () public void MainThreadDeallocationTest ()
{ {
#if OPTIMIZEALL
if (!TestRuntime.IsLinkAll)
Assert.Ignore ("This test must be processed by the linker if all optimizations are turned on.");
#endif
ObjCBlockTester.CallAssertMainThreadBlockRelease ((callback) => { ObjCBlockTester.CallAssertMainThreadBlockRelease ((callback) => {
callback (42); callback (42);
}); });

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

@ -259,8 +259,11 @@ class D : NSObject {
bundler.AssertWarning (4173, "The registrar can't compute the block signature for the delegate of type System.Delegate in the method D.D4 because System.Delegate doesn't have a specific signature.", "testApp.cs", 24); bundler.AssertWarning (4173, "The registrar can't compute the block signature for the delegate of type System.Delegate in the method D.D4 because System.Delegate doesn't have a specific signature.", "testApp.cs", 24);
bundler.AssertWarning (4173, "The registrar can't compute the block signature for the delegate of type System.MulticastDelegate in the method D.D5 because System.MulticastDelegate doesn't have a specific signature.", "testApp.cs", 30); bundler.AssertWarning (4173, "The registrar can't compute the block signature for the delegate of type System.MulticastDelegate in the method D.D5 because System.MulticastDelegate doesn't have a specific signature.", "testApp.cs", 30);
bundler.AssertWarning (4174, "Unable to locate the block to delegate conversion method for the method D.D3's parameter #1.", "testApp.cs", 18); bundler.AssertWarning (4174, "Unable to locate the block to delegate conversion method for the method D.D3's parameter #1.", "testApp.cs", 18);
bundler.AssertWarning (4176, "Unable to locate the delegate to block conversion type for the return value of the method D.D4.", "testApp.cs", 24);
bundler.AssertWarning (4176, "Unable to locate the delegate to block conversion type for the return value of the method D.D5.", "testApp.cs", 30);
bundler.AssertWarning (4176, "Unable to locate the delegate to block conversion type for the return value of the method D.D6.", "testApp.cs", 36);
bundler.AssertErrorCount (2); bundler.AssertErrorCount (2);
bundler.AssertWarningCount (3); bundler.AssertWarningCount (6);
} }
} }

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

@ -16,7 +16,7 @@ namespace LinkSdk {
public Task<string> LoadCategories () public Task<string> LoadCategories ()
{ {
return Task.Run (async () => await (new HttpClient ()).GetStringAsync ("http://google.com")); return Task.Run (async () => await (new HttpClient ()).GetStringAsync ("https://google.com"));
} }
[Test] [Test]

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

@ -747,6 +747,13 @@ namespace LinkSdk {
[Test] [Test]
// https://bugzilla.novell.com/show_bug.cgi?id=650402 // https://bugzilla.novell.com/show_bug.cgi?id=650402
#if __WATCHOS__
// Fails with:
// System.ExecutionEngineException : Attempting to JIT compile method 'System.Data.DataColumn:set_Expression (string)' while running in aot-only mode.
// because DataColumn.set_Expression uses filter clauses, which we don't support with bitcode:
// LLVM failed for 'DataColumn.set_Expression': non-finally/catch/fault clause.
[Ignore ("https://bugzilla.xamarin.com/show_bug.cgi?id=59987")]
#endif
public void ForeignKey_650402 () public void ForeignKey_650402 ()
{ {
DataSet data = new DataSet (); DataSet data = new DataSet ();

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

@ -1182,6 +1182,45 @@ namespace NS {
} }
} }
[Test]
public void MT4176 ()
{
using (var mtouch = new MTouchTool ()) {
var code = @"
namespace NS {
using System;
using Foundation;
using ObjCRuntime;
public class Consumer : NSObject
{
[Export (""getAction"")]
public Action GetFunction ()
{
throw new NotImplementedException ();
}
[Export (""getProperty"")]
public Action GetProperty {
get {
throw new NotImplementedException ();
}
}
}
}
";
mtouch.Linker = MTouchLinker.DontLink; // faster
mtouch.Registrar = MTouchRegistrar.Static;
mtouch.CreateTemporaryApp (extraCode: code, extraArg: "-debug");
mtouch.WarnAsError = new int [] { 4176 };
mtouch.AssertExecuteFailure ("build");
mtouch.AssertError (4176, "Unable to locate the delegate to block conversion type for the return value of the method NS.Consumer.GetFunction.", "testApp.cs", 11);
mtouch.AssertError (4176, "Unable to locate the delegate to block conversion type for the return value of the method NS.Consumer.get_GetProperty.", "testApp.cs", 17);
mtouch.AssertErrorCount (2);
}
}
[Test] [Test]
public void NoWarnings () public void NoWarnings ()
{ {

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

@ -148,15 +148,29 @@ typedef unsigned int (^RegistrarTestBlock) (unsigned int magic);
-(void) idAsIntPtr: (id)p1; -(void) idAsIntPtr: (id)p1;
@end @end
typedef void (^int_callback)(int32_t magic_number);
@protocol ObjCProtocolBlockTest @protocol ObjCProtocolBlockTest
@required @required
-(void) requiredCallback: (void (^)(int32_t magic_number))completionHandler; -(void) requiredCallback: (int_callback)completionHandler;
+(void) requiredStaticCallback: (void (^)(int32_t magic_number))completionHandler; +(void) requiredStaticCallback: (int_callback)completionHandler;
-(int_callback) requiredReturnValue;
+(int_callback) requiredStaticReturnValue;
@optional @optional
-(void) optionalCallback: (void (^)(int32_t magic_number))completionHandler; -(void) optionalCallback: (int_callback)completionHandler;
+(void) optionalStaticCallback: (void (^)(int32_t magic_number))completionHandler; +(void) optionalStaticCallback: (int_callback)completionHandler;
-(int_callback) optionalReturnValue;
+(int_callback) optionalStaticReturnValue;
@end @end
typedef void (^simple_callback)();
@protocol ProtocolWithBlockProperties
@required
@property simple_callback myRequiredProperty;
@property (class) simple_callback myRequiredStaticProperty;
@optional
@property simple_callback myOptionalProperty;
@property (class) simple_callback myOptionalStaticProperty;
@end
@interface ObjCBlockTester : NSObject { @interface ObjCBlockTester : NSObject {
} }
@property (retain) NSObject<ObjCProtocolBlockTest>* TestObject; @property (retain) NSObject<ObjCProtocolBlockTest>* TestObject;
@ -175,6 +189,12 @@ typedef void (^outerBlock) (innerBlock callback);
-(void) testFreedBlocks; -(void) testFreedBlocks;
+(int) freedBlockCount; +(int) freedBlockCount;
+(void) callProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance;
+(void) callProtocolWithBlockReturnValue: (id<ObjCProtocolBlockTest>) obj required: (bool) required instance: (bool) instance;
+(void) setProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance;
+(int) calledBlockCount;
@end @end
@interface FreedNotifier : NSObject { @interface FreedNotifier : NSObject {

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

@ -527,6 +527,7 @@ static UltimateMachine *shared;
@end @end
static volatile int freed_blocks = 0; static volatile int freed_blocks = 0;
static volatile int called_blocks = 0;
@implementation ObjCBlockTester @implementation ObjCBlockTester
static Class _TestClass = NULL; static Class _TestClass = NULL;
@ -654,6 +655,73 @@ static Class _TestClass = NULL;
{ {
return freed_blocks; return freed_blocks;
} }
+(int) calledBlockCount
{
return called_blocks;
}
static void block_called ()
{
OSAtomicIncrement32 (&called_blocks);
}
+(void) callProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance;
{
if (required) {
if (instance) {
obj.myRequiredProperty ();
} else {
[[(NSObject *) obj class] myRequiredStaticProperty] ();
}
} else {
if (instance) {
obj.myOptionalProperty ();
} else {
[[(NSObject *) obj class] myOptionalStaticProperty] ();
}
}
}
+(void) callProtocolWithBlockReturnValue: (id<ObjCProtocolBlockTest>) obj required: (bool) required instance: (bool) instance;
{
if (required) {
if (instance) {
[obj requiredReturnValue] (42);
} else {
[[(NSObject *) obj class] requiredStaticReturnValue] (42);
}
} else {
if (instance) {
[obj optionalReturnValue] (42);
} else {
[[(NSObject *) obj class] optionalStaticReturnValue] (42);
}
}
}
+(void) callProtocolWithBlockPropertiesRequired: (id<ProtocolWithBlockProperties>) obj
{
obj.myRequiredProperty ();
}
+(void) setProtocolWithBlockProperties: (id<ProtocolWithBlockProperties>) obj required: (bool) required instance: (bool) instance
{
simple_callback callback = ^{ block_called (); };
if (required) {
if (instance) {
obj.myRequiredProperty = callback;
} else {
[[(NSObject *) obj class] setMyRequiredStaticProperty: callback];
}
} else {
if (instance) {
obj.myOptionalProperty = callback;
} else {
[[(NSObject *) obj class] setMyOptionalStaticProperty: callback];
}
}
}
@end @end
@implementation FreedNotifier @implementation FreedNotifier

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

@ -194,7 +194,7 @@ namespace xharness
void LoadConfig () void LoadConfig ()
{ {
ParseConfigFiles (); ParseConfigFiles ();
var src_root = Path.GetDirectoryName (RootDirectory); var src_root = Path.GetDirectoryName (Path.GetFullPath (RootDirectory));
MONO_PATH = Path.GetFullPath (Path.Combine (src_root, "external", "mono")); MONO_PATH = Path.GetFullPath (Path.Combine (src_root, "external", "mono"));
WATCH_MONO_PATH = make_config ["WATCH_MONO_PATH"]; WATCH_MONO_PATH = make_config ["WATCH_MONO_PATH"];
TVOS_MONO_PATH = MONO_PATH; TVOS_MONO_PATH = MONO_PATH;

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

@ -2708,7 +2708,7 @@ function toggleAll (show)
xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null; xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null;
LogEvent (log, "Building {0} ({1})", TestName, Mode); LogEvent (log, "Building {0} ({1})", TestName, Mode);
if (!Harness.DryRun) { if (!Harness.DryRun) {
var timeout = TimeSpan.FromMinutes (15); var timeout = TimeSpan.FromMinutes (60);
var result = await xbuild.RunAsync (log, true, timeout); var result = await xbuild.RunAsync (log, true, timeout);
if (result.TimedOut) { if (result.TimedOut) {
ExecutionResult = TestExecutingResult.TimedOut; ExecutionResult = TestExecutingResult.TimedOut;

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

@ -366,6 +366,15 @@ namespace xharness
} }
} }
public override StreamReader GetReader ()
{
if (File.Exists (CapturePath)) {
return new StreamReader (new FileStream (CapturePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
} else {
return new StreamReader (new MemoryStream ());
}
}
public override void Flush () public override void Flush ()
{ {
base.Flush (); base.Flush ();

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

@ -380,6 +380,11 @@ namespace xharness
return string.Empty; return string.Empty;
} }
public static string GetMtouchLink (this XmlDocument csproj, string platform, string configuration)
{
return GetNode (csproj, "MtouchLink", platform, configuration);
}
public static void SetMtouchUseLlvm (this XmlDocument csproj, bool value, string platform, string configuration) public static void SetMtouchUseLlvm (this XmlDocument csproj, bool value, string platform, string configuration)
{ {
SetNode (csproj, "MtouchUseLlvm", true ? "true" : "false", platform, configuration); SetNode (csproj, "MtouchUseLlvm", true ? "true" : "false", platform, configuration);
@ -390,6 +395,17 @@ namespace xharness
SetNode (csproj, "MtouchEnableBitcode", true ? "true" : "false", platform, configuration); SetNode (csproj, "MtouchEnableBitcode", true ? "true" : "false", platform, configuration);
} }
public static IEnumerable<XmlNode> GetPropertyGroups (this XmlDocument csproj, string platform, string configuration)
{
var propertyGroups = csproj.SelectNodes ("//*[local-name() = 'PropertyGroup' and @Condition]");
foreach (XmlNode node in propertyGroups) {
if (!EvaluateCondition (node, platform, configuration))
continue;
yield return node;
}
}
public static void SetNode (this XmlDocument csproj, string node, string value, string platform, string configuration) public static void SetNode (this XmlDocument csproj, string node, string value, string platform, string configuration)
{ {
var projnode = csproj.SelectElementNodes (node); var projnode = csproj.SelectElementNodes (node);
@ -417,6 +433,16 @@ namespace xharness
} }
} }
public static string GetNode (this XmlDocument csproj, string name, string platform, string configuration)
{
foreach (var pg in GetPropertyGroups (csproj, platform, configuration)) {
foreach (XmlNode node in pg.ChildNodes)
if (node.Name == name)
return node.InnerText;
}
return null;
}
public static string GetImport (this XmlDocument csproj) public static string GetImport (this XmlDocument csproj)
{ {

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

@ -84,6 +84,13 @@ namespace xharness
csproj.SetMtouchUseBitcode (true, "iPhone", "Release"); csproj.SetMtouchUseBitcode (true, "iPhone", "Release");
csproj.SetMtouchUseLlvm (true, "iPhone", "Release"); csproj.SetMtouchUseLlvm (true, "iPhone", "Release");
// Not linking a watch extensions requires passing -Os to the native compiler.
// https://github.com/mono/mono/issues/9867
var configurations = new string [] { "Debug", "Debug32", "Release", "Release32", "Release-bitcode" };
foreach (var c in configurations)
if (csproj.GetMtouchLink ("iPhone", c) == "None")
csproj.AddExtraMtouchArgs ("--gcc_flags=-Os", "iPhone", c);
Harness.Save (csproj, WatchOSExtensionProjectPath); Harness.Save (csproj, WatchOSExtensionProjectPath);
WatchOSExtensionGuid = csproj.GetProjectGuid (); WatchOSExtensionGuid = csproj.GetProjectGuid ();

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

@ -45,6 +45,14 @@
<Variable name="MONO_ENV_OPTIONS" value="--trace=E:all" /> <Variable name="MONO_ENV_OPTIONS" value="--trace=E:all" />
</EnvironmentVariables> </EnvironmentVariables>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Makefile.inc' ">
<StartAction>Project</StartAction>
<StartArguments>--configure --autoconf --rootdir ..</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Makefile-mac.inc' ">
<StartAction>Project</StartAction>
<StartArguments>--configure --autoconf --rootdir .. --mac </StartArguments>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />

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

@ -1397,12 +1397,64 @@ namespace Registrar {
return rv; return rv;
} }
public DelegateProxyAttribute GetDelegateProxyAttribute (MethodDefinition method)
{
if (!TryGetAttribute (method.MethodReturnType, ObjCRuntime, "DelegateProxyAttribute", out var attrib))
return null;
var rv = new DelegateProxyAttribute ();
switch (attrib.ConstructorArguments.Count) {
case 1:
rv.DelegateType = ((TypeReference) attrib.ConstructorArguments [0].Value).Resolve ();
break;
default:
throw ErrorHelper.CreateError (4124, "Invalid DelegateProxyAttribute found on '{0}'. Please file a bug report at https://bugzilla.xamarin.com", ((MethodReference) method)?.FullName);
}
return rv;
}
protected override string PlatformName { protected override string PlatformName {
get { get {
return App.PlatformName; return App.PlatformName;
} }
} }
ProtocolMemberAttribute GetProtocolMemberAttribute (TypeReference type, string selector, ObjCMethod obj_method, MethodDefinition method)
{
var memberAttributes = GetProtocolMemberAttributes (type);
foreach (var attrib in memberAttributes) {
if (attrib.IsStatic != method.IsStatic)
continue;
if (attrib.IsProperty) {
if (method.IsSetter && attrib.SetterSelector != selector)
continue;
else if (method.IsGetter && attrib.GetterSelector != selector)
continue;
} else {
if (attrib.Selector != selector)
continue;
}
if (!obj_method.IsPropertyAccessor) {
var attribParameters = new TypeReference [attrib.ParameterType?.Length ?? 0];
for (var i = 0; i < attribParameters.Length; i++) {
attribParameters [i] = attrib.ParameterType [i];
if (attrib.ParameterByRef [i])
attribParameters [i] = new ByReferenceType (attribParameters [i]);
}
if (!ParametersMatch (method.Parameters, attribParameters))
continue;
}
return attrib;
}
return null;
}
protected override IEnumerable<ProtocolMemberAttribute> GetProtocolMemberAttributes (TypeReference type) protected override IEnumerable<ProtocolMemberAttribute> GetProtocolMemberAttributes (TypeReference type)
{ {
var td = type.Resolve (); var td = type.Resolve ();
@ -1434,6 +1486,9 @@ namespace Registrar {
case "ReturnType": case "ReturnType":
rv.ReturnType = (TypeReference)prop.Argument.Value; rv.ReturnType = (TypeReference)prop.Argument.Value;
break; break;
case "ReturnTypeDelegateProxy":
rv.ReturnTypeDelegateProxy = (TypeReference) prop.Argument.Value;
break;
case "ParameterType": case "ParameterType":
if (prop.Argument.Value != null) { if (prop.Argument.Value != null) {
var arr = (CustomAttributeArgument[])prop.Argument.Value; var arr = (CustomAttributeArgument[])prop.Argument.Value;
@ -3071,8 +3126,7 @@ namespace Registrar {
sb.WriteLine (map.ToString ()); sb.WriteLine (map.ToString ());
sb.WriteLine (map_init.ToString ()); sb.WriteLine (map_init.ToString ());
if (exceptions.Count > 0) ErrorHelper.ThrowIfErrors (exceptions);
throw new AggregateException (exceptions);
} }
static bool HasIntPtrBoolCtor (TypeDefinition type) static bool HasIntPtrBoolCtor (TypeDefinition type)
@ -3680,7 +3734,7 @@ namespace Registrar {
if (creatorMethod != null) { if (creatorMethod != null) {
token = $"0x{CreateTokenReference (creatorMethod, TokenType.Method):X} /* {creatorMethod.FullName} */ "; token = $"0x{CreateTokenReference (creatorMethod, TokenType.Method):X} /* {creatorMethod.FullName} */ ";
} else { } else {
ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4174, method.Method, "Unable to locate the block to delegate conversion method for the method {0}'s parameter #{1}.", exceptions.Add (ErrorHelper.CreateWarning (App, 4174, method.Method, "Unable to locate the block to delegate conversion method for the method {0}'s parameter #{1}.",
method.DescriptiveMethodName, i + 1)); method.DescriptiveMethodName, i + 1));
} }
} }
@ -3832,6 +3886,7 @@ namespace Registrar {
setup_return.AppendLine ("res = nsstr;"); setup_return.AppendLine ("res = nsstr;");
} else if (IsDelegate (type.Resolve ())) { } else if (IsDelegate (type.Resolve ())) {
var signature = "NULL"; var signature = "NULL";
var token = "INVALID_TOKEN_REF";
if (App.Optimizations.OptimizeBlockLiteralSetupBlock == true) { if (App.Optimizations.OptimizeBlockLiteralSetupBlock == true) {
if (type.Is ("System", "Delegate") || type.Is ("System", "MulticastDelegate")) { if (type.Is ("System", "Delegate") || type.Is ("System", "MulticastDelegate")) {
ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4173, method.Method, $"The registrar can't compute the block signature for the delegate of type {type.FullName} in the method {descriptiveMethodName} because {type.FullName} doesn't have a specific signature.")); ErrorHelper.Show (ErrorHelper.CreateWarning (App, 4173, method.Method, $"The registrar can't compute the block signature for the delegate of type {type.FullName} in the method {descriptiveMethodName} because {type.FullName} doesn't have a specific signature."));
@ -3843,8 +3898,14 @@ namespace Registrar {
signature = "\"" + ComputeSignature (method.DeclaringType.Type, null, method, isBlockSignature: true) + "\""; signature = "\"" + ComputeSignature (method.DeclaringType.Type, null, method, isBlockSignature: true) + "\"";
} }
} }
var delegateProxyType = GetDelegateProxyType (method);
if (delegateProxyType != null) {
token = $"0x{CreateTokenReference (delegateProxyType, TokenType.TypeDef):X} /* {delegateProxyType.FullName} */ ";
} else {
exceptions.Add (ErrorHelper.CreateWarning (App, 4176, method.Method, "Unable to locate the delegate to block conversion type for the return value of the method {0}.", method.DescriptiveMethodName));
}
} }
setup_return.AppendLine ("res = xamarin_get_block_for_delegate (managed_method, retval, {0}, &exception_gchandle);", signature); setup_return.AppendLine ("res = xamarin_get_block_for_delegate (managed_method, retval, {0}, {1}, &exception_gchandle);", signature, token);
setup_return.AppendLine ("if (exception_gchandle != 0) goto exception_handling;"); setup_return.AppendLine ("if (exception_gchandle != 0) goto exception_handling;");
} else { } else {
throw ErrorHelper.CreateError (4104, throw ErrorHelper.CreateError (4104,
@ -4049,6 +4110,52 @@ namespace Registrar {
} }
} }
TypeDefinition GetDelegateProxyType (ObjCMethod obj_method)
{
// A mirror of this method is also implemented in BlockLiteral:GetDelegateProxyType
// If this method is changed, that method will probably have to be updated too (tests!!!)
MethodDefinition method = obj_method.Method;
MethodDefinition first = method;
MethodDefinition last = null;
while (method != last) {
last = method;
var delegateProxyType = GetDelegateProxyAttribute (method);
if (delegateProxyType?.DelegateType != null)
return delegateProxyType.DelegateType;
method = GetBaseMethodInTypeHierarchy (method);
}
// Might be the implementation of an interface method, so find the corresponding
// MethodDefinition for the interface, and check for DelegateProxy attributes there as well.
var map = PrepareMethodMapping (first.DeclaringType);
if (map != null && map.TryGetValue (first, out var list)) {
if (list.Count != 1)
throw Shared.GetMT4127 (first, list);
var delegateProxyType = GetDelegateProxyAttribute (list [0]);
if (delegateProxyType?.DelegateType != null)
return delegateProxyType.DelegateType;
}
// Might be an implementation of an optional protocol member.
if (obj_method.DeclaringType.Protocols != null) {
string selector = null;
foreach (var proto in obj_method.DeclaringType.Protocols) {
// We store the DelegateProxy type in the ProtocolMemberAttribute, so check those.
if (selector == null)
selector = obj_method.Selector ?? string.Empty;
if (selector != null) {
var attrib = GetProtocolMemberAttribute (proto.Type, selector, obj_method, method);
if (attrib?.ReturnTypeDelegateProxy != null)
return attrib.ReturnTypeDelegateProxy.Resolve ();
}
}
}
return null;
}
MethodDefinition GetBlockWrapperCreator (ObjCMethod obj_method, int parameter) MethodDefinition GetBlockWrapperCreator (ObjCMethod obj_method, int parameter)
{ {
// A mirror of this method is also implemented in Runtime:GetBlockWrapperCreator // A mirror of this method is also implemented in Runtime:GetBlockWrapperCreator
@ -4087,48 +4194,35 @@ namespace Registrar {
if (selector == null) if (selector == null)
selector = obj_method.Selector ?? string.Empty; selector = obj_method.Selector ?? string.Empty;
if (selector != null) { if (selector != null) {
var memberAttributes = GetProtocolMemberAttributes (proto.Type); var attrib = GetProtocolMemberAttribute (proto.Type, selector, obj_method, method);
foreach (var attrib in memberAttributes) { if (attrib?.ParameterBlockProxy?.Length > parameter && attrib.ParameterBlockProxy [parameter] != null)
if (attrib.ParameterBlockProxy == null || attrib.ParameterBlockProxy.Length <= parameter || attrib.ParameterBlockProxy [parameter] == null)
continue; // no need to check anything if what we want isn't there
if (attrib.Selector != selector)
continue;
if (attrib.IsStatic != method.IsStatic)
continue;
var attribParameters = new TypeReference [attrib.ParameterType?.Length ?? 0];
for (var i = 0; i < attribParameters.Length; i++) {
attribParameters [i] = attrib.ParameterType [i];
if (attrib.ParameterByRef [i])
attribParameters [i] = new ByReferenceType (attribParameters [i]);
}
if (!ParametersMatch (method.Parameters, attribParameters))
continue;
return attrib.ParameterBlockProxy [parameter].Resolve ().Methods.First ((v) => v.Name == "Create"); return attrib.ParameterBlockProxy [parameter].Resolve ().Methods.First ((v) => v.Name == "Create");
}
if (proto.Methods != null) {
foreach (var pMethod in proto.Methods) {
if (!pMethod.IsOptional)
continue;
if (pMethod.Name != method.Name)
continue;
if (!TypeMatch (pMethod.ReturnType, method.ReturnType))
continue;
if (ParametersMatch (method.Parameters, pMethod.Parameters))
continue;
MethodDefinition extensionMethod = pMethod.Method;
if (extensionMethod == null) {
MapProtocolMember (obj_method.Method, out extensionMethod);
if (extensionMethod == null)
return null;
}
var createMethod = GetBlockProxyAttributeMethod (extensionMethod, parameter + 1);
if (createMethod != null)
return createMethod;
} }
} }
foreach (var pMethod in proto.Methods) {
if (!pMethod.IsOptional)
continue;
if (pMethod.Name != method.Name)
continue;
if (!TypeMatch (pMethod.ReturnType, method.ReturnType))
continue;
if (ParametersMatch (method.Parameters, pMethod.Parameters))
continue;
MethodDefinition extensionMethod = pMethod.Method;
if (extensionMethod == null) {
MapProtocolMember (obj_method.Method, out extensionMethod);
if (extensionMethod == null)
return null;
}
var createMethod = GetBlockProxyAttributeMethod (extensionMethod, parameter + 1);
if (createMethod != null)
return createMethod;
}
} }
} }
@ -4843,6 +4937,11 @@ namespace Registrar {
public TypeDefinition Type { get; set; } public TypeDefinition Type { get; set; }
} }
class DelegateProxyAttribute : Attribute
{
public TypeDefinition DelegateType { get; set; }
}
class BindAsAttribute : Attribute class BindAsAttribute : Attribute
{ {
public BindAsAttribute (TypeReference type) public BindAsAttribute (TypeReference type)
@ -4863,6 +4962,7 @@ namespace Registrar {
public string Name { get; set; } public string Name { get; set; }
public string Selector { get; set; } public string Selector { get; set; }
public TypeReference ReturnType { get; set; } public TypeReference ReturnType { get; set; }
public TypeReference ReturnTypeDelegateProxy { get; set; }
public TypeReference[] ParameterType { get; set; } public TypeReference[] ParameterType { get; set; }
public bool[] ParameterByRef { get; set; } public bool[] ParameterByRef { get; set; }
public TypeReference [] ParameterBlockProxy { get; set; } public TypeReference [] ParameterBlockProxy { get; set; }