File: src\libraries\System.Private.CoreLib\src\System\Reflection\Emit\SymbolType.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using CultureInfo = System.Globalization.CultureInfo;
 
namespace System.Reflection.Emit
{
    internal enum TypeKind
    {
        IsArray = 1,
        IsPointer = 2,
        IsByRef = 3,
    }
 
    // This is a kind of Type object that will represent the compound expression of a parameter type or field type.
    internal sealed partial class SymbolType : TypeInfo
    {
        #region Data Members
        #region Fields need to be kept in order
        // For Mono runtime its important to keep this declaration order in sync with MonoReflectionSymbolType struct in object-internals.h
        internal Type _baseType = null!;
        internal TypeKind _typeKind;
        internal int _rank;        // count of dimension
        #endregion
        // If LowerBound and UpperBound is equal, that means one element.
        // If UpperBound is less than LowerBound, then the size is not specified.
        internal int[] _iaLowerBound;
        internal int[] _iaUpperBound; // count of dimension
        private string? _format;      // format string to form the full name.
        private bool _isSzArray = true;
        #endregion
 
        public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
        {
            if (typeInfo == null) return false;
            return IsAssignableFrom(typeInfo.AsType());
        }
 
        #region Static Members
        internal static Type? FormCompoundType(string? format, Type baseType, int curIndex)
        {
            // This function takes a string to describe the compound type, such as "[,][]", and a baseType.
            //
            // Example: [2..4]  - one dimension array with lower bound 2 and size of 3
            // Example: [3, 5, 6] - three dimension array with lower bound 3, 5, 6
            // Example: [-3, ] [] - one dimensional array of two dimensional array (with lower bound -3 for
            //          the first dimension)
            // Example: []* - pointer to a one dimensional array
            // Example: *[] - one dimensional array. The element type is a pointer to the baseType
            // Example: []& - ByRef of a single dimensional array. Only one & is allowed and it must appear the last!
            // Example: [?] - Array with unknown bound
 
            SymbolType symbolType;
            int iLowerBound;
            int iUpperBound;
 
            if (format == null || curIndex == format.Length)
            {
                // we have consumed all of the format string
                return baseType;
            }
 
            if (format[curIndex] == '&')
            {
                // ByRef case
 
                symbolType = new SymbolType(baseType, TypeKind.IsByRef);
                symbolType.SetFormat(format, curIndex, 1);
                curIndex++;
 
                if (curIndex != format.Length)
                    // ByRef has to be the last char!!
                    throw new ArgumentException(SR.Argument_BadSigFormat);
 
                return symbolType;
            }
 
            if (format[curIndex] == '[')
            {
                // Array type.
                symbolType = new SymbolType(baseType, TypeKind.IsArray);
                int startIndex = curIndex;
                curIndex++;
 
                iLowerBound = 0;
                iUpperBound = -1;
 
                // Example: [2..4]  - one dimension array with lower bound 2 and size of 3
                // Example: [3, 5, 6] - three dimension array with lower bound 3, 5, 6
                // Example: [-3, ] [] - one dimensional array of two dimensional array (with lower bound -3 sepcified)
 
                while (format[curIndex] != ']')
                {
                    if (format[curIndex] == '*')
                    {
                        symbolType._isSzArray = false;
                        curIndex++;
                    }
                    // consume, one dimension at a time
                    if (char.IsAsciiDigit(format[curIndex]) || format[curIndex] == '-')
                    {
                        bool isNegative = false;
                        if (format[curIndex] == '-')
                        {
                            isNegative = true;
                            curIndex++;
                        }
 
                        // lower bound is specified. Consume the low bound
                        while (char.IsAsciiDigit(format[curIndex]))
                        {
                            iLowerBound *= 10;
                            iLowerBound += format[curIndex] - '0';
                            curIndex++;
                        }
 
                        if (isNegative)
                        {
                            iLowerBound = 0 - iLowerBound;
                        }
 
                        // set the upper bound to be less than LowerBound to indicate that upper bound it not specified yet!
                        iUpperBound = iLowerBound - 1;
                    }
                    if (format[curIndex] == '.')
                    {
                        // upper bound is specified
 
                        // skip over ".."
                        curIndex++;
                        if (format[curIndex] != '.')
                        {
                            // bad format!! Throw exception
                            throw new ArgumentException(SR.Argument_BadSigFormat);
                        }
 
                        curIndex++;
                        // consume the upper bound
                        if (char.IsAsciiDigit(format[curIndex]) || format[curIndex] == '-')
                        {
                            bool isNegative = false;
                            iUpperBound = 0;
                            if (format[curIndex] == '-')
                            {
                                isNegative = true;
                                curIndex++;
                            }
 
                            // lower bound is specified. Consume the low bound
                            while (char.IsAsciiDigit(format[curIndex]))
                            {
                                iUpperBound *= 10;
                                iUpperBound += format[curIndex] - '0';
                                curIndex++;
                            }
                            if (isNegative)
                            {
                                iUpperBound = 0 - iUpperBound;
                            }
                            if (iUpperBound < iLowerBound)
                            {
                                // User specified upper bound less than lower bound, this is an error.
                                // Throw error exception.
                                throw new ArgumentException(SR.Argument_BadSigFormat);
                            }
                        }
                    }
 
                    if (format[curIndex] == ',')
                    {
                        // We have more dimension to deal with.
                        // now set the lower bound, the size, and increase the dimension count!
                        curIndex++;
                        symbolType.SetBounds(iLowerBound, iUpperBound);
 
                        // clear the lower and upper bound information for next dimension
                        iLowerBound = 0;
                        iUpperBound = -1;
                    }
                    else if (format[curIndex] != ']')
                    {
                        throw new ArgumentException(SR.Argument_BadSigFormat);
                    }
                }
 
                // The last dimension information
                symbolType.SetBounds(iLowerBound, iUpperBound);
 
                // skip over ']'
                curIndex++;
 
                symbolType.SetFormat(format, startIndex, curIndex - startIndex);
 
                return FormCompoundType(format, symbolType, curIndex);
            }
            else if (format[curIndex] == '*')
            {
                // pointer type.
 
                symbolType = new SymbolType(baseType, TypeKind.IsPointer);
                symbolType.SetFormat(format, curIndex, 1);
                curIndex++;
                return FormCompoundType(format, symbolType, curIndex);
            }
 
            return null;
        }
 
