// 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;
using dnlib.Threading;
namespace dnlib.DotNet {
///
/// A high-level representation of a row in the Param table
///
[DebuggerDisplay("{Sequence} {Name}")]
public abstract class ParamDef : IHasConstant, IHasCustomAttribute, IHasFieldMarshal, IHasCustomDebugInformation {
///
/// The row id in its table
///
protected uint rid;
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
///
public MDToken MDToken => new MDToken(Table.Param, rid);
///
public uint Rid {
get => rid;
set => rid = value;
}
///
public int HasConstantTag => 1;
///
public int HasCustomAttributeTag => 4;
///
public int HasFieldMarshalTag => 1;
///
/// Gets the declaring method
///
public MethodDef DeclaringMethod {
get => declaringMethod;
internal set => declaringMethod = value;
}
///
protected MethodDef declaringMethod;
///
/// From column Param.Flags
///
public ParamAttributes Attributes {
get => (ParamAttributes)attributes;
set => attributes = (int)value;
}
/// Attributes
protected int attributes;
///
/// From column Param.Sequence
///
public ushort Sequence {
get => sequence;
set => sequence = value;
}
///
protected ushort sequence;
///
/// From column Param.Name
///
public UTF8String Name {
get => name;
set => name = value;
}
/// Name
protected UTF8String name;
///
public MarshalType MarshalType {
get {
if (!marshalType_isInitialized)
InitializeMarshalType();
return marshalType;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
marshalType = value;
marshalType_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
///
protected MarshalType marshalType;
///
protected bool marshalType_isInitialized;
void InitializeMarshalType() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (marshalType_isInitialized)
return;
marshalType = GetMarshalType_NoLock();
marshalType_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// Called to initialize
protected virtual MarshalType GetMarshalType_NoLock() => null;
/// Reset
protected void ResetMarshalType() => marshalType_isInitialized = false;
///
public Constant Constant {
get {
if (!constant_isInitialized)
InitializeConstant();
return constant;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
constant = value;
constant_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
///
protected Constant constant;
///
protected bool constant_isInitialized;
void InitializeConstant() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (constant_isInitialized)
return;
constant = GetConstant_NoLock();
constant_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// Called to initialize
protected virtual Constant GetConstant_NoLock() => null;
/// Reset
protected void ResetConstant() => constant_isInitialized = false;
///
/// 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 => 4;
///
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);
///
/// true if is not null
///
public bool HasConstant => Constant is not null;
///
/// Gets the constant element type or if there's no constant
///
public ElementType ElementType {
get {
var c = Constant;
return c is null ? ElementType.End : c.Type;
}
}
///
/// true if is not null
///
public bool HasMarshalType => MarshalType is not null;
///
public string FullName {
get {
var n = name;
if (UTF8String.IsNullOrEmpty(n))
return $"A_{sequence}";
return n.String;
}
}
///
/// 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, ParamAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
///
/// Gets/sets the bit
///
public bool IsIn {
get => ((ParamAttributes)attributes & ParamAttributes.In) != 0;
set => ModifyAttributes(value, ParamAttributes.In);
}
///
/// Gets/sets the bit
///
public bool IsOut {
get => ((ParamAttributes)attributes & ParamAttributes.Out) != 0;
set => ModifyAttributes(value, ParamAttributes.Out);
}
///
/// Gets/sets the bit
///
public bool IsLcid {
get => ((ParamAttributes)attributes & ParamAttributes.Lcid) != 0;
set => ModifyAttributes(value, ParamAttributes.Lcid);
}
///
/// Gets/sets the bit
///
public bool IsRetval {
get => ((ParamAttributes)attributes & ParamAttributes.Retval) != 0;
set => ModifyAttributes(value, ParamAttributes.Retval);
}
///
/// Gets/sets the bit
///
public bool IsOptional {
get => ((ParamAttributes)attributes & ParamAttributes.Optional) != 0;
set => ModifyAttributes(value, ParamAttributes.Optional);
}
///
/// Gets/sets the bit
///
public bool HasDefault {
get => ((ParamAttributes)attributes & ParamAttributes.HasDefault) != 0;
set => ModifyAttributes(value, ParamAttributes.HasDefault);
}
///
/// Gets/sets the bit
///
public bool HasFieldMarshal {
get => ((ParamAttributes)attributes & ParamAttributes.HasFieldMarshal) != 0;
set => ModifyAttributes(value, ParamAttributes.HasFieldMarshal);
}
}
///
/// A Param row created by the user and not present in the original .NET file
///
public class ParamDefUser : ParamDef {
///
/// Default constructor
///
public ParamDefUser() {
}
///
/// Constructor
///
/// Name
public ParamDefUser(UTF8String name)
: this(name, 0) {
}
///
/// Constructor
///
/// Name
/// Sequence
public ParamDefUser(UTF8String name, ushort sequence)
: this(name, sequence, 0) {
}
///
/// Constructor
///
/// Name
/// Sequence
/// Flags
public ParamDefUser(UTF8String name, ushort sequence, ParamAttributes flags) {
this.name = name;
this.sequence = sequence;
attributes = (int)flags;
}
}
///
/// Created from a row in the Param table
///
sealed class ParamDefMD : ParamDef, IMDTokenProviderMD {
/// The module where this instance is located
readonly ModuleDefMD readerModule;
readonly uint origRid;
///
public uint OrigRid => origRid;
///
protected override MarshalType GetMarshalType_NoLock() =>
readerModule.ReadMarshalType(Table.Param, origRid, GenericParamContext.Create(declaringMethod));
///
protected override Constant GetConstant_NoLock() =>
readerModule.ResolveConstant(readerModule.Metadata.GetConstantRid(Table.Param, origRid));
///
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.Param, 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), GenericParamContext.Create(declaringMethod), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
///
/// Constructor
///
/// The module which contains this Param row
/// Row ID
/// If is null
/// If is invalid
public ParamDefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ParamTable.IsInvalidRID(rid))
throw new BadImageFormatException($"Param rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadParamRow(origRid, out var row);
Debug.Assert(b);
attributes = row.Flags;
sequence = row.Sequence;
name = readerModule.StringsStream.ReadNoNull(row.Name);
declaringMethod = readerModule.GetOwner(this);
}
internal ParamDefMD InitializeAll() {
MemberMDInitializer.Initialize(DeclaringMethod);
MemberMDInitializer.Initialize(Attributes);
MemberMDInitializer.Initialize(Sequence);
MemberMDInitializer.Initialize(Name);
MemberMDInitializer.Initialize(MarshalType);
MemberMDInitializer.Initialize(Constant);
MemberMDInitializer.Initialize(CustomAttributes);
return this;
}
}
}