152 lines
6.0 KiB
C#
152 lines
6.0 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Text;
|
||
|
using Mono.Cecil;
|
||
|
|
||
|
namespace zzzUnity.Burst.CodeGen
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Provides some Cecil Extensions.
|
||
|
/// </summary>
|
||
|
#if BURST_COMPILER_SHARED
|
||
|
public
|
||
|
#else
|
||
|
internal
|
||
|
#endif
|
||
|
static class CecilExtensions
|
||
|
{
|
||
|
public static void BuildAssemblyQualifiedName(this TypeReference type, StringBuilder builder)
|
||
|
{
|
||
|
if (type == null) throw new ArgumentNullException(nameof(type));
|
||
|
|
||
|
TypeReference elementType;
|
||
|
type.BuildReflectionFullName(builder, out elementType, assemblyQualified: true);
|
||
|
|
||
|
if (!(elementType is GenericParameter))
|
||
|
{
|
||
|
// Recover assembly reference from scope first (e.g for types imported), otherwise from Module.Assembly
|
||
|
var assemblyReference = elementType.Scope as AssemblyNameReference ?? elementType.Module?.Assembly?.Name;
|
||
|
if (assemblyReference != null)
|
||
|
{
|
||
|
builder.Append(", ").Append(assemblyReference);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void BuildReflectionFullName(this TypeReference type, StringBuilder builder, bool assemblyQualified)
|
||
|
{
|
||
|
BuildReflectionFullName(type, builder, out _, assemblyQualified);
|
||
|
}
|
||
|
|
||
|
public static void BuildReflectionFullName(this TypeReference type, StringBuilder builder, out TypeReference elementType, bool assemblyQualified)
|
||
|
{
|
||
|
if (type == null) throw new ArgumentNullException(nameof(type));
|
||
|
|
||
|
if (type is PointerType pointerType)
|
||
|
{
|
||
|
pointerType.ElementType.BuildReflectionFullName(builder, out elementType, assemblyQualified);
|
||
|
builder.Append("*");
|
||
|
}
|
||
|
else if (type is PinnedType pinnedType)
|
||
|
{
|
||
|
pinnedType.ElementType.BuildReflectionFullName(builder, out elementType, assemblyQualified);
|
||
|
builder.Append(" pinned");
|
||
|
}
|
||
|
else if (type is ByReferenceType byReferenceType)
|
||
|
{
|
||
|
byReferenceType.ElementType.BuildReflectionFullName(builder, out elementType, assemblyQualified);
|
||
|
builder.Append("&");
|
||
|
}
|
||
|
else if (type is ArrayType arrayType)
|
||
|
{
|
||
|
arrayType.ElementType.BuildReflectionFullName(builder, out elementType, assemblyQualified);
|
||
|
builder.Append("[]");
|
||
|
}
|
||
|
else if (type is GenericParameter genericParameter)
|
||
|
{
|
||
|
elementType = type;
|
||
|
builder.Append(genericParameter.Type == GenericParameterType.Method ? "!!" : "!");
|
||
|
builder.Append(genericParameter.Position);
|
||
|
}
|
||
|
else if (type is FunctionPointerType functionPointerType)
|
||
|
{
|
||
|
elementType = type;
|
||
|
builder.Append("delegate* ");
|
||
|
builder.Append(functionPointerType.CallingConvention switch
|
||
|
{
|
||
|
MethodCallingConvention.Default => "managed",
|
||
|
MethodCallingConvention.Unmanaged => "unmanaged",
|
||
|
MethodCallingConvention.C => "unmanaged[Cdecl]",
|
||
|
MethodCallingConvention.FastCall => "unmanaged[Fastcall]",
|
||
|
MethodCallingConvention.ThisCall => "unmanaged[Thiscall]",
|
||
|
MethodCallingConvention.StdCall => "unmanaged[Stdcall]",
|
||
|
MethodCallingConvention.Generic => "generic",
|
||
|
MethodCallingConvention.VarArg => "vararg",
|
||
|
var conv => $"<unknown calling conv: {(int)conv}>",
|
||
|
});
|
||
|
builder.Append("<");
|
||
|
for (var i = 0; i < functionPointerType.Parameters.Count; i++)
|
||
|
{
|
||
|
var param = functionPointerType.Parameters[i];
|
||
|
param.ParameterType.BuildAssemblyQualifiedName(builder);
|
||
|
builder.Append(", ");
|
||
|
}
|
||
|
|
||
|
functionPointerType.MethodReturnType.ReturnType.BuildAssemblyQualifiedName(builder);
|
||
|
builder.Append(">");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
elementType = type;
|
||
|
var types = new List<TypeReference>();
|
||
|
var declaringType = type;
|
||
|
while (declaringType != null)
|
||
|
{
|
||
|
types.Add(declaringType);
|
||
|
declaringType = declaringType.DeclaringType;
|
||
|
}
|
||
|
|
||
|
var baseType = types[types.Count - 1];
|
||
|
|
||
|
if (!string.IsNullOrEmpty(baseType.Namespace))
|
||
|
{
|
||
|
builder.Append(baseType.Namespace);
|
||
|
builder.Append(".");
|
||
|
}
|
||
|
|
||
|
builder.Append(baseType.Name);
|
||
|
for (int i = types.Count - 2; i >= 0; i--)
|
||
|
{
|
||
|
var nestedType = types[i];
|
||
|
builder.Append("+").Append(nestedType.Name);
|
||
|
}
|
||
|
|
||
|
if (elementType is GenericInstanceType genericInstanceType && genericInstanceType.HasGenericArguments)
|
||
|
{
|
||
|
builder.Append("[");
|
||
|
for (var i = 0; i < genericInstanceType.GenericArguments.Count; i++)
|
||
|
{
|
||
|
var genericArgument = genericInstanceType.GenericArguments[i];
|
||
|
if (i > 0)
|
||
|
{
|
||
|
builder.Append(",");
|
||
|
}
|
||
|
|
||
|
if (assemblyQualified)
|
||
|
{
|
||
|
builder.Append("[");
|
||
|
genericArgument.BuildAssemblyQualifiedName(builder);
|
||
|
builder.Append("]");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
genericArgument.BuildReflectionFullName(builder, out var _, assemblyQualified: true);
|
||
|
}
|
||
|
}
|
||
|
builder.Append("]");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|