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;
 | |
|         }
 | |
| 
 | |
| 
 | |
| 
 | |
|     }
 | |
| 
 | |
| 
 | |
| } |