// The 'provider' parameter is only used in error messages to explain where the broken attribute comes from // (in particular it's not used to get the custom attributes themselves, since those may not come from this provider instance) static BindingImplOptions?GetBindingImplAttribute(ICustomAttributeProvider provider, IEnumerable <ICustomAttribute> attributes) { if (attributes == null) { return(null); } foreach (var ca in attributes) { TypeReference tr = ca.AttributeType; if (!tr.Is(Namespaces.ObjCRuntime, "BindingImplAttribute")) { continue; } if (ca.HasFields) { throw ErrorHelper.CreateError(2105, Errors.MT2105_A, provider.AsString()); } if (ca.HasProperties) { throw ErrorHelper.CreateError(2105, Errors.MT2105_B, provider.AsString()); } switch (ca.ConstructorArguments.Count) { case 1: var arg = ca.ConstructorArguments [0]; if (!arg.Type.Is(Namespaces.ObjCRuntime, "BindingImplOptions")) { throw ErrorHelper.CreateError(2105, Errors.MT2105_C, provider.AsString(), arg.Type.FullName); } return((BindingImplOptions)(int)arg.Value); default: throw ErrorHelper.CreateError(2105, Errors.MT2105_D, provider.AsString(), ca.ConstructorArguments.Count); } } return(null); }
void ProcessAttributeProvider(ICustomAttributeProvider provider, MethodDefinition conditionA, MethodDefinition conditionB = null) { if (provider?.HasCustomAttributes != true) { return; } foreach (var ca in provider.CustomAttributes) { var tr = ca.Constructor.DeclaringType; if (!tr.IsPlatformType("ObjCRuntime", "BindAsAttribute")) { continue; } if (ca.ConstructorArguments.Count != 1) { ErrorHelper.Show(ErrorHelper.CreateWarning(LinkContext.Target.App, 4124, provider, Errors.MT4124_E, provider.AsString(), ca.ConstructorArguments.Count)); continue; } var managedType = ca.ConstructorArguments [0].Value as TypeReference; var managedEnumType = managedType?.GetElementType().Resolve(); if (managedEnumType == null) { ErrorHelper.Show(ErrorHelper.CreateWarning(LinkContext.Target.App, 4124, provider, Errors.MT4124_H, provider.AsString(), managedType?.FullName)); continue; } // We only care about enums, BindAs attributes can be used for other types too. if (!managedEnumType.IsEnum) { continue; } Tuple <MethodDefinition, MethodDefinition> pair; if (cache != null && cache.TryGetValue(managedEnumType, out pair)) { Preserve(pair, conditionA, conditionB); continue; } // Find the Extension type TypeDefinition extensionType = null; var extensionName = managedEnumType.Name + "Extensions"; foreach (var type in managedEnumType.Module.Types) { if (type.Namespace != managedEnumType.Namespace) { continue; } if (type.Name != extensionName) { continue; } extensionType = type; break; } if (extensionType == null) { Driver.Log(1, $"Could not find a smart extension type for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); continue; } // Find the GetConstant/GetValue methods MethodDefinition getConstant = null; MethodDefinition getValue = null; foreach (var method in extensionType.Methods) { if (!method.IsStatic) { continue; } if (!method.HasParameters || method.Parameters.Count != 1) { continue; } if (method.Name == "GetConstant") { if (!method.ReturnType.IsPlatformType("Foundation", "NSString")) { continue; } if (method.Parameters [0].ParameterType != managedEnumType) { continue; } getConstant = method; } else if (method.Name == "GetValue") { if (!method.Parameters [0].ParameterType.IsPlatformType("Foundation", "NSString")) { continue; } if (method.ReturnType != managedEnumType) { continue; } getValue = method; } } if (getConstant == null) { Driver.Log(1, $"Could not find the GetConstant method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); continue; } if (getValue == null) { Driver.Log(1, $"Could not find the GetValue method on the supposedly smart extension type {extensionType.FullName} for the enum {managedEnumType.FullName} (due to BindAs attribute on {provider.AsString ()}): most likely this is because the enum isn't a smart enum."); continue; } pair = new Tuple <MethodDefinition, MethodDefinition> (getConstant, getValue); if (cache == null) { cache = new Dictionary <TypeDefinition, Tuple <MethodDefinition, MethodDefinition> > (); } cache.Add(managedEnumType, pair); Preserve(pair, conditionA, conditionB); } }
// The 'provider' parameter is only used in error messages to explain where the broken attribute comes from // (in particular it's not used to get the custom attributes themselves, since those may not come from this provider instance) static BindingImplOptions?GetBindingImplAttribute(ICustomAttributeProvider provider, IEnumerable <ICustomAttribute> attributes) { if (attributes == null) { return(null); } foreach (var ca in attributes) { TypeReference tr = ca.AttributeType; if (!tr.Is(Namespaces.ObjCRuntime, "BindingImplAttribute")) { continue; } if (ca.HasFields) { throw ErrorHelper.CreateError(2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect fields.", provider.AsString()); } if (ca.HasProperties) { throw ErrorHelper.CreateError(2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect properties.", provider.AsString()); } switch (ca.ConstructorArguments.Count) { case 1: var arg = ca.ConstructorArguments [0]; if (!arg.Type.Is(Namespaces.ObjCRuntime, "BindingImplOptions")) { throw ErrorHelper.CreateError(2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect a constructor with a '{1}' parameter type (expected 'ObjCRuntime.BindingImplOptions).", provider.AsString(), arg.Type.FullName); } return((BindingImplOptions)(int)arg.Value); default: throw ErrorHelper.CreateError(2105, "The [BindingImpl] attribute on the member '{0}' is invalid: did not expect a constructor with a {1} parameters (expected 1 parameters).", provider.AsString(), ca.ConstructorArguments.Count); } } return(null); }