// 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);
}
}
}