// dnlib: See LICENSE.txt for more info using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using dnlib.DotNet.MD; using dnlib.DotNet.Pdb; namespace dnlib.DotNet { /// /// A high-level representation of a row in the MethodSpec table /// public abstract class MethodSpec : IHasCustomAttribute, IHasCustomDebugInformation, IMethod, IContainsGenericParameter { /// /// The row id in its table /// protected uint rid; /// public MDToken MDToken => new MDToken(Table.MethodSpec, rid); /// public uint Rid { get => rid; set => rid = value; } /// public int HasCustomAttributeTag => 21; /// /// From column MethodSpec.Method /// public IMethodDefOrRef Method { get => method; set => method = value; } /// protected IMethodDefOrRef method; /// /// From column MethodSpec.Instantiation /// public CallingConventionSig Instantiation { get => instantiation; set => instantiation = value; } /// protected CallingConventionSig instantiation; /// /// Gets all custom attributes /// public CustomAttributeCollection CustomAttributes { get { if (customAttributes is null) InitializeCustomAttributes(); return customAttributes; } } /// protected CustomAttributeCollection customAttributes; /// Initializes protected virtual void InitializeCustomAttributes() => Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null); /// public bool HasCustomAttributes => CustomAttributes.Count > 0; /// public int HasCustomDebugInformationTag => 21; /// public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0; /// /// Gets all custom debug infos /// public IList CustomDebugInfos { get { if (customDebugInfos is null) InitializeCustomDebugInfos(); return customDebugInfos; } } /// protected IList customDebugInfos; /// Initializes protected virtual void InitializeCustomDebugInfos() => Interlocked.CompareExchange(ref customDebugInfos, new List(), null); /// MethodSig IMethod.MethodSig { get => method?.MethodSig; set { var m = method; if (m is not null) m.MethodSig = value; } } /// public UTF8String Name { get { var m = method; return m is null ? UTF8String.Empty : m.Name; } set { var m = method; if (m is not null) m.Name = value; } } /// public ITypeDefOrRef DeclaringType => method?.DeclaringType; /// /// Gets/sets the generic instance method sig /// public GenericInstMethodSig GenericInstMethodSig { get => instantiation as GenericInstMethodSig; set => instantiation = value; } /// int IGenericParameterProvider.NumberOfGenericParameters => GenericInstMethodSig?.GenericArguments.Count ?? 0; /// public ModuleDef Module => method?.Module; /// /// Gets the full name /// public string FullName { get { var methodGenArgs = GenericInstMethodSig?.GenericArguments; var m = method; if (m is MethodDef methodDef) return FullNameFactory.MethodFullName(methodDef.DeclaringType?.FullName, methodDef.Name, methodDef.MethodSig, null, methodGenArgs, null, null); if (m is MemberRef memberRef) { var methodSig = memberRef.MethodSig; if (methodSig is not null) { var gis = (memberRef.Class as TypeSpec)?.TypeSig as GenericInstSig; var typeGenArgs = gis?.GenericArguments; return FullNameFactory.MethodFullName(memberRef.GetDeclaringTypeFullName(), memberRef.Name, methodSig, typeGenArgs, methodGenArgs, null, null); } } return string.Empty; } } bool IIsTypeOrMethod.IsType => false; bool IIsTypeOrMethod.IsMethod => true; bool IMemberRef.IsField => false; bool IMemberRef.IsTypeSpec => false; bool IMemberRef.IsTypeRef => false; bool IMemberRef.IsTypeDef => false; bool IMemberRef.IsMethodSpec => true; bool IMemberRef.IsMethodDef => false; bool IMemberRef.IsMemberRef => false; bool IMemberRef.IsFieldDef => false; bool IMemberRef.IsPropertyDef => false; bool IMemberRef.IsEventDef => false; bool IMemberRef.IsGenericParam => false; bool IContainsGenericParameter.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this); /// public override string ToString() => FullName; } /// /// A MethodSpec row created by the user and not present in the original .NET file /// public class MethodSpecUser : MethodSpec { /// /// Default constructor /// public MethodSpecUser() { } /// /// Constructor /// /// The generic method public MethodSpecUser(IMethodDefOrRef method) : this(method, null) { } /// /// Constructor /// /// The generic method /// The instantiated method sig public MethodSpecUser(IMethodDefOrRef method, GenericInstMethodSig sig) { this.method = method; instantiation = sig; } } /// /// Created from a row in the MethodSpec table /// sealed class MethodSpecMD : MethodSpec, IMDTokenProviderMD, IContainsGenericParameter2 { /// The module where this instance is located readonly ModuleDefMD readerModule; readonly uint origRid; readonly GenericParamContext gpContext; /// public uint OrigRid => origRid; bool IContainsGenericParameter2.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this); /// protected override void InitializeCustomAttributes() { var list = readerModule.Metadata.GetCustomAttributeRidList(Table.MethodSpec, origRid); var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index])); Interlocked.CompareExchange(ref customAttributes, tmp, null); } /// protected override void InitializeCustomDebugInfos() { var list = new List(); readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list); Interlocked.CompareExchange(ref customDebugInfos, list, null); } /// /// Constructor /// /// The module which contains this MethodSpec row /// Row ID /// Generic parameter context /// If is null /// If is invalid public MethodSpecMD(ModuleDefMD readerModule, uint rid, GenericParamContext gpContext) { #if DEBUG if (readerModule is null) throw new ArgumentNullException("readerModule"); if (readerModule.TablesStream.MethodSpecTable.IsInvalidRID(rid)) throw new BadImageFormatException($"MethodSpec rid {rid} does not exist"); #endif origRid = rid; this.rid = rid; this.readerModule = readerModule; this.gpContext = gpContext; bool b = readerModule.TablesStream.TryReadMethodSpecRow(origRid, out var row); Debug.Assert(b); method = readerModule.ResolveMethodDefOrRef(row.Method, gpContext); instantiation = readerModule.ReadSignature(row.Instantiation, gpContext); } } }