void VerifyIsNotKeyword (ref List<Exception> exceptions, ObjCProperty property) { if (IsObjectiveCKeyword (property.Selector)) AddException (ref exceptions, CreateException (4164, property, "Cannot export the property '{0}' because its selector '{1}' is an Objective-C keyword. Please use a different name.", property.Name, property.Selector)); }
public void Add (ObjCProperty property, ref List<Exception> exceptions) { if (Properties == null) Properties = new List<ObjCProperty> (); // Do properties and methods live in the same objc namespace? // AddToMap (property, errorIfExists); Properties.Add (property); Registrar.VerifyInSdk (ref exceptions, property); VerifyIsNotKeyword (ref exceptions, property); }
void VerifyTypeInSDK (ref List<Exception> exceptions, TType type, ObjCMethod parameterIn = null, ObjCMethod returnTypeOf = null, ObjCProperty propertyTypeOf = null, TType baseTypeOf = null) { var attribs = GetAvailabilityAttributes (type); if (attribs == null || attribs.Count == 0) return; Version sdk = GetSDKVersion (); foreach (var attrib in attribs) { // The attributes are already filtered to the current platform. switch (attrib.AvailabilityKind) { case AvailabilityKind.Introduced: if (attrib.Version <= sdk) break; string msg = "The type '{0}' (used as {1} {2}) is not available in {3} {4} (it was introduced in {3} {5}){6} Please build with a newer {3} SDK (usually done by using the most recent version of Xcode)."; string zero = GetTypeFullName (type); string one = string.Empty; string two = string.Empty; string three = PlatformName; string four = sdk.ToString (); string five = attrib.Version.ToString (); string six = string.IsNullOrEmpty (attrib.Message) ? "." : ": '" + attrib.Message + "'."; if (baseTypeOf != null) { one = "a base type of"; two = GetTypeFullName (baseTypeOf); } else if (parameterIn != null) { one = "a parameter in"; two = parameterIn.DescriptiveMethodName; } else if (returnTypeOf != null) { one = "a return type in"; two = returnTypeOf.DescriptiveMethodName; } else if (propertyTypeOf != null) { one = "the property type of"; two = propertyTypeOf.FullName; } else { msg = "The type '{0}' is not available in {3} {4} (it was introduced in {3} {5}){6} Please build with a newer {3} SDK (usually done by using the most recent version of Xcode)."; } msg = string.Format (msg, zero, one, two, three, four, five, six); Exception ex; if (baseTypeOf != null) { ex = CreateException (4162, baseTypeOf, msg); } else if (parameterIn != null) { ex = CreateException (4162, parameterIn, msg); } else if (returnTypeOf != null) { ex = CreateException (4162, returnTypeOf, msg); } else if (propertyTypeOf != null) { ex = CreateException (4162, propertyTypeOf, msg); } else { ex = CreateException (4162, msg); } AddException (ref exceptions, ex); break; } } }
// This method is not thread-safe wrt 'types', and must be called with // a lock held on 'types'. ObjCType RegisterTypeUnsafe (TType type, ref List<Exception> exceptions) { ObjCType objcType; bool isGenericType = false; bool isProtocol = false; bool isInformalProtocol = false; if (IsGenericType (type)) { type = GetGenericTypeDefinition (type); isGenericType = true; } if (types.TryGetValue (type, out objcType)) { OnReloadType (objcType); return objcType; } var categoryAttribute = GetCategoryAttribute (type); if (categoryAttribute != null) return RegisterCategory (type, categoryAttribute, ref exceptions); if (!IsNSObject (type)) { //Trace ("{0} is not derived from NSObject", GetTypeFullName (type)); if (!IsInterface (type)) return null; if (!HasProtocolAttribute (type)) return null; if (isGenericType) { exceptions.Add (ErrorHelper.CreateError (4148, "The registrar found a generic protocol: '{0}'. Exporting generic protocols is not supported.", GetTypeFullName (type))); return null; } // This is a protocol var pAttr = GetProtocolAttribute (type); isInformalProtocol = pAttr.IsInformal; isProtocol = true; } // make sure the base type is already registered var baseType = GetBaseType (type); ObjCType baseObjCType = null; if (baseType != null) { Trace ("Registering base type {0} of {1}", GetTypeName (baseType), GetTypeName (type)); baseObjCType = RegisterTypeUnsafe (baseType, ref exceptions); } var register_attribute = GetRegisterAttribute (type); if (register_attribute != null && register_attribute.SkipRegistration) return baseObjCType; objcType = new ObjCType () { Registrar = this, RegisterAttribute = GetRegisterAttribute (type), Type = type, IsModel = HasModelAttribute (type), IsProtocol = isProtocol, IsGeneric = isGenericType, }; objcType.VerifyRegisterAttribute (); objcType.Protocols = GetProtocols (objcType, ref exceptions); objcType.BaseType = isProtocol ? null : (baseObjCType ?? objcType); objcType.IsWrapper = (isProtocol && !isInformalProtocol) ? (GetProtocolAttributeWrapperType (objcType.Type) != null) : (objcType.RegisterAttribute != null && objcType.RegisterAttribute.IsWrapper); if (!objcType.IsWrapper && objcType.BaseType != null) VerifyTypeInSDK (ref exceptions, objcType.BaseType.Type, baseTypeOf: objcType.Type); // make sure all the protocols this type implements are registered if (objcType.Protocols != null) { foreach (var p in objcType.Protocols) { Trace ("Registering implemented protocol {0} of {1}", p == null ? "null" : p.ProtocolName, GetTypeName (type)); OnRegisterProtocol (p); } } TType previous_type; if (objcType.IsProtocol) { lock (protocol_map) { if (protocol_map.TryGetValue (objcType.ExportedName, out previous_type)) throw ErrorHelper.CreateError (4126, "Cannot register two managed protocols ('{0}' and '{1}') with the same native name ('{2}').", GetAssemblyQualifiedName (type), GetAssemblyQualifiedName (previous_type), objcType.ExportedName); protocol_map.Add (objcType.ExportedName, type); } } else { lock (type_map) { if (type_map.TryGetValue (objcType.ExportedName, out previous_type)) throw ErrorHelper.CreateError (4118, "Cannot register two managed types ('{0}' and '{1}') with the same native name ('{2}').", GetAssemblyQualifiedName (type), GetAssemblyQualifiedName (previous_type), objcType.ExportedName); type_map.Add (objcType.ExportedName, type); } } types.Add (type, objcType); Trace (" [TYPE] Registering {0} => {1} IsWrapper: {2} BaseType: {3} IsModel: {4} IsProtocol: {5}", type.ToString ().Replace ('+', '/'), objcType.ExportedName, objcType.IsWrapper, objcType.BaseType == null ? "null" : objcType.BaseType.Name, objcType.IsModel, objcType.IsProtocol); // Special methods bool is_first_nonWrapper = false; var methods = new List<TMethod> (CollectMethods (type)); if (!isProtocol) { is_first_nonWrapper = !(objcType.IsWrapper || objcType.IsModel) && (objcType.BaseType.IsWrapper || objcType.BaseType.IsModel); if (is_first_nonWrapper) { bool isCalayerSubclass = IsSubClassOf (objcType.Type, CoreAnimation, "CALayer"); if (!isCalayerSubclass) { objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "release", Trampoline = Trampoline.Release, Signature = "v@:", IsStatic = false, }, ref exceptions); objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "retain", Trampoline = Trampoline.Retain, Signature = "@@:", IsStatic = false, }, ref exceptions); } objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "xamarinGetGCHandle", Trampoline = Trampoline.GetGCHandle, Signature = "i@:", IsStatic = false, }, ref exceptions); objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "xamarinSetGCHandle:", Trampoline = Trampoline.SetGCHandle, Signature = "v@:i", IsStatic = false, }, ref exceptions); } // Find conform_to_protocol if (conforms_to_protocol == null && Is (type, Foundation, "NSObject")) { foreach (var method in methods) { switch (GetMethodName (method)) { case "InvokeConformsToProtocol": invoke_conforms_to_protocol = method; break; case "ConformsToProtocol": conforms_to_protocol = method; break; } if (invoke_conforms_to_protocol != null && conforms_to_protocol != null) break; } } #if MMP || MTOUCH // Special fields if (is_first_nonWrapper) { // static registrar objcType.Add (new ObjCField () { DeclaringType = objcType, FieldType = "XamarinObject",// "^v", // void* Name = "__monoObjectGCHandle", }, ref exceptions); } #endif } var properties = new List<TProperty> (CollectProperties (type)); var hasProtocolMemberAttributes = false; if (isProtocol && !isInformalProtocol) { var attribs = GetProtocolMemberAttributes (type); foreach (var attrib in attribs) { hasProtocolMemberAttributes = true; if (attrib.IsProperty) { if (attrib.IsStatic) { // There is no such things as a static property in ObjC, so export this as just the getter[+setter]. var objcGetter = new ObjCMethod (this, objcType, null) { Name = attrib.Name, Selector = attrib.GetterSelector, Parameters = new TType[] { }, ReturnType = attrib.PropertyType, IsStatic = attrib.IsStatic, IsOptional = !attrib.IsRequired, IsConstructor = false, }; objcType.Add (objcGetter, ref exceptions); if (!string.IsNullOrEmpty (attrib.SetterSelector)) { var objcSetter = new ObjCMethod (this, objcType, null) { Name = attrib.Name, Selector = attrib.SetterSelector, Parameters = new TType[] { attrib.PropertyType }, ReturnType = GetSystemVoidType (), IsStatic = attrib.IsStatic, IsOptional = !attrib.IsRequired, IsConstructor = false, }; objcType.Add (objcSetter, ref exceptions); } } else { var objcProperty = new ObjCProperty () { Registrar = this, DeclaringType = objcType, Property = null, Name = attrib.Name, Selector = attrib.Selector, ArgumentSemantic = attrib.ArgumentSemantic, IsReadOnly = string.IsNullOrEmpty (attrib.SetterSelector), IsStatic = attrib.IsStatic, IsOptional = !attrib.IsRequired, GetterSelector = attrib.GetterSelector, SetterSelector = attrib.SetterSelector, PropertyType = attrib.PropertyType, }; objcType.Add (objcProperty, ref exceptions); } } else { var objcMethod = new ObjCMethod (this, objcType, null) { Name = attrib.Name, Selector = attrib.Selector, ArgumentSemantic = attrib.ArgumentSemantic, IsVariadic = attrib.IsVariadic, ReturnType = attrib.ReturnType ?? GetSystemVoidType (), IsStatic = attrib.IsStatic, IsOptional = !attrib.IsRequired, IsConstructor = false, }; if (attrib.ParameterType != null) { var parameters = new TType [attrib.ParameterType.Length]; for (int i = 0; i < parameters.Length; i++) { if (attrib.ParameterByRef [i]) { parameters [i] = MakeByRef (attrib.ParameterType [i]); } else { parameters [i] = attrib.ParameterType [i]; } } objcMethod.Parameters = parameters; } else { objcMethod.Parameters = new TType[] { }; } objcType.Add (objcMethod, ref exceptions); } } } foreach (TProperty property in properties) { if (hasProtocolMemberAttributes) continue; if (!isProtocol) { var ca = GetConnectAttribute (property); if (ca != null) { if (!IsINativeObject (GetPropertyType (property))) { AddException (ref exceptions, CreateException (4139, property, "The registrar cannot marshal the property type '{0}' of the property '{1}.{2}'. Properties with the [Connect] attribute must have a property type of NSObject (or a subclass of NSObject).", GetTypeFullName (GetPropertyType (property)), GetTypeFullName (type), GetPropertyName (property))); continue; } objcType.Add (new ObjCField () { DeclaringType = objcType, Name = ca.Name ?? GetPropertyName (property), #if !MTOUCH && !MMP Size = Is64Bits ? 8 : 4, Alignment = (byte) (Is64Bits ? 3 : 2), #endif FieldType = "@", IsProperty = true, }, ref exceptions); } } var ea = GetExportAttribute (property); if (ea == null) continue; if (IsStatic (property) && (objcType.IsWrapper || objcType.IsModel)) { // This is useless to export, since the user can't actually do anything with it, // it'll just call back into the base implementation. continue; } if (IsStatic (property) && isGenericType) { AddException (ref exceptions, CreateException (4131, property, "The registrar cannot export static properties in generic classes ('{0}.{1}').", GetTypeFullName (type), GetPropertyName (property))); continue; } TType property_type = null; if (isGenericType && !VerifyIsConstrainedToNSObject (GetPropertyType (property), out property_type)) { AddException (ref exceptions, CreateException (4132, property, "The registrar found an invalid generic return type '{0}' in the property '{1}.{2}'. The return type must have an 'NSObject' constraint.", GetTypeFullName (GetPropertyType (property)), GetTypeFullName (type), GetPropertyName (property))); continue; } if (property_type == null) property_type = GetPropertyType (property); Trace (" [PROPERTY] {0} => {1}", property, ea.Selector); var objcProperty = new ObjCProperty () { Registrar = this, DeclaringType = objcType, Property = property, Name = property.Name, Selector = ea.Selector ?? GetPropertyName (property), ArgumentSemantic = ea.ArgumentSemantic, PropertyType = property_type, }; TMethod getter = GetGetMethod (property); TMethod setter = GetSetMethod (property); if (getter != null && VerifyNonGenericMethod (ref exceptions, type, getter)) { var method = new ObjCMethod (this, objcType, getter) { Selector = ea.Selector ?? GetPropertyName (property), ArgumentSemantic = ea.ArgumentSemantic, ReturnType = property_type, }; List<Exception> excs = null; if (!method.ValidateSignature (ref excs)) { exceptions.Add (CreateException (4138, excs [0], property, "The registrar cannot marshal the property type '{0}' of the property '{1}.{2}'.", GetTypeFullName (property.PropertyType), property.DeclaringType.FullName, property.Name)); continue; } if (!objcType.Add (method, ref exceptions)) continue; Trace (" [GET] {0}", objcType.Methods [objcType.Methods.Count - 1].Name); } if (setter != null && VerifyNonGenericMethod (ref exceptions, type, setter)) { string setterName = ea.Selector ?? GetPropertyName (property); var method = new ObjCMethod (this, objcType, setter) { Selector = CreateSetterSelector (setterName), ArgumentSemantic = ea.ArgumentSemantic, Parameters = new TType[] { property_type }, }; List<Exception> excs = null; if (!method.ValidateSignature (ref excs)) { exceptions.Add (CreateException (4138, excs [0], property, "The registrar cannot marshal the property type '{0}' of the property '{1}.{2}'.", GetTypeFullName (property.PropertyType), property.DeclaringType.FullName, property.Name)); continue; } if (!objcType.Add (method, ref exceptions)) continue; Trace (" [SET] {0}", objcType.Methods [objcType.Methods.Count - 1].Name); } objcType.Add (objcProperty, ref exceptions); } var custom_conforms_to_protocol = !is_first_nonWrapper; // we only have to generate the conformsToProtocol method for the first non-wrapper type. #if MONOMAC ObjCMethod custom_copy_with_zone = null; var isNSCellSubclass = IsSubClassOf (type, AppKit, "NSCell"); #endif Dictionary<TMethod, List<TMethod>> method_map = null; if (!isProtocol) method_map = PrepareMethodMapping (type); foreach (TMethod method in methods) { if (hasProtocolMemberAttributes) continue; var ea = GetExportAttribute (method); if (ea == null) { List<TMethod> impls; if (method_map != null && method_map.TryGetValue (method, out impls)) { if (impls.Count != 1) { AddException (ref exceptions, Shared.GetMT4127 (method, impls)); continue; } ea = GetExportAttribute (impls [0]); } } if (ea == null) continue; if (IsStatic (method) && (objcType.IsWrapper || objcType.IsModel) && !(objcType.IsProtocol && !objcType.IsFakeProtocol)) { // This is useless to export, since the user can't actually do anything with it, // it'll just call back into the base implementation. continue; } if (objcType.IsModel && IsVirtual (method)) continue; Trace (" [METHOD] {0} => {1}", method, ea.Selector); if (!custom_conforms_to_protocol && method.DeclaringType == type && GetBaseMethod (method) == conforms_to_protocol) custom_conforms_to_protocol = true; if (!VerifyNonGenericMethod (ref exceptions, type, method)) continue; var objcMethod = new ObjCMethod (this, objcType, method); if (!objcMethod.SetExportAttribute (ea, ref exceptions)) continue; #if MONOMAC if (objcMethod.Selector == "copyWithZone:") custom_copy_with_zone = objcMethod; #endif if (IsStatic (method) && isGenericType) { AddException (ref exceptions, CreateException (4130, method, "The registrar cannot export static methods in generic classes ('{0}').", GetDescriptiveMethodName (type, method))); continue; } else if (isGenericType && !VerifyIsConstrainedToNSObject (ref exceptions, type, objcMethod)) { continue; } try { objcType.Add (objcMethod, ref exceptions); } catch (Exception ex) { AddException (ref exceptions, ex); } } if (!isProtocol && !custom_conforms_to_protocol) { objcType.Add (new ObjCMethod (this, objcType, invoke_conforms_to_protocol) { Selector = "conformsToProtocol:", Trampoline = Trampoline.Normal, Signature = "B@:^v", IsStatic = false, }, ref exceptions); } #if MONOMAC if (isNSCellSubclass) { if (custom_copy_with_zone != null) { custom_copy_with_zone.Trampoline = Trampoline.CopyWithZone2; } else { objcType.Add (new ObjCMethod (this, objcType, null) { Selector = "copyWithZone:", Trampoline = Trampoline.CopyWithZone1, Signature = "@@:^v", IsStatic = false, }, ref exceptions); } } #endif foreach (TMethod ctor in CollectConstructors (type)) { if (IsStatic (ctor)) continue; var parameters = GetParameters (ctor); if (parameters == null || parameters.Length == 0) { Trace (" [CTOR] {0} default => init", GetTypeName (type)); objcType.Add (new ObjCMethod (this, objcType, ctor) { Selector = "init", Trampoline = Trampoline.Constructor, }, ref exceptions); continue; } var ea = GetExportAttribute (ctor); if (ea == null) continue; Trace (" [CTOR] {2} {0} => {1}", GetMethodName (ctor), ea.Selector, GetTypeName (type)); if (!VerifyNonGenericMethod (ref exceptions, type, ctor)) continue; var method = new ObjCMethod (this, objcType, ctor) { Trampoline = Trampoline.Constructor, }; if (method.SetExportAttribute (ea, ref exceptions)) objcType.Add (method, ref exceptions); } if (objcType.IsProtocol) { OnRegisterProtocol (objcType); } else { OnRegisterType (objcType); } return objcType; }
void VerifyInSdk (ref List<Exception> exceptions, ObjCProperty property) { VerifyTypeInSDK (ref exceptions, property.PropertyType, propertyTypeOf: property); }