diff --git a/src/bgen/Filters.cs b/src/bgen/Filters.cs index 6fa9f9ef718f..7cc6d7a1f2ec 100644 --- a/src/bgen/Filters.cs +++ b/src/bgen/Filters.cs @@ -118,7 +118,7 @@ public void GenerateFilter (Type type) } // properties - GenerateProperties (type, type); + GenerateFilterProperties (type, type); // protocols GenerateProtocolProperties (type, type, new HashSet ()); @@ -147,14 +147,14 @@ void GenerateProtocolProperties (Type type, Type originalType, HashSet p print (""); print ($"// {pname} protocol members "); - GenerateProperties (i, originalType, fromProtocol: true); + GenerateFilterProperties (i, originalType, fromProtocol: true); // also include base interfaces/protocols GenerateProtocolProperties (i, originalType, processed); } } - void GenerateProperties (Type type, Type? originalType = null, bool fromProtocol = false) + void GenerateFilterProperties (Type type, Type? originalType = null, bool fromProtocol = false) { foreach (var p in type.GetProperties (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (p.IsUnavailable (this)) @@ -235,6 +235,7 @@ void GenerateProperties (Type type, Type? originalType = null, bool fromProtocol } } + void PrintFilterExport (PropertyInfo p, ExportAttribute? export, bool setter) { if (export is null) diff --git a/src/bgen/Generator.cs b/src/bgen/Generator.cs index ec9d7df0c90e..32d32f3f2a39 100644 --- a/src/bgen/Generator.cs +++ b/src/bgen/Generator.cs @@ -5579,9 +5579,9 @@ string GetAssemblyName () } public class FieldBlock { - public FieldBlock (AttributeManager AttributeManager, TypeManager TypeManager, Type type, string generatedTypeName) + public FieldBlock (AttributeManager AttributeManager, TypeManager TypeManager, Type type, string generatedTypeName, GeneratedType gtype, string assemblyName) { - string TypeName = generatedTypeName; + TypeName = generatedTypeName; is_category_class = AttributeManager.HasAttribute (type); is_static_class = AttributeManager.HasAttribute (type) || is_category_class; is_partial = AttributeManager.HasAttribute (type); @@ -5609,10 +5609,16 @@ public FieldBlock (AttributeManager AttributeManager, TypeManager TypeManager, T #else } else if (model.AutoGeneratedName) { #endif - register_name = Registrar.Registrar.SanitizeObjectiveCName (GetAssemblyName () + "__" + type.FullName); + register_name = Registrar.Registrar.SanitizeObjectiveCName (assemblyName + "__" + type.FullName); } } + + instance_fields_to_clear_on_dispose = new List (); + this.gtype = gtype; + appearance_selectors = gtype.ImplementsAppearance ? gtype.AppearanceSelectors : null; } + + public string TypeName; public bool is_category_class; public bool is_static_class; public bool is_partial; @@ -5629,39 +5635,47 @@ public FieldBlock (AttributeManager AttributeManager, TypeManager TypeManager, T public Type base_type; public string objc_type_name; public string register_name; + + public List instance_fields_to_clear_on_dispose; + public GeneratedType gtype; + public List appearance_selectors; + + public string class_mod = null; + + public List field_exports = new (); + public List notifications = new (); } - public void Generate (Type type) + public bool DetermineTypeNeedsThreadChecks (Type type) { - if (ZeroCopyStrings) { - ErrorHelper.Warning (1027); - ZeroCopyStrings = false; - } - - type_wants_zero_copy = AttributeManager.HasAttribute (type) || ZeroCopyStrings; var tsa = AttributeManager.GetCustomAttribute (type); // if we're inside a special namespace then default is non-thread safe, otherwise default is thread safe if (ns.UINamespaces.Contains (type.Namespace)) { // Any type inside these namespaces requires, by default, a thread check // unless it has a [ThreadSafe] or [ThreadSafe (true)] attribute - type_needs_thread_checks = tsa is null || !tsa.Safe; + return tsa is null || !tsa.Safe; } else { // Any type outside these namespaces do NOT require a thread check // unless it has a [ThreadSafe (false)] attribute - type_needs_thread_checks = tsa is not null && !tsa.Safe; + return tsa is not null && !tsa.Safe; } + } - string TypeName = GetGeneratedTypeName (type); + public void Generate (Type type) + { + // 0. Method for type wants zero copy + if (ZeroCopyStrings) { + ErrorHelper.Warning (1027); + ZeroCopyStrings = false; + } + type_wants_zero_copy = AttributeManager.HasAttribute (type) || ZeroCopyStrings; + + type_needs_thread_checks = DetermineTypeNeedsThreadChecks (type); indent = 0; - var instance_fields_to_clear_on_dispose = new List (); - var gtype = GeneratedTypes.Lookup (type); - var appearance_selectors = gtype.ImplementsAppearance ? gtype.AppearanceSelectors : null; - - - + using (var sw = GetOutputStreamForType (type)) { this.sw = sw; - FieldBlock fb = new(AttributeManager, TypeManager, type, GetGeneratedTypeName (type)); + FieldBlock fb = new(AttributeManager, TypeManager, type, GetGeneratedTypeName (type),GeneratedTypes.Lookup (type), GetAssemblyName ()); Header (sw); @@ -5676,7 +5690,7 @@ public void Generate (Type type) if (fb.is_model && fb.base_type == TypeManager.System_Object) ErrorHelper.Warning (1060, type.FullName); - GenerateProtocolTypes (type, fb.class_visibility, TypeName, fb.protocol.Name ?? fb.objc_type_name, fb.protocol); + GenerateProtocolTypes (type, fb.class_visibility, fb.TypeName, fb.protocol.Name ?? fb.objc_type_name, fb.protocol); } if (type.Namespace is not null) { @@ -5685,16 +5699,17 @@ public void Generate (Type type) } bool core_image_filter = false; - string class_mod = null; is_direct_binding_value = null; is_direct_binding = null; if (BindThirdPartyLibrary) is_direct_binding_value = string.Format ("GetType ().Assembly == global::{0}.this_assembly", ns.Messaging); + + if (is_static_class || is_category_class || is_partial) { base_type = TypeManager.System_Object; if (!is_partial) - class_mod = "static "; + fb.class_mod = "static "; } else { if (is_protocol) { var pName = !string.IsNullOrEmpty (protocol.Name) ? $"Name = \"{protocol.Name}\"" : string.Empty; @@ -5746,127 +5761,10 @@ public void Generate (Type type) return; } - // Order of this list is such that the base type will be first, - // followed by the protocol interface, followed by any other - // interfaces in ascending order - var implements_list = new List (); - - foreach (var protocolType in type.GetInterfaces ()) { - if (!AttributeManager.HasAttribute (protocolType)) { - if (protocolType.Name [0] != 'I') - continue; + GenerateImplements (type,fb); - string nonInterfaceName = protocolType.Name.Substring (1); - if (!types.Any (x => x.Name.Contains (nonInterfaceName))) - continue; - - if (is_category_class) - continue; - // 1. MKUserLocation implements the MKAnnotation protocol - // 2. The MKAnnotation protocol has a required 'coordinate' getter, and an optional 'coordinate' setter. - // We've bound the former using an [Abstract] readonly Coordinate property, and the latter using a SetCoordinate method. - // 3. MKUserLocation has a readwrite 'coordinate' property, which we've bound as a readwrite Coordinate property. - // 4. If we make MKUserLocation implement the MKAnnotation protocol in the api bindings, then we'll - // inline all the MKAnnotation protocol members in MKUserLocation. This includes the SetCoordinate method, - // which causes problems, because it implements the 'setCoordinate:' selector, which the Coordinate property - // does as well, resulting in: - // error MM4119: Could not register the selector 'setCoordinate:' of the member 'MapKit.MKUserLocation.set_Coordinate' because the selector is already registered on the member 'SetCoordinate'. - // - // So we can't make the MKUserLocation implement the MKAnnotation protocol in the api definition (for now at least). - if (type.Name == "MKUserLocation" && protocolType.Name == "IMKAnnotation") - continue; -#if !NET - if (type.Name == "NSFontAssetRequest" || protocolType.Name == "INSProgressReporting") - continue; -#endif - - ErrorHelper.Warning (1111, protocolType, type, nonInterfaceName); - continue; - } - - // skip protocols that aren't available on the current platform - if (protocolType.IsUnavailable (this)) - continue; - - // A protocol this class implements. We need to implement the corresponding interface for the protocol. - string pname = protocolType.Name; - // the extra 'I' is only required for the bindings being built, if it comes from something already - // built (e.g. monotouch.dll) then the interface will alreadybe prefixed - if (protocolType.Assembly.GetName ().Name == "temp") - pname = "I" + pname; - var iface = FormatType (type, protocolType.Namespace, pname); - if (!implements_list.Contains (iface)) - implements_list.Add (iface); - } - - implements_list.Sort (StringComparer.Ordinal); - - if (is_protocol) - implements_list.Insert (0, "I" + type.Name); - - if (base_type != TypeManager.System_Object && TypeName != "NSObject" && !is_category_class) - implements_list.Insert (0, FormatType (type, base_type)); - - if (type.IsNested) { - var nestedName = type.FullName.Substring (type.Namespace.Length + 1); - var container = nestedName.Substring (0, nestedName.IndexOf ('+')); - - print ("partial class {0} {{", container); - indent++; - } - - var class_name = TypeName; - var where_list = string.Empty; - if (type.IsGenericType) { - class_name += "<"; - var gargs = type.GetGenericArguments (); - for (int i = 0; i < gargs.Length; i++) { - if (i > 0) - class_name += ", "; - class_name += FormatType (type, gargs [i]); - - where_list += "\n\t\twhere " + gargs [i].Name + " : "; - var constraints = gargs [i].GetGenericParameterConstraints (); - if (constraints.Length > 0) { - var comma = string.Empty; - if (IsProtocol (constraints [0])) { - where_list += "NSObject"; - comma = ", "; - } - - for (int c = 0; c < constraints.Length; c++) { - where_list += comma + FormatType (type, constraints [c]); - comma = ", "; - } - } else { - where_list += "NSObject"; - } - } - class_name += ">"; - if (where_list.Length > 0) - where_list += " "; - } - - print ("{0} unsafe {1}partial class {2} {3} {4}{{", - class_visibility, - class_mod, - class_name, - implements_list.Count == 0 ? string.Empty : ": " + string.Join (", ", implements_list), - where_list); - - indent++; - - if (!is_model && !is_partial) { - foreach (var ea in selectors [type].OrderBy (s => s, StringComparer.Ordinal)) { - var selectorField = SelectorField (ea, true); - if (!InlineSelectors) { - selectorField = selectorField.Substring (0, selectorField.Length - 6 /* Handle */); - print_generated_code (); - print ("const string {0} = \"{1}\";", selectorField, ea); - print ("static readonly {2} {0} = Selector.GetHandle (\"{1}\");", SelectorField (ea), ea, NativeHandleType); - } - } - } + GenerateSelectorFields (type,fb); + print (""); // Regular bindings (those that are not-static) or categories need this @@ -6040,317 +5938,10 @@ public void Generate (Type type) } } - var bound_methods = new HashSet (); // List of methods bound on the class itself (not via protocols) - var generated_methods = new List (); // All method that have been generated - foreach (var mi in GetTypeContractMethods (type).OrderByDescending (m => m.Name == "Constructor").ThenBy (m => m.Name, StringComparer.Ordinal)) { - if (mi.IsSpecialName || (mi.Name == "Constructor" && type != mi.DeclaringType)) - continue; - - if (mi.IsUnavailable (this)) - continue; - - if (appearance_selectors is not null && AttributeManager.HasAttribute (mi)) - appearance_selectors.Add (mi); - - var minfo = new MemberInformation (this, this, mi, type, is_category_class ? bta.BaseType : null, isModel: is_model); - // the type above is not the the we're generating, e.g. it would be `NSCopying` for `Copy(NSZone?)` - minfo.is_type_sealed = is_sealed; - - if (type == mi.DeclaringType || type.IsSubclassOf (mi.DeclaringType)) { - // not an injected protocol method. - bound_methods.Add (minfo); - } else { - // don't inject a protocol method if the class already - // implements the same method. - if (bound_methods.Contains (minfo)) - continue; - - var protocolsThatHaveThisMethod = GetTypeContractMethods (type).Where (x => { var sel = GetSelector (x); return sel is not null && sel == minfo.selector; }); - if (protocolsThatHaveThisMethod.Count () > 1) { - // If multiple protocols have this method and we haven't generated a copy yet - if (generated_methods.Any (x => x.selector == minfo.selector)) - continue; - - // Verify all of the versions have the same arguments / return value - // And just generate the first one (us) - var methodParams = mi.GetParameters (); - foreach (var duplicateMethod in protocolsThatHaveThisMethod) { - if (mi.ReturnType != duplicateMethod.ReturnType) - throw new BindingException (1038, true, mi.Name, type.Name); - - if (methodParams.Length != duplicateMethod.GetParameters ().Length) - throw new BindingException (1039, true, minfo.selector, type.Name, mi.GetParameters ().Length, duplicateMethod.GetParameters ().Length); - } - - int i = 0; - foreach (var param in methodParams) { - foreach (var duplicateMethod in protocolsThatHaveThisMethod) { - var duplicateParam = duplicateMethod.GetParameters () [i]; - if (param.IsOut != duplicateParam.IsOut) - throw new BindingException (1040, true, minfo.selector, type.Name, i); - if (param.ParameterType != duplicateParam.ParameterType) - throw new BindingException (1041, true, minfo.selector, type.Name, i, param.ParameterType, duplicateParam.ParameterType); - } - i++; - } - } - } - - generated_methods.Add (minfo); - GenerateMethod (minfo); - } - - var field_exports = new List (); - var notifications = new List (); - var bound_properties = new List (); // List of properties bound on the class itself (not via protocols) - var generated_properties = new List (); // All properties that have been generated - - foreach (var pi in GetTypeContractProperties (type).OrderBy (p => p.Name, StringComparer.Ordinal)) { - - if (pi.IsUnavailable (this)) - continue; - - if (AttributeManager.HasAttribute (pi)) { - field_exports.Add (pi); - - if (AttributeManager.HasAttribute (pi)) - notifications.Add (pi); - continue; - } - - if (appearance_selectors is not null && AttributeManager.HasAttribute (pi)) - appearance_selectors.Add (pi); - - if (type == pi.DeclaringType || type.IsSubclassOf (pi.DeclaringType)) { - // not an injected protocol property. - bound_properties.Add (pi.Name); - } else { - // don't inject a protocol property if the class already - // implements the same property. - if (bound_properties.Contains (pi.Name)) - continue; - - var protocolsThatHaveThisProp = GetTypeContractProperties (type).Where (x => x.Name == pi.Name); - if (protocolsThatHaveThisProp.Count () > 1) { - // If multiple protocols have this property and we haven't generated a copy yet - if (generated_properties.Contains (pi.Name)) - continue; - - // If there is a version that has get and set - if (protocolsThatHaveThisProp.Any (x => x.CanRead && x.CanWrite)) { - // Skip if we are not it - if (!(pi.CanRead && pi.CanWrite)) - continue; - } else { - // Verify all of the versions have the same get/set abilities since there is no universal get/set version - // And just generate the first one (us) - if (!protocolsThatHaveThisProp.All (x => x.CanRead == pi.CanRead && x.CanWrite == pi.CanWrite)) - throw new BindingException (1037, true, pi.Name, type.Name); - } - } - } - - generated_properties.Add (pi.Name); - GenerateProperty (type, pi, instance_fields_to_clear_on_dispose, is_model); - } - - if (field_exports.Count != 0) { - foreach (var field_pi in field_exports.OrderBy (f => f.Name, StringComparer.Ordinal)) { - var fieldAttr = AttributeManager.GetCustomAttribute (field_pi); - ComputeLibraryName (fieldAttr, type, field_pi.Name, out string library_name, out string library_path); + GenerateMethods (type, fb); + GenerateProperties (type, fb); + GenerateFields (type, fb); - bool is_unified_internal = field_pi.IsUnifiedInternal (this); - - string fieldTypeName; - string smartEnumTypeName = null; - if (IsSmartEnum (field_pi.PropertyType)) { - fieldTypeName = FormatType (TypeManager.NSString.DeclaringType, TypeManager.NSString); - smartEnumTypeName = FormatType (field_pi.DeclaringType, field_pi.PropertyType); - } else - fieldTypeName = FormatType (field_pi.DeclaringType, field_pi.PropertyType); - - bool nullable = false; - // Value types we dont cache for now, to avoid Nullable - if (!field_pi.PropertyType.IsValueType || smartEnumTypeName is not null) { - print_generated_code (); - PrintPreserveAttribute (field_pi); - print ("static {0}? _{1};", fieldTypeName, field_pi.Name); - } - - PrintAttributes (field_pi, preserve: true, advice: true); - PrintObsoleteAttributes (field_pi); - print ("[Field (\"{0}\", \"{1}\")]", fieldAttr.SymbolName, library_path ?? library_name); - PrintPlatformAttributes (field_pi); - if (AttributeManager.HasAttribute (field_pi)) { - print ("[EditorBrowsable (EditorBrowsableState.Advanced)]"); - } - // Check if this is a notification and print Advice to use our Notification API - if (AttributeManager.HasAttribute (field_pi)) - print ($"[Advice (\"Use {type.Name}.Notifications.Observe{GetNotificationName (field_pi)} helper method instead.\")]"); - - print ("{0} static {1}{2} {3}{4} {{", field_pi.IsInternal (this) ? "internal" : "public", - smartEnumTypeName ?? fieldTypeName, - nullable ? "?" : "", - field_pi.Name, - is_unified_internal ? "_" : ""); - indent++; - - PrintAttributes (field_pi, platform: true); - PrintAttributes (field_pi.GetGetMethod (), preserve: true, advice: true); - print ("get {"); - indent++; - if (field_pi.PropertyType == TypeManager.NSString) { - print ("if (_{0} is null)", field_pi.Name); - indent++; - print ("_{0} = Dlfcn.GetStringConstant (Libraries.{2}.Handle, \"{1}\")!;", field_pi.Name, fieldAttr.SymbolName, library_name); - indent--; - print ("return _{0};", field_pi.Name); - } else if (field_pi.PropertyType.Name == "NSArray") { - print ("if (_{0} is null)", field_pi.Name); - indent++; - print ("_{0} = Runtime.GetNSObject (Dlfcn.GetIndirect (Libraries.{2}.Handle, \"{1}\"))!;", field_pi.Name, fieldAttr.SymbolName, library_name); - indent--; - print ("return _{0};", field_pi.Name); - } else if (field_pi.PropertyType.Name == "UTType") { - print ("if (_{0} is null)", field_pi.Name); - indent++; - print ("_{0} = Runtime.GetNSObject (Dlfcn.GetIntPtr (Libraries.{2}.Handle, \"{1}\"))!;", field_pi.Name, fieldAttr.SymbolName, library_name); - indent--; - print ("return _{0};", field_pi.Name); - } else if (field_pi.PropertyType == TypeManager.System_Int32) { - print ("return Dlfcn.GetInt32 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_UInt32) { - print ("return Dlfcn.GetUInt32 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_Double) { - print ("return Dlfcn.GetDouble (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_Float) { - print ("return Dlfcn.GetFloat (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_IntPtr) { - print ("return Dlfcn.GetIntPtr (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType.FullName == "System.Drawing.SizeF") { - print ("return Dlfcn.GetSizeF (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_Int64) { - print ("return Dlfcn.GetInt64 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_UInt64) { - print ("return Dlfcn.GetUInt64 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else - // - // Handle various blittable value types here - // - if (Frameworks.HaveCoreMedia && Frameworks.HaveAVFoundation && (field_pi.PropertyType == TypeManager.CMTime || - field_pi.PropertyType == TypeManager.AVCaptureWhiteBalanceGains)) { - print ("return *(({3} *) Dlfcn.dlsym (Libraries.{2}.Handle, \"{1}\"));", field_pi.Name, fieldAttr.SymbolName, library_name, - FormatType (type, field_pi.PropertyType.Namespace, field_pi.PropertyType.Name)); - } else if (field_pi.PropertyType == TypeManager.System_nint) { - print ("return Dlfcn.GetNInt (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_nuint) { - print ("return Dlfcn.GetNUInt (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_nfloat) { - print ("return Dlfcn.GetNFloat (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.CoreGraphics_CGSize) { - print ("return Dlfcn.GetCGSize (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType.IsEnum) { - var btype = field_pi.PropertyType.GetEnumUnderlyingType (); - if (smartEnumTypeName is not null) { - print ("if (_{0} is null)", field_pi.Name); - indent++; - print ("_{0} = Dlfcn.GetStringConstant (Libraries.{2}.Handle, \"{1}\")!;", field_pi.Name, fieldAttr.SymbolName, library_name); - indent--; - print ($"return {smartEnumTypeName}Extensions.GetValue (_{field_pi.Name});"); - } else if (GetNativeEnumToManagedExpression (field_pi.PropertyType, out var preExpression, out var postExpression, out var _)) { - if (btype == TypeManager.System_nint || btype == TypeManager.System_Int64) - print ($"return {preExpression}Dlfcn.GetNInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\"){postExpression};"); - else if (btype == TypeManager.System_nuint || btype == TypeManager.System_UInt64) - print ($"return {preExpression}Dlfcn.GetNUInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\"){postExpression};"); - else - throw new BindingException (1014, true, fieldTypeName, FormatPropertyInfo (field_pi)); - } else { - if (btype == TypeManager.System_Int32) - print ($"return ({fieldTypeName}) Dlfcn.GetInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); - else if (btype == TypeManager.System_UInt32) - print ($"return ({fieldTypeName}) Dlfcn.GetUInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); - else if (btype == TypeManager.System_Int64) - print ($"return ({fieldTypeName}) Dlfcn.GetInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); - else if (btype == TypeManager.System_UInt64) - print ($"return ({fieldTypeName}) Dlfcn.GetUInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); - else - throw new BindingException (1014, true, fieldTypeName, FormatPropertyInfo (field_pi)); - } - } else { - if (field_pi.PropertyType == TypeManager.System_String) - throw new BindingException (1013, true); - else - throw new BindingException (1014, true, fieldTypeName, FormatPropertyInfo (field_pi)); - } - - indent--; - print ("}"); - - if (field_pi.CanWrite) { - PrintAttributes (field_pi, platform: true); - PrintAttributes (field_pi.GetSetMethod (), preserve: true, advice: true); - print ("set {"); - indent++; - if (field_pi.PropertyType == TypeManager.System_Int32) { - print ("Dlfcn.SetInt32 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_UInt32) { - print ("Dlfcn.SetUInt32 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_Double) { - print ("Dlfcn.SetDouble (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_Float) { - print ("Dlfcn.SetFloat (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_IntPtr) { - print ("Dlfcn.SetIntPtr (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType.FullName == "System.Drawing.SizeF") { - print ("Dlfcn.SetSizeF (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_Int64) { - print ("Dlfcn.SetInt64 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_UInt64) { - print ("Dlfcn.SetUInt64 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.NSString) { - print ("Dlfcn.SetString (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType.Name == "NSArray") { - print ("Dlfcn.SetArray (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_nint) { - print ("Dlfcn.SetNInt (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_nuint) { - print ("Dlfcn.SetNUInt (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.System_nfloat) { - print ("Dlfcn.SetNFloat (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType == TypeManager.CoreGraphics_CGSize) { - print ("Dlfcn.SetCGSize (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, fieldAttr.SymbolName, library_name); - } else if (field_pi.PropertyType.IsEnum) { - var btype = field_pi.PropertyType.GetEnumUnderlyingType (); - if (smartEnumTypeName is not null) - print ($"Dlfcn.SetString (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", value.GetConstant ());"); - else if (GetNativeEnumToNativeExpression (field_pi.PropertyType, out var preExpression, out var postExpression, out var _)) { - if (btype == TypeManager.System_nint || (BindThirdPartyLibrary && btype == TypeManager.System_Int64)) - print ($"Dlfcn.SetNInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (nint) {preExpression}value{postExpression});"); - else if (btype == TypeManager.System_nuint || (BindThirdPartyLibrary && btype == TypeManager.System_UInt64)) - print ($"Dlfcn.SetNUInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (nuint) {preExpression}value{postExpression});"); - else - throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, field_pi.Name); - } else { - if (btype == TypeManager.System_Int32) - print ($"Dlfcn.SetInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (int) value);"); - else if (btype == TypeManager.System_UInt32) - print ($"Dlfcn.SetUInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (uint) value);"); - else if (btype == TypeManager.System_Int64) - print ($"Dlfcn.SetInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (long) value);"); - else if (btype == TypeManager.System_UInt64) - print ($"Dlfcn.SetUInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (ulong) value);"); - else - throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, field_pi.Name); - } - } else - throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, field_pi.Name); - indent--; - print ("}"); - } - indent--; - print ("}"); - } - } var eventArgTypes = new Dictionary (); @@ -6736,117 +6327,8 @@ public void Generate (Type type) } } - // - // Appearance class - // - var gt = GeneratedTypes.Lookup (type); - if (gt.ImplementsAppearance) { - var parent_implements_appearance = gt.Parent is not null && gt.ParentGenerated.ImplementsAppearance; - string base_class; - - if (parent_implements_appearance) { - var parent = GetGeneratedTypeName (gt.Parent); - base_class = "global::" + gt.Parent.FullName + "." + parent + "Appearance"; - } else - base_class = "UIAppearance"; - - string appearance_type_name = TypeName + "Appearance"; - print ("public partial class {0} : {1} {{", appearance_type_name, base_class); - indent++; - print ("protected internal {0} (IntPtr handle) : base (handle) {{}}", appearance_type_name); - - if (appearance_selectors is not null) { - var currently_ignored_fields = new List (); - - foreach (MemberInfo mi in appearance_selectors.OrderBy (m => m.Name, StringComparer.Ordinal)) { - if (mi is MethodInfo) - GenerateMethod (type, mi as MethodInfo, - is_model: false, - category_extension_type: is_category_class ? base_type : null, - is_appearance: true); - else - GenerateProperty (type, mi as PropertyInfo, currently_ignored_fields, false); - } - } - - indent--; - print ("}\n"); - print ("public static {0}{1} Appearance {{", parent_implements_appearance ? "new " : "", appearance_type_name); - indent++; - print ("get {{ return new {0} (global::{1}.IntPtr_objc_msgSend (class_ptr, {2})); }}", appearance_type_name, ns.Messaging, InlineSelectors ? "ObjCRuntime.Selector.GetHandle (\"appearance\")" : "UIAppearance.SelectorAppearance"); - indent--; - print ("}\n"); - print ("public static {0}{1} GetAppearance () where T: {2} {{", parent_implements_appearance ? "new " : "", appearance_type_name, TypeName); - indent++; - print ("return new {0} (global::{1}.IntPtr_objc_msgSend (Class.GetHandle (typeof (T)), {2}));", appearance_type_name, ns.Messaging, InlineSelectors ? "ObjCRuntime.Selector.GetHandle (\"appearance\")" : "UIAppearance.SelectorAppearance"); - indent--; - print ("}\n"); - print ("public static {0}{1} AppearanceWhenContainedIn (params Type [] containers)", parent_implements_appearance ? "new " : "", appearance_type_name); - print ("{"); - indent++; - print ("return new {0} (UIAppearance.GetAppearance (class_ptr, containers));", appearance_type_name); - indent--; - print ("}\n"); - - print ("public static {0}{1} GetAppearance (UITraitCollection traits) {{", parent_implements_appearance ? "new " : "", appearance_type_name); - indent++; - print ("return new {0} (UIAppearance.GetAppearance (class_ptr, traits));", appearance_type_name); - indent--; - print ("}\n"); - - print ("public static {0}{1} GetAppearance (UITraitCollection traits, params Type [] containers) {{", parent_implements_appearance ? "new " : "", appearance_type_name); - indent++; - print ("return new {0} (UIAppearance.GetAppearance (class_ptr, traits, containers));", appearance_type_name); - indent--; - print ("}\n"); - - print ("public static {0}{1} GetAppearance (UITraitCollection traits) where T: {2} {{", parent_implements_appearance ? "new " : "", appearance_type_name, TypeName); - indent++; - print ("return new {0} (UIAppearance.GetAppearance (Class.GetHandle (typeof (T)), traits));", appearance_type_name); - indent--; - print ("}\n"); - - print ("public static {0}{1} GetAppearance (UITraitCollection traits, params Type [] containers) where T: {2}{{", parent_implements_appearance ? "new " : "", appearance_type_name, TypeName); - indent++; - print ("return new {0} (UIAppearance.GetAppearance (Class.GetHandle (typeof (T)), containers));", appearance_type_name); - indent--; - print ("}\n"); - - print (""); - } - // - // Notification extensions - // - if (notifications.Count > 0) { - print ("\n"); - print ("//"); - print ("// Notifications"); - print ("//"); - - print ("public static partial class Notifications {\n"); - foreach (var property in notifications.OrderBy (p => p.Name, StringComparer.Ordinal)) { - string notification_name = GetNotificationName (property); - string notification_center = GetNotificationCenter (property); - - foreach (var notification_attribute in AttributeManager.GetCustomAttributes (property)) { - Type event_args_type = notification_attribute.Type; - string event_name = event_args_type is null ? "NSNotificationEventArgs" : event_args_type.FullName; - - if (event_args_type is not null) - notification_event_arg_types [event_args_type] = event_args_type; - print ("\tpublic static NSObject Observe{0} (EventHandler<{1}> handler)", notification_name, event_name); - print ("\t{"); - print ("\t\treturn {0}.AddObserver ({1}, notification => handler (null, new {2} (notification)));", notification_center, property.Name, event_name); - print ("\t}"); - print ("\tpublic static NSObject Observe{0} (NSObject objectToObserve, EventHandler<{1}> handler)", notification_name, event_name); - print ("\t{"); - print ("\t\treturn {0}.AddObserver ({1}, notification => handler (null, new {2} (notification)), objectToObserve);", notification_center, property.Name, event_name); - print ("\t}"); - } - } - print ("\n}"); - } - + GenerateAppearanceClass (fb); + GenerateNotifications (fb); indent--; print ("}} /* class {0} */", TypeName); @@ -6905,6 +6387,7 @@ public void Generate (Type type) print ("//"); } + GenerateAsync (fb); foreach (var async_type in async_result_types.OrderBy (t => t.Item1, StringComparer.Ordinal)) { if (async_result_types_emitted.Contains (async_type.Item1)) continue; @@ -6952,6 +6435,626 @@ public void Generate (Type type) } } + private void GenerateAppearanceClass (FieldBlock fb) + { + var gt = GeneratedTypes.Lookup (type); + if (gt.ImplementsAppearance) { + var parent_implements_appearance = gt.Parent is not null && gt.ParentGenerated.ImplementsAppearance; + string base_class; + + if (parent_implements_appearance) { + var parent = GetGeneratedTypeName (gt.Parent); + base_class = "global::" + gt.Parent.FullName + "." + parent + "Appearance"; + } else + base_class = "UIAppearance"; + + string appearance_type_name = TypeName + "Appearance"; + print ("public partial class {0} : {1} {{", appearance_type_name, base_class); + indent++; + print ("protected internal {0} (IntPtr handle) : base (handle) {{}}", appearance_type_name); + + if (appearance_selectors is not null) { + var currently_ignored_fields = new List (); + + foreach (MemberInfo mi in appearance_selectors.OrderBy (m => m.Name, StringComparer.Ordinal)) { + if (mi is MethodInfo) + GenerateMethod (type, mi as MethodInfo, + is_model: false, + category_extension_type: is_category_class ? base_type : null, + is_appearance: true); + else + GenerateProperty (type, mi as PropertyInfo, currently_ignored_fields, false); + } + } + + indent--; + print ("}\n"); + print ("public static {0}{1} Appearance {{", parent_implements_appearance ? "new " : "", appearance_type_name); + indent++; + print ("get {{ return new {0} (global::{1}.IntPtr_objc_msgSend (class_ptr, {2})); }}", appearance_type_name, ns.Messaging, InlineSelectors ? "ObjCRuntime.Selector.GetHandle (\"appearance\")" : "UIAppearance.SelectorAppearance"); + indent--; + print ("}\n"); + print ("public static {0}{1} GetAppearance () where T: {2} {{", parent_implements_appearance ? "new " : "", appearance_type_name, TypeName); + indent++; + print ("return new {0} (global::{1}.IntPtr_objc_msgSend (Class.GetHandle (typeof (T)), {2}));", appearance_type_name, ns.Messaging, InlineSelectors ? "ObjCRuntime.Selector.GetHandle (\"appearance\")" : "UIAppearance.SelectorAppearance"); + indent--; + print ("}\n"); + print ("public static {0}{1} AppearanceWhenContainedIn (params Type [] containers)", parent_implements_appearance ? "new " : "", appearance_type_name); + print ("{"); + indent++; + print ("return new {0} (UIAppearance.GetAppearance (class_ptr, containers));", appearance_type_name); + indent--; + print ("}\n"); + + print ("public static {0}{1} GetAppearance (UITraitCollection traits) {{", parent_implements_appearance ? "new " : "", appearance_type_name); + indent++; + print ("return new {0} (UIAppearance.GetAppearance (class_ptr, traits));", appearance_type_name); + indent--; + print ("}\n"); + + print ("public static {0}{1} GetAppearance (UITraitCollection traits, params Type [] containers) {{", parent_implements_appearance ? "new " : "", appearance_type_name); + indent++; + print ("return new {0} (UIAppearance.GetAppearance (class_ptr, traits, containers));", appearance_type_name); + indent--; + print ("}\n"); + + print ("public static {0}{1} GetAppearance (UITraitCollection traits) where T: {2} {{", parent_implements_appearance ? "new " : "", appearance_type_name, TypeName); + indent++; + print ("return new {0} (UIAppearance.GetAppearance (Class.GetHandle (typeof (T)), traits));", appearance_type_name); + indent--; + print ("}\n"); + + print ("public static {0}{1} GetAppearance (UITraitCollection traits, params Type [] containers) where T: {2}{{", parent_implements_appearance ? "new " : "", appearance_type_name, TypeName); + indent++; + print ("return new {0} (UIAppearance.GetAppearance (Class.GetHandle (typeof (T)), containers));", appearance_type_name); + indent--; + print ("}\n"); + + print (""); + } + } + + private void GenerateNotifications (FieldBlock fb) + { + // + // Notification extensions + // + if (fb.notifications.Count > 0) { + print ("\n"); + print ("//"); + print ("// Notifications"); + print ("//"); + + print ("public static partial class Notifications {\n"); + foreach (var property in fb.notifications.OrderBy (p => p.Name, StringComparer.Ordinal)) { + string notification_name = GetNotificationName (property); + string notification_center = GetNotificationCenter (property); + + foreach (var notification_attribute in AttributeManager.GetCustomAttributes (property)) { + Type event_args_type = notification_attribute.Type; + string event_name = event_args_type is null ? "NSNotificationEventArgs" : event_args_type.FullName; + + if (event_args_type is not null) + notification_event_arg_types [event_args_type] = event_args_type; + print ("\tpublic static NSObject Observe{0} (EventHandler<{1}> handler)", notification_name, event_name); + print ("\t{"); + print ("\t\treturn {0}.AddObserver ({1}, notification => handler (null, new {2} (notification)));", notification_center, property.Name, event_name); + print ("\t}"); + print ("\tpublic static NSObject Observe{0} (NSObject objectToObserve, EventHandler<{1}> handler)", notification_name, event_name); + print ("\t{"); + print ("\t\treturn {0}.AddObserver ({1}, notification => handler (null, new {2} (notification)), objectToObserve);", notification_center, property.Name, event_name); + print ("\t}"); + } + } + print ("\n}"); + } + } + + private void GenerateFields (Type type, FieldBlock fb) + { + if (fb.field_exports.Count != 0) { + foreach (var field_pi in fb.field_exports.OrderBy (f => f.Name, StringComparer.Ordinal)) { + var fieldAttr = AttributeManager.GetCustomAttribute (field_pi); + ComputeLibraryName (fieldAttr, type, field_pi.Name, out string library_name, out string library_path); + + bool is_unified_internal = field_pi.IsUnifiedInternal (this); + + string fieldTypeName; + string smartEnumTypeName = null; + if (IsSmartEnum (field_pi.PropertyType)) { + fieldTypeName = FormatType (TypeManager.NSString.DeclaringType, TypeManager.NSString); + smartEnumTypeName = FormatType (field_pi.DeclaringType, field_pi.PropertyType); + } else + fieldTypeName = FormatType (field_pi.DeclaringType, field_pi.PropertyType); + + bool nullable = false; + // Value types we dont cache for now, to avoid Nullable + if (!field_pi.PropertyType.IsValueType || smartEnumTypeName is not null) { + print_generated_code (); + PrintPreserveAttribute (field_pi); + print ("static {0}? _{1};", fieldTypeName, field_pi.Name); + } + + PrintAttributes (field_pi, preserve: true, advice: true); + PrintObsoleteAttributes (field_pi); + print ("[Field (\"{0}\", \"{1}\")]", fieldAttr.SymbolName, library_path ?? library_name); + PrintPlatformAttributes (field_pi); + if (AttributeManager.HasAttribute (field_pi)) { + print ("[EditorBrowsable (EditorBrowsableState.Advanced)]"); + } + + // Check if this is a notification and print Advice to use our Notification API + if (AttributeManager.HasAttribute (field_pi)) + print ( + $"[Advice (\"Use {type.Name}.Notifications.Observe{GetNotificationName (field_pi)} helper method instead.\")]"); + + print ("{0} static {1}{2} {3}{4} {{", field_pi.IsInternal (this) ? "internal" : "public", + smartEnumTypeName ?? fieldTypeName, + nullable ? "?" : "", + field_pi.Name, + is_unified_internal ? "_" : ""); + indent++; + + PrintAttributes (field_pi, platform: true); + PrintAttributes (field_pi.GetGetMethod (), preserve: true, advice: true); + print ("get {"); + indent++; + if (field_pi.PropertyType == TypeManager.NSString) { + print ("if (_{0} is null)", field_pi.Name); + indent++; + print ("_{0} = Dlfcn.GetStringConstant (Libraries.{2}.Handle, \"{1}\")!;", field_pi.Name, + fieldAttr.SymbolName, library_name); + indent--; + print ("return _{0};", field_pi.Name); + } else if (field_pi.PropertyType.Name == "NSArray") { + print ("if (_{0} is null)", field_pi.Name); + indent++; + print ("_{0} = Runtime.GetNSObject (Dlfcn.GetIndirect (Libraries.{2}.Handle, \"{1}\"))!;", + field_pi.Name, fieldAttr.SymbolName, library_name); + indent--; + print ("return _{0};", field_pi.Name); + } else if (field_pi.PropertyType.Name == "UTType") { + print ("if (_{0} is null)", field_pi.Name); + indent++; + print ("_{0} = Runtime.GetNSObject (Dlfcn.GetIntPtr (Libraries.{2}.Handle, \"{1}\"))!;", + field_pi.Name, fieldAttr.SymbolName, library_name); + indent--; + print ("return _{0};", field_pi.Name); + } else if (field_pi.PropertyType == TypeManager.System_Int32) { + print ("return Dlfcn.GetInt32 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_UInt32) { + print ("return Dlfcn.GetUInt32 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_Double) { + print ("return Dlfcn.GetDouble (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_Float) { + print ("return Dlfcn.GetFloat (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_IntPtr) { + print ("return Dlfcn.GetIntPtr (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType.FullName == "System.Drawing.SizeF") { + print ("return Dlfcn.GetSizeF (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_Int64) { + print ("return Dlfcn.GetInt64 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_UInt64) { + print ("return Dlfcn.GetUInt64 (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else + // + // Handle various blittable value types here + // + if (Frameworks.HaveCoreMedia && Frameworks.HaveAVFoundation && + (field_pi.PropertyType == TypeManager.CMTime || + field_pi.PropertyType == TypeManager.AVCaptureWhiteBalanceGains)) { + print ("return *(({3} *) Dlfcn.dlsym (Libraries.{2}.Handle, \"{1}\"));", field_pi.Name, + fieldAttr.SymbolName, library_name, + FormatType (type, field_pi.PropertyType.Namespace, field_pi.PropertyType.Name)); + } else if (field_pi.PropertyType == TypeManager.System_nint) { + print ("return Dlfcn.GetNInt (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, fieldAttr.SymbolName, + library_name); + } else if (field_pi.PropertyType == TypeManager.System_nuint) { + print ("return Dlfcn.GetNUInt (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_nfloat) { + print ("return Dlfcn.GetNFloat (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.CoreGraphics_CGSize) { + print ("return Dlfcn.GetCGSize (Libraries.{2}.Handle, \"{1}\");", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType.IsEnum) { + var btype = field_pi.PropertyType.GetEnumUnderlyingType (); + if (smartEnumTypeName is not null) { + print ("if (_{0} is null)", field_pi.Name); + indent++; + print ("_{0} = Dlfcn.GetStringConstant (Libraries.{2}.Handle, \"{1}\")!;", field_pi.Name, + fieldAttr.SymbolName, library_name); + indent--; + print ($"return {smartEnumTypeName}Extensions.GetValue (_{field_pi.Name});"); + } else if (GetNativeEnumToManagedExpression (field_pi.PropertyType, out var preExpression, + out var postExpression, out var _)) { + if (btype == TypeManager.System_nint || btype == TypeManager.System_Int64) + print ( + $"return {preExpression}Dlfcn.GetNInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\"){postExpression};"); + else if (btype == TypeManager.System_nuint || btype == TypeManager.System_UInt64) + print ( + $"return {preExpression}Dlfcn.GetNUInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\"){postExpression};"); + else + throw new BindingException (1014, true, fieldTypeName, FormatPropertyInfo (field_pi)); + } else { + if (btype == TypeManager.System_Int32) + print ( + $"return ({fieldTypeName}) Dlfcn.GetInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); + else if (btype == TypeManager.System_UInt32) + print ( + $"return ({fieldTypeName}) Dlfcn.GetUInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); + else if (btype == TypeManager.System_Int64) + print ( + $"return ({fieldTypeName}) Dlfcn.GetInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); + else if (btype == TypeManager.System_UInt64) + print ( + $"return ({fieldTypeName}) Dlfcn.GetUInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\");"); + else + throw new BindingException (1014, true, fieldTypeName, FormatPropertyInfo (field_pi)); + } + } else { + if (field_pi.PropertyType == TypeManager.System_String) + throw new BindingException (1013, true); + else + throw new BindingException (1014, true, fieldTypeName, FormatPropertyInfo (field_pi)); + } + + indent--; + print ("}"); + + if (field_pi.CanWrite) { + PrintAttributes (field_pi, platform: true); + PrintAttributes (field_pi.GetSetMethod (), preserve: true, advice: true); + print ("set {"); + indent++; + if (field_pi.PropertyType == TypeManager.System_Int32) { + print ("Dlfcn.SetInt32 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_UInt32) { + print ("Dlfcn.SetUInt32 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_Double) { + print ("Dlfcn.SetDouble (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_Float) { + print ("Dlfcn.SetFloat (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_IntPtr) { + print ("Dlfcn.SetIntPtr (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType.FullName == "System.Drawing.SizeF") { + print ("Dlfcn.SetSizeF (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_Int64) { + print ("Dlfcn.SetInt64 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_UInt64) { + print ("Dlfcn.SetUInt64 (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.NSString) { + print ("Dlfcn.SetString (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType.Name == "NSArray") { + print ("Dlfcn.SetArray (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_nint) { + print ("Dlfcn.SetNInt (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_nuint) { + print ("Dlfcn.SetNUInt (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.System_nfloat) { + print ("Dlfcn.SetNFloat (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType == TypeManager.CoreGraphics_CGSize) { + print ("Dlfcn.SetCGSize (Libraries.{2}.Handle, \"{1}\", value);", field_pi.Name, + fieldAttr.SymbolName, library_name); + } else if (field_pi.PropertyType.IsEnum) { + var btype = field_pi.PropertyType.GetEnumUnderlyingType (); + if (smartEnumTypeName is not null) + print ( + $"Dlfcn.SetString (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", value.GetConstant ());"); + else if (GetNativeEnumToNativeExpression (field_pi.PropertyType, out var preExpression, + out var postExpression, out var _)) { + if (btype == TypeManager.System_nint || + (BindThirdPartyLibrary && btype == TypeManager.System_Int64)) + print ( + $"Dlfcn.SetNInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (nint) {preExpression}value{postExpression});"); + else if (btype == TypeManager.System_nuint || + (BindThirdPartyLibrary && btype == TypeManager.System_UInt64)) + print ( + $"Dlfcn.SetNUInt (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (nuint) {preExpression}value{postExpression});"); + else + throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, + field_pi.Name); + } else { + if (btype == TypeManager.System_Int32) + print ( + $"Dlfcn.SetInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (int) value);"); + else if (btype == TypeManager.System_UInt32) + print ( + $"Dlfcn.SetUInt32 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (uint) value);"); + else if (btype == TypeManager.System_Int64) + print ( + $"Dlfcn.SetInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (long) value);"); + else if (btype == TypeManager.System_UInt64) + print ( + $"Dlfcn.SetUInt64 (Libraries.{library_name}.Handle, \"{fieldAttr.SymbolName}\", (ulong) value);"); + else + throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, + field_pi.Name); + } + } else + throw new BindingException (1021, true, fieldTypeName, field_pi.DeclaringType.FullName, + field_pi.Name); + + indent--; + print ("}"); + } + + indent--; + print ("}"); + } + } + } + + private void GenerateProperties (Type type, FieldBlock fb) + { + var bound_properties = new List (); // List of properties bound on the class itself (not via protocols) + var generated_properties = new List (); // All properties that have been generated + + foreach (var pi in GetTypeContractProperties (type).OrderBy (p => p.Name, StringComparer.Ordinal)) { + + if (pi.IsUnavailable (this)) + continue; + + if (AttributeManager.HasAttribute (pi)) { + fb.field_exports.Add (pi); + + if (AttributeManager.HasAttribute (pi)) + fb.notifications.Add (pi); + continue; + } + + if (fb.appearance_selectors is not null && AttributeManager.HasAttribute (pi)) + fb.appearance_selectors.Add (pi); + + if (type == pi.DeclaringType || type.IsSubclassOf (pi.DeclaringType)) { + // not an injected protocol property. + bound_properties.Add (pi.Name); + } else { + // don't inject a protocol property if the class already + // implements the same property. + if (bound_properties.Contains (pi.Name)) + continue; + + var protocolsThatHaveThisProp = GetTypeContractProperties (type).Where (x => x.Name == pi.Name); + if (protocolsThatHaveThisProp.Count () > 1) { + // If multiple protocols have this property and we haven't generated a copy yet + if (generated_properties.Contains (pi.Name)) + continue; + + // If there is a version that has get and set + if (protocolsThatHaveThisProp.Any (x => x.CanRead && x.CanWrite)) { + // Skip if we are not it + if (!(pi.CanRead && pi.CanWrite)) + continue; + } else { + // Verify all of the versions have the same get/set abilities since there is no universal get/set version + // And just generate the first one (us) + if (!protocolsThatHaveThisProp.All (x => x.CanRead == pi.CanRead && x.CanWrite == pi.CanWrite)) + throw new BindingException (1037, true, pi.Name, type.Name); + } + } + } + + generated_properties.Add (pi.Name); + GenerateProperty (type, pi, fb.instance_fields_to_clear_on_dispose, fb.is_model); + } + } + + private void GenerateMethods (Type type, FieldBlock fb) + { + var bound_methods = new HashSet (); // List of methods bound on the class itself (not via protocols) + var generated_methods = new List (); // All method that have been generated + foreach (var mi in GetTypeContractMethods (type).OrderByDescending (m => m.Name == "Constructor").ThenBy (m => m.Name, StringComparer.Ordinal)) { + if (mi.IsSpecialName || (mi.Name == "Constructor" && type != mi.DeclaringType)) + continue; + + if (mi.IsUnavailable (this)) + continue; + + // TODO Have to make sure fb is passed by reference for this method + if (fb.appearance_selectors is not null && AttributeManager.HasAttribute (mi)) + fb.appearance_selectors.Add (mi); + + var minfo = new MemberInformation (this, this, mi, type, fb.is_category_class ? fb.bta.BaseType : null, isModel: fb.is_model); + // the type above is not the the we're generating, e.g. it would be `NSCopying` for `Copy(NSZone?)` + minfo.is_type_sealed = fb.is_sealed; + + if (type == mi.DeclaringType || type.IsSubclassOf (mi.DeclaringType)) { + // not an injected protocol method. + bound_methods.Add (minfo); + } else { + // don't inject a protocol method if the class already + // implements the same method. + if (bound_methods.Contains (minfo)) + continue; + + var protocolsThatHaveThisMethod = GetTypeContractMethods (type).Where (x => { var sel = GetSelector (x); return sel is not null && sel == minfo.selector; }); + if (protocolsThatHaveThisMethod.Count () > 1) { + // If multiple protocols have this method and we haven't generated a copy yet + if (generated_methods.Any (x => x.selector == minfo.selector)) + continue; + + // Verify all of the versions have the same arguments / return value + // And just generate the first one (us) + var methodParams = mi.GetParameters (); + foreach (var duplicateMethod in protocolsThatHaveThisMethod) { + if (mi.ReturnType != duplicateMethod.ReturnType) + throw new BindingException (1038, true, mi.Name, type.Name); + + if (methodParams.Length != duplicateMethod.GetParameters ().Length) + throw new BindingException (1039, true, minfo.selector, type.Name, mi.GetParameters ().Length, duplicateMethod.GetParameters ().Length); + } + + int i = 0; + foreach (var param in methodParams) { + foreach (var duplicateMethod in protocolsThatHaveThisMethod) { + var duplicateParam = duplicateMethod.GetParameters () [i]; + if (param.IsOut != duplicateParam.IsOut) + throw new BindingException (1040, true, minfo.selector, type.Name, i); + if (param.ParameterType != duplicateParam.ParameterType) + throw new BindingException (1041, true, minfo.selector, type.Name, i, param.ParameterType, duplicateParam.ParameterType); + } + i++; + } + } + } + + generated_methods.Add (minfo); + GenerateMethod (minfo); + } + } + + // TODO needs to take it selectors and INline selectors, I guess. Still good for a split off + public void GenerateSelectorFields (Type type, FieldBlock fb) + { + if (!fb.is_model && !fb.is_partial) { + foreach (var ea in selectors [type].OrderBy (s => s, StringComparer.Ordinal)) { + var selectorField = SelectorField (ea, true); + if (!InlineSelectors) { + selectorField = selectorField.Substring (0, selectorField.Length - 6 /* Handle */); + print_generated_code (); + print ("const string {0} = \"{1}\";", selectorField, ea); + print ("static readonly {2} {0} = Selector.GetHandle (\"{1}\");", SelectorField (ea), ea, NativeHandleType); + } + } + } + } + + private void GenerateImplements (Type type, FieldBlock fb) + { + // Order of this list is such that the base type will be first, + // followed by the protocol interface, followed by any other + // interfaces in ascending order + var implements_list = new List (); + + foreach (var protocolType in type.GetInterfaces ()) { + if (!AttributeManager.HasAttribute (protocolType)) { + if (protocolType.Name [0] != 'I') + continue; + + string nonInterfaceName = protocolType.Name.Substring (1); + if (!types.Any (x => x.Name.Contains (nonInterfaceName))) + continue; + + if (fb.is_category_class) + continue; + // 1. MKUserLocation implements the MKAnnotation protocol + // 2. The MKAnnotation protocol has a required 'coordinate' getter, and an optional 'coordinate' setter. + // We've bound the former using an [Abstract] readonly Coordinate property, and the latter using a SetCoordinate method. + // 3. MKUserLocation has a readwrite 'coordinate' property, which we've bound as a readwrite Coordinate property. + // 4. If we make MKUserLocation implement the MKAnnotation protocol in the api bindings, then we'll + // inline all the MKAnnotation protocol members in MKUserLocation. This includes the SetCoordinate method, + // which causes problems, because it implements the 'setCoordinate:' selector, which the Coordinate property + // does as well, resulting in: + // error MM4119: Could not register the selector 'setCoordinate:' of the member 'MapKit.MKUserLocation.set_Coordinate' because the selector is already registered on the member 'SetCoordinate'. + // + // So we can't make the MKUserLocation implement the MKAnnotation protocol in the api definition (for now at least). + if (type.Name == "MKUserLocation" && protocolType.Name == "IMKAnnotation") + continue; +#if !NET + if (type.Name == "NSFontAssetRequest" || protocolType.Name == "INSProgressReporting") + continue; +#endif + + ErrorHelper.Warning (1111, protocolType, type, nonInterfaceName); + continue; + } + + // skip protocols that aren't available on the current platform + if (protocolType.IsUnavailable (this)) + continue; + + // A protocol this class implements. We need to implement the corresponding interface for the protocol. + string pname = protocolType.Name; + // the extra 'I' is only required for the bindings being built, if it comes from something already + // built (e.g. monotouch.dll) then the interface will alreadybe prefixed + if (protocolType.Assembly.GetName ().Name == "temp") + pname = "I" + pname; + var iface = FormatType (type, protocolType.Namespace, pname); + if (!implements_list.Contains (iface)) + implements_list.Add (iface); + } + + implements_list.Sort (StringComparer.Ordinal); + + if (fb.is_protocol) + implements_list.Insert (0, "I" + type.Name); + + if (fb.base_type != TypeManager.System_Object && fb.TypeName != "NSObject" && !fb.is_category_class) + implements_list.Insert (0, FormatType (type, fb.base_type)); + + if (type.IsNested) { + var nestedName = type.FullName.Substring (type.Namespace.Length + 1); + var container = nestedName.Substring (0, nestedName.IndexOf ('+')); + + print ("partial class {0} {{", container); + indent++; + } + + var class_name = fb.TypeName; + var where_list = string.Empty; + if (type.IsGenericType) { + class_name += "<"; + var gargs = type.GetGenericArguments (); + for (int i = 0; i < gargs.Length; i++) { + if (i > 0) + class_name += ", "; + class_name += FormatType (type, gargs [i]); + + where_list += "\n\t\twhere " + gargs [i].Name + " : "; + var constraints = gargs [i].GetGenericParameterConstraints (); + if (constraints.Length > 0) { + var comma = string.Empty; + if (IsProtocol (constraints [0])) { + where_list += "NSObject"; + comma = ", "; + } + + for (int c = 0; c < constraints.Length; c++) { + where_list += comma + FormatType (type, constraints [c]); + comma = ", "; + } + } else { + where_list += "NSObject"; + } + } + class_name += ">"; + if (where_list.Length > 0) + where_list += " "; + } + + print ("{0} unsafe {1}partial class {2} {3} {4}{{", + fb.class_visibility, + fb.class_mod, + class_name, + implements_list.Count == 0 ? string.Empty : ": " + string.Join (", ", implements_list), + where_list); + + indent++; + } + static string GetDelegateTypePropertyName (string delName) { return "GetInternalEvent" + delName + "Type";