[registrar] Make the generated static registrar code implement protocols from [Adopts] attributes.

Make the generated static registrar code implement protocols from [Adopts]
attributes, so that we can just query the ObjC runtime to see if a type
implements a protocol instead of keeping this information around ourselves.
This commit is contained in:
Rolf Bjarne Kvinge 2018-02-10 01:19:23 +01:00
Родитель 0fa2aa0fb5
Коммит 14daaad78e
3 изменённых файлов: 55 добавлений и 0 удалений

Просмотреть файл

@ -378,6 +378,11 @@ namespace Registrar {
return attr == null ? null : attr.WrapperType; return attr == null ? null : attr.WrapperType;
} }
protected override IList<AdoptsAttribute> GetAdoptsAttributes (Type type)
{
return (AdoptsAttribute[]) type.GetCustomAttributes (typeof (AdoptsAttribute), false);
}
protected override string GetAssemblyName (Assembly assembly) protected override string GetAssemblyName (Assembly assembly)
{ {
return assembly.GetName ().Name; return assembly.GetName ().Name;

Просмотреть файл

@ -135,6 +135,7 @@ namespace Registrar {
public TType Type; public TType Type;
public ObjCType BaseType; public ObjCType BaseType;
public ObjCType [] Protocols; public ObjCType [] Protocols;
public string [] AdoptedProtocols;
public bool IsModel; public bool IsModel;
// if this type represents an ObjC protocol (!= has the protocol attribute, since that can be applied to all kinds of things). // if this type represents an ObjC protocol (!= has the protocol attribute, since that can be applied to all kinds of things).
public bool IsProtocol; 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 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 (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 BindAsAttribute GetBindAsAttribute (TProperty property);
protected abstract IList<AdoptsAttribute> GetAdoptsAttributes (TType type);
public abstract TType GetNullableType (TType type); // For T? returns T. For T returns null. 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 HasReleaseAttribute (TMethod method); // Returns true of the method's return type/value has a [Release] attribute.
protected abstract bool IsINativeObject (TType type); protected abstract bool IsINativeObject (TType type);
@ -1640,6 +1642,17 @@ namespace Registrar {
return protocolList.ToArray (); 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<Exception> exceptions) ObjCType RegisterCategory (TType type, CategoryAttribute attrib, ref List<Exception> exceptions)
{ {
if (IsINativeObject (type)) { if (IsINativeObject (type)) {
@ -1823,6 +1836,7 @@ namespace Registrar {
}; };
objcType.VerifyRegisterAttribute (ref exceptions); objcType.VerifyRegisterAttribute (ref exceptions);
objcType.Protocols = GetProtocols (objcType, ref exceptions); objcType.Protocols = GetProtocols (objcType, ref exceptions);
objcType.AdoptedProtocols = GetAdoptedProtocols (objcType);
objcType.BaseType = isProtocol ? null : (baseObjCType ?? objcType); objcType.BaseType = isProtocol ? null : (baseObjCType ?? objcType);
objcType.IsWrapper = (isProtocol && !isInformalProtocol) ? (GetProtocolAttributeWrapperType (objcType.Type) != null) : (objcType.RegisterAttribute != null && objcType.RegisterAttribute.IsWrapper); objcType.IsWrapper = (isProtocol && !isInformalProtocol) ? (GetProtocolAttributeWrapperType (objcType.Type) != null) : (objcType.RegisterAttribute != null && objcType.RegisterAttribute.IsWrapper);

Просмотреть файл

@ -1602,6 +1602,28 @@ namespace Registrar {
return null; return null;
} }
protected override IList<AdoptsAttribute> GetAdoptsAttributes (TypeReference type)
{
var attributes = GetCustomAttributes (type.Resolve (), ObjCRuntime, "AdoptsAttribute");
if (attributes == null || !attributes.Any ())
return null;
var rv = new List<AdoptsAttribute> ();
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) protected override BindAsAttribute GetBindAsAttribute (PropertyDefinition property)
{ {
if (property == null) if (property == null)
@ -2652,6 +2674,15 @@ namespace Registrar {
CheckNamespace (tp.Protocols [p], exceptions); 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; tp = tp.BaseType;
} }
if (any_protocols) if (any_protocols)
@ -4497,4 +4528,9 @@ namespace Registrar {
public bool IsWrapper { get; set; } public bool IsWrapper { get; set; }
public bool SkipRegistration { get; set; } public bool SkipRegistration { get; set; }
} }
class AdoptsAttribute : Attribute
{
public string ProtocolType { get; set; }
}
} }