        #endregion
 
        #region Constructor
        internal SymbolType(Type baseType, TypeKind typeKind)
        {
            ArgumentNullException.ThrowIfNull(baseType);
 
            _baseType = baseType;
            _typeKind = typeKind;
            _iaLowerBound = new int[4];
            _iaUpperBound = new int[4];
        }
 
        #endregion
 
        #region Internal Members
        private void SetBounds(int lower, int upper)
        {
            // Increase the rank, set lower and upper bound
 
            if (lower != 0 || upper != -1)
                _isSzArray = false;
 
            if (_iaLowerBound.Length <= _rank)
            {
                // resize the bound array
                int[] iaTemp = new int[_rank * 2];
                Array.Copy(_iaLowerBound, iaTemp, _rank);
                _iaLowerBound = iaTemp;
                Array.Copy(_iaUpperBound, iaTemp, _rank);
                _iaUpperBound = iaTemp;
            }
 
            _iaLowerBound[_rank] = lower;
            _iaUpperBound[_rank] = upper;
            _rank++;
        }
 
        internal void SetFormat(string format, int curIndex, int length)
        {
            // Cache the text display format for this SymbolType
 
            _format = format.Substring(curIndex, length);
        }
        #endregion
 
        #region Type Overrides
 
        public override bool IsTypeDefinition => false;
 
        public override bool IsSZArray => _rank <= 1 && _isSzArray;
 
        public override Type? GetNullableUnderlyingType() => null;
 
        public override Type MakePointerType()
        {
            return FormCompoundType(_format + "*", _baseType, 0)!;
        }
 
        public override Type MakeByRefType()
        {
            return FormCompoundType(_format + "&", _baseType, 0)!;
        }
 
