File: System\Reflection\TypeLoading\Types\RoFunctionPointerType.cs
Web Access
Project: src\src\libraries\System.Reflection.MetadataLoadContext\src\System.Reflection.MetadataLoadContext.csproj (System.Reflection.MetadataLoadContext)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using System.Reflection.TypeLoading.Ecma;
using System.Text;
using StructLayoutAttribute = System.Runtime.InteropServices.StructLayoutAttribute;
 
namespace System.Reflection.TypeLoading
{
    /// <summary>
    /// All RoTypes that return true for IsFunctionPointer.
    /// </summary>
    internal sealed class RoFunctionPointerType : RoType
    {
        private readonly EcmaModule _module;
        private readonly SignatureCallingConvention _callKind;
        private readonly bool _isUnmanaged;
        internal readonly Type _returnType;
        internal readonly Type[] _parameterTypes;
 
        private volatile string? _toString;
 
        private string GetToString() => _toString ??= ComputeToString();
 
        internal RoFunctionPointerType(EcmaModule module, MethodSignature<RoType> signature)
        {
            Debug.Assert(module != null);
 
            _module = module;
            _returnType = signature.ReturnType;
 
            ImmutableArray<RoType> sigParameterTypes = signature.ParameterTypes;
            _parameterTypes = new RoType[sigParameterTypes.Length];
            for (int i = 0; i < sigParameterTypes.Length; i++)
            {
                _parameterTypes[i] = sigParameterTypes[i];
            }
 
            _callKind = GetCallingConvention(signature, out _isUnmanaged);
        }
 
        public sealed override bool IsFunctionPointer => true;
        public sealed override bool IsUnmanagedFunctionPointer => _isUnmanaged;
        public sealed override Type GetFunctionPointerReturnType() => _returnType.UnderlyingSystemType;
        public sealed override Type[] GetFunctionPointerParameterTypes() => _parameterTypes.CloneArrayToUnmodifiedTypes();
        protected sealed override string? ComputeFullName() => null;
        protected sealed override string ComputeName() => string.Empty;
 
        internal static SignatureCallingConvention GetCallingConvention(MethodSignature<RoType> signature, out bool isUnmanaged)
        {
            SignatureCallingConvention callKind = signature.Header.CallingConvention;
 
            isUnmanaged = false;
 
            switch (callKind)
            {
                case SignatureCallingConvention.CDecl:
                case SignatureCallingConvention.StdCall:
                case SignatureCallingConvention.ThisCall:
                case SignatureCallingConvention.FastCall:
                case SignatureCallingConvention.Unmanaged:
                    isUnmanaged = true;
                    break;
            }
 
            return callKind;
        }
 
        internal SignatureCallingConvention CallKind => _callKind;
 
        private string ComputeToString()
        {
            Type t = _returnType;
            StringBuilder sb = new(t.ToString());
            sb.Append('(');
            AppendParameters(sb);
            sb.Append(')');
            return sb.ToString();
 
            void AppendParameters(StringBuilder sb)
            {
                for (int i = 0; i < _parameterTypes.Length; i++)
                {
                    if (i != 0)
                    {
                        sb.Append(", ");
                    }
 
                    sb.Append(_parameterTypes[i].ToString());
                }
            }
        }
 
        protected sealed override string? ComputeNamespace() => null;
        public sealed override string ToString() => GetToString();
        public sealed override string? AssemblyQualifiedName => null;
 
        internal sealed override RoModule GetRoModule() => _module;
        public sealed override int GetHashCode()
        {
            return ToString().GetHashCode();
        }
 
        public sealed override bool Equals([NotNullWhen(true)] Type? type) => Equals((object?)type);
        public sealed override bool Equals([NotNullWhen(true)] object? obj)
        {
            // Treat as an unmodified type; do not not include the modified type values including
            // calling conventions and custom modifiers.
 
            if (obj is not RoFunctionPointerType other)
                return false;
 
            if (GetFunctionPointerReturnType() != other.GetFunctionPointerReturnType())
                return false;
 
            if (IsUnmanagedFunctionPointer != other.IsUnmanagedFunctionPointer)
                return false;
 
            Type[] args = GetFunctionPointerParameterTypes();
            Type[] otherArgs = other.GetFunctionPointerParameterTypes();
            if (!args.Length.Equals(otherArgs.Length))
                return false;
 
            for (int i = 0; i < args.Length; i++)
            {
                if (args[i] != otherArgs[i])
                    return false;
            }
 
            return true;
        }
 
