225 lines
11 KiB
C#
225 lines
11 KiB
C#
|
using System;
|
||
|
using Microsoft.CodeAnalysis;
|
||
|
|
||
|
namespace Godot.SourceGenerators
|
||
|
{
|
||
|
public static class MarshalUtils
|
||
|
{
|
||
|
public class TypeCache
|
||
|
{
|
||
|
public INamedTypeSymbol GodotObjectType { get; }
|
||
|
public INamedTypeSymbol GodotGenericDictionary { get; }
|
||
|
public INamedTypeSymbol GodotGenericArray { get; }
|
||
|
public INamedTypeSymbol IDictionary { get; }
|
||
|
public INamedTypeSymbol ICollection { get; }
|
||
|
public INamedTypeSymbol GenericIDictionary { get; }
|
||
|
public INamedTypeSymbol SystemGenericDictionary { get; }
|
||
|
public INamedTypeSymbol SystemGenericList { get; }
|
||
|
|
||
|
public TypeCache(GeneratorExecutionContext context)
|
||
|
{
|
||
|
INamedTypeSymbol GetTypeByMetadataNameOrThrow(string fullyQualifiedMetadataName)
|
||
|
{
|
||
|
return context.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ??
|
||
|
throw new InvalidOperationException("Type not found: " + fullyQualifiedMetadataName);
|
||
|
}
|
||
|
|
||
|
GodotObjectType = GetTypeByMetadataNameOrThrow("Godot.Object");
|
||
|
GodotGenericDictionary = GetTypeByMetadataNameOrThrow("Godot.Collections.Dictionary`2");
|
||
|
GodotGenericArray = GetTypeByMetadataNameOrThrow("Godot.Collections.Array`1");
|
||
|
IDictionary = GetTypeByMetadataNameOrThrow("System.Collections.IDictionary");
|
||
|
ICollection = GetTypeByMetadataNameOrThrow("System.Collections.ICollection");
|
||
|
GenericIDictionary = GetTypeByMetadataNameOrThrow("System.Collections.Generic.IDictionary`2");
|
||
|
SystemGenericDictionary = GetTypeByMetadataNameOrThrow("System.Collections.Generic.Dictionary`2");
|
||
|
SystemGenericList = GetTypeByMetadataNameOrThrow("System.Collections.Generic.List`1");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static MarshalType? ConvertManagedTypeToVariantType(ITypeSymbol type, TypeCache typeCache)
|
||
|
{
|
||
|
var specialType = type.SpecialType;
|
||
|
|
||
|
switch (specialType)
|
||
|
{
|
||
|
case SpecialType.System_Boolean:
|
||
|
return MarshalType.Boolean;
|
||
|
case SpecialType.System_Char:
|
||
|
return MarshalType.Char;
|
||
|
case SpecialType.System_SByte:
|
||
|
return MarshalType.SByte;
|
||
|
case SpecialType.System_Int16:
|
||
|
return MarshalType.Int16;
|
||
|
case SpecialType.System_Int32:
|
||
|
return MarshalType.Int32;
|
||
|
case SpecialType.System_Int64:
|
||
|
return MarshalType.Int64;
|
||
|
case SpecialType.System_Byte:
|
||
|
return MarshalType.Byte;
|
||
|
case SpecialType.System_UInt16:
|
||
|
return MarshalType.UInt16;
|
||
|
case SpecialType.System_UInt32:
|
||
|
return MarshalType.UInt32;
|
||
|
case SpecialType.System_UInt64:
|
||
|
return MarshalType.UInt64;
|
||
|
case SpecialType.System_Single:
|
||
|
return MarshalType.Single;
|
||
|
case SpecialType.System_Double:
|
||
|
return MarshalType.Double;
|
||
|
case SpecialType.System_String:
|
||
|
return MarshalType.String;
|
||
|
case SpecialType.System_Object:
|
||
|
return MarshalType.SystemObject;
|
||
|
case SpecialType.System_ValueType:
|
||
|
{
|
||
|
if (type.ContainingAssembly.Name == "GodotSharp" &&
|
||
|
type.ContainingNamespace.Name == "Godot")
|
||
|
{
|
||
|
return type switch
|
||
|
{
|
||
|
{ Name: "Vector2" } => MarshalType.Vector2,
|
||
|
{ Name: "Vector2i" } => MarshalType.Vector2i,
|
||
|
{ Name: "Rect2" } => MarshalType.Rect2,
|
||
|
{ Name: "Rect2i" } => MarshalType.Rect2i,
|
||
|
{ Name: "Transform2D" } => MarshalType.Transform2D,
|
||
|
{ Name: "Vector3" } => MarshalType.Vector3,
|
||
|
{ Name: "Vector3i" } => MarshalType.Vector3i,
|
||
|
{ Name: "Basis" } => MarshalType.Basis,
|
||
|
{ Name: "Quaternion" } => MarshalType.Quaternion,
|
||
|
{ Name: "Transform3D" } => MarshalType.Transform3D,
|
||
|
{ Name: "AABB" } => MarshalType.AABB,
|
||
|
{ Name: "Color" } => MarshalType.Color,
|
||
|
{ Name: "Plane" } => MarshalType.Plane,
|
||
|
{ Name: "RID" } => MarshalType.RID,
|
||
|
{ Name: "Callable" } => MarshalType.Callable,
|
||
|
{ Name: "SignalInfo" } => MarshalType.SignalInfo,
|
||
|
{ TypeKind: TypeKind.Enum } => MarshalType.Enum,
|
||
|
_ => null
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
if (type.TypeKind == TypeKind.Array)
|
||
|
{
|
||
|
var arrayType = (IArrayTypeSymbol)type;
|
||
|
var elementType = arrayType.ElementType;
|
||
|
|
||
|
switch (elementType.SpecialType)
|
||
|
{
|
||
|
case SpecialType.System_Byte:
|
||
|
return MarshalType.ByteArray;
|
||
|
case SpecialType.System_Int32:
|
||
|
return MarshalType.Int32Array;
|
||
|
case SpecialType.System_Int64:
|
||
|
return MarshalType.Int64Array;
|
||
|
case SpecialType.System_Single:
|
||
|
return MarshalType.SingleArray;
|
||
|
case SpecialType.System_Double:
|
||
|
return MarshalType.DoubleArray;
|
||
|
case SpecialType.System_String:
|
||
|
return MarshalType.StringArray;
|
||
|
case SpecialType.System_Object:
|
||
|
return MarshalType.SystemObjectArray;
|
||
|
}
|
||
|
|
||
|
if (elementType.SimpleDerivesFrom(typeCache.GodotObjectType))
|
||
|
return MarshalType.GodotObjectOrDerivedArray;
|
||
|
|
||
|
if (type.ContainingAssembly.Name == "GodotSharp" &&
|
||
|
type.ContainingNamespace.Name == "Godot")
|
||
|
{
|
||
|
return elementType switch
|
||
|
{
|
||
|
{ Name: "Vector2" } => MarshalType.Vector2Array,
|
||
|
{ Name: "Vector3" } => MarshalType.Vector3Array,
|
||
|
{ Name: "Color" } => MarshalType.ColorArray,
|
||
|
_ => null
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
else if (type is INamedTypeSymbol { IsGenericType: true } genericType)
|
||
|
{
|
||
|
var genericTypeDef = genericType.ConstructedFrom;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.GodotGenericDictionary))
|
||
|
return MarshalType.GodotGenericDictionary;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.GodotGenericArray))
|
||
|
return MarshalType.GodotGenericArray;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.SystemGenericDictionary))
|
||
|
return MarshalType.SystemGenericDictionary;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.SystemGenericList))
|
||
|
return MarshalType.SystemGenericList;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(genericTypeDef, typeCache.GenericIDictionary))
|
||
|
return MarshalType.GenericIDictionary;
|
||
|
|
||
|
return genericTypeDef.SpecialType switch
|
||
|
{
|
||
|
SpecialType.System_Collections_Generic_ICollection_T => MarshalType.GenericICollection,
|
||
|
SpecialType.System_Collections_Generic_IEnumerable_T => MarshalType.GenericIEnumerable,
|
||
|
_ => null
|
||
|
};
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (type.SimpleDerivesFrom(typeCache.GodotObjectType))
|
||
|
return MarshalType.GodotObjectOrDerived;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(type, typeCache.IDictionary))
|
||
|
return MarshalType.IDictionary;
|
||
|
|
||
|
if (SymbolEqualityComparer.Default.Equals(type, typeCache.ICollection))
|
||
|
return MarshalType.ICollection;
|
||
|
|
||
|
if (specialType == SpecialType.System_Collections_IEnumerable)
|
||
|
return MarshalType.IEnumerable;
|
||
|
|
||
|
if (type.ContainingAssembly.Name == "GodotSharp")
|
||
|
{
|
||
|
switch (type.ContainingNamespace.Name)
|
||
|
{
|
||
|
case "Godot":
|
||
|
return type switch
|
||
|
{
|
||
|
{ Name: "StringName" } => MarshalType.StringName,
|
||
|
{ Name: "NodePath" } => MarshalType.NodePath,
|
||
|
_ => null
|
||
|
};
|
||
|
case "Godot.Collections" when !(type is INamedTypeSymbol { IsGenericType: true }):
|
||
|
return type switch
|
||
|
{
|
||
|
{ Name: "Dictionary" } => MarshalType.GodotDictionary,
|
||
|
{ Name: "Array" } => MarshalType.GodotArray,
|
||
|
_ => null
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
private static bool SimpleDerivesFrom(this ITypeSymbol? type, ITypeSymbol candidateBaseType)
|
||
|
{
|
||
|
while (type != null)
|
||
|
{
|
||
|
if (SymbolEqualityComparer.Default.Equals(type, candidateBaseType))
|
||
|
return true;
|
||
|
|
||
|
type = type.BaseType;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|