File: System\Reflection\TypeLoading\Methods\RoDefinitionMethod.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;
 
namespace System.Reflection.TypeLoading
{
    /// <summary>
    /// Base class for all RoMethod objects created by a MetadataLoadContext that has a MethodDef token associated with it
    /// and for which IsConstructedGenericMethod returns false.
    /// </summary>
    internal abstract class RoDefinitionMethod : RoMethod
    {
        protected RoDefinitionMethod(Type reflectedType)
            : base(reflectedType)
        {
            Debug.Assert(reflectedType != null);
        }
 
        internal abstract MethodSig<RoParameter> SpecializeMethodSig(IRoMethodBase member);
        internal abstract MethodSig<string> SpecializeMethodSigStrings(in TypeContext typeContext);
        internal abstract MethodBody? SpecializeMethodBody(IRoMethodBase owner);
    }
 
    /// <summary>
    /// Class for all RoMethod objects created by a MetadataLoadContext that has a MethodDef token associated with it
    /// and for which IsConstructedGenericMethod returns false.
    /// </summary>
    internal sealed partial class RoDefinitionMethod<TMethodDecoder> : RoDefinitionMethod where TMethodDecoder : IMethodDecoder
    {
        private readonly RoInstantiationProviderType _declaringType;
        private readonly TMethodDecoder _decoder;
 
        internal RoDefinitionMethod(RoInstantiationProviderType declaringType, Type reflectedType, TMethodDecoder decoder)
            : base(reflectedType)
        {
            Debug.Assert(declaringType != null);
            _declaringType = declaringType;
            _decoder = decoder;
        }
 
        internal sealed override RoType GetRoDeclaringType() => _declaringType;
        internal sealed override RoModule GetRoModule() => _decoder.GetRoModule();
 
        protected sealed override string ComputeName() => _decoder.ComputeName();
        public sealed override int MetadataToken => _decoder.MetadataToken;
 
        public sealed override IEnumerable<CustomAttributeData> CustomAttributes
        {
            get
            {
                foreach (CustomAttributeData cad in _decoder.ComputeTrueCustomAttributes())
                    yield return cad;
 
                if ((MethodImplementationFlags & MethodImplAttributes.PreserveSig) != 0)
                {
                    ConstructorInfo? ci = Loader.TryGetPreserveSigCtor();
                    if (ci != null)
                        yield return new RoPseudoCustomAttributeData(ci);
                }
 
                CustomAttributeData? dllImportCustomAttribute = ComputeDllImportCustomAttributeDataIfAny();
                if (dllImportCustomAttribute != null)
                    yield return dllImportCustomAttribute;
            }
        }
 
        protected sealed override MethodAttributes ComputeAttributes() => _decoder.ComputeAttributes();
        protected sealed override CallingConventions ComputeCallingConvention() => _decoder.ComputeCallingConvention();
        protected sealed override MethodImplAttributes ComputeMethodImplementationFlags() => _decoder.ComputeMethodImplementationFlags();
        protected sealed override MethodSig<RoParameter> ComputeMethodSig() => _decoder.SpecializeMethodSig(this);
        public sealed override MethodBody? GetMethodBody() => _decoder.SpecializeMethodBody(this);
        protected sealed override MethodSig<string> ComputeMethodSigStrings() => _decoder.SpecializeMethodSigStrings(TypeContext);
 
        public sealed override bool Equals([NotNullWhen(true)] object? obj)
        {
            if (!(obj is RoDefinitionMethod<TMethodDecoder> other))
                return false;
 
            if (MetadataToken != other.MetadataToken)
                return false;
 
            if (DeclaringType != other.DeclaringType)
                return false;
 
            if (ReflectedType != other.ReflectedType)
                return false;
 
            return true;
        }
 
        public sealed override int GetHashCode() => MetadataToken.GetHashCode() ^ DeclaringType.GetHashCode();
 
        public sealed override bool IsConstructedGenericMethod => false;
        public sealed override bool IsGenericMethodDefinition => GetGenericTypeParametersNoCopy().Length != 0;
        public sealed override MethodInfo GetGenericMethodDefinition() => IsGenericMethodDefinition ? this : throw new InvalidOperationException(); // Very uninformative but compatible exception
 
        [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 MethodInfo MakeGenericMethod(params Type[] typeArguments)
        {
            if (typeArguments is null)
                throw new ArgumentNullException(nameof(typeArguments));
 
            if (!IsGenericMethodDefinition)
                throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericMethodDefinition, this));
 
            int count = typeArguments.Length;
            RoType[] roTypeArguments = new RoType[count];
            for (int i = 0; i < count; i++)
            {
                Type typeArgument = typeArguments[i];
                if (typeArgument == null)
                    throw new ArgumentNullException();
 
                if (!(typeArgument is RoType roTypeArgument && roTypeArgument.Loader == Loader))
                    throw new ArgumentException(SR.Format(SR.MakeGenericType_NotLoadedByMetadataLoadContext, typeArgument));
 
                roTypeArguments[i] = roTypeArgument;
            }
 
            if (count != GetGenericTypeParametersNoCopy().Length)
                throw new ArgumentException(SR.Argument_GenericArgsCount, nameof(typeArguments));
 
            return new RoConstructedGenericMethod(this, roTypeArguments);
        }
 
        internal sealed override RoType[] GetGenericTypeArgumentsNoCopy() => Array.Empty<RoType>();
        internal sealed override RoType[] GetGenericTypeParametersNoCopy() => GetGenericArgumentsOrParametersNoCopy();
 
        protected sealed override RoType[] ComputeGenericArgumentsOrParameters() => _decoder.ComputeGenericArgumentsOrParameters();
 
        // Used by RoConstructedGenericMethod to construct instantiated versions of method properties.
        internal sealed override MethodSig<RoParameter> SpecializeMethodSig(IRoMethodBase member) => _decoder.SpecializeMethodSig(member);
        internal sealed override MethodSig<string> SpecializeMethodSigStrings(in TypeContext typeContext) => _decoder.SpecializeMethodSigStrings(typeContext);
        internal sealed override MethodBody? SpecializeMethodBody(IRoMethodBase owner) => _decoder.SpecializeMethodBody(owner);
 
        public sealed override TypeContext TypeContext => new TypeContext(_declaringType.Instantiation, GetGenericTypeParametersNoCopy());
    }
}