File: System\Reflection\TypeLoading\Types\RoDefinitionType.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.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
 
namespace System.Reflection.TypeLoading
{
    /// <summary>
    /// Base type for all RoTypes that return true for IsTypeDefinition.
    /// </summary>
    internal abstract partial class RoDefinitionType : RoInstantiationProviderType
    {
        protected RoDefinitionType()
            : base()
        {
        }
 
        public sealed override bool IsTypeDefinition => true;
        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 IsFunctionPointer => false;
        public sealed override bool IsUnmanagedFunctionPointer => 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 => IsGenericTypeDefinition;
 
        protected sealed override string? ComputeFullName()
        {
            Debug.Assert(!IsConstructedGenericType);
            Debug.Assert(!IsGenericParameter);
            Debug.Assert(!HasElementType);
 
            string name = Name;
 
            Type? declaringType = DeclaringType;
            if (declaringType != null)
            {
                string? declaringTypeFullName = declaringType.FullName;
                return declaringTypeFullName + "+" + name;
            }
 
            string? ns = Namespace;
            if (ns == null)
                return name;
            return ns + "." + name;
        }
 
        public sealed override string ToString() => Loader.GetDisposedString() ?? FullName!;
        internal abstract int GetGenericParameterCount();
        internal abstract override RoType[] GetGenericTypeParametersNoCopy();
 
        public sealed override IEnumerable<CustomAttributeData> CustomAttributes
        {
            get
            {
                foreach (CustomAttributeData cad in GetTrueCustomAttributes())
                {
                    yield return cad;
                }
 
                if (0 != (Attributes & TypeAttributes.Import))
                {
                    ConstructorInfo? ci = Loader.TryGetComImportCtor();
                    if (ci != null)
                        yield return new RoPseudoCustomAttributeData(ci);
                }
            }
        }
 
        protected abstract IEnumerable<CustomAttributeData> GetTrueCustomAttributes();
 
        public sealed override Type GetGenericTypeDefinition() => IsGenericTypeDefinition ? this : throw new InvalidOperationException(SR.InvalidOperation_NotGenericType);
 
        internal sealed override RoType? ComputeBaseTypeWithoutDesktopQuirk() => SpecializeBaseType(Instantiation);
        internal abstract RoType? SpecializeBaseType(RoType[] instantiation);
 
        internal sealed override IEnumerable<RoType> ComputeDirectlyImplementedInterfaces() => SpecializeInterfaces(Instantiation);
        internal abstract IEnumerable<RoType> SpecializeInterfaces(RoType[] instantiation);
 
        [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)
        {
            if (typeArguments is null)
                throw new ArgumentNullException(nameof(typeArguments));
 
            if (!IsGenericTypeDefinition)
                throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this));
 
            int count = typeArguments.Length;
            if (count != GetGenericParameterCount())
                throw new ArgumentException(SR.Argument_GenericArgsCount, nameof(typeArguments));
 
            bool foundSigType = false;
            RoType[] runtimeTypeArguments = new RoType[count];
            for (int i = 0; i < count; i++)
            {
                Type typeArgument = typeArguments[i];
                if (typeArgument == null)
                    throw new ArgumentNullException();
                if (typeArgument.IsSignatureType())
                {
                    foundSigType = true;
                }
                else
                {
                    if (!(typeArgument is RoType roTypeArgument && roTypeArgument.Loader == Loader))
                        throw new ArgumentException(SR.Format(SR.MakeGenericType_NotLoadedByMetadataLoadContext, typeArgument));
                    runtimeTypeArguments[i] = roTypeArgument;
                }
            }
            if (foundSigType)
                return this.MakeSignatureGenericType(typeArguments);
 
