/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace dnSpy.Debugger.DotNet.Metadata.Impl { sealed class DmdMethodSpec : DmdMethodInfoBase { public override string Name => genericMethodDefinition.Name; public override DmdType? DeclaringType => genericMethodDefinition.DeclaringType; public override DmdType? ReflectedType => genericMethodDefinition.ReflectedType; public override int MetadataToken => genericMethodDefinition.MetadataToken; public override DmdMethodImplAttributes MethodImplementationFlags => genericMethodDefinition.MethodImplementationFlags; public override DmdMethodAttributes Attributes => genericMethodDefinition.Attributes; public override uint RVA => genericMethodDefinition.RVA; public override bool IsMetadataReference => false; public override bool IsGenericMethodDefinition => false; public override bool IsGenericMethod => true; readonly DmdMethodDef genericMethodDefinition; readonly DmdMethodSignature methodSignature; readonly ReadOnlyCollection genericArguments; public DmdMethodSpec(DmdMethodDef genericMethodDefinition, IList genericArguments) { this.genericMethodDefinition = genericMethodDefinition ?? throw new ArgumentNullException(nameof(genericMethodDefinition)); methodSignature = genericMethodDefinition.GetMethodSignature(genericArguments); this.genericArguments = ReadOnlyCollectionHelpers.Create(genericArguments); } public override DmdMethodInfo? Resolve(bool throwOnError) => this; public override DmdMethodSignature GetMethodSignature() => methodSignature; internal override DmdMethodInfo? GetParentDefinition() => genericMethodDefinition.GetParentDefinition(); public override ReadOnlyCollection GetGenericArguments() => genericArguments; public override DmdMethodInfo GetGenericMethodDefinition() { var method = genericMethodDefinition; if ((object?)method.ReflectedType == method.DeclaringType) return method; return method.DeclaringType!.GetMethod(method.Module, method.MetadataToken) as DmdMethodInfo ?? throw new InvalidOperationException(); } public override DmdMethodInfo MakeGenericMethod(IList typeArguments) => AppDomain.MakeGenericMethod(this, typeArguments); public override DmdMethodBody? GetMethodBody() => genericMethodDefinition.GetMethodBody(genericArguments); internal override DmdMethodBody? GetMethodBody(IList genericMethodArguments) => genericMethodDefinition.GetMethodBody(genericMethodArguments); public override ReadOnlyCollection GetCustomAttributesData() => genericMethodDefinition.GetCustomAttributesData(); public override ReadOnlyCollection GetSecurityAttributesData() => genericMethodDefinition.GetSecurityAttributesData(); public override DmdParameterInfo ReturnParameter { get { if (__parameters_DONT_USE is null) InitializeParameters(); return __returnParameter_DONT_USE!; } } public override ReadOnlyCollection GetParameters() { if (__parameters_DONT_USE is null) InitializeParameters(); return __parameters_DONT_USE!; } void InitializeParameters() { if (__parameters_DONT_USE is not null) return; var newRP = new DmdCreatedParameterInfo(this, genericMethodDefinition.ReturnParameter, methodSignature.ReturnType); var defParameters = genericMethodDefinition.GetParameters(); var paramTypes = methodSignature.GetParameterTypes(); var parameters = defParameters.Count == 0 ? Array.Empty() : new DmdParameterInfo[Math.Min(paramTypes.Count, defParameters.Count)]; for (int i = 0; i < parameters.Length; i++) parameters[i] = new DmdCreatedParameterInfo(this, defParameters[i], paramTypes[i]); lock (LockObject) { if (__parameters_DONT_USE is null) { __returnParameter_DONT_USE = newRP; __parameters_DONT_USE = ReadOnlyCollectionHelpers.Create(parameters); } } } volatile ReadOnlyCollection? __parameters_DONT_USE; volatile DmdParameterInfo? __returnParameter_DONT_USE; } }