// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
///
/// The table row can be referenced by a MD token
///
public interface IMDTokenProvider {
///
/// Returns the metadata token
///
MDToken MDToken { get; }
///
/// Gets/sets the row ID
///
uint Rid { get; set; }
}
///
/// All *MD classes implement this interface.
///
public interface IMDTokenProviderMD : IMDTokenProvider {
///
/// Gets the original row ID
///
uint OrigRid { get; }
}
///
/// An assembly. Implemented by , and
/// .
///
public interface IAssembly : IFullName {
///
/// The assembly version
///
Version Version { get; set; }
///
/// Assembly flags
///
AssemblyAttributes Attributes { get; set; }
///
/// Public key or public key token
///
PublicKeyBase PublicKeyOrToken { get; }
///
/// Locale, aka culture
///
UTF8String Culture { get; set; }
///
/// Gets the full name of the assembly but use a public key token
///
string FullNameToken { get; }
///
/// Gets/sets the bit
///
bool HasPublicKey { get; set; }
///
/// Gets/sets the processor architecture
///
AssemblyAttributes ProcessorArchitecture { get; set; }
///
/// Gets/sets the processor architecture
///
AssemblyAttributes ProcessorArchitectureFull { get; set; }
///
/// true if unspecified processor architecture
///
bool IsProcessorArchitectureNone { get; }
///
/// true if neutral (PE32) architecture
///
bool IsProcessorArchitectureMSIL { get; }
///
/// true if x86 (PE32) architecture
///
bool IsProcessorArchitectureX86 { get; }
///
/// true if IA-64 (PE32+) architecture
///
bool IsProcessorArchitectureIA64 { get; }
///
/// true if x64 (PE32+) architecture
///
bool IsProcessorArchitectureX64 { get; }
///
/// true if ARM (PE32) architecture
///
bool IsProcessorArchitectureARM { get; }
///
/// true if eg. reference assembly (not runnable)
///
bool IsProcessorArchitectureNoPlatform { get; }
///
/// Gets/sets the bit
///
bool IsProcessorArchitectureSpecified { get; set; }
///
/// Gets/sets the bit
///
bool EnableJITcompileTracking { get; set; }
///
/// Gets/sets the bit
///
bool DisableJITcompileOptimizer { get; set; }
///
/// Gets/sets the bit
///
bool IsRetargetable { get; set; }
///
/// Gets/sets the content type
///
AssemblyAttributes ContentType { get; set; }
///
/// true if content type is Default
///
bool IsContentTypeDefault { get; }
///
/// true if content type is WindowsRuntime
///
bool IsContentTypeWindowsRuntime { get; }
}
public static partial class Extensions {
///
/// Checks whether appears to be the core library (eg.
/// mscorlib, System.Runtime or corefx).
///
/// If is a reference to a private corlib (eg. System.Private.CoreLib),
/// this method returns false unless is an
/// whose manifest (first) module defines System.Object. This check is performed in
/// the constructor and the result can be found in .
///
/// Note that this method also returns true if it appears to be a 'public' corlib,
/// eg. mscorlib, etc, even if it internally possibly references a private corlib.
///
/// The assembly
public static bool IsCorLib(this IAssembly asm) {
if (asm is AssemblyDef asmDef) {
var manifestModule = asmDef.ManifestModule;
if (manifestModule is not null) {
var isCorModule = manifestModule.IsCoreLibraryModule;
if (isCorModule is not null)
return isCorModule.Value;
}
}
string asmName;
return asm is not null &&
UTF8String.IsNullOrEmpty(asm.Culture) &&
((asmName = UTF8String.ToSystemStringOrEmpty(asm.Name)).Equals("mscorlib", StringComparison.OrdinalIgnoreCase) ||
asmName.Equals("System.Runtime", StringComparison.OrdinalIgnoreCase) ||
// This name could change but since CoreCLR is used a lot, it's worth supporting
asmName.Equals("System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) ||
asmName.Equals("netstandard", StringComparison.OrdinalIgnoreCase) ||
asmName.Equals("corefx", StringComparison.OrdinalIgnoreCase));
}
///
/// Converts to a instance
///
/// The assembly
/// A new instance
public static AssemblyRef ToAssemblyRef(this IAssembly asm) {
if (asm is null)
return null;
// Always create a new one, even if it happens to be an AssemblyRef
return new AssemblyRefUser(asm.Name, asm.Version, asm.PublicKeyOrToken, asm.Culture) { Attributes = asm.Attributes };
}
///
/// Converts to a
///
/// The type
/// true if we should try to resolve in order to figure out whether
/// is a
/// A instance or null if
/// is invalid
public static TypeSig ToTypeSig(this ITypeDefOrRef type, bool resolveToCheckValueType = true) {
if (type is null)
return null;
var module = type.Module;
if (module is not null) {
var corLibType = module.CorLibTypes.GetCorLibTypeSig(type);
if (corLibType is not null)
return corLibType;
}
var td = type as TypeDef;
if (td is not null)
return CreateClassOrValueType(type, td.IsValueType);
if (type is TypeRef tr) {
if (resolveToCheckValueType)
td = tr.Resolve();
return CreateClassOrValueType(type, td is null ? false : td.IsValueType);
}
if (type is TypeSpec ts)
return ts.TypeSig;
return null;
}
static TypeSig CreateClassOrValueType(ITypeDefOrRef type, bool isValueType) {
if (isValueType)
return new ValueTypeSig(type);
return new ClassSig(type);
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static TypeDefOrRefSig TryGetTypeDefOrRefSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as TypeDefOrRefSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static ClassOrValueTypeSig TryGetClassOrValueTypeSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as ClassOrValueTypeSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static ValueTypeSig TryGetValueTypeSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as ValueTypeSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static ClassSig TryGetClassSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as ClassSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static GenericSig TryGetGenericSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as GenericSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static GenericVar TryGetGenericVar(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as GenericVar;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static GenericMVar TryGetGenericMVar(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as GenericMVar;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static GenericInstSig TryGetGenericInstSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as GenericInstSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static PtrSig TryGetPtrSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as PtrSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static ByRefSig TryGetByRefSig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as ByRefSig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static ArraySig TryGetArraySig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as ArraySig;
}
///
/// Returns a
///
/// The type
/// A or null if it's not a
///
public static SZArraySig TryGetSZArraySig(this ITypeDefOrRef type) {
var ts = type as TypeSpec;
return ts is null ? null : ts.TypeSig.RemovePinnedAndModifiers() as SZArraySig;
}
///
/// Returns the base type of . Throws if we can't resolve
/// a .
///
/// The type
/// The base type or null if there's no base type
public static ITypeDefOrRef GetBaseTypeThrow(this ITypeDefOrRef tdr) => tdr.GetBaseType(true);
///
/// Returns the base type of
///
/// The type
/// true if we should throw if we can't
/// resolve a . false if we should ignore the error and
/// just return null.
/// The base type or null if there's no base type, or if
/// is true and we couldn't resolve
/// a
public static ITypeDefOrRef GetBaseType(this ITypeDefOrRef tdr, bool throwOnResolveFailure = false) {
if (tdr is TypeDef td)
return td.BaseType;
if (tdr is TypeRef tr) {
td = throwOnResolveFailure ? tr.ResolveThrow() : tr.Resolve();
return td?.BaseType;
}
var ts = tdr as TypeSpec;
if (ts is null)
return null;
var git = ts.TypeSig.ToGenericInstSig();
if (git is not null)
tdr = git.GenericType?.TypeDefOrRef;
else
tdr = ts.TypeSig.ToTypeDefOrRefSig()?.TypeDefOrRef;
td = tdr as TypeDef;
if (td is not null)
return td.BaseType;
tr = tdr as TypeRef;
if (tr is not null) {
td = throwOnResolveFailure ? tr.ResolveThrow() : tr.Resolve();
return td?.BaseType;
}
return null;
}
///
/// Gets the scope type, resolves it, and returns the
///
/// Type
/// A or null if input was null or if we
/// couldn't resolve the reference.
public static TypeDef ResolveTypeDef(this ITypeDefOrRef tdr) {
if (tdr is TypeDef td)
return td;
if (tdr is TypeRef tr)
return tr.Resolve();
if (tdr is null)
return null;
tdr = tdr.ScopeType;
td = tdr as TypeDef;
if (td is not null)
return td;
tr = tdr as TypeRef;
if (tr is not null)
return tr.Resolve();
return null;
}
///
/// Gets the scope type, resolves it, and returns the
///
/// Type
/// A instance.
/// If the type couldn't be resolved
public static TypeDef ResolveTypeDefThrow(this ITypeDefOrRef tdr) {
if (tdr is TypeDef td)
return td;
if (tdr is TypeRef tr)
return tr.ResolveThrow();
if (tdr is null)
throw new TypeResolveException("Can't resolve a null pointer");
tdr = tdr.ScopeType;
td = tdr as TypeDef;
if (td is not null)
return td;
tr = tdr as TypeRef;
if (tr is not null)
return tr.ResolveThrow();
throw new TypeResolveException($"Could not resolve type: {tdr} ({tdr?.DefinitionAssembly})");
}
///
/// Resolves an to a . Returns null if it
/// was not possible to resolve it. See also
///
/// Field to resolve
/// The or null if is
/// null or if it wasn't possible to resolve it (the field doesn't exist or its
/// assembly couldn't be loaded)
public static FieldDef ResolveFieldDef(this IField field) {
if (field is FieldDef fd)
return fd;
if (field is MemberRef mr)
return mr.ResolveField();
return null;
}
///
/// Resolves an to a and throws an exception if
/// it was not possible to resolve it. See also
///
/// Field to resolve
/// The
public static FieldDef ResolveFieldDefThrow(this IField field) {
if (field is FieldDef fd)
return fd;
if (field is MemberRef mr)
return mr.ResolveFieldThrow();
throw new MemberRefResolveException($"Could not resolve field: {field}");
}
///
/// Resolves an to a . Returns null if it
/// was not possible to resolve it. See also . If
/// is a , then the
/// property is resolved and returned.
///
/// Method to resolve
/// The or null if is
/// null or if it wasn't possible to resolve it (the method doesn't exist or its
/// assembly couldn't be loaded)
public static MethodDef ResolveMethodDef(this IMethod method) {
if (method is MethodDef md)
return md;
if (method is MemberRef mr)
return mr.ResolveMethod();
if (method is MethodSpec ms) {
md = ms.Method as MethodDef;
if (md is not null)
return md;
mr = ms.Method as MemberRef;
if (mr is not null)
return mr.ResolveMethod();
}
return null;
}
///
/// Resolves an to a and throws an exception
/// if it was not possible to resolve it. See also . If
/// is a , then the
/// property is resolved and returned.
///
/// Method to resolve
/// The
public static MethodDef ResolveMethodDefThrow(this IMethod method) {
if (method is MethodDef md)
return md;
if (method is MemberRef mr)
return mr.ResolveMethodThrow();
if (method is MethodSpec ms) {
md = ms.Method as MethodDef;
if (md is not null)
return md;
mr = ms.Method as MemberRef;
if (mr is not null)
return mr.ResolveMethodThrow();
}
throw new MemberRefResolveException($"Could not resolve method: {method}");
}
///
/// Returns the definition assembly of a
///
/// Member reference
///
static internal IAssembly GetDefinitionAssembly(this MemberRef mr) {
if (mr is null)
return null;
var parent = mr.Class;
if (parent is ITypeDefOrRef tdr)
return tdr.DefinitionAssembly;
if (parent is ModuleRef)
return mr.Module?.Assembly;
if (parent is MethodDef md)
return md.DeclaringType?.DefinitionAssembly;
return null;
}
///
/// Gets the normal visible parameters, doesn't include the hidden 'this' parameter
///
/// this
/// The normal visible parameters
public static IList GetParams(this IMethod method) => method?.MethodSig.GetParams();
///
/// Gets the normal visible parameter count, doesn't include the hidden 'this' parameter
///
/// this
/// Normal visible parameter count
public static int GetParamCount(this IMethod method) => method?.MethodSig.GetParamCount() ?? 0;
///
/// Checks whether any normal visible parameter exists, doesn't include the hidden 'this' parameter
///
/// this
/// true if there's at least one normal visible parameter
public static bool HasParams(this IMethod method) => method.GetParamCount() > 0;
///
/// Gets a normal visible parameter, doesn't include the hidden 'this' parameter
///
/// this
/// Normal visible parameter index
///
public static TypeSig GetParam(this IMethod method, int index) => method?.MethodSig.GetParams() is { } types && index >= 0 && index < types.Count ? types[index] : null;
}
///
/// Implemented by and , which are the only
/// valid managed entry point tokens.
///
public interface IManagedEntryPoint : ICodedToken {
}
///
/// Interface to access a module def/ref
///
public interface IModule : IScope, IFullName {
}
///
/// Type of scope
///
public enum ScopeType {
///
/// It's an instance
///
AssemblyRef,
///
/// It's a instance
///
ModuleRef,
///
/// It's a instance
///
ModuleDef,
}
///
/// Implemented by modules and assemblies
///
public interface IScope {
///
/// Gets the scope type
///
ScopeType ScopeType { get; }
///
/// Gets the scope name
///
string ScopeName { get; }
}
///
/// Interface to get the full name of a type, field, or method
///
public interface IFullName {
///
/// Gets the full name
///
string FullName { get; }
///
/// Simple name of implementer
///
UTF8String Name { get; set; }
}
///
/// Implemented by all member refs and types
///
public interface IOwnerModule {
///
/// Gets the owner module
///
ModuleDef Module { get; }
}
///
/// Methods to check whether the implementer is a type or a method.
///
public interface IIsTypeOrMethod {
///
/// true if it's a type
///
bool IsType { get; }
///
/// true if it's a method
///
bool IsMethod { get; }
}
///
/// Implemented by types, fields, methods, properties, events
///
public interface IMemberRef : ICodedToken, IFullName, IOwnerModule, IIsTypeOrMethod {
///
/// Gets the declaring type
///
ITypeDefOrRef DeclaringType { get; }
///
/// true if it's a or a that's
/// referencing a field.
///
bool IsField { get; }
///
/// true if it's a
///
bool IsTypeSpec { get; }
///
/// true if it's a
///
bool IsTypeRef { get; }
///
/// true if it's a
///
bool IsTypeDef { get; }
///
/// true if it's a
///
bool IsMethodSpec { get; }
///
/// true if it's a
///
bool IsMethodDef { get; }
///
/// true if it's a
///
bool IsMemberRef { get; }
///
/// true if it's a
///
bool IsFieldDef { get; }
///
/// true if it's a
///
bool IsPropertyDef { get; }
///
/// true if it's a
///
bool IsEventDef { get; }
///
/// true if it's a
///
bool IsGenericParam { get; }
}
///
/// All member definitions implement this interface: ,
/// , , ,
/// , and .
///
public interface IMemberDef : IDnlibDef, IMemberRef {
///
/// Gets the declaring type
///
new TypeDef DeclaringType { get; }
}
///
/// Implemented by the following classes: ,
/// , , ,
/// , , ,
/// and
///
public interface IDnlibDef : ICodedToken, IFullName, IHasCustomAttribute {
}
///
/// Implemented by types and methods
///
public interface IGenericParameterProvider : ICodedToken, IIsTypeOrMethod {
///
/// Gets the number of generic parameters / arguments
///
int NumberOfGenericParameters { get; }
}
///
/// Implemented by fields ( and )
///
public interface IField : ICodedToken, ITokenOperand, IFullName, IMemberRef {
///
/// Gets/sets the field signature
///
FieldSig FieldSig { get; set; }
}
///
/// Implemented by methods (, and )
///
public interface IMethod : ICodedToken, ITokenOperand, IFullName, IGenericParameterProvider, IMemberRef {
///
/// Method signature
///
MethodSig MethodSig { get; set; }
}
///
/// Implemented by tables that can be a token in the ldtoken instruction
///
public interface ITokenOperand : ICodedToken {
}
///
/// The table row can be referenced by a coded token
///
public interface ICodedToken : IMDTokenProvider {
}
///
/// TypeDefOrRef coded token interface
///
public interface ITypeDefOrRef : ICodedToken, IHasCustomAttribute, IMemberRefParent, IType, ITokenOperand, IMemberRef {
///
/// The coded token tag
///
int TypeDefOrRefTag { get; }
}
///
/// HasConstant coded token interface
///
public interface IHasConstant : ICodedToken, IHasCustomAttribute, IFullName {
///
/// The coded token tag
///
int HasConstantTag { get; }
///
/// Gets/sets the constant value
///
Constant Constant { get; set; }
}
///
/// HasCustomAttribute coded token interface
///
public interface IHasCustomAttribute : ICodedToken {
///
/// The coded token tag
///
int HasCustomAttributeTag { get; }
///
/// Gets all custom attributes
///
CustomAttributeCollection CustomAttributes { get; }
///
/// true if is not empty
///
bool HasCustomAttributes { get; }
}
///
/// HasFieldMarshal coded token interface
///
public interface IHasFieldMarshal : ICodedToken, IHasCustomAttribute, IHasConstant, IFullName {
///
/// The coded token tag
///
int HasFieldMarshalTag { get; }
///
/// Gets/sets the marshal type
///
MarshalType MarshalType { get; set; }
///
/// true if is not null
///
bool HasMarshalType { get; }
}
///
/// HasDeclSecurity coded token interface
///
public interface IHasDeclSecurity : ICodedToken, IHasCustomAttribute, IFullName {
///
/// The coded token tag
///
int HasDeclSecurityTag { get; }
///
/// Gets the permission sets
///
IList DeclSecurities { get; }
///
/// true if is not empty
///
bool HasDeclSecurities { get; }
}
///
/// MemberRefParent coded token interface
///
public interface IMemberRefParent : ICodedToken, IHasCustomAttribute, IFullName {
///
/// The coded token tag
///
int MemberRefParentTag { get; }
}
///
/// HasSemantic coded token interface
///
public interface IHasSemantic : ICodedToken, IHasCustomAttribute, IFullName, IMemberRef {
///
/// The coded token tag
///
int HasSemanticTag { get; }
}
///
/// MethodDefOrRef coded token interface
///
public interface IMethodDefOrRef : ICodedToken, IHasCustomAttribute, ICustomAttributeType, IMethod {
///
/// The coded token tag
///
int MethodDefOrRefTag { get; }
}
///
/// MemberForwarded coded token interface
///
public interface IMemberForwarded : ICodedToken, IHasCustomAttribute, IFullName, IMemberRef {
///
/// The coded token tag
///
int MemberForwardedTag { get; }
///
/// Gets/sets the impl map
///
ImplMap ImplMap { get; set; }
///
/// true if is not null
///
bool HasImplMap { get; }
}
///
/// Implementation coded token interface
///
public interface IImplementation : ICodedToken, IHasCustomAttribute, IFullName {
///
/// The coded token tag
///
int ImplementationTag { get; }
}
///
/// CustomAttributeType coded token interface
///
public interface ICustomAttributeType : ICodedToken, IHasCustomAttribute, IMethod {
///
/// The coded token tag
///
int CustomAttributeTypeTag { get; }
}
///
/// ResolutionScope coded token interface
///
public interface IResolutionScope : ICodedToken, IHasCustomAttribute, IFullName {
///
/// The coded token tag
///
int ResolutionScopeTag { get; }
}
///
/// TypeOrMethodDef coded token interface
///
public interface ITypeOrMethodDef : ICodedToken, IHasCustomAttribute, IHasDeclSecurity, IMemberRefParent, IFullName, IMemberRef, IGenericParameterProvider {
///
/// The coded token tag
///
int TypeOrMethodDefTag { get; }
///
/// Gets the generic parameters
///
IList GenericParameters { get; }
///
/// true if is not empty
///
bool HasGenericParameters { get; }
}
///
/// HasCustomDebugInformation interface
///
public interface IHasCustomDebugInformation {
///
/// The custom debug information tag
///
int HasCustomDebugInformationTag { get; }
///
/// Gets the custom debug infos
///
IList CustomDebugInfos { get; }
///
/// true if is not empty
///
bool HasCustomDebugInfos { get; }
}
public static partial class Extensions {
///
/// Converts a to a
///
/// The sig
public static ITypeDefOrRef ToTypeDefOrRef(this TypeSig sig) {
if (sig is null)
return null;
if (sig is TypeDefOrRefSig tdrSig)
return tdrSig.TypeDefOrRef;
var module = sig.Module;
if (module is null)
return new TypeSpecUser(sig);
return module.UpdateRowId(new TypeSpecUser(sig));
}
///
/// Returns true if it's an integer or a floating point type
///
/// Type
///
internal static bool IsPrimitive(this IType tdr) {
if (tdr is null)
return false;
if (!tdr.DefinitionAssembly.IsCorLib())
return false;
switch (tdr.FullName) {
case "System.Boolean":
case "System.Char":
case "System.SByte":
case "System.Byte":
case "System.Int16":
case "System.UInt16":
case "System.Int32":
case "System.UInt32":
case "System.Int64":
case "System.UInt64":
case "System.Single":
case "System.Double":
case "System.IntPtr":
case "System.UIntPtr":
return true;
default:
return false;
}
}
}
}