            // We are intentionally not validating constraints as constraint validation is an execution-time issue that does not block our
            // library and should not block a metadata inspection tool.
            return this.GetUniqueConstructedGenericType(runtimeTypeArguments);
        }
 
        public sealed override Guid GUID
        {
            get
            {
                CustomAttributeData? cad = TryFindCustomAttribute(Utf8Constants.SystemRuntimeInteropServices, Utf8Constants.GuidAttribute);
                if (cad == null)
                    return default;
                IList<CustomAttributeTypedArgument> ctas = cad.ConstructorArguments;
                if (ctas.Count != 1)
                    return default;
                CustomAttributeTypedArgument cta = ctas[0];
                if (cta.ArgumentType != Loader.TryGetCoreType(CoreType.String))
                    return default;
                if (!(cta.Value is string guidString))
                    return default;
                return new Guid(guidString);
            }
        }
 
        public sealed override StructLayoutAttribute? StructLayoutAttribute
        {
            get
            {
                // Note: CoreClr checks HasElementType and IsGenericParameter in addition to IsInterface but those properties cannot be true here as this
                // RoType subclass is solely for TypeDef types.)
                if (IsInterface)
                    return null;
 
                TypeAttributes attributes = Attributes;
                LayoutKind layoutKind = (attributes & TypeAttributes.LayoutMask) switch
                {
                    TypeAttributes.ExplicitLayout => LayoutKind.Explicit,
                    TypeAttributes.AutoLayout => LayoutKind.Auto,
                    TypeAttributes.SequentialLayout => LayoutKind.Sequential,
                    _ => LayoutKind.Auto,
                };
                CharSet charSet = (attributes & TypeAttributes.StringFormatMask) switch
                {
                    TypeAttributes.AnsiClass => CharSet.Ansi,
                    TypeAttributes.AutoClass => CharSet.Auto,
                    TypeAttributes.UnicodeClass => CharSet.Unicode,
                    _ => CharSet.None,
                };
                GetPackSizeAndSize(out int pack, out int size);
 
                return new StructLayoutAttribute(layoutKind)
                {
                    CharSet = charSet,
                    Pack = pack,
                    Size = size,
                };
            }
        }
 
        protected abstract void GetPackSizeAndSize(out int packSize, out int size);
 
        protected sealed override TypeCode GetTypeCodeImpl()
        {
            Type t = IsEnum ? GetEnumUnderlyingType() : this;
            CoreTypes ct = Loader.GetAllFoundCoreTypes();
            if (t == ct[CoreType.Boolean])
                return TypeCode.Boolean;
            if (t == ct[CoreType.Char])
                return TypeCode.Char;
            if (t == ct[CoreType.SByte])
                return TypeCode.SByte;
            if (t == ct[CoreType.Byte])
                return TypeCode.Byte;
            if (t == ct[CoreType.Int16])
                return TypeCode.Int16;
            if (t == ct[CoreType.UInt16])
                return TypeCode.UInt16;
            if (t == ct[CoreType.Int32])
                return TypeCode.Int32;
            if (t == ct[CoreType.UInt32])
                return TypeCode.UInt32;
            if (t == ct[CoreType.Int64])
                return TypeCode.Int64;
            if (t == ct[CoreType.UInt64])
                return TypeCode.UInt64;
            if (t == ct[CoreType.Single])
                return TypeCode.Single;
            if (t == ct[CoreType.Double])
                return TypeCode.Double;
            if (t == ct[CoreType.String])
                return TypeCode.String;
            if (t == ct[CoreType.DateTime])
                return TypeCode.DateTime;
            if (t == ct[CoreType.Decimal])
                return TypeCode.Decimal;
            if (t == ct[CoreType.DBNull])
                return TypeCode.DBNull;
            return TypeCode.Object;
        }
 
        internal sealed override RoType? GetRoElementType() => null;
        public sealed override int GetArrayRank() => throw new ArgumentException(SR.Argument_HasToBeArrayClass);
        internal sealed override RoType[] GetGenericTypeArgumentsNoCopy() => Array.Empty<RoType>();
        protected internal sealed override RoType[] GetGenericArgumentsNoCopy() => GetGenericTypeParametersNoCopy();
        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 MethodBase DeclaringMethod => throw new InvalidOperationException(SR.Arg_NotGenericParameter);
        public sealed override Type GetFunctionPointerReturnType() => throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer);
        public sealed override Type[] GetFunctionPointerParameterTypes() => throw new InvalidOperationException(SR.InvalidOperation_NotFunctionPointer);
        internal sealed override IEnumerable<ConstructorInfo> GetConstructorsCore(NameFilter? filter) => SpecializeConstructors(filter, this);
        internal sealed override IEnumerable<MethodInfo> GetMethodsCore(NameFilter? filter, Type reflectedType) => SpecializeMethods(filter, reflectedType, this);
        internal sealed override IEnumerable<EventInfo> GetEventsCore(NameFilter? filter, Type reflectedType) => SpecializeEvents(filter, reflectedType, this);
        internal sealed override IEnumerable<FieldInfo> GetFieldsCore(NameFilter? filter, Type reflectedType) => SpecializeFields(filter, reflectedType, this);
        internal sealed override IEnumerable<PropertyInfo> GetPropertiesCore(NameFilter? filter, Type reflectedType) => SpecializeProperties(filter, reflectedType, this);
 
        // Like CoreGetDeclared but allows specifying an alternate declaringType (which must be a generic instantiation of the true declaring type)
        internal abstract IEnumerable<ConstructorInfo> SpecializeConstructors(NameFilter? filter, RoInstantiationProviderType declaringType);
        internal abstract IEnumerable<MethodInfo> SpecializeMethods(NameFilter? filter, Type reflectedType, RoInstantiationProviderType declaringType);
        internal abstract IEnumerable<EventInfo> SpecializeEvents(NameFilter? filter, Type reflectedType, RoInstantiationProviderType declaringType);
        internal abstract IEnumerable<FieldInfo> SpecializeFields(NameFilter? filter, Type reflectedType, RoInstantiationProviderType declaringType);
        internal abstract IEnumerable<PropertyInfo> SpecializeProperties(NameFilter? filter, Type reflectedType, RoInstantiationProviderType declaringType);
 
        // Helpers for the typeref-resolution/name lookup logic.
        internal abstract bool IsTypeNameEqual(ReadOnlySpan<byte> ns, ReadOnlySpan<byte> name);
        internal abstract RoDefinitionType? GetNestedTypeCore(ReadOnlySpan<byte> utf8Name);
 
        internal sealed override RoType[] Instantiation => GetGenericTypeParametersNoCopy();
    }
}