// dnlib: See LICENSE.txt for more info using System; using System.Threading; using dnlib.Utils; using dnlib.PE; using dnlib.DotNet.MD; using dnlib.DotNet.Emit; using dnlib.Threading; using dnlib.DotNet.Pdb; using System.Collections.Generic; using System.Diagnostics; namespace dnlib.DotNet { /// /// A high-level representation of a row in the Method table /// public abstract class MethodDef : IHasCustomAttribute, IHasDeclSecurity, IMemberRefParent, IMethodDefOrRef, IMemberForwarded, ICustomAttributeType, ITypeOrMethodDef, IManagedEntryPoint, IHasCustomDebugInformation, IListListener, IListListener, IMemberDef { internal static readonly UTF8String StaticConstructorName = ".cctor"; internal static readonly UTF8String InstanceConstructorName = ".ctor"; /// /// The row id in its table /// protected uint rid; #if THREAD_SAFE readonly Lock theLock = Lock.Create(); #endif /// /// All parameters /// protected ParameterList parameterList; /// public MDToken MDToken => new MDToken(Table.Method, rid); /// public uint Rid { get => rid; set => rid = value; } /// public int HasCustomAttributeTag => 0; /// public int HasDeclSecurityTag => 1; /// public int MemberRefParentTag => 3; /// public int MethodDefOrRefTag => 0; /// public int MemberForwardedTag => 1; /// public int CustomAttributeTypeTag => 2; /// public int TypeOrMethodDefTag => 1; /// /// From column Method.RVA /// public RVA RVA { get => rva; set => rva = value; } /// protected RVA rva; /// /// From column Method.ImplFlags /// public MethodImplAttributes ImplAttributes { get => (MethodImplAttributes)implAttributes; set => implAttributes = (int)value; } /// Implementation attributes protected int implAttributes; /// /// From column Method.Flags /// public MethodAttributes Attributes { get => (MethodAttributes)attributes; set => attributes = (int)value; } /// Attributes protected int attributes; /// /// From column Method.Name /// public UTF8String Name { get => name; set => name = value; } /// Name protected UTF8String name; /// /// From column Method.Signature /// public CallingConventionSig Signature { get => signature; set => signature = value; } /// protected CallingConventionSig signature; /// /// From column Method.ParamList /// public IList ParamDefs { get { if (paramDefs is null) InitializeParamDefs(); return paramDefs; } } /// protected LazyList paramDefs; /// Initializes protected virtual void InitializeParamDefs() => Interlocked.CompareExchange(ref paramDefs, new LazyList(this), null); /// public IList GenericParameters { get { if (genericParameters is null) InitializeGenericParameters(); return genericParameters; } } /// protected LazyList genericParameters; /// Initializes protected virtual void InitializeGenericParameters() => Interlocked.CompareExchange(ref genericParameters, new LazyList(this), null); /// public IList DeclSecurities { get { if (declSecurities is null) InitializeDeclSecurities(); return declSecurities; } } /// protected IList declSecurities; /// Initializes protected virtual void InitializeDeclSecurities() => Interlocked.CompareExchange(ref declSecurities, new List(), null); /// public ImplMap ImplMap { get { if (!implMap_isInitialized) InitializeImplMap(); return implMap; } set { #if THREAD_SAFE theLock.EnterWriteLock(); try { #endif implMap = value; implMap_isInitialized = true; #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } #endif } } /// protected ImplMap implMap; /// protected bool implMap_isInitialized; void InitializeImplMap() { #if THREAD_SAFE theLock.EnterWriteLock(); try { #endif if (implMap_isInitialized) return; implMap = GetImplMap_NoLock(); implMap_isInitialized = true; #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } #endif } /// Called to initialize protected virtual ImplMap GetImplMap_NoLock() => null; /// Reset protected void ResetImplMap() => implMap_isInitialized = false; /// /// Gets/sets the method body. See also /// public MethodBody MethodBody { get { if (!methodBody_isInitialized) InitializeMethodBody(); return methodBody; } set { #if THREAD_SAFE theLock.EnterWriteLock(); try { #endif methodBody = value; methodBody_isInitialized = true; #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } #endif } } /// protected MethodBody methodBody; /// protected bool methodBody_isInitialized; void InitializeMethodBody() { #if THREAD_SAFE theLock.EnterWriteLock(); try { #endif if (methodBody_isInitialized) return; methodBody = GetMethodBody_NoLock(); methodBody_isInitialized = true; #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } #endif } /// /// Frees the method body if it has been loaded. This does nothing if /// returns false. /// public void FreeMethodBody() { if (!CanFreeMethodBody) return; if (!methodBody_isInitialized) return; #if THREAD_SAFE theLock.EnterWriteLock(); try { #endif methodBody = null; methodBody_isInitialized = false; #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } #endif } /// Called to initialize protected virtual MethodBody GetMethodBody_NoLock() => null; /// /// true if can free the method body /// protected virtual bool CanFreeMethodBody => true; /// /// 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 int HasCustomDebugInformationTag => 0; /// 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); /// /// Gets the methods this method implements /// public IList Overrides { get { if (overrides is null) InitializeOverrides(); return overrides; } } /// protected IList overrides; /// Initializes protected virtual void InitializeOverrides() => Interlocked.CompareExchange(ref overrides, new List(), null); /// /// Gets the export info or null if the method isn't exported to unmanaged code. /// public MethodExportInfo ExportInfo { get => exportInfo; set => exportInfo = value; } /// protected MethodExportInfo exportInfo; /// public bool HasCustomAttributes => CustomAttributes.Count > 0; /// public bool HasDeclSecurities => DeclSecurities.Count > 0; /// /// true if is not empty /// public bool HasParamDefs => ParamDefs.Count > 0; /// /// Gets/sets the declaring type (owner type) /// public TypeDef DeclaringType { get => declaringType2; set { var currentDeclaringType = DeclaringType2; if (currentDeclaringType == value) return; if (currentDeclaringType is not null) currentDeclaringType.Methods.Remove(this); // Will set DeclaringType2 = null if (value is not null) value.Methods.Add(this); // Will set DeclaringType2 = value } } /// ITypeDefOrRef IMemberRef.DeclaringType => declaringType2; /// /// Called by and should normally not be called by any user /// code. Use instead. Only call this if you must set the /// declaring type without inserting it in the declaring type's method list. /// public TypeDef DeclaringType2 { get => declaringType2; set => declaringType2 = value; } /// protected TypeDef declaringType2; /// public ModuleDef Module => declaringType2?.Module; 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 => false; bool IMemberRef.IsMethodDef => true; bool IMemberRef.IsMemberRef => false; bool IMemberRef.IsFieldDef => false; bool IMemberRef.IsPropertyDef => false; bool IMemberRef.IsEventDef => false; bool IMemberRef.IsGenericParam => false; /// /// Gets/sets the CIL method body. See also /// public CilBody Body { get { if (!methodBody_isInitialized) InitializeMethodBody(); return methodBody as CilBody; } set => MethodBody = value; } /// /// Gets/sets the native method body /// public NativeMethodBody NativeBody { get { if (!methodBody_isInitialized) InitializeMethodBody(); return methodBody as NativeMethodBody; } set => MethodBody = value; } /// /// true if there's at least one in /// public bool HasGenericParameters => GenericParameters.Count > 0; /// /// true if it has a /// public bool HasBody => Body is not null; /// /// true if there's at least one in /// public bool HasOverrides => Overrides.Count > 0; /// /// true if is not null /// public bool HasImplMap => ImplMap is not null; /// /// Gets the full name /// public string FullName => FullNameFactory.MethodFullName(declaringType2?.FullName, name, MethodSig, null, null, this, null); /// /// Gets/sets the /// public MethodSig MethodSig { get => signature as MethodSig; set => signature = value; } /// /// Gets the parameters /// public ParameterList Parameters => parameterList; /// int IGenericParameterProvider.NumberOfGenericParameters { get { var sig = MethodSig; return sig is null ? 0 : (int)sig.GenParamCount; } } /// /// true if the method has a hidden 'this' parameter /// public bool HasThis { get { var ms = MethodSig; return ms is null ? false : ms.HasThis; } } /// /// true if the method has an explicit 'this' parameter /// public bool ExplicitThis { get { var ms = MethodSig; return ms is null ? false : ms.ExplicitThis; } } /// /// Gets the calling convention /// public CallingConvention CallingConvention { get { var ms = MethodSig; return ms is null ? 0 : ms.CallingConvention & CallingConvention.Mask; } } /// /// Gets/sets the method return type /// public TypeSig ReturnType { get => MethodSig?.RetType; set { var ms = MethodSig; if (ms is not null) ms.RetType = value; } } /// /// true if the method returns a value (i.e., return type is not ) /// public bool HasReturnType => ReturnType.RemovePinnedAndModifiers().GetElementType() != ElementType.Void; /// /// Gets/sets the method semantics attributes. If you remove/add a method to a property or /// an event, you must manually update this property or eg. won't /// work as expected. /// public MethodSemanticsAttributes SemanticsAttributes { get { if ((semAttrs & SEMATTRS_INITD) == 0) InitializeSemanticsAttributes(); return (MethodSemanticsAttributes)semAttrs; } set => semAttrs = (ushort)value | SEMATTRS_INITD; } /// Set when has been initialized protected internal static int SEMATTRS_INITD = unchecked((int)0x80000000); /// protected internal int semAttrs; /// Initializes protected virtual void InitializeSemanticsAttributes() => semAttrs = 0 | SEMATTRS_INITD; /// /// Set or clear flags in /// /// true if flags should be set, false if flags should /// be cleared /// Flags to set or clear void ModifyAttributes(bool set, MethodSemanticsAttributes flags) { if ((semAttrs & SEMATTRS_INITD) == 0) InitializeSemanticsAttributes(); if (set) semAttrs |= (int)flags; else semAttrs &= ~(int)flags; } /// /// Modify property: = /// ( & ) | . /// /// Value to AND /// Value to OR void ModifyAttributes(MethodAttributes andMask, MethodAttributes orMask) => attributes = (attributes & (int)andMask) | (int)orMask; /// /// Set or clear flags in /// /// true if flags should be set, false if flags should /// be cleared /// Flags to set or clear void ModifyAttributes(bool set, MethodAttributes flags) { if (set) attributes |= (int)flags; else attributes &= ~(int)flags; } /// /// Modify property: = /// ( & ) | . /// /// Value to AND /// Value to OR void ModifyImplAttributes(MethodImplAttributes andMask, MethodImplAttributes orMask) => implAttributes = (implAttributes & (int)andMask) | (int)orMask; /// /// Set or clear flags in /// /// true if flags should be set, false if flags should /// be cleared /// Flags to set or clear void ModifyImplAttributes(bool set, MethodImplAttributes flags) { if (set) implAttributes |= (int)flags; else implAttributes &= ~(int)flags; } /// /// Gets/sets the method access /// public MethodAttributes Access { get => (MethodAttributes)attributes & MethodAttributes.MemberAccessMask; set => ModifyAttributes(~MethodAttributes.MemberAccessMask, value & MethodAttributes.MemberAccessMask); } /// /// true if is set /// public bool IsCompilerControlled => IsPrivateScope; /// /// true if is set /// public bool IsPrivateScope => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope; /// /// true if is set /// public bool IsPrivate => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private; /// /// true if is set /// public bool IsFamilyAndAssembly => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem; /// /// true if is set /// public bool IsAssembly => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Assembly; /// /// true if is set /// public bool IsFamily => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Family; /// /// true if is set /// public bool IsFamilyOrAssembly => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem; /// /// true if is set /// public bool IsPublic => ((MethodAttributes)attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; /// /// Gets/sets the bit /// public bool IsStatic { get => ((MethodAttributes)attributes & MethodAttributes.Static) != 0; set => ModifyAttributes(value, MethodAttributes.Static); } /// /// Gets/sets the bit /// public bool IsFinal { get => ((MethodAttributes)attributes & MethodAttributes.Final) != 0; set => ModifyAttributes(value, MethodAttributes.Final); } /// /// Gets/sets the bit /// public bool IsVirtual { get => ((MethodAttributes)attributes & MethodAttributes.Virtual) != 0; set => ModifyAttributes(value, MethodAttributes.Virtual); } /// /// Gets/sets the bit /// public bool IsHideBySig { get => ((MethodAttributes)attributes & MethodAttributes.HideBySig) != 0; set => ModifyAttributes(value, MethodAttributes.HideBySig); } /// /// Gets/sets the bit /// public bool IsNewSlot { get => ((MethodAttributes)attributes & MethodAttributes.NewSlot) != 0; set => ModifyAttributes(value, MethodAttributes.NewSlot); } /// /// Gets/sets the bit /// public bool IsReuseSlot { get => ((MethodAttributes)attributes & MethodAttributes.NewSlot) == 0; set => ModifyAttributes(!value, MethodAttributes.NewSlot); } /// /// Gets/sets the bit /// public bool IsCheckAccessOnOverride { get => ((MethodAttributes)attributes & MethodAttributes.CheckAccessOnOverride) != 0; set => ModifyAttributes(value, MethodAttributes.CheckAccessOnOverride); } /// /// Gets/sets the bit /// public bool IsAbstract { get => ((MethodAttributes)attributes & MethodAttributes.Abstract) != 0; set => ModifyAttributes(value, MethodAttributes.Abstract); } /// /// Gets/sets the bit /// public bool IsSpecialName { get => ((MethodAttributes)attributes & MethodAttributes.SpecialName) != 0; set => ModifyAttributes(value, MethodAttributes.SpecialName); } /// /// Gets/sets the bit /// public bool IsPinvokeImpl { get => ((MethodAttributes)attributes & MethodAttributes.PinvokeImpl) != 0; set => ModifyAttributes(value, MethodAttributes.PinvokeImpl); } /// /// Gets/sets the bit /// public bool IsUnmanagedExport { get => ((MethodAttributes)attributes & MethodAttributes.UnmanagedExport) != 0; set => ModifyAttributes(value, MethodAttributes.UnmanagedExport); } /// /// Gets/sets the bit /// public bool IsRuntimeSpecialName { get => ((MethodAttributes)attributes & MethodAttributes.RTSpecialName) != 0; set => ModifyAttributes(value, MethodAttributes.RTSpecialName); } /// /// Gets/sets the bit /// public bool HasSecurity { get => ((MethodAttributes)attributes & MethodAttributes.HasSecurity) != 0; set => ModifyAttributes(value, MethodAttributes.HasSecurity); } /// /// Gets/sets the bit /// public bool IsRequireSecObject { get => ((MethodAttributes)attributes & MethodAttributes.RequireSecObject) != 0; set => ModifyAttributes(value, MethodAttributes.RequireSecObject); } /// /// Gets/sets the code type /// public MethodImplAttributes CodeType { get => (MethodImplAttributes)implAttributes & MethodImplAttributes.CodeTypeMask; set => ModifyImplAttributes(~MethodImplAttributes.CodeTypeMask, value & MethodImplAttributes.CodeTypeMask); } /// /// true if is set /// public bool IsIL => ((MethodImplAttributes)implAttributes & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.IL; /// /// true if is set /// public bool IsNative => ((MethodImplAttributes)implAttributes & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.Native; /// /// true if is set /// public bool IsOPTIL => ((MethodImplAttributes)implAttributes & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.OPTIL; /// /// true if is set /// public bool IsRuntime => ((MethodImplAttributes)implAttributes & MethodImplAttributes.CodeTypeMask) == MethodImplAttributes.Runtime; /// /// Gets/sets the bit /// public bool IsUnmanaged { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.Unmanaged) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.Unmanaged); } /// /// Gets/sets the bit /// public bool IsManaged { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.Unmanaged) == 0; set => ModifyImplAttributes(!value, MethodImplAttributes.Unmanaged); } /// /// Gets/sets the bit /// public bool IsForwardRef { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.ForwardRef) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.ForwardRef); } /// /// Gets/sets the bit /// public bool IsPreserveSig { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.PreserveSig) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.PreserveSig); } /// /// Gets/sets the bit /// public bool IsInternalCall { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.InternalCall) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.InternalCall); } /// /// Gets/sets the bit /// public bool IsSynchronized { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.Synchronized) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.Synchronized); } /// /// Gets/sets the bit /// public bool IsNoInlining { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.NoInlining) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.NoInlining); } /// /// Gets/sets the bit /// public bool IsAggressiveInlining { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.AggressiveInlining) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.AggressiveInlining); } /// /// Gets/sets the bit /// public bool IsNoOptimization { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.NoOptimization) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.NoOptimization); } /// /// Gets/sets the bit /// public bool IsAggressiveOptimization { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.AggressiveOptimization) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.AggressiveOptimization); } /// /// Gets/sets the bit /// public bool HasSecurityMitigations { get => ((MethodImplAttributes)implAttributes & MethodImplAttributes.SecurityMitigations) != 0; set => ModifyImplAttributes(value, MethodImplAttributes.SecurityMitigations); } /// /// Gets/sets the bit /// public bool IsSetter { get => (SemanticsAttributes & MethodSemanticsAttributes.Setter) != 0; set => ModifyAttributes(value, MethodSemanticsAttributes.Setter); } /// /// Gets/sets the bit /// public bool IsGetter { get => (SemanticsAttributes & MethodSemanticsAttributes.Getter) != 0; set => ModifyAttributes(value, MethodSemanticsAttributes.Getter); } /// /// Gets/sets the bit /// public bool IsOther { get => (SemanticsAttributes & MethodSemanticsAttributes.Other) != 0; set => ModifyAttributes(value, MethodSemanticsAttributes.Other); } /// /// Gets/sets the bit /// public bool IsAddOn { get => (SemanticsAttributes & MethodSemanticsAttributes.AddOn) != 0; set => ModifyAttributes(value, MethodSemanticsAttributes.AddOn); } /// /// Gets/sets the bit /// public bool IsRemoveOn { get => (SemanticsAttributes & MethodSemanticsAttributes.RemoveOn) != 0; set => ModifyAttributes(value, MethodSemanticsAttributes.RemoveOn); } /// /// Gets/sets the bit /// public bool IsFire { get => (SemanticsAttributes & MethodSemanticsAttributes.Fire) != 0; set => ModifyAttributes(value, MethodSemanticsAttributes.Fire); } /// /// true if this is the static type constructor /// public bool IsStaticConstructor => IsRuntimeSpecialName && UTF8String.Equals(name, StaticConstructorName); /// /// true if this is an instance constructor /// public bool IsInstanceConstructor => IsRuntimeSpecialName && UTF8String.Equals(name, InstanceConstructorName); /// /// true if this is a static or an instance constructor /// public bool IsConstructor => IsStaticConstructor || IsInstanceConstructor; /// void IListListener.OnLazyAdd(int index, ref GenericParam value) => OnLazyAdd2(index, ref value); internal virtual void OnLazyAdd2(int index, ref GenericParam value) { #if DEBUG if (value.Owner != this) throw new InvalidOperationException("Added generic param's Owner != this"); #endif } /// void IListListener.OnAdd(int index, GenericParam value) { if (value.Owner is not null) throw new InvalidOperationException("Generic param is already owned by another type/method. Set Owner to null first."); value.Owner = this; } /// void IListListener.OnRemove(int index, GenericParam value) => value.Owner = null; /// void IListListener.OnResize(int index) { } /// void IListListener.OnClear() { foreach (var gp in genericParameters.GetEnumerable_NoLock()) gp.Owner = null; } /// void IListListener.OnLazyAdd(int index, ref ParamDef value) => OnLazyAdd2(index, ref value); internal virtual void OnLazyAdd2(int index, ref ParamDef value) { #if DEBUG if (value.DeclaringMethod != this) throw new InvalidOperationException("Added param's DeclaringMethod != this"); #endif } /// void IListListener.OnAdd(int index, ParamDef value) { if (value.DeclaringMethod is not null) throw new InvalidOperationException("Param is already owned by another method. Set DeclaringMethod to null first."); value.DeclaringMethod = this; } /// void IListListener.OnRemove(int index, ParamDef value) => value.DeclaringMethod = null; /// void IListListener.OnResize(int index) { } /// void IListListener.OnClear() { foreach (var pd in paramDefs.GetEnumerable_NoLock()) pd.DeclaringMethod = null; } /// public override string ToString() => FullName; } /// /// A Method row created by the user and not present in the original .NET file /// public class MethodDefUser : MethodDef { /// /// Default constructor /// public MethodDefUser() { paramDefs = new LazyList(this); genericParameters = new LazyList(this); parameterList = new ParameterList(this, null); semAttrs = 0 | SEMATTRS_INITD; } /// /// Constructor /// /// Method name public MethodDefUser(UTF8String name) : this(name, null, 0, 0) { } /// /// Constructor /// /// Method name /// Method sig public MethodDefUser(UTF8String name, MethodSig methodSig) : this(name, methodSig, 0, 0) { } /// /// Constructor /// /// Method name /// Method sig /// Flags public MethodDefUser(UTF8String name, MethodSig methodSig, MethodAttributes flags) : this(name, methodSig, 0, flags) { } /// /// Constructor /// /// Method name /// Method sig /// Impl flags public MethodDefUser(UTF8String name, MethodSig methodSig, MethodImplAttributes implFlags) : this(name, methodSig, implFlags, 0) { } /// /// Constructor /// /// Method name /// Method sig /// Impl flags /// Flags public MethodDefUser(UTF8String name, MethodSig methodSig, MethodImplAttributes implFlags, MethodAttributes flags) { this.name = name; signature = methodSig; paramDefs = new LazyList(this); genericParameters = new LazyList(this); implAttributes = (int)implFlags; attributes = (int)flags; parameterList = new ParameterList(this, null); semAttrs = 0 | SEMATTRS_INITD; } } /// /// Created from a row in the Method table /// sealed class MethodDefMD : MethodDef, IMDTokenProviderMD { /// The module where this instance is located readonly ModuleDefMD readerModule; readonly uint origRid; readonly RVA origRva; readonly MethodImplAttributes origImplAttributes; /// public uint OrigRid => origRid; /// protected override void InitializeParamDefs() { var list = readerModule.Metadata.GetParamRidList(origRid); var tmp = new LazyList(list.Count, this, list, (list2, index) => readerModule.ResolveParam(list2[index])); Interlocked.CompareExchange(ref paramDefs, tmp, null); } /// protected override void InitializeGenericParameters() { var list = readerModule.Metadata.GetGenericParamRidList(Table.Method, origRid); var tmp = new LazyList(list.Count, this, list, (list2, index) => readerModule.ResolveGenericParam(list2[index])); Interlocked.CompareExchange(ref genericParameters, tmp, null); } /// protected override void InitializeDeclSecurities() { var list = readerModule.Metadata.GetDeclSecurityRidList(Table.Method, origRid); var tmp = new LazyList(list.Count, list, (list2, index) => readerModule.ResolveDeclSecurity(list2[index])); Interlocked.CompareExchange(ref declSecurities, tmp, null); } /// protected override ImplMap GetImplMap_NoLock() => readerModule.ResolveImplMap(readerModule.Metadata.GetImplMapRid(Table.Method, origRid)); /// protected override MethodBody GetMethodBody_NoLock() => readerModule.ReadMethodBody(this, origRva, origImplAttributes, new GenericParamContext(declaringType2, this)); /// protected override void InitializeCustomAttributes() { var list = readerModule.Metadata.GetCustomAttributeRidList(Table.Method, 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(); if (Interlocked.CompareExchange(ref customDebugInfos, list, null) is null) { var body = Body; readerModule.InitializeCustomDebugInfos(this, body, list); } } /// protected override void InitializeOverrides() { var dt = declaringType2 as TypeDefMD; var tmp = dt is null ? new List() : dt.GetMethodOverrides(this, new GenericParamContext(declaringType2, this)); Interlocked.CompareExchange(ref overrides, tmp, null); } /// protected override void InitializeSemanticsAttributes() { if (DeclaringType is TypeDefMD dt) dt.InitializeMethodSemanticsAttributes(); semAttrs |= SEMATTRS_INITD; } /// /// Constructor /// /// The module which contains this Method row /// Row ID /// If is null /// If is invalid public MethodDefMD(ModuleDefMD readerModule, uint rid) { #if DEBUG if (readerModule is null) throw new ArgumentNullException("readerModule"); if (readerModule.TablesStream.MethodTable.IsInvalidRID(rid)) throw new BadImageFormatException($"Method rid {rid} does not exist"); #endif origRid = rid; this.rid = rid; this.readerModule = readerModule; bool b = readerModule.TablesStream.TryReadMethodRow(origRid, out var row); Debug.Assert(b); rva = (RVA)row.RVA; implAttributes = row.ImplFlags; attributes = row.Flags; name = readerModule.StringsStream.ReadNoNull(row.Name); origRva = rva; origImplAttributes = (MethodImplAttributes)implAttributes; declaringType2 = readerModule.GetOwnerType(this); signature = readerModule.ReadSignature(row.Signature, new GenericParamContext(declaringType2, this)); parameterList = new ParameterList(this, declaringType2); exportInfo = readerModule.GetExportInfo(rid); } internal MethodDefMD InitializeAll() { MemberMDInitializer.Initialize(RVA); MemberMDInitializer.Initialize(Attributes); MemberMDInitializer.Initialize(ImplAttributes); MemberMDInitializer.Initialize(Name); MemberMDInitializer.Initialize(Signature); MemberMDInitializer.Initialize(ImplMap); MemberMDInitializer.Initialize(MethodBody); MemberMDInitializer.Initialize(DeclaringType); MemberMDInitializer.Initialize(CustomAttributes); MemberMDInitializer.Initialize(Overrides); MemberMDInitializer.Initialize(ParamDefs); MemberMDInitializer.Initialize(GenericParameters); MemberMDInitializer.Initialize(DeclSecurities); return this; } /// internal override void OnLazyAdd2(int index, ref GenericParam value) { if (value.Owner != this) { // More than one owner... This module has invalid metadata. value = readerModule.ForceUpdateRowId(readerModule.ReadGenericParam(value.Rid).InitializeAll()); value.Owner = this; } } /// internal override void OnLazyAdd2(int index, ref ParamDef value) { if (value.DeclaringMethod != this) { // More than one owner... This module has invalid metadata. value = readerModule.ForceUpdateRowId(readerModule.ReadParam(value.Rid).InitializeAll()); value.DeclaringMethod = this; } } } }