Merge remote-tracking branch 'origin/master' into mono-2018-06
This commit is contained in:
Коммит
28347f9167
|
@ -378,6 +378,20 @@ will be shown.
|
|||
|
||||
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
|
||||
|
||||
## MM51xx: compilation
|
||||
|
|
|
@ -1787,6 +1787,20 @@ will be shown.
|
|||
|
||||
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
|
||||
|
||||
### MT51xx: Compilation
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
<_DebugFileExt Condition="'$(_DebugFileExt)' == ''">.mdb</_DebugFileExt>
|
||||
</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" />
|
||||
|
||||
<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",
|
||||
"MonoObject *", "IntPtr", "method",
|
||||
"MonoObject *", "IntPtr", "block",
|
||||
"const char *", "IntPtr", "signature"
|
||||
"const char *", "IntPtr", "signature",
|
||||
"unsigned int", "uint", "token_ref"
|
||||
) {
|
||||
WrappedManagedFunction = "CreateDelegateProxy",
|
||||
OnlyDynamicUsage = false,
|
||||
|
|
|
@ -2187,10 +2187,10 @@ xamarin_get_delegate_for_block_parameter (MonoMethod *method, guint32 token_ref,
|
|||
}
|
||||
|
||||
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.
|
||||
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
|
||||
|
|
|
@ -60,7 +60,7 @@ xamarin_marshal_return_value (MonoType *mtype, const char *type, MonoObject *ret
|
|||
case _C_PTR: {
|
||||
MonoClass *klass = mono_class_from_mono_type (mtype);
|
||||
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 {
|
||||
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_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);
|
||||
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);
|
||||
void xamarin_set_nsobject_handle (MonoObject *obj, id handle);
|
||||
uint8_t xamarin_get_nsobject_flags (MonoObject *obj);
|
||||
|
|
|
@ -59,6 +59,7 @@ namespace Foundation {
|
|||
public string Name { get; set; }
|
||||
public string Selector { get; set; }
|
||||
public Type ReturnType { get; set; }
|
||||
public Type ReturnTypeDelegateProxy { get; set; }
|
||||
public Type[] ParameterType { get; set; }
|
||||
public bool[] ParameterByRef { get; set; }
|
||||
public Type[] ParameterBlockProxy { get; set; }
|
||||
|
|
25
src/Makefile
25
src/Makefile
|
@ -168,11 +168,7 @@ $(IOS_BUILD_DIR)/reference/System.Drawing.dll: $(IOS_SYSTEM_DRAWING_SOURCES) mon
|
|||
$(IOS_SYSTEM_DRAWING_SOURCES)
|
||||
|
||||
$(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,
|
||||
@# 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 $< $@
|
||||
$(Q_GEN) mono-cil-strip $< $@
|
||||
|
||||
$(IOS_BUILD_DIR)/reference/Xamarin.iOS.pdb: $(IOS_BUILD_DIR)/native-64/Xamarin.iOS.pdb | $(IOS_BUILD_DIR)/reference
|
||||
$(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
|
||||
|
||||
$(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),
|
||||
@# 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 $< $@
|
||||
$(Q_GEN) mono-cil-strip $< $@
|
||||
|
||||
$(WATCH_BUILD_DIR)/reference/Xamarin.WatchOS.pdb: $(WATCH_BUILD_DIR)/watch-32/Xamarin.WatchOS.pdb | $(WATCH_BUILD_DIR)/reference
|
||||
$(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_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),
|
||||
@# and that'll break if we strip out the code from the reference assembly.
|
||||
@#$(Q_GEN) mono-cil-strip $< $@
|
||||
$(Q) cp $< $@
|
||||
$(Q_GEN) mono-cil-strip $< $@
|
||||
|
||||
$(TVOS_BUILD_DIR)/reference/Xamarin.TVOS.pdb: $(TVOS_BUILD_DIR)/tvos-64/Xamarin.TVOS.pdb | $(TVOS_BUILD_DIR)/reference
|
||||
$(Q) cp $< $@
|
||||
|
@ -1060,8 +1049,8 @@ TVOS_TARGETS += \
|
|||
$(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.pdb \
|
||||
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.dll \
|
||||
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/32bits/Xamarin.TVOS.pdb \
|
||||
$(IOS_DESTDIR)$(MONOTOUCH_PREFIX)/lib/64bits/Xamarin.TVOS.dll \
|
||||
$(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.pdb \
|
||||
$(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 $< $@
|
||||
|
||||
# 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 $< $@
|
||||
|
||||
$(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 $< $@
|
||||
|
||||
$(TVOS_TARGETS_DIRS):
|
||||
|
|
|
@ -247,8 +247,50 @@ namespace ObjCRuntime {
|
|||
return descriptor->copy_helper == ((BlockDescriptor *) literal->block_descriptor)->copy_helper;
|
||||
}
|
||||
|
||||
static Type GetDelegateProxyType (MethodInfo minfo, uint token_ref, out MethodInfo baseMethod)
|
||||
{
|
||||
// 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, string signature)
|
||||
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, uint token_ref, string signature)
|
||||
{
|
||||
if (@delegate == null)
|
||||
return IntPtr.Zero;
|
||||
|
@ -256,26 +298,22 @@ namespace ObjCRuntime {
|
|||
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);
|
||||
|
||||
var baseMethod = minfo.GetBaseDefinition ();
|
||||
|
||||
var delegateProxies = baseMethod.ReturnTypeCustomAttributes.GetCustomAttributes (typeof (DelegateProxyAttribute), false);
|
||||
if (delegateProxies.Length == 0)
|
||||
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)
|
||||
Type delegateProxyType = GetDelegateProxyType (minfo, token_ref, out var baseMethod);
|
||||
if (baseMethod == null)
|
||||
baseMethod = minfo; // 'baseMethod' is only used in error messages, and if it's null, we just use the closest alternative we have (minfo).
|
||||
if (delegateProxyType == 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);
|
||||
|
||||
var delegateProxyField = delegateProxy.DelegateType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
var delegateProxyField = delegateProxyType.GetField ("Handler", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
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);
|
||||
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))
|
||||
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.
|
||||
// Note that we must create a heap-allocated block, so we
|
||||
|
|
|
@ -32,6 +32,7 @@ using ProductException=MonoMac.RuntimeException;
|
|||
using ObjCRuntime;
|
||||
#endif
|
||||
#else
|
||||
using System.Linq;
|
||||
using Mono.Cecil.Cil;
|
||||
#endif
|
||||
|
||||
|
@ -297,6 +298,26 @@ namespace ObjCRuntime {
|
|||
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)
|
||||
{
|
||||
List<Exception> exceptions = new List<Exception> ();
|
||||
|
|
|
@ -447,9 +447,9 @@ namespace ObjCRuntime {
|
|||
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 ()
|
||||
|
@ -776,6 +776,48 @@ namespace ObjCRuntime {
|
|||
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
|
||||
// a the block in the given method at the given parameter into a strongly typed
|
||||
|
@ -824,40 +866,12 @@ namespace ObjCRuntime {
|
|||
// 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.
|
||||
if (selector == null)
|
||||
selector = method.GetCustomAttribute<ExportAttribute> ()?.Selector ?? string.Empty;
|
||||
selector = GetExportAttribute (method)?.Selector ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty (selector)) {
|
||||
var memberAttributes = iface.GetCustomAttributes<ProtocolMemberAttribute> ();
|
||||
foreach (var attrib in memberAttributes) {
|
||||
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;
|
||||
|
||||
var attrib = GetProtocolMemberAttribute (iface, selector, method);
|
||||
if (attrib != null && attrib.ParameterBlockProxy.Length > parameter && attrib.ParameterBlockProxy [parameter] != null)
|
||||
return attrib.ParameterBlockProxy [parameter].GetMethod ("Create");
|
||||
}
|
||||
}
|
||||
|
||||
// Might be an implementation of an optional protocol member.
|
||||
// We look that up on the corresponding extension method.
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -4778,6 +4778,7 @@ public partial class Generator : IMemberGatherer {
|
|||
sel = ba.Selector;
|
||||
}
|
||||
|
||||
PrintBlockProxy (pi.PropertyType);
|
||||
PrintAttributes (pi, platform:true);
|
||||
|
||||
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)
|
||||
{
|
||||
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 (", Name = \"").Append (mi.Name).Append ("\"");
|
||||
sb.Append (", Selector = \"").Append (attrib.Selector).Append ("\"");
|
||||
if (mi.ReturnType != TypeManager.System_Void)
|
||||
sb.Append (", ReturnType = typeof (").Append (RenderType (GetCorrectGenericType (mi.ReturnType))).Append(")");
|
||||
if (mi.ReturnType != TypeManager.System_Void) {
|
||||
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 ();
|
||||
if (parameters != null && parameters.Length > 0) {
|
||||
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 (", 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 (")]");
|
||||
print (sb.ToString ());
|
||||
}
|
||||
|
@ -5565,6 +5590,7 @@ public partial class Generator : IMemberGatherer {
|
|||
}
|
||||
if (pi.CanWrite) {
|
||||
var setMethod = pi.GetSetMethod ();
|
||||
PrintBlockProxy (pi.PropertyType);
|
||||
PrintAttributes (setMethod, notImplemented:true);
|
||||
if (!AttributeManager.HasAttribute<NotImplementedAttribute> (setMethod))
|
||||
PrintExport (minfo, GetSetterExportAttribute (pi));
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<MtouchLink>None</MtouchLink>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<MtouchArch>i386, x86_64</MtouchArch>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
|
||||
<DebugType>none</DebugType>
|
||||
|
@ -39,6 +40,7 @@
|
|||
<MtouchLink>None</MtouchLink>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<MtouchArch>i386, x86_64</MtouchArch>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
|
@ -52,6 +54,7 @@
|
|||
<MtouchDebug>True</MtouchDebug>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug32|iPhone' ">
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
|
@ -65,6 +68,7 @@
|
|||
<MtouchDebug>True</MtouchDebug>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<MtouchArch>ARMv7</MtouchArch>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug64|iPhone' ">
|
||||
<DebugSymbols>True</DebugSymbols>
|
||||
|
@ -78,6 +82,7 @@
|
|||
<MtouchDebug>True</MtouchDebug>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<MtouchArch>ARM64</MtouchArch>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
|
||||
<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>
|
||||
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||
<MtouchUseLlvm>true</MtouchUseLlvm>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release32|iPhone' ">
|
||||
<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>
|
||||
<MtouchArch>ARMv7</MtouchArch>
|
||||
<MtouchUseLlvm>true</MtouchUseLlvm>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release64|iPhone' ">
|
||||
<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>
|
||||
<MtouchArch>ARM64</MtouchArch>
|
||||
<MtouchUseLlvm>true</MtouchUseLlvm>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release-bitcode|iPhone' ">
|
||||
<DebugType>none</DebugType>
|
||||
|
@ -131,6 +139,7 @@
|
|||
<MtouchArch>ARMv7, ARM64</MtouchArch>
|
||||
<MtouchExtraArgs>--bitcode:full</MtouchExtraArgs>
|
||||
<MtouchUseLlvm>true</MtouchUseLlvm>
|
||||
<MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
|
|
@ -289,6 +289,22 @@ namespace Bindings.Test {
|
|||
[Static]
|
||||
[Export ("optionalStaticCallback:")]
|
||||
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 { }
|
||||
|
@ -339,6 +355,23 @@ namespace Bindings.Test {
|
|||
[Static]
|
||||
[Export ("freedBlockCount")]
|
||||
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);
|
||||
|
@ -350,6 +383,28 @@ namespace Bindings.Test {
|
|||
[Export ("evilCallback")]
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -92,6 +123,38 @@ namespace Xamarin.BindingTests
|
|||
{
|
||||
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
|
||||
|
@ -101,5 +164,86 @@ namespace Xamarin.BindingTests
|
|||
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]
|
||||
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) => {
|
||||
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.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 (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.AssertWarningCount (3);
|
||||
bundler.AssertWarningCount (6);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace LinkSdk {
|
|||
|
||||
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]
|
||||
|
|
|
@ -747,6 +747,13 @@ namespace LinkSdk {
|
|||
|
||||
[Test]
|
||||
// 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 ()
|
||||
{
|
||||
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]
|
||||
public void NoWarnings ()
|
||||
{
|
||||
|
|
|
@ -148,15 +148,29 @@ typedef unsigned int (^RegistrarTestBlock) (unsigned int magic);
|
|||
-(void) idAsIntPtr: (id)p1;
|
||||
@end
|
||||
|
||||
typedef void (^int_callback)(int32_t magic_number);
|
||||
@protocol ObjCProtocolBlockTest
|
||||
@required
|
||||
-(void) requiredCallback: (void (^)(int32_t magic_number))completionHandler;
|
||||
+(void) requiredStaticCallback: (void (^)(int32_t magic_number))completionHandler;
|
||||
-(void) requiredCallback: (int_callback)completionHandler;
|
||||
+(void) requiredStaticCallback: (int_callback)completionHandler;
|
||||
-(int_callback) requiredReturnValue;
|
||||
+(int_callback) requiredStaticReturnValue;
|
||||
@optional
|
||||
-(void) optionalCallback: (void (^)(int32_t magic_number))completionHandler;
|
||||
+(void) optionalStaticCallback: (void (^)(int32_t magic_number))completionHandler;
|
||||
-(void) optionalCallback: (int_callback)completionHandler;
|
||||
+(void) optionalStaticCallback: (int_callback)completionHandler;
|
||||
-(int_callback) optionalReturnValue;
|
||||
+(int_callback) optionalStaticReturnValue;
|
||||
@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 {
|
||||
}
|
||||
@property (retain) NSObject<ObjCProtocolBlockTest>* TestObject;
|
||||
|
@ -175,6 +189,12 @@ typedef void (^outerBlock) (innerBlock callback);
|
|||
|
||||
-(void) testFreedBlocks;
|
||||
+(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
|
||||
|
||||
@interface FreedNotifier : NSObject {
|
||||
|
|
|
@ -527,6 +527,7 @@ static UltimateMachine *shared;
|
|||
@end
|
||||
|
||||
static volatile int freed_blocks = 0;
|
||||
static volatile int called_blocks = 0;
|
||||
|
||||
@implementation ObjCBlockTester
|
||||
static Class _TestClass = NULL;
|
||||
|
@ -654,6 +655,73 @@ static Class _TestClass = NULL;
|
|||
{
|
||||
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
|
||||
|
||||
@implementation FreedNotifier
|
||||
|
|
|
@ -194,7 +194,7 @@ namespace xharness
|
|||
void LoadConfig ()
|
||||
{
|
||||
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"));
|
||||
WATCH_MONO_PATH = make_config ["WATCH_MONO_PATH"];
|
||||
TVOS_MONO_PATH = MONO_PATH;
|
||||
|
|
|
@ -2708,7 +2708,7 @@ function toggleAll (show)
|
|||
xbuild.StartInfo.EnvironmentVariables ["MSBuildExtensionsPath"] = null;
|
||||
LogEvent (log, "Building {0} ({1})", TestName, Mode);
|
||||
if (!Harness.DryRun) {
|
||||
var timeout = TimeSpan.FromMinutes (15);
|
||||
var timeout = TimeSpan.FromMinutes (60);
|
||||
var result = await xbuild.RunAsync (log, true, timeout);
|
||||
if (result.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 ()
|
||||
{
|
||||
base.Flush ();
|
||||
|
|
|
@ -380,6 +380,11 @@ namespace xharness
|
|||
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)
|
||||
{
|
||||
SetNode (csproj, "MtouchUseLlvm", true ? "true" : "false", platform, configuration);
|
||||
|
@ -390,6 +395,17 @@ namespace xharness
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -84,6 +84,13 @@ namespace xharness
|
|||
csproj.SetMtouchUseBitcode (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);
|
||||
|
||||
WatchOSExtensionGuid = csproj.GetProjectGuid ();
|
||||
|
|
|
@ -45,6 +45,14 @@
|
|||
<Variable name="MONO_ENV_OPTIONS" value="--trace=E:all" />
|
||||
</EnvironmentVariables>
|
||||
</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>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml" />
|
||||
|
|
|
@ -1397,12 +1397,64 @@ namespace Registrar {
|
|||
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 {
|
||||
get {
|
||||
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)
|
||||
{
|
||||
var td = type.Resolve ();
|
||||
|
@ -1434,6 +1486,9 @@ namespace Registrar {
|
|||
case "ReturnType":
|
||||
rv.ReturnType = (TypeReference)prop.Argument.Value;
|
||||
break;
|
||||
case "ReturnTypeDelegateProxy":
|
||||
rv.ReturnTypeDelegateProxy = (TypeReference) prop.Argument.Value;
|
||||
break;
|
||||
case "ParameterType":
|
||||
if (prop.Argument.Value != null) {
|
||||
var arr = (CustomAttributeArgument[])prop.Argument.Value;
|
||||
|
@ -3071,8 +3126,7 @@ namespace Registrar {
|
|||
sb.WriteLine (map.ToString ());
|
||||
sb.WriteLine (map_init.ToString ());
|
||||
|
||||
if (exceptions.Count > 0)
|
||||
throw new AggregateException (exceptions);
|
||||
ErrorHelper.ThrowIfErrors (exceptions);
|
||||
}
|
||||
|
||||
static bool HasIntPtrBoolCtor (TypeDefinition type)
|
||||
|
@ -3680,7 +3734,7 @@ namespace Registrar {
|
|||
if (creatorMethod != null) {
|
||||
token = $"0x{CreateTokenReference (creatorMethod, TokenType.Method):X} /* {creatorMethod.FullName} */ ";
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
|
@ -3832,6 +3886,7 @@ namespace Registrar {
|
|||
setup_return.AppendLine ("res = nsstr;");
|
||||
} else if (IsDelegate (type.Resolve ())) {
|
||||
var signature = "NULL";
|
||||
var token = "INVALID_TOKEN_REF";
|
||||
if (App.Optimizations.OptimizeBlockLiteralSetupBlock == true) {
|
||||
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."));
|
||||
|
@ -3843,8 +3898,14 @@ namespace Registrar {
|
|||
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;");
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
// A mirror of this method is also implemented in Runtime:GetBlockWrapperCreator
|
||||
|
@ -4087,27 +4194,12 @@ namespace Registrar {
|
|||
if (selector == null)
|
||||
selector = obj_method.Selector ?? string.Empty;
|
||||
if (selector != null) {
|
||||
var memberAttributes = GetProtocolMemberAttributes (proto.Type);
|
||||
foreach (var attrib in memberAttributes) {
|
||||
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;
|
||||
|
||||
var attrib = GetProtocolMemberAttribute (proto.Type, selector, obj_method, method);
|
||||
if (attrib?.ParameterBlockProxy?.Length > parameter && attrib.ParameterBlockProxy [parameter] != null)
|
||||
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;
|
||||
|
@ -4130,6 +4222,8 @@ namespace Registrar {
|
|||
return createMethod;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -4843,6 +4937,11 @@ namespace Registrar {
|
|||
public TypeDefinition Type { get; set; }
|
||||
}
|
||||
|
||||
class DelegateProxyAttribute : Attribute
|
||||
{
|
||||
public TypeDefinition DelegateType { get; set; }
|
||||
}
|
||||
|
||||
class BindAsAttribute : Attribute
|
||||
{
|
||||
public BindAsAttribute (TypeReference type)
|
||||
|
@ -4863,6 +4962,7 @@ namespace Registrar {
|
|||
public string Name { get; set; }
|
||||
public string Selector { get; set; }
|
||||
public TypeReference ReturnType { get; set; }
|
||||
public TypeReference ReturnTypeDelegateProxy { get; set; }
|
||||
public TypeReference[] ParameterType { get; set; }
|
||||
public bool[] ParameterByRef { get; set; }
|
||||
public TypeReference [] ParameterBlockProxy { get; set; }
|
||||
|
|
Загрузка…
Ссылка в новой задаче