static int GetValueTypeSize(Type type, List <Type> fieldTypes, bool is_64_bits) { int size = 0; int maxElementSize = 1; if (type.IsExplicitLayout) { // Find the maximum of "field size + field offset" for each field. foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { #if BGENERATOR var fieldOffset = AttributeManager.GetCustomAttribute <FieldOffsetAttribute> (field); #else var fieldOffset = (FieldOffsetAttribute)Attribute.GetCustomAttribute(field, typeof(FieldOffsetAttribute)); #endif var elementSize = 0; GetValueTypeSize(type, field.FieldType, fieldTypes, is_64_bits, ref elementSize, ref maxElementSize); size = Math.Max(size, elementSize + fieldOffset.Value); } } else { GetValueTypeSize(type, type, fieldTypes, is_64_bits, ref size, ref maxElementSize); } if (size % maxElementSize != 0) { size += (maxElementSize - size % maxElementSize); } return(size); }
public void GenerateFilter(Type type) { var is_abstract = AttributeManager.HasAttribute <AbstractAttribute> (type); var filter = AttributeManager.GetCustomAttribute <CoreImageFilterAttribute> (type); var base_type = AttributeManager.GetCustomAttribute <BaseTypeAttribute> (type); var type_name = type.Name; var native_name = base_type.Name ?? type_name; var base_name = base_type.BaseType.Name; // internal static CIFilter FromName (string filterName, IntPtr handle) filters.Add(type_name); // type declaration print("public{0} partial class {1} : {2} {{", is_abstract ? " abstract" : String.Empty, type_name, base_name); print(""); indent++; // default constructor - if type is not abstract string v; if (!is_abstract) { v = GetVisibility(filter.DefaultCtorVisibility); if (v.Length > 0) { print_generated_code(); print("{0}{1} () : base (\"{2}\")", v, type.Name, native_name); PrintEmptyBody(); } } // IntPtr constructor - always present var intptrctor_visibility = filter.IntPtrCtorVisibility; if (intptrctor_visibility == MethodAttributes.PrivateScope) { // since it was not generated code we never fixed the .ctor(IntPtr) visibility for unified if (Generator.XamcoreVersion >= 3) { intptrctor_visibility = MethodAttributes.FamORAssem; } else { intptrctor_visibility = MethodAttributes.Public; } } print_generated_code(); print("{0}{1} (IntPtr handle) : base (handle)", GetVisibility(intptrctor_visibility), type_name); PrintEmptyBody(); // NSObjectFlag constructor - always present (needed to implement NSCoder for subclasses) print_generated_code(); print("[EditorBrowsable (EditorBrowsableState.Advanced)]"); print("protected {0} (NSObjectFlag t) : base (t)", type_name); PrintEmptyBody(); // NSCoder constructor - all filters conforms to NSCoding print_generated_code(); print("[EditorBrowsable (EditorBrowsableState.Advanced)]"); print("[Export (\"initWithCoder:\")]"); print("public {0} (NSCoder coder) : base (NSObjectFlag.Empty)", type_name); print("{"); indent++; print("IntPtr h;"); print("if (IsDirectBinding) {"); indent++; print("h = global::{0}.Messaging.IntPtr_objc_msgSend_IntPtr (this.Handle, Selector.GetHandle (\"initWithCoder:\"), coder.Handle);", ns.CoreObjCRuntime); indent--; print("} else {"); indent++; print("h = global::{0}.Messaging.IntPtr_objc_msgSendSuper_IntPtr (this.SuperHandle, Selector.GetHandle (\"initWithCoder:\"), coder.Handle);", ns.CoreObjCRuntime); indent--; print("}"); print("InitializeHandle (h, \"initWithCoder:\");"); indent--; print("}"); print(""); // string constructor // default is protected (for abstract) but backward compatibility (XAMCORE_2_0) requires some hacks v = GetVisibility(filter.StringCtorVisibility); if (is_abstract && (v.Length == 0)) { v = "protected "; } if (v.Length > 0) { print_generated_code(); print("{0} {1} (string name) : base (CreateFilter (name))", v, type_name); PrintEmptyBody(); } // properties foreach (var p in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (p.IsUnavailable()) { continue; } print(""); print_generated_code(); var ptype = p.PropertyType.Name; // keep C# names as they are reserved keywords (e.g. Boolean also exists in OpenGL for Mac) switch (ptype) { case "Boolean": ptype = "bool"; break; case "Int32": ptype = "int"; break; case "Single": ptype = "float"; break; case "String": ptype = "string"; break; } print("public {0} {1} {{", ptype, p.Name); indent++; var name = AttributeManager.GetCustomAttribute <CoreImageFilterPropertyAttribute> (p)?.Name; if (p.GetGetMethod() != null) { GenerateFilterGetter(ptype, name); } if (p.GetSetMethod() != null) { GenerateFilterSetter(ptype, name); } indent--; print("}"); } indent--; print("}"); // namespace closing (it's optional to use namespaces even if it's a bad practice, ref #35283) if (indent > 0) { indent--; print("}"); } }
// caller already: // - setup the header and namespace // - call/emit PrintPlatformAttributes on the type void GenerateEnum(Type type) { if (AttributeManager.HasAttribute <FlagsAttribute> (type)) { print("[Flags]"); } var native = AttributeManager.GetCustomAttribute <NativeAttribute> (type); if (native != null) { if (String.IsNullOrEmpty(native.NativeName)) { print("[Native]"); } else { print("[Native (\"{0}\")]", native.NativeName); } } CopyObsolete(type); var unique_constants = new HashSet <string> (); var fields = new Dictionary <FieldInfo, FieldAttribute> (); Tuple <FieldInfo, FieldAttribute> null_field = null; Tuple <FieldInfo, FieldAttribute> default_symbol = null; var underlying_type = GetCSharpTypeName(TypeManager.GetUnderlyingEnumType(type)); print("public enum {0} : {1} {{", type.Name, underlying_type); indent++; foreach (var f in type.GetFields()) { // skip value__ field if (f.IsSpecialName) { continue; } PrintPlatformAttributes(f); CopyObsolete(f); print("{0} = {1},", f.Name, f.GetRawConstantValue()); var fa = AttributeManager.GetCustomAttribute <FieldAttribute> (f); if (fa == null) { continue; } if (f.IsUnavailable()) { continue; } if (fa.SymbolName == null) { null_field = new Tuple <FieldInfo, FieldAttribute> (f, fa); } else if (unique_constants.Contains(fa.SymbolName)) { throw new BindingException(1046, true, $"The [Field] constant {fa.SymbolName} cannot only be used once inside enum {type.Name}."); } else { fields.Add(f, fa); unique_constants.Add(fa.SymbolName); } if (AttributeManager.GetCustomAttribute <DefaultEnumValueAttribute> (f) != null) { if (default_symbol != null) { throw new BindingException(1045, true, $"Only a single [DefaultEnumValue] attribute can be used inside enum {type.Name}."); } default_symbol = new Tuple <FieldInfo, FieldAttribute> (f, fa); } } indent--; print("}"); unique_constants.Clear(); var library_name = type.Namespace; var error = AttributeManager.GetCustomAttribute <ErrorDomainAttribute> (type); if ((fields.Count > 0) || (error != null)) { print(""); // the *Extensions has the same version requirement as the enum itself PrintPlatformAttributes(type); print("[CompilerGenerated]"); print("static public partial class {0}Extensions {{", type.Name); indent++; var field = fields.FirstOrDefault(); var fieldAttr = field.Value; ComputeLibraryName(fieldAttr, type, field.Key?.Name, out library_name, out string library_path); } if (error != null) { // this attribute is important for our tests print("[Field (\"{0}\", \"{1}\")]", error.ErrorDomain, library_name); print("static NSString _domain;"); print(""); print("public static NSString GetDomain (this {0} self)", type.Name); print("{"); indent++; print("if (_domain == null)"); indent++; print("_domain = Dlfcn.GetStringConstant (Libraries.{0}.Handle, \"{1}\");", library_name, error.ErrorDomain); indent--; print("return _domain;"); indent--; print("}"); } if (fields.Count > 0) { print("static IntPtr[] values = new IntPtr [{0}];", fields.Count); print(""); int n = 0; foreach (var kvp in fields) { var f = kvp.Key; var fa = kvp.Value; // the attributes (availability and field) are important for our tests PrintPlatformAttributes(f); libraries.TryGetValue(library_name, out var libPath); var libname = fa.LibraryName?.Replace("+", string.Empty); // We need to check for special cases inside FieldAttributes // fa.LibraryName could contain a different framework i.e UITrackingRunLoopMode (UIKit) inside NSRunLoopMode enum (Foundation). // libPath could have a custom path i.e. CoreImage which in macOS is inside Quartz // library_name contains the Framework constant name the Field is inside of, used as fallback. bool useFieldAttrLibName = libname != null && !string.Equals(libname, library_name, StringComparison.OrdinalIgnoreCase); print("[Field (\"{0}\", \"{1}\")]", fa.SymbolName, useFieldAttrLibName ? libname : libPath ?? library_name); print("internal unsafe static IntPtr {0} {{", fa.SymbolName); indent++; print("get {"); indent++; print("fixed (IntPtr *storage = &values [{0}])", n++); indent++; print("return Dlfcn.CachePointer (Libraries.{0}.Handle, \"{1}\", storage);", useFieldAttrLibName ? libname : library_name, fa.SymbolName); indent--; indent--; print("}"); indent--; print("}"); print(""); } print("public static NSString GetConstant (this {0} self)", type.Name); print("{"); indent++; print("IntPtr ptr = IntPtr.Zero;"); print("switch (({0}) self) {{", underlying_type); var default_symbol_name = default_symbol?.Item2.SymbolName; // more than one enum member can share the same numeric value - ref: #46285 foreach (var kvp in fields) { print("case {0}: // {1}.{2}", Convert.ToInt64(kvp.Key.GetRawConstantValue()), type.Name, kvp.Key.Name); var sn = kvp.Value.SymbolName; if (sn == default_symbol_name) { print("default:"); } indent++; print("ptr = {0};", sn); print("break;"); indent--; } print("}"); print("return (NSString) Runtime.GetNSObject (ptr);"); indent--; print("}"); print(""); print("public static {0} GetValue (NSString constant)", type.Name); print("{"); indent++; print("if (constant == null)"); indent++; // if we do not have a enum value that maps to a null field then we throw if (null_field == null) { print("throw new ArgumentNullException (nameof (constant));"); } else { print("return {0}.{1};", type.Name, null_field.Item1.Name); } indent--; foreach (var kvp in fields) { print("if (constant.IsEqualTo ({0}))", kvp.Value.SymbolName); indent++; print("return {0}.{1};", type.Name, kvp.Key.Name); indent--; } // if there's no default then we throw on unknown constants if (default_symbol == null) { print("throw new NotSupportedException (constant + \" has no associated enum value in \" + nameof ({0}) + \" on this platform.\");", type.Name); } else { print("return {0}.{1};", type.Name, default_symbol.Item1.Name); } indent--; print("}"); } if ((fields.Count > 0) || (error != null)) { indent--; print("}"); } // namespace closing (it's optional to use namespaces even if it's a bad practice, ref #35283) if (indent > 0) { indent--; print("}"); } }
public void GenerateFilter(Type type) { var is_abstract = AttributeManager.HasAttribute <AbstractAttribute> (type); var filter = AttributeManager.GetCustomAttribute <CoreImageFilterAttribute> (type); var base_type = AttributeManager.GetCustomAttribute <BaseTypeAttribute> (type); var type_name = type.Name; var native_name = base_type.Name ?? type_name; var base_name = base_type.BaseType.Name; // internal static CIFilter FromName (string filterName, IntPtr handle) filters.Add(type_name); // filters are now exposed as protocols so we need to conform to them var interfaces = String.Empty; foreach (var i in type.GetInterfaces()) { interfaces += $", I{i.Name}"; } // type declaration print("public{0} partial class {1} : {2}{3} {{", is_abstract ? " abstract" : String.Empty, type_name, base_name, interfaces); print(""); indent++; // default constructor - if type is not abstract string v; if (!is_abstract) { v = GetVisibility(filter.DefaultCtorVisibility); if (v.Length > 0) { print_generated_code(); print("{0}{1} () : base (\"{2}\")", v, type.Name, native_name); PrintEmptyBody(); } } // IntPtr constructor - always present var intptrctor_visibility = filter.IntPtrCtorVisibility; if (intptrctor_visibility == MethodAttributes.PrivateScope) { // since it was not generated code we never fixed the .ctor(IntPtr) visibility for unified if (XamcoreVersion >= 3) { intptrctor_visibility = MethodAttributes.FamORAssem; } else { intptrctor_visibility = MethodAttributes.Public; } } print_generated_code(); print("{0}{1} (IntPtr handle) : base (handle)", GetVisibility(intptrctor_visibility), type_name); PrintEmptyBody(); // NSObjectFlag constructor - always present (needed to implement NSCoder for subclasses) print_generated_code(); print("[EditorBrowsable (EditorBrowsableState.Advanced)]"); print("protected {0} (NSObjectFlag t) : base (t)", type_name); PrintEmptyBody(); // NSCoder constructor - all filters conforms to NSCoding print_generated_code(); print("[EditorBrowsable (EditorBrowsableState.Advanced)]"); print("[Export (\"initWithCoder:\")]"); print("public {0} (NSCoder coder) : base (NSObjectFlag.Empty)", type_name); print("{"); indent++; print("IntPtr h;"); print("if (IsDirectBinding) {"); indent++; print("h = global::{0}.Messaging.IntPtr_objc_msgSend_IntPtr (this.Handle, Selector.GetHandle (\"initWithCoder:\"), coder.Handle);", ns.CoreObjCRuntime); indent--; print("} else {"); indent++; print("h = global::{0}.Messaging.IntPtr_objc_msgSendSuper_IntPtr (this.SuperHandle, Selector.GetHandle (\"initWithCoder:\"), coder.Handle);", ns.CoreObjCRuntime); indent--; print("}"); print("InitializeHandle (h, \"initWithCoder:\");"); indent--; print("}"); print(""); // string constructor // default is protected (for abstract) but backward compatibility (XAMCORE_2_0) requires some hacks v = GetVisibility(filter.StringCtorVisibility); if (is_abstract && (v.Length == 0)) { v = "protected "; } if (v.Length > 0) { print_generated_code(); print("{0} {1} (string name) : base (CreateFilter (name))", v, type_name); PrintEmptyBody(); } // properties GenerateProperties(type); // protocols GenerateProtocolProperties(type, new HashSet <string> ()); indent--; print("}"); // namespace closing (it's optional to use namespaces even if it's a bad practice, ref #35283) if (indent > 0) { indent--; print("}"); } }
void GenerateProperties(Type type) { foreach (var p in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (p.IsUnavailable(this)) { continue; } if (AttributeManager.HasAttribute <StaticAttribute> (p)) { continue; } print(""); PrintPropertyAttributes(p); print_generated_code(); var ptype = p.PropertyType.Name; // keep C# names as they are reserved keywords (e.g. Boolean also exists in OpenGL for Mac) switch (ptype) { case "Boolean": ptype = "bool"; break; case "Int32": ptype = "int"; break; case "Single": ptype = "float"; break; case "String": ptype = "string"; break; // adding `using ImageIO;` would lead to `error CS0104: 'CGImageProperties' is an ambiguous reference between 'CoreGraphics.CGImageProperties' and 'ImageIO.CGImageProperties'` case "CGImageMetadata": ptype = "ImageIO.CGImageMetadata"; break; } print("public {0} {1} {{", ptype, p.Name); indent++; // an export will be present (only) if it's defined in a protocol var export = AttributeManager.GetCustomAttribute <ExportAttribute> (p); var name = AttributeManager.GetCustomAttribute <CoreImageFilterPropertyAttribute> (p)?.Name; // we can skip the name when it's identical to a protocol selector if (name == null) { if (export == null) { throw new BindingException(1072, true, $"Missing [CoreImageFilterProperty] attribute on {0} property {1}", type.Name, p.Name); } var sel = export.Selector; if (sel.StartsWith("input", StringComparison.Ordinal)) { name = sel; } else { name = "input" + Capitalize(sel); } } if (p.GetGetMethod() != null) { PrintFilterExport(p, export, setter: false); GenerateFilterGetter(ptype, name); } if (p.GetSetMethod() != null) { PrintFilterExport(p, export, setter: true); GenerateFilterSetter(ptype, name); } indent--; print("}"); } }
void GenerateProperties(Type type, Type originalType = null, bool fromProtocol = false) { foreach (var p in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (p.IsUnavailable(this)) { continue; } if (AttributeManager.HasAttribute <StaticAttribute> (p)) { continue; } print(""); // an export will be present (only) if it's defined in a protocol var export = AttributeManager.GetCustomAttribute <ExportAttribute> (p); // this is a bit special since CoreImage filter protocols are much newer than the our generated, key-based bindings // so we do not want to advertise the protocol versions since most properties would be incorrectly advertised PrintPropertyAttributes(p, originalType, skipTypeInjection: export != null); print_generated_code(); var ptype = p.PropertyType.Name; var nullable = false; // keep C# names as they are reserved keywords (e.g. Boolean also exists in OpenGL for Mac) switch (ptype) { case "Boolean": ptype = "bool"; break; case "Int32": ptype = "int"; break; case "Single": ptype = "float"; break; case "String": ptype = "string"; break; // adding `using ImageIO;` would lead to `error CS0104: 'CGImageProperties' is an ambiguous reference between 'CoreGraphics.CGImageProperties' and 'ImageIO.CGImageProperties'` case "CGImageMetadata": ptype = "ImageIO.CGImageMetadata"; break; case "CIVector": case "CIColor": case "CIImage": // protocol-based bindings have annotations - but the older, key-based, versions did not if (!fromProtocol) { nullable = true; } break; } if (AttributeManager.HasAttribute <NullAllowedAttribute> (p)) { nullable = true; } print("public {0}{1} {2} {{", ptype, nullable ? "?" : "", p.Name); indent++; var name = AttributeManager.GetCustomAttribute <CoreImageFilterPropertyAttribute> (p)?.Name; // we can skip the name when it's identical to a protocol selector if (name == null) { if (export == null) { throw new BindingException(1074, true, type.Name, p.Name); } var sel = export.Selector; if (sel.StartsWith("input", StringComparison.Ordinal)) { name = sel; } else { name = "input" + Capitalize(sel); } } if (p.GetGetMethod() != null) { PrintFilterExport(p, export, setter: false); GenerateFilterGetter(ptype, name); } if (p.GetSetMethod() != null) { PrintFilterExport(p, export, setter: true); GenerateFilterSetter(ptype, name); } indent--; print("}"); } }
static void GetValueTypeSize(Type original_type, Type type, List <Type> field_types, bool is_64_bits, ref int size, ref int max_element_size) { // FIXME: // SIMD types are not handled correctly here (they need 16-bit alignment). // However we don't annotate those types in any way currently, so first we'd need to // add the proper attributes so that the generator can distinguish those types from other types. var type_size = 0; switch (type.FullName) { case "System.Char": case "System.Boolean": case "System.SByte": case "System.Byte": type_size = 1; break; case "System.Int16": case "System.UInt16": type_size = 2; break; case "System.Single": case "System.Int32": case "System.UInt32": type_size = 4; break; case "System.Double": case "System.Int64": case "System.UInt64": type_size = 8; break; case "System.IntPtr": case "System.nfloat": case "System.nuint": case "System.nint": type_size = is_64_bits ? 8 : 4; break; } if (type_size != 0) { field_types.Add(type); size = AlignAndAdd(original_type, size, type_size, ref max_element_size); return; } // composite struct foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { #if BGENERATOR var marshalAs = AttributeManager.GetCustomAttribute <MarshalAsAttribute> (field); #else var marshalAs = (MarshalAsAttribute)Attribute.GetCustomAttribute(field, typeof(MarshalAsAttribute)); #endif if (marshalAs == null) { GetValueTypeSize(original_type, field.FieldType, field_types, is_64_bits, ref size, ref max_element_size); continue; } var multiplier = 1; switch (marshalAs.Value) { case UnmanagedType.ByValArray: var types = new List <Type> (); GetValueTypeSize(original_type, field.FieldType.GetElementType(), types, is_64_bits, ref type_size, ref max_element_size); multiplier = marshalAs.SizeConst; break; case UnmanagedType.U1: case UnmanagedType.I1: type_size = 1; break; case UnmanagedType.U2: case UnmanagedType.I2: type_size = 2; break; case UnmanagedType.U4: case UnmanagedType.I4: case UnmanagedType.R4: type_size = 4; break; case UnmanagedType.U8: case UnmanagedType.I8: case UnmanagedType.R8: type_size = 8; break; default: throw new Exception($"Unhandled MarshalAs attribute: {marshalAs.Value} on field {field.DeclaringType.FullName}.{field.Name}"); } field_types.Add(field.FieldType); size = AlignAndAdd(original_type, size, type_size, ref max_element_size); size += (multiplier - 1) * size; } }