Exemple #1
0
			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));
			}
Exemple #2
0
			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);
			}
Exemple #3
0
		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;
				}
			}
		}
Exemple #4
0
		// 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;
		}
Exemple #5
0
		void VerifyInSdk (ref List<Exception> exceptions, ObjCProperty property)
		{
			VerifyTypeInSDK (ref exceptions, property.PropertyType, propertyTypeOf: property);
		}