fishnet installed
This commit is contained in:
@ -0,0 +1,54 @@
|
||||
using MonoFN.Cecil;
|
||||
using System.Linq;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class CustomAttributeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds a field within an attribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="customAttr"></param>
|
||||
/// <param name="field"></param>
|
||||
/// <param name="defaultValue"></param>
|
||||
/// <returns></returns>
|
||||
internal static T GetField<T>(this CustomAttribute customAttr, string field, T defaultValue)
|
||||
{
|
||||
foreach (CustomAttributeNamedArgument customField in customAttr.Fields)
|
||||
{
|
||||
if (customField.Name == field)
|
||||
{
|
||||
return (T)customField.Argument.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if any of the attributes match IAtrribute.
|
||||
/// </summary>
|
||||
/// <typeparam name="TAttribute"></typeparam>
|
||||
/// <param name="attributeProvider"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool HasCustomAttribute<TAttribute>(this ICustomAttributeProvider attributeProvider)
|
||||
{
|
||||
return attributeProvider.CustomAttributes.Any(attr => attr.AttributeType.Is<TAttribute>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if ca is of type target.
|
||||
/// </summary>
|
||||
/// <param name="ca"></param>
|
||||
/// <param name="targetFullName"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool Is(this CustomAttribute ca, string targetFullName)
|
||||
{
|
||||
return ca.AttributeType.FullName == targetFullName;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a66d771ab331fae408142a5c04abd74e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,41 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Unity.CompilationPipeline.Common.Diagnostics;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal static class Diagnostics
|
||||
{
|
||||
internal static void AddError(this List<DiagnosticMessage> diagnostics, string message)
|
||||
{
|
||||
diagnostics.AddMessage(DiagnosticType.Error, (SequencePoint)null, message);
|
||||
}
|
||||
|
||||
internal static void AddWarning(this List<DiagnosticMessage> diagnostics, string message)
|
||||
{
|
||||
diagnostics.AddMessage(DiagnosticType.Warning, (SequencePoint)null, message);
|
||||
}
|
||||
|
||||
internal static void AddError(this List<DiagnosticMessage> diagnostics, MethodDefinition methodDef, string message)
|
||||
{
|
||||
diagnostics.AddMessage(DiagnosticType.Error, methodDef.DebugInformation.SequencePoints.FirstOrDefault(), message);
|
||||
}
|
||||
|
||||
internal static void AddMessage(this List<DiagnosticMessage> diagnostics, DiagnosticType diagnosticType, SequencePoint sequencePoint, string message)
|
||||
{
|
||||
diagnostics.Add(new DiagnosticMessage
|
||||
{
|
||||
DiagnosticType = diagnosticType,
|
||||
File = sequencePoint?.Document.Url.Replace($"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}", ""),
|
||||
Line = sequencePoint?.StartLine ?? 0,
|
||||
Column = sequencePoint?.StartColumn ?? 0,
|
||||
MessageData = $" - {message}"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb7b65b572b01444cbe3c9d830cd3587
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,38 @@
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using MonoFN.Cecil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class FieldReferenceExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Resolve favoring cached results first.
|
||||
/// </summary>
|
||||
internal static FieldDefinition CachedResolve(this FieldReference fieldRef, CodegenSession session)
|
||||
{
|
||||
return session.GetClass<GeneralHelper>().GetFieldReferenceResolve(fieldRef);
|
||||
}
|
||||
|
||||
|
||||
public static FieldReference MakeHostGenericIfNeeded(this FieldDefinition fd, CodegenSession session)
|
||||
{
|
||||
TypeReference declaringTr = fd.DeclaringType;
|
||||
|
||||
if (declaringTr.HasGenericParameters)
|
||||
{
|
||||
GenericInstanceType git = declaringTr.MakeGenericInstanceType();
|
||||
FieldReference result = new FieldReference(fd.Name, fd.FieldType, git);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return session.ImportReference(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d983ebd0c9e1b745902030c2f7a8e99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,191 @@
|
||||
using FishNet.CodeGenerating.Helping.Extension;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
internal static class Constructors
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first constructor that optionally has, or doesn't have parameters.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetFirstConstructor(this TypeReference typeRef, CodegenSession session, bool requireParameters)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetFirstConstructor(requireParameters);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the first constructor that optionally has, or doesn't have parameters.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetFirstConstructor(this TypeDefinition typeDef, bool requireParameters)
|
||||
{
|
||||
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor && methodDef.IsPublic)
|
||||
{
|
||||
if (requireParameters && methodDef.Parameters.Count > 0)
|
||||
return methodDef;
|
||||
else if (!requireParameters && methodDef.Parameters.Count == 0)
|
||||
return methodDef;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first public constructor with no parameters.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the first public constructor with no parameters.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeDefinition typeDef)
|
||||
{
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == 0)
|
||||
return methodDef;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all constructors on typeDef.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static List<MethodDefinition> GetConstructors(this TypeDefinition typeDef)
|
||||
{
|
||||
List<MethodDefinition> lst = new List<MethodDefinition>();
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor)
|
||||
lst.Add(methodDef);
|
||||
}
|
||||
|
||||
return lst;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, Type[] arguments)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor(arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeDefinition typeDef, Type[] arguments)
|
||||
{
|
||||
Type[] argsCopy = (arguments == null) ? new Type[0] : arguments;
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length)
|
||||
{
|
||||
bool match = true;
|
||||
for (int i = 0; i < argsCopy.Length; i++)
|
||||
{
|
||||
if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName)
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
return methodDef;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, TypeReference[] arguments)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor(arguments);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets constructor which has arguments.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeDefinition typeDef, TypeReference[] arguments)
|
||||
{
|
||||
TypeReference[] argsCopy = (arguments == null) ? new TypeReference[0] : arguments;
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == argsCopy.Length)
|
||||
{
|
||||
bool match = true;
|
||||
for (int i = 0; i < argsCopy.Length; i++)
|
||||
{
|
||||
if (methodDef.Parameters[0].ParameterType.FullName != argsCopy[i].FullName)
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
return methodDef;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the constructor with parameterCount for typeRef.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeReference typeRef, CodegenSession session, int parameterCount)
|
||||
{
|
||||
return typeRef.CachedResolve(session).GetConstructor(parameterCount);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the constructor with parameterCount for typeRef.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodDefinition GetConstructor(this TypeDefinition typeDef, int parameterCount)
|
||||
{
|
||||
foreach (MethodDefinition methodDef in typeDef.Methods)
|
||||
{
|
||||
if (methodDef.IsConstructor && methodDef.IsPublic && methodDef.Parameters.Count == parameterCount)
|
||||
return methodDef;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a7e03137ca78704e999f3a3dc68b953
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,169 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class ILProcessorExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a debug log for text without any conditions.
|
||||
/// </summary>
|
||||
public static void DebugLog(this ILProcessor processor, CodegenSession session, string txt)
|
||||
{
|
||||
processor.Emit(OpCodes.Ldstr, txt);
|
||||
processor.Emit(OpCodes.Call, session.GetClass<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a debug log for vd without any conditions.
|
||||
/// </summary>
|
||||
public static void DebugLog(this ILProcessor processor, CodegenSession session, VariableDefinition vd)
|
||||
{
|
||||
processor.Emit(OpCodes.Ldloc, vd);
|
||||
processor.Emit(OpCodes.Box, vd.VariableType);
|
||||
processor.Emit(OpCodes.Call, session.GetClass<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a debug log for vd without any conditions.
|
||||
/// </summary>
|
||||
public static void DebugLog(this ILProcessor processor, CodegenSession session, FieldDefinition fd, bool loadArg0)
|
||||
{
|
||||
if (loadArg0)
|
||||
processor.Emit(OpCodes.Ldarg_0);
|
||||
processor.Emit(OpCodes.Ldfld, fd);
|
||||
processor.Emit(OpCodes.Box, fd.FieldType);
|
||||
processor.Emit(OpCodes.Call, session.GetClass<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a debug log for pd without any conditions.
|
||||
/// </summary>
|
||||
public static void DebugLog(this ILProcessor processor, CodegenSession session, ParameterDefinition pd)
|
||||
{
|
||||
processor.Emit(OpCodes.Ldloc, pd);
|
||||
processor.Emit(OpCodes.Box, pd.ParameterType);
|
||||
processor.Emit(OpCodes.Call, session.GetClass<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Creates a debug log for mr without any conditions.
|
||||
///// </summary>
|
||||
//public static void DebugLog(this ILProcessor processor, MethodReference mr)
|
||||
//{
|
||||
// processor.Emit(OpCodes.Call, mr);
|
||||
// processor.Emit(OpCodes.Box, mr.ReturnType);
|
||||
// processor.Emit(OpCodes.Call, base.GetClass<GeneralHelper>().Debug_LogCommon_MethodRef);
|
||||
//}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions at the beginning.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertAt(this ILProcessor processor, int target, List<Instruction> instructions)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Insert(i + target, instructions[i]);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions at the beginning.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertFirst(this ILProcessor processor, List<Instruction> instructions)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Insert(i, instructions[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions at the end while also moving Ret down.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertLast(this ILProcessor processor, List<Instruction> instructions)
|
||||
{
|
||||
bool retRemoved = false;
|
||||
int startingCount = processor.Body.Instructions.Count;
|
||||
//Remove ret if it exist and add it back in later.
|
||||
if (startingCount > 0)
|
||||
{
|
||||
if (processor.Body.Instructions[startingCount - 1].OpCode == OpCodes.Ret)
|
||||
{
|
||||
processor.Body.Instructions.RemoveAt(startingCount - 1);
|
||||
retRemoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Instruction inst in instructions)
|
||||
processor.Append(inst);
|
||||
|
||||
//Add ret back if it was removed.
|
||||
if (retRemoved)
|
||||
processor.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions before target.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertBefore(this ILProcessor processor, Instruction target, List<Instruction> instructions)
|
||||
{
|
||||
int index = processor.Body.Instructions.IndexOf(target);
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Insert(index + i, instructions[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds instructions to the end of processor.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void Add(this ILProcessor processor, List<Instruction> instructions)
|
||||
{
|
||||
for (int i = 0; i < instructions.Count; i++)
|
||||
processor.Body.Instructions.Add(instructions[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts instructions before returns. Only works on void types.
|
||||
/// </summary>
|
||||
/// <param name="processor"></param>
|
||||
/// <param name="instructions"></param>
|
||||
public static void InsertBeforeReturns(this ILProcessor processor, CodegenSession session, List<Instruction> instructions)
|
||||
{
|
||||
if (processor.Body.Method.ReturnType.FullName != session.Module.TypeSystem.Void.FullName)
|
||||
{
|
||||
session.LogError($"Cannot insert instructions before returns on {processor.Body.Method.FullName} because it does not return void.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Insert at the end of the method
|
||||
* and get the first instruction that was inserted.
|
||||
* Any returns or breaks which would exit the method
|
||||
* will jump to this instruction instead. */
|
||||
processor.InsertLast(instructions);
|
||||
Instruction startInst = processor.Body.Instructions[processor.Body.Instructions.Count - instructions.Count];
|
||||
|
||||
//Look for anything that jumps to rets.
|
||||
for (int i = 0; i < processor.Body.Instructions.Count; i++)
|
||||
{
|
||||
Instruction inst = processor.Body.Instructions[i];
|
||||
if (inst.Operand is Instruction operInst)
|
||||
{
|
||||
if (operInst.OpCode == OpCodes.Ret)
|
||||
inst.Operand = startInst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 820cf8401d4d71c4196dda444559ef8a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,12 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping
|
||||
{
|
||||
public static class Instructions
|
||||
{
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 360667149f16b6c4aba61fd05427cbfb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,55 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Cil;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class MethodDefinitionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears the method content and returns ret.
|
||||
/// </summary>
|
||||
internal static void ClearMethodWithRet(this MethodDefinition md, CodegenSession session, ModuleDefinition importReturnModule = null)
|
||||
{
|
||||
md.Body.Instructions.Clear();
|
||||
ILProcessor processor = md.Body.GetILProcessor();
|
||||
processor.Add(session.GetClass<GeneralHelper>().CreateRetDefault(md, importReturnModule));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ParameterDefinition index from end of parameters.
|
||||
/// </summary>
|
||||
/// <param name="md"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
internal static ParameterDefinition GetEndParameter(this MethodDefinition md, int index)
|
||||
{
|
||||
//Not enough parameters.
|
||||
if (md.Parameters.Count < (index + 1))
|
||||
return null;
|
||||
|
||||
return md.Parameters[md.Parameters.Count - (index + 1)];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a variable type within the body and returns it's VariableDef.
|
||||
/// </summary>
|
||||
internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, TypeReference variableTypeRef)
|
||||
{
|
||||
VariableDefinition variableDef = new VariableDefinition(variableTypeRef);
|
||||
methodDef.Body.Variables.Add(variableDef);
|
||||
return variableDef;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a variable type within the body and returns it's VariableDef.
|
||||
/// </summary>
|
||||
internal static VariableDefinition CreateVariable(this MethodDefinition methodDef, CodegenSession session, System.Type variableType)
|
||||
{
|
||||
return CreateVariable(methodDef, session.GetClass<GeneralHelper>().GetTypeReference(variableType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 999d4ae4862274f4ba50569c221976dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,155 @@
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee1c15a06ab386e439ec5aa41e3496f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,63 @@
|
||||
using FishNet.CodeGenerating.ILCore;
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
public static class ModuleDefinitionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a class within a module.
|
||||
/// </summary>
|
||||
/// <param name="moduleDef"></param>
|
||||
/// <returns></returns>
|
||||
public static TypeDefinition GetClass(this ModuleDefinition moduleDef, string className, string namespaceName = "")
|
||||
{
|
||||
if (namespaceName.Length == 0)
|
||||
namespaceName = FishNetILPP.RUNTIME_ASSEMBLY_NAME;
|
||||
|
||||
return moduleDef.GetType(namespaceName, className);
|
||||
}
|
||||
|
||||
public static MethodReference ImportReference(this ModuleDefinition moduleDef, Expression<Action> expression)
|
||||
{
|
||||
return ImportReference(moduleDef, (LambdaExpression)expression);
|
||||
}
|
||||
public static MethodReference ImportReference<T>(this ModuleDefinition module, Expression<Action<T>> expression)
|
||||
{
|
||||
return ImportReference(module, (LambdaExpression)expression);
|
||||
}
|
||||
|
||||
public static MethodReference ImportReference(this ModuleDefinition module, LambdaExpression expression)
|
||||
{
|
||||
if (expression.Body is MethodCallExpression outermostExpression)
|
||||
{
|
||||
MethodInfo methodInfo = outermostExpression.Method;
|
||||
return module.ImportReference(methodInfo);
|
||||
}
|
||||
|
||||
if (expression.Body is NewExpression newExpression)
|
||||
{
|
||||
ConstructorInfo methodInfo = newExpression.Constructor;
|
||||
// constructor is null when creating an ArraySegment<object>
|
||||
methodInfo = methodInfo ?? newExpression.Type.GetConstructors()[0];
|
||||
return module.ImportReference(methodInfo);
|
||||
}
|
||||
|
||||
if (expression.Body is MemberExpression memberExpression)
|
||||
{
|
||||
var property = memberExpression.Member as PropertyInfo;
|
||||
return module.ImportReference(property.GetMethod);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid Expression {expression.Body.GetType()}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42648785493390646898f5fa13e1dfd6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,24 @@
|
||||
using MonoFN.Cecil;
|
||||
using System;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class ParameterDefinitionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns if parameterDef is Type.
|
||||
/// </summary>
|
||||
/// <param name="parameterDef"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Is(this ParameterDefinition parameterDef, Type type)
|
||||
{
|
||||
return parameterDef.ParameterType.FullName == type.FullName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31071055a2e388141b8f11e1ba4e147e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,521 @@
|
||||
using FishNet.CodeGenerating.Extension;
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
|
||||
internal static class TypeDefinitionExtensionsOld
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creates a GenericInstanceType and adds parameters.
|
||||
/// </summary>
|
||||
internal static GenericInstanceType CreateGenericInstanceType(this TypeDefinition type, Collection<GenericParameter> parameters)
|
||||
{
|
||||
GenericInstanceType git = new GenericInstanceType(type);
|
||||
foreach (GenericParameter gp in parameters)
|
||||
git.GenericArguments.Add(gp);
|
||||
|
||||
return git;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds public fields in type and base type
|
||||
/// </summary>
|
||||
/// <param name="variable"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<FieldDefinition> FindAllPublicFields(this TypeDefinition typeDef, CodegenSession session
|
||||
, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
|
||||
GeneralHelper gh = session.GetClass<GeneralHelper>();
|
||||
while (typeDef != null)
|
||||
{
|
||||
if (IsExcluded(typeDef, excludedBaseTypes, excludedAssemblyPrefixes))
|
||||
break;
|
||||
|
||||
foreach (FieldDefinition fd in typeDef.Fields)
|
||||
{
|
||||
if (fd.IsStatic)
|
||||
continue;
|
||||
if (fd.IsNotSerialized)
|
||||
continue;
|
||||
if (gh.CodegenExclude(fd))
|
||||
continue;
|
||||
if (fd.IsPrivate)
|
||||
continue;
|
||||
|
||||
yield return fd;
|
||||
}
|
||||
|
||||
try { typeDef = typeDef.BaseType?.CachedResolve(session); }
|
||||
catch { break; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds public properties on typeDef and all base types which have a public get/set accessor.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyDefinition> FindAllPublicProperties(this TypeDefinition typeDef, CodegenSession session
|
||||
, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
GeneralHelper gh = session.GetClass<GeneralHelper>();
|
||||
while (typeDef != null)
|
||||
{
|
||||
if (IsExcluded(typeDef, excludedBaseTypes, excludedAssemblyPrefixes))
|
||||
break;
|
||||
|
||||
foreach (PropertyDefinition pd in typeDef.Properties)
|
||||
{
|
||||
//Missing get or set method.
|
||||
if (pd.GetMethod == null || pd.SetMethod == null)
|
||||
continue;
|
||||
if (gh.CodegenExclude(pd))
|
||||
continue;
|
||||
if (pd.GetMethod.IsPrivate)
|
||||
continue;
|
||||
if (pd.SetMethod.IsPrivate)
|
||||
continue;
|
||||
if (pd.GetMethod.ReturnType.IsGenericParameter)
|
||||
continue;
|
||||
|
||||
yield return pd;
|
||||
}
|
||||
|
||||
try { typeDef = typeDef.BaseType?.CachedResolve(session); }
|
||||
catch { break; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is excluded.
|
||||
/// </summary>
|
||||
private static bool IsExcluded(TypeDefinition typeDef, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
if (excludedBaseTypes != null)
|
||||
{
|
||||
foreach (System.Type t in excludedBaseTypes)
|
||||
{
|
||||
if (typeDef.FullName == t.FullName)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (excludedAssemblyPrefixes != null)
|
||||
{
|
||||
foreach (string s in excludedAssemblyPrefixes)
|
||||
{
|
||||
int len = s.Length;
|
||||
string tdAsmName = typeDef.Module.Assembly.FullName;
|
||||
if (tdAsmName.Length >= len && tdAsmName.Substring(0, len).ToLower() == s.ToLower())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//Fall through, not excluded.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is excluded.
|
||||
/// </summary>
|
||||
public static bool IsExcluded(this TypeDefinition typeDef, string excludedAssemblyPrefix)
|
||||
{
|
||||
|
||||
int len = excludedAssemblyPrefix.Length;
|
||||
string tdAsmName = typeDef.Module.Assembly.FullName;
|
||||
if (tdAsmName.Length >= len && tdAsmName.Substring(0, len).ToLower() == excludedAssemblyPrefix.ToLower())
|
||||
return true;
|
||||
|
||||
//Fall through, not excluded.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef or any of it's parents inherit from NetworkBehaviour.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool InheritsNetworkBehaviour(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
string nbFullName = session.GetClass<NetworkBehaviourHelper>().FullName;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
while (copyTd != null)
|
||||
{
|
||||
if (copyTd.FullName == nbFullName)
|
||||
return true;
|
||||
|
||||
copyTd = copyTd.GetNextBaseTypeDefinition(session);
|
||||
}
|
||||
|
||||
//Fall through, network behaviour not found.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a nested TypeDefinition of name.
|
||||
/// </summary>
|
||||
internal static TypeDefinition GetNestedType(this TypeDefinition typeDef, string name)
|
||||
{
|
||||
foreach (TypeDefinition nestedTd in typeDef.NestedTypes)
|
||||
{
|
||||
if (nestedTd.Name == name)
|
||||
return nestedTd;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the BaseType for TypeDef exist and is not NetworkBehaviour,
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool CanProcessBaseType(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
return (typeDef != null && typeDef.BaseType != null && typeDef.BaseType.FullName != session.GetClass<NetworkBehaviourHelper>().FullName);
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns if the BaseType for TypeDef exist and is not NetworkBehaviour,
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static TypeDefinition GetNextBaseClassToProcess(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
if (typeDef.BaseType != null && typeDef.BaseType.FullName != session.GetClass<NetworkBehaviourHelper>().FullName)
|
||||
return typeDef.BaseType.CachedResolve(session);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static TypeDefinition GetLastBaseClass(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
TypeDefinition copyTd = typeDef;
|
||||
while (copyTd.BaseType != null)
|
||||
copyTd = copyTd.BaseType.CachedResolve(session);
|
||||
|
||||
return copyTd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a type in current and inherited types.
|
||||
/// </summary>
|
||||
internal static TypeDefinition GetClassInInheritance(this TypeDefinition typeDef, CodegenSession session, string typeFullName)
|
||||
{
|
||||
TypeDefinition copyTd = typeDef;
|
||||
do
|
||||
{
|
||||
if (copyTd.FullName == typeFullName)
|
||||
return copyTd;
|
||||
|
||||
if (copyTd.BaseType != null)
|
||||
copyTd = copyTd.BaseType.CachedResolve(session);
|
||||
else
|
||||
copyTd = null;
|
||||
|
||||
} while (copyTd != null);
|
||||
|
||||
//Not found.
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a type in current and inherited types.
|
||||
/// </summary>
|
||||
internal static TypeDefinition GetClassInInheritance(this TypeDefinition typeDef, CodegenSession session, TypeDefinition targetTypeDef)
|
||||
{
|
||||
if (typeDef == null)
|
||||
return null;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
do
|
||||
{
|
||||
if (copyTd == targetTypeDef)
|
||||
return copyTd;
|
||||
|
||||
if (copyTd.BaseType != null)
|
||||
copyTd = copyTd.BaseType.CachedResolve(session);
|
||||
else
|
||||
copyTd = null;
|
||||
|
||||
} while (copyTd != null);
|
||||
|
||||
//Not found.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is static (abstract, sealed).
|
||||
/// </summary>
|
||||
internal static bool IsStatic(this TypeDefinition typeDef)
|
||||
{
|
||||
//Combining flags in a single check some reason doesn't work right with HasFlag.
|
||||
return (typeDef.Attributes.HasFlag(TypeAttributes.Abstract) && typeDef.Attributes.HasFlag(TypeAttributes.Sealed));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enum underlying type for typeDef.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static TypeReference GetEnumUnderlyingTypeReference(this TypeDefinition typeDef)
|
||||
{
|
||||
foreach (FieldDefinition field in typeDef.Fields)
|
||||
{
|
||||
if (!field.IsStatic)
|
||||
return field.FieldType;
|
||||
}
|
||||
throw new ArgumentException($"Invalid enum {typeDef.FullName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is derived from type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool InheritsFrom<T>(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
return typeDef.InheritsFrom(session, typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeDef is derived from type.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool InheritsFrom(this TypeDefinition typeDef, CodegenSession session, Type type)
|
||||
{
|
||||
if (!typeDef.IsClass)
|
||||
return false;
|
||||
|
||||
TypeDefinition copyTd = typeDef;
|
||||
while (copyTd.BaseType != null)
|
||||
{
|
||||
if (copyTd.BaseType.IsType(type))
|
||||
return true;
|
||||
|
||||
copyTd = copyTd.GetNextBaseTypeDefinition(session);
|
||||
}
|
||||
|
||||
//Fall through.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a method to typeDef.
|
||||
/// </summary>
|
||||
/// <param name="typDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="attributes"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition AddMethod(this TypeDefinition typDef, string methodName, MethodAttributes attributes)
|
||||
{
|
||||
return AddMethod(typDef, methodName, attributes, typDef.Module.ImportReference(typeof(void)));
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a method to typeDef.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="attributes"></param>
|
||||
/// <param name="typeReference"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition AddMethod(this TypeDefinition typeDef, string methodName, MethodAttributes attributes, TypeReference typeReference)
|
||||
{
|
||||
var method = new MethodDefinition(methodName, attributes, typeReference);
|
||||
typeDef.Methods.Add(method);
|
||||
return method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the first method by a given name.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition GetMethod(this TypeDefinition typeDef, string methodName)
|
||||
{
|
||||
return typeDef.Methods.FirstOrDefault(method => method.Name == methodName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the first method by a given name.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <returns></returns>
|
||||
internal static MethodDefinition GetMethod(this TypeDefinition typeDef, string methodName, Type[] types)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a type is a subclass of another.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="ClassTypeFullName"></param>
|
||||
/// <returns></returns>
|
||||
internal static bool IsSubclassOf(this TypeDefinition typeDef,CodegenSession session, string ClassTypeFullName)
|
||||
{
|
||||
if (!typeDef.IsClass) return false;
|
||||
|
||||
TypeReference baseTypeRef = typeDef.BaseType;
|
||||
while (baseTypeRef != null)
|
||||
{
|
||||
if (baseTypeRef.FullName == ClassTypeFullName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
baseTypeRef = baseTypeRef.CachedResolve(session).BaseType;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a field reference by name.
|
||||
/// </summary>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <param name="fieldName"></param>
|
||||
/// <returns></returns>
|
||||
public static FieldReference GetFieldReference(this TypeDefinition typeDef, string fieldName, CodegenSession session)
|
||||
{
|
||||
if (typeDef.HasFields)
|
||||
{
|
||||
for (int i = 0; i < typeDef.Fields.Count; i++)
|
||||
{
|
||||
if (typeDef.Fields[i].Name == fieldName)
|
||||
return session.ImportReference(typeDef.Fields[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterface<TInterface>(this TypeDefinition typeDef)
|
||||
{
|
||||
for (int i = 0; i < typeDef.Interfaces.Count; i++)
|
||||
{
|
||||
if (typeDef.Interfaces[i].InterfaceType.Is<TInterface>())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterface(this TypeDefinition typeDef, string interfaceName)
|
||||
{
|
||||
for (int i = 0; i < typeDef.Interfaces.Count; i++)
|
||||
{
|
||||
if (typeDef.Interfaces[i].InterfaceType.FullName == interfaceName)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterfaceRecursive<T>(this TypeDefinition typeDef, CodegenSession session)
|
||||
{
|
||||
TypeDefinition climbTypeDef = typeDef;
|
||||
|
||||
while (climbTypeDef != null)
|
||||
{
|
||||
if (climbTypeDef.Interfaces.Any(i => i.InterfaceType.Is<T>()))
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
if (climbTypeDef.BaseType != null)
|
||||
climbTypeDef = climbTypeDef.BaseType.CachedResolve(session);
|
||||
else
|
||||
climbTypeDef = null;
|
||||
}
|
||||
//Could not resolve assembly; can happen for assemblies being checked outside FishNet/csharp.
|
||||
catch (AssemblyResolutionException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the TypeDefinition implements TInterface.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInterface"></typeparam>
|
||||
/// <param name="typeDef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool ImplementsInterfaceRecursive(this TypeDefinition typeDef, CodegenSession session, string interfaceName)
|
||||
{
|
||||
TypeDefinition climbTypeDef = typeDef;
|
||||
|
||||
while (climbTypeDef != null)
|
||||
{
|
||||
if (climbTypeDef.Interfaces.Any(i => i.InterfaceType.FullName == interfaceName))
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
if (climbTypeDef.BaseType != null)
|
||||
climbTypeDef = climbTypeDef.BaseType.CachedResolve(session);
|
||||
else
|
||||
climbTypeDef = null;
|
||||
}
|
||||
//Could not resolve assembly; can happen for assemblies being checked outside FishNet/csharp.
|
||||
catch (AssemblyResolutionException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 645e49fe7eeff3a4e9eb65d77fc6e2ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,138 @@
|
||||
using MonoFN.Cecil;
|
||||
using MonoFN.Cecil.Rocks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.CodeGenerating.Helping.Extension
|
||||
{
|
||||
|
||||
internal static class TypeReferenceExtensionsOld
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Resolve favoring cached results first.
|
||||
/// </summary>
|
||||
internal static TypeDefinition CachedResolve(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
return session.GetClass<GeneralHelper>().GetTypeReferenceResolve(typeRef);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeRef is a class or struct.
|
||||
/// </summary>
|
||||
internal static bool IsClassOrStruct(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
TypeDefinition typeDef = typeRef.CachedResolve(session);
|
||||
return (!typeDef.IsPrimitive && !typeDef.IsEnum && (typeDef.IsClass || typeDef.IsValueType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all properties on typeRef and all base types which have a public get/set accessor.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyDefinition> FindAllSerializableProperties(this TypeReference typeRef, CodegenSession session, System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
return typeRef.CachedResolve(session).FindAllPublicProperties(session, excludedBaseTypes, excludedAssemblyPrefixes);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all public fields in typeRef and base type.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<FieldDefinition> FindAllSerializableFields(this TypeReference typeRef, CodegenSession session,
|
||||
System.Type[] excludedBaseTypes = null, string[] excludedAssemblyPrefixes = null)
|
||||
{
|
||||
return typeRef.Resolve().FindAllPublicFields(session, excludedBaseTypes, excludedAssemblyPrefixes);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a typeRef is type.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsType(this TypeReference typeRef, Type type)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
return typeRef.GetElementType().FullName == type.FullName;
|
||||
else
|
||||
return typeRef.FullName == type.FullName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeRef is a multidimensional array.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsMultidimensionalArray(this TypeReference typeRef)
|
||||
{
|
||||
return typeRef is ArrayType arrayType && arrayType.Rank > 1;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns if typeRef can be resolved.
|
||||
/// </summary>
|
||||
/// <param name="typeRef"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CanBeResolved(this TypeReference typeRef, CodegenSession session)
|
||||
{
|
||||
while (typeRef != null)
|
||||
{
|
||||
if (typeRef.Scope.Name == "Windows")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeRef.Scope.Name == "mscorlib")
|
||||
{
|
||||
TypeDefinition resolved = typeRef.CachedResolve(session);
|
||||
return resolved != null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
typeRef = typeRef.CachedResolve(session).BaseType;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a generic type out of another type, if needed.
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static TypeReference ConvertToGenericIfNeeded(this TypeDefinition type)
|
||||
{
|
||||
if (type.HasGenericParameters)
|
||||
{
|
||||
// get all the generic parameters and make a generic instance out of it
|
||||
TypeReference[] genericTypes = new TypeReference[type.GenericParameters.Count];
|
||||
for (int i = 0; i < type.GenericParameters.Count; i++)
|
||||
{
|
||||
genericTypes[i] = type.GenericParameters[i].GetElementType();
|
||||
}
|
||||
|
||||
return type.MakeGenericInstanceType(genericTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2344f5ab0fda07b498c03fbe0e082c14
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user