File: System\Reflection\Emit\MethodBuilderImpl.cs
Web Access
Project: src\src\libraries\System.Reflection.Emit\src\System.Reflection.Emit.csproj (System.Reflection.Emit)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.InteropServices;
 
namespace System.Reflection.Emit
{
    internal sealed class MethodBuilderImpl : MethodBuilder
    {
        private Type _returnType;
        internal Type[]? _parameterTypes;
        private readonly ModuleBuilderImpl _module;
        private readonly string _name;
        private readonly CallingConventions _callingConventions;
        private readonly TypeBuilderImpl _declaringType;
        private MethodAttributes _attributes;
        private MethodImplAttributes _methodImplFlags;
        private GenericTypeParameterBuilderImpl[]? _typeParameters;
        private ILGeneratorImpl? _ilGenerator;
        private bool _initLocals;
        internal Type[]? _returnTypeRequiredModifiers;
        internal Type[]? _returnTypeOptionalCustomModifiers;
        internal Type[][]? _parameterTypeRequiredCustomModifiers;
        internal Type[][]? _parameterTypeOptionalCustomModifiers;
 
        internal bool _canBeRuntimeImpl;
        internal DllImportData? _dllImportData;
        internal List<CustomAttributeWrapper>? _customAttributes;
        internal ParameterBuilderImpl[]? _parameterBuilders;
        internal MethodDefinitionHandle _handle;
 
        internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConventions callingConventions,
            Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers,
            Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers,
            ModuleBuilderImpl module, TypeBuilderImpl declaringType)
        {
            _module = module;
            _returnType = returnType ?? _module.GetTypeFromCoreAssembly(CoreTypeId.Void);
            _name = name;
            _attributes = attributes;
 
            if ((attributes & MethodAttributes.Static) == 0)
            {
                // turn on the has this calling convention
                callingConventions |= CallingConventions.HasThis;
            }
            else if ((attributes & (MethodAttributes.Virtual | MethodAttributes.Abstract)) == MethodAttributes.Virtual)
            {
                throw new ArgumentException(SR.Argument_NoStaticVirtual);
            }
 
            _callingConventions = callingConventions;
            _declaringType = declaringType;
            _returnTypeRequiredModifiers = returnTypeRequiredCustomModifiers;
            _returnTypeOptionalCustomModifiers = returnTypeOptionalCustomModifiers;
 
            if (parameterTypes != null)
            {
                _parameterTypeRequiredCustomModifiers = parameterTypeRequiredCustomModifiers;
                _parameterTypeOptionalCustomModifiers = parameterTypeOptionalCustomModifiers;
                _parameterTypes = new Type[parameterTypes.Length];
                _parameterBuilders = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
                for (int i = 0; i < parameterTypes.Length; i++)
                {
                    ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
                }
            }
 
            _methodImplFlags = MethodImplAttributes.IL;
            _initLocals = true;
        }
 
        internal void CreateDllImportData(string dllName, string entryName, CallingConvention nativeCallConv, CharSet nativeCharSet)
        {
            _dllImportData = DllImportData.Create(dllName, entryName, nativeCallConv, nativeCharSet);
        }
 
        internal int ParameterCount => _parameterTypes == null ? 0 : _parameterTypes.Length;
 
        internal Type[]? ParameterTypes => _parameterTypes;
 
        internal ILGeneratorImpl? ILGeneratorImpl => _ilGenerator;
 
        public new bool IsConstructor
        {
            get
            {
                if ((_attributes & (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName)) != (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName))
                {
                    return false;
                }
 
                return _name.Equals(ConstructorInfo.ConstructorName) || _name.Equals(ConstructorInfo.TypeConstructorName);
            }
        }
 
        internal BlobBuilder GetMethodSignatureBlob() => MetadataSignatureHelper.GetMethodSignature(_module, _parameterTypes,
            _returnType, ModuleBuilderImpl.GetSignatureConvention(_callingConventions), GetGenericArguments().Length, !IsStatic, optionalParameterTypes: null,
            _returnTypeRequiredModifiers, _returnTypeOptionalCustomModifiers, _parameterTypeRequiredCustomModifiers, _parameterTypeOptionalCustomModifiers);
 
        protected override bool InitLocalsCore
        {
            get { ThrowIfGeneric(); return _initLocals; }
            set { ThrowIfGeneric(); _initLocals = value; }
        }
 
