Browse Source

#2397: Add TypeSystemExtensions.IsUnmanagedType

pull/2589/head
Siegfried Pammer 3 years ago
parent
commit
26183f798b
  1. 85
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

85
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -135,7 +135,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -135,7 +135,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
#endregion
#region IsOpen / IsUnbound / IsKnownType
#region IsOpen / IsUnbound / IsUnmanagedType / IsKnownType
sealed class TypeClassificationVisitor : TypeVisitor
{
internal bool isOpen;
@ -220,6 +220,89 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -220,6 +220,89 @@ namespace ICSharpCode.Decompiler.TypeSystem
return (type is ITypeDefinition || type is UnknownType) && type.TypeParameterCount > 0;
}
/// <summary>
/// Gets whether the type is considered unmanaged.
/// </summary>
/// <remarks>
/// The C# 6.0 spec lists the following criteria: An unmanaged type is one of the following
/// * sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool
/// * any enum type
/// * any pointer type
/// * any user-defined struct type that is not a constructed (= generic) type and contains fields of unmanaged types only.
///
/// C# 8.0 removes the restriction that constructed (= generic) types are not considered unmanaged types.
/// </remarks>
public static bool IsUnmanagedType(this IType type, bool allowGenerics)
{
HashSet<IType> types = null;
return IsUnmanagedTypeInternal(type);
bool IsUnmanagedTypeInternal(IType type)
{
if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer)
{
return true;
}
if (type is ITypeParameter tp)
{
return tp.HasUnmanagedConstraint;
}
var def = type.GetDefinition();
if (def == null)
{
return false;
}
switch (def.KnownTypeCode)
{
case KnownTypeCode.Void:
case KnownTypeCode.Boolean:
case KnownTypeCode.Char:
case KnownTypeCode.SByte:
case KnownTypeCode.Byte:
case KnownTypeCode.Int16:
case KnownTypeCode.UInt16:
case KnownTypeCode.Int32:
case KnownTypeCode.UInt32:
case KnownTypeCode.Int64:
case KnownTypeCode.UInt64:
case KnownTypeCode.Decimal:
case KnownTypeCode.Single:
case KnownTypeCode.Double:
case KnownTypeCode.IntPtr:
case KnownTypeCode.UIntPtr:
case KnownTypeCode.TypedReference:
//case KnownTypeCode.ArgIterator:
//case KnownTypeCode.RuntimeArgumentHandle:
return true;
}
if (type.Kind == TypeKind.Struct)
{
if (!allowGenerics && def.TypeParameterCount > 0)
{
return false;
}
if (types == null)
{
types = new HashSet<IType>();
}
types.Add(type);
foreach (var f in type.GetFields())
{
if (types.Contains(f.Type))
{
return false;
}
if (!IsUnmanagedTypeInternal(f.Type))
{
return false;
}
}
return true;
}
return false;
}
}
/// <summary>
/// Gets whether the type is the specified known type.
/// For generic known types, this returns true for any parameterization of the type (and also for the definition itself).

Loading…
Cancel
Save