Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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));
        }
Beispiel #4
0
        protected override Type GetProtocolAttributeWrapperType(Type type)
        {
            var attr = SharedDynamic.GetOneAttribute <ProtocolAttribute> (type);

            return(attr == null ? null : attr.WrapperType);
        }
Beispiel #5
0
 protected override CategoryAttribute GetCategoryAttribute(Type type)
 {
     return(SharedDynamic.GetOneAttribute <CategoryAttribute> (type));
 }
Beispiel #6
0
 protected override ProtocolAttribute GetProtocolAttribute(Type type)
 {
     return(SharedDynamic.GetOneAttribute <ProtocolAttribute> (type));
 }
Beispiel #7
0
 protected override RegisterAttribute GetRegisterAttribute(Type type)
 {
     return(SharedDynamic.GetOneAttribute <RegisterAttribute> (type));
 }
Beispiel #8
0
 protected override ExportAttribute GetExportAttribute(PropertyInfo property)
 {
     return(SharedDynamic.GetOneAttribute <ExportAttribute> (GetBasePropertyInTypeHierarchy(property) ?? property));
 }
Beispiel #9
0
 protected override Dictionary <MethodBase, List <MethodBase> > PrepareMethodMapping(Type type)
 {
     return(SharedDynamic.PrepareInterfaceMethodMapping(type));
 }
Beispiel #10
0
 protected override ConnectAttribute GetConnectAttribute(PropertyInfo property)
 {
     return(SharedDynamic.GetOneAttribute <ConnectAttribute> (property));
 }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        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);
            }
        }