        [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
        public override Type MakeArrayType()
        {
            return FormCompoundType(_format + "[]", _baseType, 0)!;
        }
 
        [RequiresDynamicCode("The code for an array of the specified type might not be available.")]
        public override Type MakeArrayType(int rank)
        {
            string s = FormatRank(rank);
            SymbolType? st = FormCompoundType(_format + s, _baseType, 0) as SymbolType;
            return st!;
        }
 
        internal static string FormatRank(int rank)
        {
            if (rank <= 0)
            {
                throw new IndexOutOfRangeException();
            }
 
            return rank == 1 ? "[*]" : "[" + new string(',', rank - 1) + "]";
        }
 
        public override int GetArrayRank()
        {
            if (!IsArray)
                throw new ArgumentException(SR.Argument_HasToBeArrayClass);
 
            return _rank;
        }
 
        public override Guid GUID => throw new NotSupportedException(SR.NotSupported_NonReflectedType);
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
            DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
            DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
            DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
        public override object InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target,
            object?[]? args, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParameters)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        public override Module Module
        {
            get
            {
                Type baseType;
 
                for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType) ;
 
                return baseType.Module;
            }
        }
        public override Assembly Assembly
        {
            get
            {
                Type baseType;
 
                for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType) ;
 
                return baseType.Assembly;
            }
        }
 
        public override RuntimeTypeHandle TypeHandle => throw new NotSupportedException(SR.NotSupported_NonReflectedType);
 
        public override string Name
        {
            get
            {
                Type baseType;
                string? sFormat = _format;
 
                for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType)
                    sFormat = ((SymbolType)baseType)._format + sFormat;
 
                return baseType.Name + sFormat;
            }
        }
 
        public override string? FullName => TypeNameBuilder.ToString(this, TypeNameBuilder.Format.FullName);
 
        public override string? AssemblyQualifiedName => TypeNameBuilder.ToString(this, TypeNameBuilder.Format.AssemblyQualifiedName);
 
        public override string ToString()
        {
            return TypeNameBuilder.ToString(this, TypeNameBuilder.Format.ToString)!;
        }
 
        public override string? Namespace => _baseType.Namespace;
 
        public override Type BaseType => typeof(Array);
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
        protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder? binder,
                CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
        public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
        protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder,
                CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
        public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
        public override FieldInfo GetField(string name, BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
        public override FieldInfo[] GetFields(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
        public override Type GetInterface(string name, bool ignoreCase)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
        public override Type[] GetInterfaces()
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
        public override EventInfo GetEvent(string name, BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents)]
        public override EventInfo[] GetEvents()
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
        protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder,
                Type? returnType, Type[]? types, ParameterModifier[]? modifiers)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
        public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
        public override Type[] GetNestedTypes(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
        public override Type GetNestedType(string name, BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(GetAllMembersInternal)]
        public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(GetAllMembersInternal)]
        public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        private const DynamicallyAccessedMemberTypes GetAllMembersInternal = DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
            DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
            DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
            DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
            DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
            DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
 
        public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type interfaceType)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
        public override EventInfo[] GetEvents(BindingFlags bindingAttr)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        protected override TypeAttributes GetAttributeFlagsImpl()
        {
            // Return the attribute flags of the base type?
            Type baseType;
            for (baseType = _baseType; baseType is SymbolType; baseType = ((SymbolType)baseType)._baseType) ;
            return baseType.Attributes;
        }
 
        protected override bool IsArrayImpl()
        {
            return _typeKind == TypeKind.IsArray;
        }
 
        protected override bool IsPointerImpl()
        {
            return _typeKind == TypeKind.IsPointer;
        }
 
        protected override bool IsByRefImpl()
        {
            return _typeKind == TypeKind.IsByRef;
        }
 
        protected override bool IsPrimitiveImpl()
        {
            return false;
        }
 
        protected override bool IsValueTypeImpl()
        {
            return false;
        }
 
        protected override bool IsCOMObjectImpl()
        {
            return false;
        }
 
        public override bool IsConstructedGenericType => false;
 
        public override Type? GetElementType()
        {
            return _baseType;
        }
 
        protected override bool HasElementTypeImpl()
        {
            return _baseType != null;
        }
 
        public override Type UnderlyingSystemType => this;
 
        public override object[] GetCustomAttributes(bool inherit)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        public override object[] GetCustomAttributes(Type attributeType, bool inherit)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
 
        public override bool IsDefined(Type attributeType, bool inherit)
        {
            throw new NotSupportedException(SR.NotSupported_NonReflectedType);
        }
        #endregion
    }
}