        public sealed override bool IsTypeDefinition => false;
        public sealed override bool IsGenericTypeDefinition => false;
        protected sealed override bool HasElementTypeImpl() => false;
        protected sealed override bool IsArrayImpl() => false;
        public sealed override bool IsSZArray => false;
        public sealed override bool IsVariableBoundArray => false;
        protected sealed override bool IsByRefImpl() => false;
        protected sealed override bool IsPointerImpl() => false;
        public sealed override bool IsConstructedGenericType => false;
        public sealed override bool IsGenericParameter => false;
        public sealed override bool IsGenericTypeParameter => false;
        public sealed override bool IsGenericMethodParameter => false;
 
        public sealed override bool ContainsGenericParameters
        {
            get
            {
                if (_returnType.ContainsGenericParameters)
                    return true;
 
                foreach (Type parameterType in _parameterTypes)
                {
                    if (parameterType.ContainsGenericParameters)
                        return true;
                }
 
                return false;
            }
        }
 
        protected sealed override TypeCode GetTypeCodeImpl() => TypeCode.Object;
 
        public sealed override int GetArrayRank() => throw new ArgumentException(SR.Argument_HasToBeArrayClass);
 
        public sealed override MethodBase DeclaringMethod => throw new InvalidOperationException(SR.Arg_NotGenericParameter);
        protected sealed override RoType? ComputeDeclaringType() => null;
 
        public sealed override IEnumerable<CustomAttributeData> CustomAttributes => Array.Empty<CustomAttributeData>();
        internal sealed override bool IsCustomAttributeDefined(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name) => false;
        internal sealed override CustomAttributeData? TryFindCustomAttribute(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name) => null;
 
        public sealed override int MetadataToken => 0x02000000; // nil TypeDef token
 
        internal sealed override RoType? GetRoElementType() => null;
 
        public sealed override Type GetGenericTypeDefinition() => throw new InvalidOperationException(SR.InvalidOperation_NotGenericType);
        internal sealed override RoType[] GetGenericTypeParametersNoCopy() => Array.Empty<RoType>();
        internal sealed override RoType[] GetGenericTypeArgumentsNoCopy() => Array.Empty<RoType>();
        protected internal sealed override RoType[] GetGenericArgumentsNoCopy() => Array.Empty<RoType>();
        [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
        public sealed override Type MakeGenericType(params Type[] typeArguments) => throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this));
 
        public sealed override GenericParameterAttributes GenericParameterAttributes => throw new InvalidOperationException(SR.Arg_NotGenericParameter);
        public sealed override int GenericParameterPosition => throw new InvalidOperationException(SR.Arg_NotGenericParameter);
        public sealed override Type[] GetGenericParameterConstraints() => throw new InvalidOperationException(SR.Arg_NotGenericParameter);
 
        public sealed override Guid GUID => Guid.Empty;
        public sealed override StructLayoutAttribute? StructLayoutAttribute => null;
        protected internal sealed override RoType ComputeEnumUnderlyingType() => throw new ArgumentException(SR.Arg_MustBeEnum);
 
        // Low level support for the BindingFlag-driven enumerator apis.
        internal sealed override IEnumerable<EventInfo> GetEventsCore(NameFilter? filter, Type reflectedType) => Array.Empty<EventInfo>();
        internal sealed override IEnumerable<FieldInfo> GetFieldsCore(NameFilter? filter, Type reflectedType) => Array.Empty<FieldInfo>();
        internal sealed override IEnumerable<PropertyInfo> GetPropertiesCore(NameFilter? filter, Type reflectedType) => Array.Empty<PropertyInfo>();
        internal sealed override IEnumerable<RoType> GetNestedTypesCore(NameFilter? filter) => Array.Empty<RoType>();
 
 
        protected sealed override TypeAttributes ComputeAttributeFlags() => TypeAttributes.Public;
 
        internal sealed override RoType? ComputeBaseTypeWithoutDesktopQuirk() => null;
        internal sealed override IEnumerable<RoType> ComputeDirectlyImplementedInterfaces() => Array.Empty<RoType>();
 
        internal sealed override IEnumerable<ConstructorInfo> GetConstructorsCore(NameFilter? filter) => Array.Empty<ConstructorInfo>();
        internal sealed override IEnumerable<MethodInfo> GetMethodsCore(NameFilter? filter, Type reflectedType) => Array.Empty<MethodInfo>();
    }
}