protected override ExportAttribute GetExportAttribute(MethodBase method) { MethodInfo minfo = method as MethodInfo; if (minfo != null) { return(SharedDynamic.GetOneAttribute <ExportAttribute> (minfo.GetBaseDefinition())); } ConstructorInfo cinfo = method as ConstructorInfo; if (cinfo != null) { return(SharedDynamic.GetOneAttribute <ExportAttribute> (cinfo)); } return(null); }
public static Dictionary <MethodBase, List <MethodBase> > PrepareInterfaceMethodMapping(Type type) { Dictionary <MethodBase, List <MethodBase> > rv = null; var ifaces = type.FindInterfaces((v, o) => { var attribs = v.GetCustomAttributes(typeof(ProtocolAttribute), true); return(attribs != null && attribs.Length > 0); }, null); foreach (var iface in ifaces) { var map = type.GetInterfaceMap(iface); for (int i = 0; i < map.InterfaceMethods.Length; i++) { var ifaceMethod = map.InterfaceMethods [i]; var impl = map.TargetMethods [i]; if (SharedDynamic.GetOneAttribute <ExportAttribute> (ifaceMethod) == null) { continue; } List <MethodBase> list; if (rv == null) { rv = new Dictionary <MethodBase, List <MethodBase> > (); rv [impl] = list = new List <MethodBase> (); } else if (!rv.TryGetValue(impl, out list)) { rv [impl] = list = new List <MethodBase> (); } list.Add(ifaceMethod); } } return(rv); }
protected override BindAsAttribute GetBindAsAttribute(MethodBase method, int parameter_index) { ICustomAttributeProvider provider; if (method == null) { return(null); } var minfo = method as MethodInfo; if (minfo != null) { minfo = minfo.GetBaseDefinition(); if (parameter_index == -1) { provider = minfo.ReturnTypeCustomAttributes; } else { provider = minfo.GetParameters() [parameter_index]; } } else { var cinfo = method as ConstructorInfo; if (parameter_index == -1) { throw ErrorHelper.CreateError(99, $"Internal error: can't get the BindAs attribute for the return value of a constructor ({GetDescriptiveMethodName (method)}). Please file a bug report with a test case (https://bugzilla.xamarin.com)."); } else { provider = cinfo.GetParameters() [parameter_index]; } } return(SharedDynamic.GetOneAttribute <BindAsAttribute> (provider)); }
protected override Type GetProtocolAttributeWrapperType(Type type) { var attr = SharedDynamic.GetOneAttribute <ProtocolAttribute> (type); return(attr == null ? null : attr.WrapperType); }
protected override CategoryAttribute GetCategoryAttribute(Type type) { return(SharedDynamic.GetOneAttribute <CategoryAttribute> (type)); }
protected override ProtocolAttribute GetProtocolAttribute(Type type) { return(SharedDynamic.GetOneAttribute <ProtocolAttribute> (type)); }
protected override RegisterAttribute GetRegisterAttribute(Type type) { return(SharedDynamic.GetOneAttribute <RegisterAttribute> (type)); }
protected override ExportAttribute GetExportAttribute(PropertyInfo property) { return(SharedDynamic.GetOneAttribute <ExportAttribute> (GetBasePropertyInTypeHierarchy(property) ?? property)); }
protected override Dictionary <MethodBase, List <MethodBase> > PrepareMethodMapping(Type type) { return(SharedDynamic.PrepareInterfaceMethodMapping(type)); }
protected override ConnectAttribute GetConnectAttribute(PropertyInfo property) { return(SharedDynamic.GetOneAttribute <ConnectAttribute> (property)); }
Dictionary <IntPtr, MethodDescription> RegisterMethods(Type type) { // Caller must hold the obj_lock. Dictionary <IntPtr, MethodDescription> methods = new Dictionary <IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer); foreach (PropertyInfo pinfo in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { ExportAttribute ea = (ExportAttribute)Attribute.GetCustomAttribute(pinfo, typeof(ExportAttribute)); if (ea == null) { continue; } MethodInfo g = pinfo.GetGetMethod(true); if (g != null) { IntPtr selector = Selector.GetHandle(ea.ToGetter(pinfo).Selector); #if DEBUG_POPULATE Console.WriteLine("[GETTER] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int)selector, Method.Signature(g), type, pinfo); #endif methods [selector] = new MethodDescription(g, ea.ArgumentSemantic); } MethodInfo s = pinfo.GetSetMethod(true); if (s != null) { IntPtr selector = Selector.GetHandle(ea.ToSetter(pinfo).Selector); #if DEBUG_POPULATE Console.WriteLine("[SETTER] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int)selector, Method.Signature(s), type, pinfo); #endif methods [selector] = new MethodDescription(s, ea.ArgumentSemantic); } } var method_interface_map = SharedDynamic.PrepareInterfaceMethodMapping(type); foreach (MethodInfo minfo in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { ExportAttribute ea = (ExportAttribute)Attribute.GetCustomAttribute(minfo.GetBaseDefinition(), typeof(ExportAttribute)); if (ea == null) { ea = GetMappedExportAttribute(method_interface_map, minfo); } if (ea == null) { continue; } IntPtr selector = Selector.GetHandle(ea.Selector ?? minfo.Name); MethodDescription md; if (!methods.TryGetValue(selector, out md)) { #if DEBUG_POPULATE Console.WriteLine("[METHOD] Registering {0}[0x{1:x}|{2}] from {3} -> ({4} on {5})", ea.Selector, (int)selector, Method.Signature(minfo), type, minfo, minfo.DeclaringType); #endif methods.Add(selector, new MethodDescription(minfo, ea.ArgumentSemantic)); continue; } // // More than one method can exist for hidden methods. Choose one closest to // the caller type // if (minfo.DeclaringType.IsSubclassOf(md.method.DeclaringType)) { #if DEBUG_POPULATE Console.WriteLine("[METHOD] Re-registering {0}[0x{1:x}|{2}] from {3} -> ({4} on {5})", ea.Selector, (int)selector, Method.Signature(minfo), type, minfo, minfo.DeclaringType); #endif methods [selector] = new MethodDescription(minfo, ea.ArgumentSemantic); } } bool default_ctor_found = false; foreach (ConstructorInfo cinfo in type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if (!default_ctor_found && !cinfo.IsStatic && cinfo.GetParameters().Length == 0) { default_ctor_found = true; methods [Selector.GetHandle("init")] = new MethodDescription(cinfo, ArgumentSemantic.Assign); } ExportAttribute ea = (ExportAttribute)Attribute.GetCustomAttribute(cinfo, typeof(ExportAttribute)); if (ea == null) { continue; } if (ea.Selector == null) { throw new Exception("Constructor's must have a Export attribute with the selector specified"); } IntPtr selector = Selector.GetHandle(ea.Selector); #if DEBUG_POPULATE Console.WriteLine("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int)selector, Method.Signature(cinfo), type, cinfo); #endif methods [selector] = new MethodDescription(cinfo, ea.ArgumentSemantic); } method_map [type] = methods; return(methods); }
unsafe IntPtr Register(Type type, string name, bool is_wrapper) { IntPtr parent = IntPtr.Zero; IntPtr handle = IntPtr.Zero; lock (lock_obj) { handle = Class.objc_getClass(name); if (handle != IntPtr.Zero) { if (!type_map.ContainsKey(handle)) { type_map [handle] = type; } return(handle); } /*FIXME pick a more suitable exception type */ /*FIXME try to guess the name of the missing library - quite trivial for monotouch.dll*/ if (is_wrapper) { if (Runtime.Arch == Arch.DEVICE) { // types decorated with [Model] attribute are not registered (see registrar.cs and regression from #769) // a missing [Model] attribute will cause this error on devices (e.g. bug #4864) if (!Attribute.IsDefined(type, typeof(ModelAttribute), false)) { throw new Exception(string.Format("Wrapper type '{0}' is missing its native ObjectiveC class '{1}'.", type.FullName, name)); } } else { /*On simulator this is a common issue since we eagerly register all types. This is an issue with unlinked * monotouch.dll since we don't link all frameworks most of the time. */ return(IntPtr.Zero); } } Dictionary <IntPtr, MethodDescription> methods = new Dictionary <IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer); Type parent_type = type.BaseType; string parent_name = null; while (Attribute.IsDefined(parent_type, typeof(ModelAttribute), false)) { parent_type = parent_type.BaseType; } RegisterAttribute parent_attr = (RegisterAttribute)Attribute.GetCustomAttribute(parent_type, typeof(RegisterAttribute), false); parent_name = parent_attr == null ? parent_type.FullName : parent_attr.Name ?? parent_type.FullName; parent = Class.objc_getClass(parent_name); if (parent == IntPtr.Zero && parent_type.Assembly != NSObject.PlatformAssembly) { bool parent_is_wrapper = parent_attr == null ? false : parent_attr.IsWrapper; // Its possible as we scan that we might be derived from a type that isn't reigstered yet. Register(parent_type, parent_name, parent_is_wrapper); parent = Class.objc_getClass(parent_name); } if (parent == IntPtr.Zero) { // This spams mtouch, we need a way to differentiate from mtouch's (ab)use // Console.WriteLine ("CRITICAL WARNING: Falling back to NSObject for type {0} reported as {1}", type, parent_type); parent = Class.objc_getClass("NSObject"); } handle = Class.objc_allocateClassPair(parent, name, IntPtr.Zero); Class.class_addIvar(handle, "__monoObjectGCHandle", (IntPtr)Marshal.SizeOf(typeof(Int32)), (byte)4, "i"); foreach (PropertyInfo prop in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) { ConnectAttribute cattr = (ConnectAttribute)Attribute.GetCustomAttribute(prop, typeof(ConnectAttribute)); if (cattr != null) { string ivar_name = cattr.Name ?? prop.Name; Class.class_addIvar(handle, ivar_name, (IntPtr)Marshal.SizeOf(typeof(IntPtr)), (byte)Math.Log(Marshal.SizeOf(typeof(IntPtr)), 2), "@"); } var exportAtt = (ExportAttribute)Attribute.GetCustomAttribute(prop, typeof(ExportAttribute)); if (exportAtt != null) { var m = prop.GetGetMethod(true); if (m != null) { var ea = exportAtt.ToGetter(prop); RegisterMethod(m, ea, type, handle, false); var sel = Selector.GetHandle(ea.Selector); methods [sel] = new MethodDescription(m, ea.ArgumentSemantic); } m = prop.GetSetMethod(true); if (m != null) { var ea = exportAtt.ToSetter(prop); RegisterMethod(m, ea, type, handle, false); var sel = Selector.GetHandle(ea.Selector); methods [sel] = new MethodDescription(m, ea.ArgumentSemantic); } // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html int count = 0; var props = new Class.objc_attribute_prop [3]; props [count++] = new Class.objc_attribute_prop { name = "T", value = TypeConverter.ToNative(prop.PropertyType) }; switch (exportAtt.ArgumentSemantic) { case ArgumentSemantic.Copy: props [count++] = new Class.objc_attribute_prop { name = "C", value = "" }; break; case ArgumentSemantic.Retain: props [count++] = new Class.objc_attribute_prop { name = "&", value = "" }; break; } props [count++] = new Class.objc_attribute_prop { name = "V", value = exportAtt.Selector }; Class.class_addProperty(handle, exportAtt.Selector, props, count); #if DEBUG_REGISTER Console.WriteLine("[PROPERTY] Registering {0} of type {2} ({3}) on {1}", exportAtt.Selector, type, prop.PropertyType, TypeConverter.ToNative(prop.PropertyType)); #endif } } Class.class_addMethod(handle, Selector.GetHandle(Selector.Release), Method.ReleaseTrampoline, "v@:"); Class.class_addMethod(handle, Selector.GetHandle(Selector.Retain), Method.RetainTrampoline, "@@:"); Class.class_addMethod(handle, Selector.GetHandle("xamarinGetGCHandle"), Method.GetGCHandleTrampoline, "i@:"); Class.class_addMethod(handle, Selector.GetHandle("xamarinSetGCHandle:"), Method.SetGCHandleTrampoline, "v@:i"); var method_interface_map = SharedDynamic.PrepareInterfaceMethodMapping(type); foreach (MethodInfo minfo in type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { ExportAttribute ea = (ExportAttribute)Attribute.GetCustomAttribute(minfo.GetBaseDefinition(), typeof(ExportAttribute)); if (ea == null) { ea = GetMappedExportAttribute(method_interface_map, minfo); } if (ea == null) { continue; } if (minfo.IsGenericMethod || minfo.IsGenericMethodDefinition) { Console.WriteLine("The registrar found an exported generic method: '{0}.{1}'. Exporting generic methods is not supported.", minfo.DeclaringType.FullName, minfo.Name); continue; } bool is_conforms_to_protocol; bool is_model = false; is_conforms_to_protocol = minfo.DeclaringType.Assembly == NSObject.PlatformAssembly && minfo.DeclaringType.Name == "NSObject" && minfo.Name == "ConformsToProtocol"; if (!is_conforms_to_protocol) { is_model = minfo.IsVirtual && ((minfo.DeclaringType != type && minfo.DeclaringType.Assembly == NSObject.PlatformAssembly) || (Attribute.IsDefined(minfo.DeclaringType, typeof(ModelAttribute), false))); } if (is_model) { continue; } RegisterMethod(minfo, ea, type, handle, false); var sel = Selector.GetHandle(ea.Selector ?? minfo.Name); methods [sel] = new MethodDescription(minfo, ea.ArgumentSemantic); } bool default_ctor_found = false; foreach (ConstructorInfo cinfo in type.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if (!default_ctor_found && !cinfo.IsStatic && cinfo.GetParameters().Length == 0) { #if DEBUG_REGISTER Console.WriteLine("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", "init", (int)Selector.Init, Method.Signature(cinfo), type, cinfo); #endif default_ctor_found = true; Class.class_addMethod(handle, Selector.GetHandle("init"), Method.ConstructorTrampoline, Method.Signature(cinfo)); methods [Selector.GetHandle("init")] = new MethodDescription(cinfo, ArgumentSemantic.Assign); } ExportAttribute ea = (ExportAttribute)Attribute.GetCustomAttribute(cinfo, typeof(ExportAttribute)); if (ea == null) { continue; } IntPtr sel = Selector.GetHandle(ea.Selector); Class.class_addMethod(handle, sel, Method.ConstructorTrampoline, Method.Signature(cinfo)); #if DEBUG_REGISTER Console.WriteLine("[CTOR] Registering {0}[0x{1:x}|{2}] on {3} -> ({4})", ea.Selector, (int)sel, Method.Signature(cinfo), type, cinfo); #endif methods [sel] = new MethodDescription(cinfo, ea.ArgumentSemantic); } Class.objc_registerClassPair(handle); type_map [handle] = type; method_map [type] = methods; AddCustomType(type); return(handle); } }