        private void ThrowIfGeneric() { if (IsGenericMethod && !IsGenericMethodDefinition) throw new InvalidOperationException(); }
 
        protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names)
        {
            if (_typeParameters != null)
                throw new InvalidOperationException(SR.InvalidOperation_GenericParametersAlreadySet);
 
            var typeParameters = new GenericTypeParameterBuilderImpl[names.Length];
            for (int i = 0; i < names.Length; i++)
            {
                string name = names[i];
                ArgumentNullException.ThrowIfNull(names, nameof(names));
                typeParameters[i] = new GenericTypeParameterBuilderImpl(name, i, this, _declaringType);
            }
 
            return _typeParameters = typeParameters;
        }
 
        protected override ParameterBuilder DefineParameterCore(int position, ParameterAttributes attributes, string? strParamName)
        {
            _declaringType.ThrowIfCreated();
 
            if (position > 0 && (_parameterTypes == null || position > _parameterTypes.Length))
            {
                throw new ArgumentOutOfRangeException(SR.ArgumentOutOfRange_ParamSequence);
            }
 
            _parameterBuilders ??= new ParameterBuilderImpl[1];
 
            attributes &= ~ParameterAttributes.ReservedMask;
            ParameterBuilderImpl parameter = new ParameterBuilderImpl(this, position, attributes, strParamName);
            _parameterBuilders[position] = parameter;
            return parameter;
        }
 
        protected override ILGenerator GetILGeneratorCore(int size)
        {
            if (IsGenericMethod && !IsGenericMethodDefinition)
            {
                throw new InvalidOperationException();
            }
 
            if ((_methodImplFlags & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL ||
                (_methodImplFlags & MethodImplAttributes.Unmanaged) != 0 ||
                (_attributes & MethodAttributes.PinvokeImpl) != 0)
            {
                throw new InvalidOperationException(SR.InvalidOperation_ShouldNotHaveMethodBody);
            }
 
            if ((_attributes & MethodAttributes.Abstract) != 0)
            {
                throw new InvalidOperationException(SR.InvalidOperation_ShouldNotHaveMethodBody);
            }
 
            return _ilGenerator ??= new ILGeneratorImpl(this, size);
        }
 
        internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute) =>
            SetCustomAttributeCore(con, binaryAttribute);
 
        protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
        {
            // Handle pseudo custom attributes
            switch (con.ReflectedType!.FullName)
            {
                case "System.Runtime.CompilerServices.MethodImplAttribute":
                    int implValue = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2));
                    _methodImplFlags |= (MethodImplAttributes)implValue;
                    _canBeRuntimeImpl = true;
                    return;
                case "System.Runtime.InteropServices.DllImportAttribute":
                    {
                        _dllImportData = DllImportData.Create(CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute), out var preserveSig);
                        _attributes |= MethodAttributes.PinvokeImpl;
                        _canBeRuntimeImpl = true;
                        if (preserveSig)
                        {
                            _methodImplFlags |= MethodImplAttributes.PreserveSig;
                        }
                    }
                    return;
                case "System.Runtime.InteropServices.PreserveSigAttribute":
                    _methodImplFlags |= MethodImplAttributes.PreserveSig;
                    return;
                case "System.Runtime.CompilerServices.SpecialNameAttribute":
                    _attributes |= MethodAttributes.SpecialName;
                    return;
                case "System.Security.SuppressUnmanagedCodeSecurityAttribute":
                    _attributes |= MethodAttributes.HasSecurity;
                    break;
            }
 
            _customAttributes ??= new List<CustomAttributeWrapper>();
            _customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
        }
 
        protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
        {
            _declaringType.ThrowIfCreated();
 
            _canBeRuntimeImpl = true;
            _methodImplFlags = attributes;
        }
 
        protected override void SetSignatureCore(Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers, Type[]? parameterTypes,
            Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers)
        {
            if (returnType != null)
            {
                _returnType = returnType;
                _returnTypeOptionalCustomModifiers = returnTypeOptionalCustomModifiers;
                _returnTypeRequiredModifiers = returnTypeRequiredCustomModifiers;
            }
 
            if (parameterTypes != null)
            {
                _parameterTypes = new Type[parameterTypes.Length];
                _parameterBuilders = new ParameterBuilderImpl[parameterTypes.Length + 1]; // parameter 0 reserved for return type
                for (int i = 0; i < parameterTypes.Length; i++)
                {
                    ArgumentNullException.ThrowIfNull(_parameterTypes[i] = parameterTypes[i], nameof(parameterTypes));
                }
 
                _parameterTypeOptionalCustomModifiers = parameterTypeOptionalCustomModifiers;
                _parameterTypeRequiredCustomModifiers = parameterTypeRequiredCustomModifiers;
            }
        }
 
        public override string Name => _name;
        public override MethodAttributes Attributes => _attributes;
        public override CallingConventions CallingConvention => _callingConventions;
        public override Type? DeclaringType => _declaringType._isHiddenGlobalType ? null : _declaringType;
        public override Module Module => _module;
        public override bool ContainsGenericParameters => _typeParameters != null;
        public override bool IsGenericMethod => _typeParameters != null;
        public override bool IsGenericMethodDefinition => _typeParameters != null;
        public override bool IsSecurityCritical => true;
        public override bool IsSecuritySafeCritical => false;
        public override bool IsSecurityTransparent => false;
        public override int MetadataToken => _handle == default ? 0 : MetadataTokens.GetToken(_handle);
        public override RuntimeMethodHandle MethodHandle => throw new NotSupportedException(SR.NotSupported_DynamicModule);
        public override Type? ReflectedType => DeclaringType;
        public override ParameterInfo ReturnParameter
        {
            get
            {
                if (_parameterBuilders == null || _parameterBuilders[0] == null)
                {
                    return new ParameterInfoWrapper(new ParameterBuilderImpl(this, 0, ParameterAttributes.Retval, null), _returnType);
                }
                else
                {
                    return new ParameterInfoWrapper(_parameterBuilders[0], _returnType);
                }
            }
        }
 
        public override Type ReturnType => _returnType;
        public override ICustomAttributeProvider ReturnTypeCustomAttributes { get => throw new NotImplementedException(); }
 
        public override MethodInfo GetBaseDefinition() => this;
 
        public override object[] GetCustomAttributes(bool inherit) => throw new NotSupportedException(SR.NotSupported_DynamicModule);
 
        public override object[] GetCustomAttributes(Type attributeType, bool inherit) => throw new NotSupportedException(SR.NotSupported_DynamicModule);
 
        public override Type[] GetGenericArguments() => _typeParameters ?? Type.EmptyTypes;
 
        public override MethodInfo GetGenericMethodDefinition() => !IsGenericMethod ? throw new InvalidOperationException() : this;
 
        public override MethodImplAttributes GetMethodImplementationFlags()
            => _methodImplFlags;
 
        public override ParameterInfo[] GetParameters()
        {
            // This is called from ILGenerator when Emit(OpCode, ConstructorInfo) when the ctor is
            // instance of 'ConstructorOnTypeBuilderInstantiation', so we could not throw here even
            // the type was not baked. Runtime implementation throws when the type is not baked.
 
            if (_parameterTypes == null)
            {
                return Array.Empty<ParameterInfo>();
            }
 
            _parameterBuilders ??= new ParameterBuilderImpl[_parameterTypes.Length + 1]; // parameter 0 reserved for return type
            ParameterInfo[] parameters = new ParameterInfo[_parameterTypes.Length];
 
            for (int i = 0; i < _parameterTypes.Length; i++)
            {
                if (_parameterBuilders[i + 1] == null)
                {
                    parameters[i] = new ParameterInfoWrapper(new ParameterBuilderImpl(this, i, ParameterAttributes.None, null), _parameterTypes[i]);
                }
                else
                {
                    parameters[i] = new ParameterInfoWrapper(_parameterBuilders[i + 1], _parameterTypes[i]);
                }
            }
 
            return parameters;
        }
 
        public override object Invoke(object? obj, BindingFlags invokeAttr, Binder? binder, object?[]? parameters, CultureInfo? culture)
             => throw new NotSupportedException(SR.NotSupported_DynamicModule);
 
        public override bool IsDefined(Type attributeType, bool inherit) => throw new NotSupportedException(SR.NotSupported_DynamicModule);
 
        [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")]
        [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 override MethodInfo MakeGenericMethod(params Type[] typeArguments) =>
            MethodBuilderInstantiation.MakeGenericMethod(this, typeArguments);
    }
}