xamarin-macios/tools/linker/MobileExtensions.cs

162 строки
5.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Tuner;
using ObjCRuntime;
using Xamarin.Bundler;
using Xamarin.Tuner;
namespace Xamarin.Linker {
public static class MobileExtensions {
// Returns a string representation of the specified provider that is suitable for user-visible error/warning messages.
public static string AsString (this ICustomAttributeProvider provider)
{
if (provider is MemberReference member)
return member.DeclaringType.FullName + "." + member.Name;
if (provider is MethodReturnType returnType)
return AsString ((ICustomAttributeProvider) returnType.Method);
return provider.ToString ();
}
public static bool HasCustomAttribute (this ICustomAttributeProvider provider, DerivedLinkContext context, string @namespace, string name, out ICustomAttribute attrib)
{
attrib = null;
if (provider?.HasCustomAttribute (@namespace, name, out attrib) == true)
return true;
var attribs = context?.GetCustomAttributes (provider, @namespace, name);
attrib = attribs?.FirstOrDefault ();
return attrib is not null;
}
// This method will look in any stored attributes in the link context as well as the provider itself.
public static bool HasCustomAttribute (this ICustomAttributeProvider provider, DerivedLinkContext context, string @namespace, string name)
{
if (provider?.HasCustomAttribute (@namespace, name) == true)
return true;
return context?.GetCustomAttributes (provider, @namespace, name)?.Count > 0;
}
public static bool HasCustomAttribute (this ICustomAttributeProvider provider, string @namespace, string name)
{
return HasCustomAttribute (provider, @namespace, name, out _);
}
public static bool HasCustomAttribute (this ICustomAttributeProvider provider, string @namespace, string name, out ICustomAttribute attrib)
{
attrib = null;
if (provider is null || !provider.HasCustomAttributes)
return false;
foreach (CustomAttribute attribute in provider.CustomAttributes) {
TypeReference tr = attribute.Constructor.DeclaringType;
if (tr.Is (@namespace, name)) {
attrib = attribute;
return true;
}
}
return false;
}
static bool HasGeneratedCodeAttribute (ICustomAttributeProvider provider, DerivedLinkContext context)
{
return provider.HasCustomAttribute (context, "System.Runtime.CompilerServices", "CompilerGeneratedAttribute");
}
// 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 is 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;
}
static BindingImplOptions? GetBindingImplAttribute (ICustomAttributeProvider provider, DerivedLinkContext context)
{
if (provider is not null && provider.HasCustomAttributes) {
var rv = GetBindingImplAttribute (provider, provider.CustomAttributes);
if (rv is not null)
return rv;
}
return GetBindingImplAttribute (provider, context?.GetCustomAttributes (provider, Namespaces.ObjCRuntime, "BindingImplAttribute"));
}
public static PropertyDefinition GetPropertyByAccessor (this MethodDefinition method)
{
foreach (PropertyDefinition property in method.DeclaringType.Properties) {
if (property.GetMethod == method || property.SetMethod == method)
return property;
}
return null;
}
public static bool IsGeneratedCode (this MethodDefinition self, DerivedLinkContext link_context)
{
// check the property too
if (self.IsGetter || self.IsSetter) {
if (HasGeneratedCodeAttribute (GetPropertyByAccessor (self), link_context))
return true;
}
return HasGeneratedCodeAttribute (self, link_context);
}
public static bool IsBindingImplOptimizableCode (this MethodDefinition self, DerivedLinkContext link_context)
{
var attrib = GetBindingImplAttribute (self, link_context);
if ((attrib & BindingImplOptions.Optimizable) == BindingImplOptions.Optimizable)
return true;
// Check the property too
if (self.IsGetter || self.IsSetter) {
attrib = GetBindingImplAttribute (GetPropertyByAccessor (self), link_context);
if ((attrib & BindingImplOptions.Optimizable) == BindingImplOptions.Optimizable)
return true;
}
return false;
}
public static bool IsOptimizableCode (this MethodDefinition self, DerivedLinkContext link_context)
{
if (IsBindingImplOptimizableCode (self, link_context))
return true;
if (IsGeneratedCode (self, link_context))
return true;
return false;
}
}
}