sk-client/Assets/ToLua/Injection/Editor/ToLuaInjectionHelper.cs

386 lines
10 KiB
C#

#if ENABLE_LUA_INJECTION
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Unity.CecilTools;
using System.Linq;
[Flags]
public enum InjectFilter
{
IgnoreConstructor = 1,
IgnoreProperty = 1 << 1,
IgnoreGeneric = 1 << 2,
IgnoreNoToLuaAttr = 1 << 3,
}
public static class ToLuaInjectionHelper
{
public static string GetArrayRank(TypeReference t)
{
ArrayType type = t as ArrayType;
int count = type.Rank;
if (count == 1)
{
return "[]";
}
using (CString.Block())
{
CString sb = CString.Alloc(64);
sb.Append('[');
for (int i = 1; i < count; i++)
{
sb.Append(',');
}
sb.Append(']');
return sb.ToString();
}
}
public static string GetTypeName(TypeReference t, bool bFull = false)
{
if (t.IsArray)
{
string str = GetTypeName(ElementType.For(t));
str += GetArrayRank(t);
return str;
}
else if (t.IsByReference)
{
//t = t.GetElementType();
return GetTypeName(ElementType.For(t)) + "&";
}
else if (t.IsGenericInstance)
{
return GetGenericName(t, bFull);
}
else if (t.MetadataType == MetadataType.Void)
{
return "void";
}
else
{
string name = GetPrimitiveTypeStr(t, bFull);
return name.Replace('+', '.');
}
}
public static string[] GetGenericName(Mono.Collections.Generic.Collection<TypeReference> types, int offset, int count, bool bFull)
{
string[] results = new string[count];
for (int i = 0; i < count; i++)
{
int pos = i + offset;
if (types[pos].IsGenericInstance)
{
results[i] = GetGenericName(types[pos], bFull);
}
else
{
results[i] = GetTypeName(types[pos]);
}
}
return results;
}
public static MethodReference GetBaseMethodInstance(this MethodDefinition target)
{
MethodDefinition baseMethodDef = null;
var baseType = target.DeclaringType.BaseType;
while (baseType != null)
{
if (baseType.MetadataToken.TokenType == TokenType.TypeRef)
{
break;
}
var baseTypeDef = baseType.Resolve();
baseMethodDef = MetadataResolver.GetMethod(baseTypeDef.Methods, target);
if (baseMethodDef != null && !baseMethodDef.IsAbstract)
{
if (baseType.IsGenericInstance)
{
MethodReference baseMethodRef = baseType.Module.Import(baseMethodDef);
var baseTypeInstance = (GenericInstanceType)baseType;
return baseMethodRef.MakeGenericMethod(baseTypeInstance.GenericArguments.ToArray());
}
break;
}
else baseMethodDef = null;
baseType = baseTypeDef.BaseType;
}
return baseMethodDef;
}
public static bool IsGenericTypeDefinition(this TypeReference type)
{
if (type.HasGenericParameters)
{
return true;
}
else if (type.IsByReference || type.IsArray)
{
return ElementType.For(type).IsGenericTypeDefinition();
}
else if (type.IsNested)
{
var parent = type.DeclaringType;
while (parent != null)
{
if (parent.IsGenericTypeDefinition())
{
return true;
}
if (parent.IsNested)
{
parent = parent.DeclaringType;
}
else
{
break;
}
}
}
return type.IsGenericParameter;
}
public static bool IsGenericMethodDefinition(this MethodDefinition md)
{
if (md.HasGenericParameters
#if UNITY_5_2 || UNITY_5_3 || UNITY_5_3_OR_NEWER
|| md.ContainsGenericParameter
#endif
)
{
return true;
}
if (md.DeclaringType != null && md.DeclaringType.IsGenericTypeDefinition())
{
return true;
}
if (md.ReturnType.IsGenericTypeDefinition())
{
return true;
}
foreach (var param in md.Parameters)
{
if (param.ParameterType.IsGenericTypeDefinition())
{
return true;
}
}
return false;
}
public static bool GotPassedByReferenceParam(this MethodReference md)
{
return md.Parameters.Any(param => param.ParameterType.IsByReference);
}
public static TypeReference MakeGenericType(this TypeReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
{
throw new ArgumentException();
}
var instance = new GenericInstanceType(self);
foreach (var argument in arguments)
{
instance.GenericArguments.Add(argument);
}
return instance;
}
public static MethodReference MakeGenericMethod(this MethodReference self, params TypeReference[] arguments)
{
if (self.DeclaringType.IsGenericTypeDefinition())
{
return self.CloneMethod(self.DeclaringType.MakeGenericType(arguments));
}
else
{
var genericInstanceMethod = new GenericInstanceMethod(self.CloneMethod());
foreach (var argument in arguments)
{
genericInstanceMethod.GenericArguments.Add(argument);
}
return genericInstanceMethod;
}
}
public static MethodReference CloneMethod(this MethodReference self, TypeReference declaringType = null)
{
var reference = new MethodReference(self.Name, self.ReturnType, declaringType ?? self.DeclaringType)
{
HasThis = self.HasThis,
ExplicitThis = self.ExplicitThis,
CallingConvention = self.CallingConvention,
};
foreach (ParameterDefinition parameterDef in self.Parameters)
{
reference.Parameters.Add(new ParameterDefinition(parameterDef.Name, parameterDef.Attributes, parameterDef.ParameterType));
}
foreach (GenericParameter genParamDef in self.GenericParameters)
{
reference.GenericParameters.Add(new GenericParameter(genParamDef.Name, reference));
}
return reference;
}
public static bool IsEnumerator(this MethodDefinition md)
{
return md.ReturnType.FullName == "System.Collections.IEnumerator";
}
public static bool ReturnVoid(this MethodDefinition target)
{
return target.ReturnType.FullName == "System.Void";
}
public static bool HasFlag(this LuaInterface.InjectType flag, LuaInterface.InjectType destFlag)
{
return (flag & destFlag) == destFlag;
}
public static bool HasFlag(this LuaInterface.InjectType flag, byte destFlag)
{
return ((byte)flag & destFlag) == destFlag;
}
public static bool HasFlag(this InjectFilter flag, InjectFilter destFlag)
{
return (flag & destFlag) == destFlag;
}
public static string GetPrimitiveTypeStr(TypeReference t, bool bFull)
{
switch (t.MetadataType)
{
case MetadataType.Single:
return "float";
case MetadataType.String:
return "string";
case MetadataType.Int32:
return "int";
case MetadataType.Double:
return "double";
case MetadataType.Boolean:
return "bool";
case MetadataType.UInt32:
return "uint";
case MetadataType.SByte:
return "sbyte";
case MetadataType.Byte:
return "byte";
case MetadataType.Int16:
return "short";
case MetadataType.UInt16:
return "ushort";
case MetadataType.Char:
return "char";
case MetadataType.Int64:
return "long";
case MetadataType.UInt64:
return "ulong";
case MetadataType.Object:
return "object";
default:
return bFull ? t.FullName.Replace("/", "+") : t.Name;
}
}
static string CombineTypeStr(string space, string name)
{
if (string.IsNullOrEmpty(space))
{
return name;
}
else
{
return space + "." + name;
}
}
static string GetGenericName(TypeReference t, bool bFull)
{
GenericInstanceType type = t as GenericInstanceType;
var gArgs = type.GenericArguments;
string typeName = bFull ? t.FullName.Replace("/", "+") : t.Name;
int count = gArgs.Count;
int pos = typeName.IndexOf("[");
if (pos > 0)
{
typeName = typeName.Substring(0, pos);
}
string str = null;
string name = null;
int offset = 0;
pos = typeName.IndexOf("+");
while (pos > 0)
{
str = typeName.Substring(0, pos);
typeName = typeName.Substring(pos + 1);
pos = str.IndexOf('`');
if (pos > 0)
{
count = (int)(str[pos + 1] - '0');
str = str.Substring(0, pos);
str += "<" + string.Join(",", GetGenericName(gArgs, offset, count, bFull)) + ">";
offset += count;
}
name = CombineTypeStr(name, str);
pos = typeName.IndexOf("+");
}
str = typeName;
if (offset < gArgs.Count)
{
pos = str.IndexOf('`');
count = (int)(str[pos + 1] - '0');
str = str.Substring(0, pos);
str += "<" + string.Join(",", GetGenericName(gArgs, offset, count, bFull)) + ">";
}
return CombineTypeStr(name, str);
}
public static void Foreach<T>(this IEnumerable<T> source, Action<T> callback)
{
foreach (var val in source)
{
callback(val);
}
}
}
#endif