diff --git a/src/ObjCRuntime/DynamicRegistrar.cs b/src/ObjCRuntime/DynamicRegistrar.cs index 65ec1992fd..ad6361208f 100644 --- a/src/ObjCRuntime/DynamicRegistrar.cs +++ b/src/ObjCRuntime/DynamicRegistrar.cs @@ -378,6 +378,11 @@ namespace Registrar { return attr == null ? null : attr.WrapperType; } + protected override IList GetAdoptsAttributes (Type type) + { + return (AdoptsAttribute[]) type.GetCustomAttributes (typeof (AdoptsAttribute), false); + } + protected override string GetAssemblyName (Assembly assembly) { return assembly.GetName ().Name; diff --git a/src/ObjCRuntime/Registrar.cs b/src/ObjCRuntime/Registrar.cs index 23bbea897c..cbd0ef4351 100644 --- a/src/ObjCRuntime/Registrar.cs +++ b/src/ObjCRuntime/Registrar.cs @@ -135,6 +135,7 @@ namespace Registrar { public TType Type; public ObjCType BaseType; public ObjCType [] Protocols; + public string [] AdoptedProtocols; public bool IsModel; // if this type represents an ObjC protocol (!= has the protocol attribute, since that can be applied to all kinds of things). public bool IsProtocol; @@ -1028,6 +1029,7 @@ namespace Registrar { protected abstract TType GetProtocolAttributeWrapperType (TType type); // Return null if no attribute is found. Do not consider base types. protected abstract BindAsAttribute GetBindAsAttribute (TMethod method, int parameter_index); // If parameter_index = -1 then get the attribute for the return type. Return null if no attribute is found. Must consider base method. protected abstract BindAsAttribute GetBindAsAttribute (TProperty property); + protected abstract IList GetAdoptsAttributes (TType type); public abstract TType GetNullableType (TType type); // For T? returns T. For T returns null. protected abstract bool HasReleaseAttribute (TMethod method); // Returns true of the method's return type/value has a [Release] attribute. protected abstract bool IsINativeObject (TType type); @@ -1640,6 +1642,17 @@ namespace Registrar { return protocolList.ToArray (); } + string [] GetAdoptedProtocols (ObjCType type) + { + var attribs = GetAdoptsAttributes (type.Type); + if (attribs == null || attribs.Count == 0) + return null; + var rv = new string [attribs.Count]; + for (var i = 0; i < attribs.Count; i++) + rv [i] = attribs [i].ProtocolType; + return rv; + } + ObjCType RegisterCategory (TType type, CategoryAttribute attrib, ref List exceptions) { if (IsINativeObject (type)) { @@ -1823,6 +1836,7 @@ namespace Registrar { }; objcType.VerifyRegisterAttribute (ref exceptions); objcType.Protocols = GetProtocols (objcType, ref exceptions); + objcType.AdoptedProtocols = GetAdoptedProtocols (objcType); objcType.BaseType = isProtocol ? null : (baseObjCType ?? objcType); objcType.IsWrapper = (isProtocol && !isInformalProtocol) ? (GetProtocolAttributeWrapperType (objcType.Type) != null) : (objcType.RegisterAttribute != null && objcType.RegisterAttribute.IsWrapper); diff --git a/tools/common/StaticRegistrar.cs b/tools/common/StaticRegistrar.cs index 68327d245e..c8c8a381f1 100644 --- a/tools/common/StaticRegistrar.cs +++ b/tools/common/StaticRegistrar.cs @@ -1602,6 +1602,28 @@ namespace Registrar { return null; } + protected override IList GetAdoptsAttributes (TypeReference type) + { + var attributes = GetCustomAttributes (type.Resolve (), ObjCRuntime, "AdoptsAttribute"); + if (attributes == null || !attributes.Any ()) + return null; + + var rv = new List (); + foreach (var ca in attributes) { + var attrib = new AdoptsAttribute (); + switch (ca.ConstructorArguments.Count) { + case 1: + attrib.ProtocolType = (string) ca.ConstructorArguments [0].Value; + break; + default: + throw ErrorHelper.CreateError (4124, "Invalid AdoptsAttribute found on '{0}': expected 1 constructor arguments, got {1}. Please file a bug report at https://bugzilla.xamarin.com", type.FullName, 1, ca.ConstructorArguments.Count); + } + rv.Add (attrib); + } + + return rv; + } + protected override BindAsAttribute GetBindAsAttribute (PropertyDefinition property) { if (property == null) @@ -2652,6 +2674,15 @@ namespace Registrar { CheckNamespace (tp.Protocols [p], exceptions); } } + if (App.Optimizations.RegisterProtocols == true && tp.AdoptedProtocols != null) { + for (int p = 0; p < tp.AdoptedProtocols.Length; p++) { + if (tp.AdoptedProtocols [p] == "UIAppearance") + continue; // This is not a real protocol + iface.Append (any_protocols ? ", " : "<"); + any_protocols = true; + iface.Append (tp.AdoptedProtocols [p]); + } + } tp = tp.BaseType; } if (any_protocols) @@ -4497,4 +4528,9 @@ namespace Registrar { public bool IsWrapper { get; set; } public bool SkipRegistration { get; set; } } + + class AdoptsAttribute : Attribute + { + public string ProtocolType { get; set; } + } }