using System;
using System.Collections.Generic;
using System.Text;
using Mono.Cecil;
namespace zzzUnity.Burst.CodeGen
{
///
/// Provides some Cecil Extensions.
///
#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 => $"",
});
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();
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("]");
}
}
}
}
}