using MonoFN.Cecil; using MonoFN.Cecil.Rocks; using System; namespace FishNet.CodeGenerating.Helping.Extension { internal static class MethodReferenceExtensions { /// /// Makes a generic method with specified arguments. /// /// /// /// 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; } /// /// Makes a generic method with the same arguments as the original. /// /// /// 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; } /// /// Returns a method reference for a generic method. /// public static MethodReference GetMethodReference(this MethodReference mr, CodegenSession session, TypeReference typeReference) { return mr.GetMethodReference(session, new TypeReference[] { typeReference }); } /// /// Returns a method reference for a generic method. /// 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; } } /// /// Gets a Resolve favoring cached results first. /// internal static MethodDefinition CachedResolve(this MethodReference methodRef, CodegenSession session) { return session.GetClass().GetMethodReferenceResolve(methodRef); } /// /// 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 /// Note that calling ArraySegment`T.get_Count directly gives an invalid IL error /// /// /// /// 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); } /// /// 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 /// Note that calling ArraySegment`T.get_Count directly gives an invalid IL error /// /// /// /// 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(this MethodReference method, string name) { return method.DeclaringType.Is() && method.Name == name; } public static bool Is(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; } } }