155 lines
6.0 KiB
C#
155 lines
6.0 KiB
C#
using MonoFN.Cecil;
|
|
using MonoFN.Cecil.Rocks;
|
|
using System;
|
|
|
|
namespace FishNet.CodeGenerating.Helping.Extension
|
|
{
|
|
|
|
internal static class MethodReferenceExtensions
|
|
{
|
|
/// <summary>
|
|
/// Makes a generic method with specified arguments.
|
|
/// </summary>
|
|
/// <param name="method"></param>
|
|
/// <param name="genericArguments"></param>
|
|
/// <returns></returns>
|
|
public static GenericInstanceMethod MakeGenericMethod(this MethodReference method, params TypeReference[] genericArguments)
|
|
{
|
|
GenericInstanceMethod result = new GenericInstanceMethod(method);
|
|
foreach (TypeReference argument in genericArguments)
|
|
result.GenericArguments.Add(argument);
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes a generic method with the same arguments as the original.
|
|
/// </summary>
|
|
/// <param name="method"></param>
|
|
/// <returns></returns>
|
|
public static GenericInstanceMethod MakeGenericMethod(this MethodReference method)
|
|
{
|
|
GenericInstanceMethod result = new GenericInstanceMethod(method);
|
|
foreach (ParameterDefinition pd in method.Parameters)
|
|
result.GenericArguments.Add(pd.ParameterType);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a method reference for a generic method.
|
|
/// </summary>
|
|
public static MethodReference GetMethodReference(this MethodReference mr, CodegenSession session, TypeReference typeReference)
|
|
{
|
|
return mr.GetMethodReference(session, new TypeReference[] { typeReference });
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a method reference for a generic method.
|
|
/// </summary>
|
|
public static MethodReference GetMethodReference(this MethodReference mr, CodegenSession session, TypeReference[] typeReferences)
|
|
{
|
|
if (mr.HasGenericParameters)
|
|
{
|
|
if (typeReferences == null || typeReferences.Length == 0)
|
|
{
|
|
session.LogError($"Method {mr.Name} has generic parameters but TypeReferences are null or 0 length.");
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
GenericInstanceMethod gim = mr.MakeGenericMethod(typeReferences);
|
|
return gim;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return mr;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets a Resolve favoring cached results first.
|
|
/// </summary>
|
|
internal static MethodDefinition CachedResolve(this MethodReference methodRef, CodegenSession session)
|
|
{
|
|
return session.GetClass<GeneralHelper>().GetMethodReferenceResolve(methodRef);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a method of a generic class such as ArraySegment`T.get_Count,
|
|
/// and a generic instance such as ArraySegment`int
|
|
/// Creates a reference to the specialized method ArraySegment`int`.get_Count
|
|
/// <para> Note that calling ArraySegment`T.get_Count directly gives an invalid IL error </para>
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="instanceType"></param>
|
|
/// <returns></returns>
|
|
public static MethodReference MakeHostInstanceGeneric(this MethodReference self, CodegenSession session, GenericInstanceType instanceType)
|
|
{
|
|
MethodReference reference = new MethodReference(self.Name, self.ReturnType, instanceType)
|
|
{
|
|
CallingConvention = self.CallingConvention,
|
|
HasThis = self.HasThis,
|
|
ExplicitThis = self.ExplicitThis
|
|
};
|
|
|
|
foreach (ParameterDefinition parameter in self.Parameters)
|
|
reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
|
|
|
|
foreach (GenericParameter generic_parameter in self.GenericParameters)
|
|
reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
|
|
|
|
return session.ImportReference(reference);
|
|
}
|
|
/// <summary>
|
|
/// Given a method of a generic class such as ArraySegment`T.get_Count,
|
|
/// and a generic instance such as ArraySegment`int
|
|
/// Creates a reference to the specialized method ArraySegment`int`.get_Count
|
|
/// <para> Note that calling ArraySegment`T.get_Count directly gives an invalid IL error </para>
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="instanceType"></param>
|
|
/// <returns></returns>
|
|
public static MethodReference MakeHostInstanceGeneric(this MethodReference self, TypeReference typeRef, params TypeReference[] args)
|
|
{
|
|
GenericInstanceType git = typeRef.MakeGenericInstanceType(args);
|
|
MethodReference reference = new MethodReference(self.Name, self.ReturnType, git)
|
|
{
|
|
CallingConvention = self.CallingConvention,
|
|
HasThis = self.HasThis,
|
|
ExplicitThis = self.ExplicitThis
|
|
};
|
|
|
|
foreach (ParameterDefinition parameter in self.Parameters)
|
|
reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
|
|
|
|
foreach (GenericParameter generic_parameter in self.GenericParameters)
|
|
reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
|
|
|
|
return reference;
|
|
}
|
|
public static bool Is<T>(this MethodReference method, string name)
|
|
{
|
|
return method.DeclaringType.Is<T>() && method.Name == name;
|
|
}
|
|
public static bool Is<T>(this TypeReference td)
|
|
{
|
|
return Is(td, typeof(T));
|
|
}
|
|
|
|
public static bool Is(this TypeReference td, Type t)
|
|
{
|
|
if (t.IsGenericType)
|
|
{
|
|
return td.GetElementType().FullName == t.FullName;
|
|
}
|
|
return td.FullName == t.FullName;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
} |