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