1195 lines
42 KiB
C#
1195 lines
42 KiB
C#
|
// dnlib: See LICENSE.txt for more info
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Reflection;
|
||
|
|
||
|
namespace dnlib.DotNet {
|
||
|
/// <summary>
|
||
|
/// <see cref="Importer"/> options
|
||
|
/// </summary>
|
||
|
[Flags]
|
||
|
public enum ImporterOptions {
|
||
|
/// <summary>
|
||
|
/// Use <see cref="TypeDef"/>s whenever possible if the <see cref="TypeDef"/> is located
|
||
|
/// in this module.
|
||
|
/// </summary>
|
||
|
TryToUseTypeDefs = 1,
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use <see cref="MethodDef"/>s whenever possible if the <see cref="MethodDef"/> is located
|
||
|
/// in this module.
|
||
|
/// </summary>
|
||
|
TryToUseMethodDefs = 2,
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use <see cref="FieldDef"/>s whenever possible if the <see cref="FieldDef"/> is located
|
||
|
/// in this module.
|
||
|
/// </summary>
|
||
|
TryToUseFieldDefs = 4,
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use <see cref="TypeDef"/>s, <see cref="MethodDef"/>s and <see cref="FieldDef"/>s
|
||
|
/// whenever possible if the definition is located in this module.
|
||
|
/// </summary>
|
||
|
/// <seealso cref="TryToUseTypeDefs"/>
|
||
|
/// <seealso cref="TryToUseMethodDefs"/>
|
||
|
/// <seealso cref="TryToUseFieldDefs"/>
|
||
|
TryToUseDefs = TryToUseTypeDefs | TryToUseMethodDefs | TryToUseFieldDefs,
|
||
|
|
||
|
/// <summary>
|
||
|
/// Use already existing <see cref="AssemblyRef"/>s whenever possible
|
||
|
/// </summary>
|
||
|
TryToUseExistingAssemblyRefs = 8,
|
||
|
|
||
|
/// <summary>
|
||
|
/// Don't set this flag. For internal use only.
|
||
|
/// </summary>
|
||
|
FixSignature = int.MinValue,
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Re-maps entities that were renamed in the target module
|
||
|
/// </summary>
|
||
|
public abstract class ImportMapper {
|
||
|
/// <summary>
|
||
|
/// Matches source <see cref="ITypeDefOrRef"/> to the one that is already present in the target module under a different name.
|
||
|
/// </summary>
|
||
|
/// <param name="source"><see cref="ITypeDefOrRef"/> referenced by the entity that is being imported.</param>
|
||
|
/// <returns>matching <see cref="ITypeDefOrRef"/> or <c>null</c> if there's no match.</returns>
|
||
|
public virtual ITypeDefOrRef Map(ITypeDefOrRef source) => null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Matches source <see cref="FieldDef"/> to the one that is already present in the target module under a different name.
|
||
|
/// </summary>
|
||
|
/// <param name="source"><see cref="FieldDef"/> referenced by the entity that is being imported.</param>
|
||
|
/// <returns>matching <see cref="IField"/> or <c>null</c> if there's no match.</returns>
|
||
|
public virtual IField Map(FieldDef source) => null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Matches source <see cref="MethodDef"/> to the one that is already present in the target module under a different name.
|
||
|
/// </summary>
|
||
|
/// <param name="source"><see cref="MethodDef"/> referenced by the entity that is being imported.</param>
|
||
|
/// <returns>matching <see cref="IMethod"/> or <c>null</c> if there's no match.</returns>
|
||
|
public virtual IMethod Map(MethodDef source) => null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Matches source <see cref="MemberRef"/> to the one that is already present in the target module under a different name.
|
||
|
/// </summary>
|
||
|
/// <param name="source"><see cref="MemberRef"/> referenced by the entity that is being imported.</param>
|
||
|
/// <returns>matching <see cref="MemberRef"/> or <c>null</c> if there's no match.</returns>
|
||
|
public virtual MemberRef Map(MemberRef source) => null;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Overrides default behavior of <see cref="Importer.Import(Type)"/>
|
||
|
/// May be used to use reference assemblies for <see cref="Type"/> resolution, for example.
|
||
|
/// </summary>
|
||
|
/// <param name="source"><see cref="Type"/> to create <see cref="ITypeDefOrRef"/> for. <paramref name="source"/> is non-generic type or generic type without generic arguments.</param>
|
||
|
/// <returns><see cref="ITypeDefOrRef"/> or null to use default <see cref="Importer"/>'s type resolution</returns>
|
||
|
public virtual ITypeDefOrRef Map(Type source) => null;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports <see cref="Type"/>s, <see cref="ConstructorInfo"/>s, <see cref="MethodInfo"/>s
|
||
|
/// and <see cref="FieldInfo"/>s as references
|
||
|
/// </summary>
|
||
|
public struct Importer {
|
||
|
readonly ModuleDef module;
|
||
|
internal readonly GenericParamContext gpContext;
|
||
|
readonly ImportMapper mapper;
|
||
|
RecursionCounter recursionCounter;
|
||
|
ImporterOptions options;
|
||
|
|
||
|
bool TryToUseTypeDefs => (options & ImporterOptions.TryToUseTypeDefs) != 0;
|
||
|
bool TryToUseMethodDefs => (options & ImporterOptions.TryToUseMethodDefs) != 0;
|
||
|
bool TryToUseFieldDefs => (options & ImporterOptions.TryToUseFieldDefs) != 0;
|
||
|
bool TryToUseExistingAssemblyRefs => (options & ImporterOptions.TryToUseExistingAssemblyRefs) != 0;
|
||
|
|
||
|
bool FixSignature {
|
||
|
get => (options & ImporterOptions.FixSignature) != 0;
|
||
|
set {
|
||
|
if (value)
|
||
|
options |= ImporterOptions.FixSignature;
|
||
|
else
|
||
|
options &= ~ImporterOptions.FixSignature;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module that will own all references</param>
|
||
|
public Importer(ModuleDef module)
|
||
|
: this(module, 0, new GenericParamContext(), null) {
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module that will own all references</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
public Importer(ModuleDef module, GenericParamContext gpContext)
|
||
|
: this(module, 0, gpContext, null) {
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module that will own all references</param>
|
||
|
/// <param name="options">Importer options</param>
|
||
|
public Importer(ModuleDef module, ImporterOptions options)
|
||
|
: this(module, options, new GenericParamContext(), null) {
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module that will own all references</param>
|
||
|
/// <param name="options">Importer options</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
public Importer(ModuleDef module, ImporterOptions options, GenericParamContext gpContext)
|
||
|
: this(module, options, gpContext, null) {
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module that will own all references</param>
|
||
|
/// <param name="options">Importer options</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <param name="mapper">Mapper for renamed entities</param>
|
||
|
public Importer(ModuleDef module, ImporterOptions options, GenericParamContext gpContext, ImportMapper mapper) {
|
||
|
this.module = module;
|
||
|
recursionCounter = new RecursionCounter();
|
||
|
this.options = options;
|
||
|
this.gpContext = gpContext;
|
||
|
this.mapper = mapper;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
|
||
|
public ITypeDefOrRef Import(Type type) => module.UpdateRowId(ImportAsTypeSig(type).ToTypeDefOrRef());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>. See also <see cref="Import(Type)"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns></returns>
|
||
|
[Obsolete("Use 'Import(Type)' instead.")]
|
||
|
public ITypeDefOrRef ImportDeclaringType(Type type) => Import(type);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <param name="requiredModifiers">A list of all required modifiers or <c>null</c></param>
|
||
|
/// <param name="optionalModifiers">A list of all optional modifiers or <c>null</c></param>
|
||
|
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
|
||
|
public ITypeDefOrRef Import(Type type, IList<Type> requiredModifiers, IList<Type> optionalModifiers) =>
|
||
|
module.UpdateRowId(ImportAsTypeSig(type, requiredModifiers, optionalModifiers).ToTypeDefOrRef());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="Type"/> as a <see cref="TypeSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
|
||
|
public TypeSig ImportAsTypeSig(Type type) => ImportAsTypeSig(type, null, false);
|
||
|
|
||
|
TypeSig ImportAsTypeSig(Type type, Type declaringType, bool? treatAsGenericInst = null) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
bool treatAsGenericInst2 = treatAsGenericInst ?? declaringType.MustTreatTypeAsGenericInstType(type);
|
||
|
switch (treatAsGenericInst2 ? ElementType.GenericInst : type.GetElementType2()) {
|
||
|
case ElementType.Void: return module.CorLibTypes.Void;
|
||
|
case ElementType.Boolean: return module.CorLibTypes.Boolean;
|
||
|
case ElementType.Char: return module.CorLibTypes.Char;
|
||
|
case ElementType.I1: return module.CorLibTypes.SByte;
|
||
|
case ElementType.U1: return module.CorLibTypes.Byte;
|
||
|
case ElementType.I2: return module.CorLibTypes.Int16;
|
||
|
case ElementType.U2: return module.CorLibTypes.UInt16;
|
||
|
case ElementType.I4: return module.CorLibTypes.Int32;
|
||
|
case ElementType.U4: return module.CorLibTypes.UInt32;
|
||
|
case ElementType.I8: return module.CorLibTypes.Int64;
|
||
|
case ElementType.U8: return module.CorLibTypes.UInt64;
|
||
|
case ElementType.R4: return module.CorLibTypes.Single;
|
||
|
case ElementType.R8: return module.CorLibTypes.Double;
|
||
|
case ElementType.String: return module.CorLibTypes.String;
|
||
|
case ElementType.TypedByRef:return module.CorLibTypes.TypedReference;
|
||
|
case ElementType.U: return module.CorLibTypes.UIntPtr;
|
||
|
case ElementType.Object: return module.CorLibTypes.Object;
|
||
|
case ElementType.Ptr: return new PtrSig(ImportAsTypeSig(type.GetElementType(), declaringType));
|
||
|
case ElementType.ByRef: return new ByRefSig(ImportAsTypeSig(type.GetElementType(), declaringType));
|
||
|
case ElementType.SZArray: return new SZArraySig(ImportAsTypeSig(type.GetElementType(), declaringType));
|
||
|
case ElementType.ValueType: return new ValueTypeSig(CreateTypeDefOrRef(type));
|
||
|
case ElementType.Class: return new ClassSig(CreateTypeDefOrRef(type));
|
||
|
case ElementType.Var: return new GenericVar((uint)type.GenericParameterPosition, gpContext.Type);
|
||
|
case ElementType.MVar: return new GenericMVar((uint)type.GenericParameterPosition, gpContext.Method);
|
||
|
|
||
|
case ElementType.I:
|
||
|
FixSignature = true; // FnPtr is mapped to System.IntPtr
|
||
|
return module.CorLibTypes.IntPtr;
|
||
|
|
||
|
case ElementType.Array:
|
||
|
// We don't know sizes and lower bounds. Assume it's `0..`
|
||
|
var lowerBounds = new int[type.GetArrayRank()];
|
||
|
var sizes = Array2.Empty<uint>();
|
||
|
FixSignature = true;
|
||
|
return new ArraySig(ImportAsTypeSig(type.GetElementType(), declaringType), (uint)type.GetArrayRank(), sizes, lowerBounds);
|
||
|
|
||
|
case ElementType.GenericInst:
|
||
|
var typeGenArgs = type.GetGenericArguments();
|
||
|
var git = new GenericInstSig(ImportAsTypeSig(type.GetGenericTypeDefinition(), null, false) as ClassOrValueTypeSig, (uint)typeGenArgs.Length);
|
||
|
foreach (var ga in typeGenArgs)
|
||
|
git.GenericArguments.Add(ImportAsTypeSig(ga, declaringType));
|
||
|
return git;
|
||
|
|
||
|
case ElementType.Sentinel:
|
||
|
case ElementType.Pinned:
|
||
|
case ElementType.FnPtr: // mapped to System.IntPtr
|
||
|
case ElementType.CModReqd:
|
||
|
case ElementType.CModOpt:
|
||
|
case ElementType.ValueArray:
|
||
|
case ElementType.R:
|
||
|
case ElementType.Internal:
|
||
|
case ElementType.Module:
|
||
|
case ElementType.End:
|
||
|
default:
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ITypeDefOrRef TryResolve(TypeRef tr) {
|
||
|
if (!TryToUseTypeDefs || tr is null)
|
||
|
return tr;
|
||
|
if (!IsThisModule(tr))
|
||
|
return tr;
|
||
|
var td = tr.Resolve();
|
||
|
if (td is null || td.Module != module)
|
||
|
return tr;
|
||
|
return td;
|
||
|
}
|
||
|
|
||
|
IMethodDefOrRef TryResolveMethod(IMethodDefOrRef mdr) {
|
||
|
if (!TryToUseMethodDefs || mdr is null)
|
||
|
return mdr;
|
||
|
|
||
|
var mr = mdr as MemberRef;
|
||
|
if (mr is null)
|
||
|
return mdr;
|
||
|
if (!mr.IsMethodRef)
|
||
|
return mr;
|
||
|
|
||
|
var declType = GetDeclaringType(mr);
|
||
|
if (declType is null)
|
||
|
return mr;
|
||
|
if (declType.Module != module)
|
||
|
return mr;
|
||
|
return (IMethodDefOrRef)declType.ResolveMethod(mr) ?? mr;
|
||
|
}
|
||
|
|
||
|
IField TryResolveField(MemberRef mr) {
|
||
|
if (!TryToUseFieldDefs || mr is null)
|
||
|
return mr;
|
||
|
|
||
|
if (!mr.IsFieldRef)
|
||
|
return mr;
|
||
|
|
||
|
var declType = GetDeclaringType(mr);
|
||
|
if (declType is null)
|
||
|
return mr;
|
||
|
if (declType.Module != module)
|
||
|
return mr;
|
||
|
return (IField)declType.ResolveField(mr) ?? mr;
|
||
|
}
|
||
|
|
||
|
TypeDef GetDeclaringType(MemberRef mr) {
|
||
|
if (mr is null)
|
||
|
return null;
|
||
|
|
||
|
if (mr.Class is TypeDef td)
|
||
|
return td;
|
||
|
|
||
|
td = TryResolve(mr.Class as TypeRef) as TypeDef;
|
||
|
if (td is not null)
|
||
|
return td;
|
||
|
|
||
|
var modRef = mr.Class as ModuleRef;
|
||
|
if (IsThisModule(modRef))
|
||
|
return module.GlobalType;
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
bool IsThisModule(TypeRef tr) {
|
||
|
if (tr is null)
|
||
|
return false;
|
||
|
var scopeType = tr.GetNonNestedTypeRefScope() as TypeRef;
|
||
|
if (scopeType is null)
|
||
|
return false;
|
||
|
|
||
|
if (module == scopeType.ResolutionScope)
|
||
|
return true;
|
||
|
|
||
|
if (scopeType.ResolutionScope is ModuleRef modRef)
|
||
|
return IsThisModule(modRef);
|
||
|
|
||
|
var asmRef = scopeType.ResolutionScope as AssemblyRef;
|
||
|
return Equals(module.Assembly, asmRef);
|
||
|
}
|
||
|
|
||
|
bool IsThisModule(ModuleRef modRef) =>
|
||
|
modRef is not null &&
|
||
|
module.Name == modRef.Name &&
|
||
|
Equals(module.Assembly, modRef.DefinitionAssembly);
|
||
|
|
||
|
static bool Equals(IAssembly a, IAssembly b) {
|
||
|
if (a == b)
|
||
|
return true;
|
||
|
if (a is null || b is null)
|
||
|
return false;
|
||
|
return Utils.Equals(a.Version, b.Version) &&
|
||
|
PublicKeyBase.TokenEquals(a.PublicKeyOrToken, b.PublicKeyOrToken) &&
|
||
|
UTF8String.Equals(a.Name, b.Name) &&
|
||
|
UTF8String.CaseInsensitiveEquals(a.Culture, b.Culture);
|
||
|
}
|
||
|
|
||
|
ITypeDefOrRef CreateTypeDefOrRef(Type type) {
|
||
|
var tdr = mapper?.Map(type);
|
||
|
if (tdr is TypeSpec)
|
||
|
throw new InvalidOperationException();
|
||
|
if (tdr is TypeDef td)
|
||
|
return td;
|
||
|
if (tdr is TypeRef tr)
|
||
|
return TryResolve(tr);
|
||
|
|
||
|
if (TryToUseTypeDefs && IsThisModule(type.Module) && module.ResolveToken(type.MetadataToken) is TypeDef def)
|
||
|
return def;
|
||
|
|
||
|
return TryResolve(CreateTypeRef(type));
|
||
|
}
|
||
|
|
||
|
TypeRef CreateTypeRef(Type type) {
|
||
|
if (!type.IsNested)
|
||
|
return module.UpdateRowId(new TypeRefUser(module, type.Namespace ?? string.Empty, ReflectionExtensions.Unescape(type.Name) ?? string.Empty, CreateScopeReference(type)));
|
||
|
type.GetTypeNamespaceAndName_TypeDefOrRef(out var @namespace, out var name);
|
||
|
return module.UpdateRowId(new TypeRefUser(module, @namespace ?? string.Empty, name ?? string.Empty, CreateTypeRef(type.DeclaringType)));
|
||
|
}
|
||
|
|
||
|
IResolutionScope CreateScopeReference(Type type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
var asmName = type.Assembly.GetName();
|
||
|
var modAsm = module.Assembly;
|
||
|
if (modAsm is not null) {
|
||
|
if (UTF8String.ToSystemStringOrEmpty(modAsm.Name).Equals(asmName.Name, StringComparison.OrdinalIgnoreCase)) {
|
||
|
if (UTF8String.ToSystemStringOrEmpty(module.Name).Equals(type.Module.ScopeName, StringComparison.OrdinalIgnoreCase))
|
||
|
return module;
|
||
|
return module.UpdateRowId(new ModuleRefUser(module, type.Module.ScopeName));
|
||
|
}
|
||
|
}
|
||
|
var pkt = asmName.GetPublicKeyToken();
|
||
|
if (pkt is null || pkt.Length == 0)
|
||
|
pkt = null;
|
||
|
if (TryToUseExistingAssemblyRefs && module.GetAssemblyRef(asmName.Name) is AssemblyRef asmRef)
|
||
|
return asmRef;
|
||
|
return module.UpdateRowId(new AssemblyRefUser(asmName.Name, asmName.Version, PublicKeyBase.CreatePublicKeyToken(pkt), asmName.CultureInfo?.Name ?? string.Empty));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="Type"/> as a <see cref="ITypeDefOrRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <param name="requiredModifiers">A list of all required modifiers or <c>null</c></param>
|
||
|
/// <param name="optionalModifiers">A list of all optional modifiers or <c>null</c></param>
|
||
|
/// <returns>The imported type or <c>null</c> if <paramref name="type"/> is invalid</returns>
|
||
|
public TypeSig ImportAsTypeSig(Type type, IList<Type> requiredModifiers, IList<Type> optionalModifiers) =>
|
||
|
ImportAsTypeSig(type, requiredModifiers, optionalModifiers, null);
|
||
|
|
||
|
TypeSig ImportAsTypeSig(Type type, IList<Type> requiredModifiers, IList<Type> optionalModifiers, Type declaringType) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (IsEmpty(requiredModifiers) && IsEmpty(optionalModifiers))
|
||
|
return ImportAsTypeSig(type, declaringType);
|
||
|
|
||
|
FixSignature = true; // Order of modifiers is unknown
|
||
|
var ts = ImportAsTypeSig(type, declaringType);
|
||
|
|
||
|
// We don't know the original order of the modifiers.
|
||
|
// Assume all required modifiers are closer to the real type.
|
||
|
// Assume all modifiers should be applied in the same order as in the lists.
|
||
|
|
||
|
if (requiredModifiers is not null) {
|
||
|
foreach (var modifier in requiredModifiers)
|
||
|
ts = new CModReqdSig(Import(modifier), ts);
|
||
|
}
|
||
|
|
||
|
if (optionalModifiers is not null) {
|
||
|
foreach (var modifier in optionalModifiers)
|
||
|
ts = new CModOptSig(Import(modifier), ts);
|
||
|
}
|
||
|
|
||
|
return ts;
|
||
|
}
|
||
|
|
||
|
static bool IsEmpty<T>(IList<T> list) => list is null || list.Count == 0;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="MethodBase"/> as a <see cref="IMethod"/>. This will be either
|
||
|
/// a <see cref="MemberRef"/> or a <see cref="MethodSpec"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="methodBase">The method</param>
|
||
|
/// <returns>The imported method or <c>null</c> if <paramref name="methodBase"/> is invalid
|
||
|
/// or if we failed to import the method</returns>
|
||
|
public IMethod Import(MethodBase methodBase) => Import(methodBase, false);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="MethodBase"/> as a <see cref="IMethod"/>. This will be either
|
||
|
/// a <see cref="MemberRef"/> or a <see cref="MethodSpec"/>.
|
||
|
/// </summary>
|
||
|
/// <param name="methodBase">The method</param>
|
||
|
/// <param name="forceFixSignature">Always verify method signature to make sure the
|
||
|
/// returned reference matches the metadata in the source assembly</param>
|
||
|
/// <returns>The imported method or <c>null</c> if <paramref name="methodBase"/> is invalid
|
||
|
/// or if we failed to import the method</returns>
|
||
|
public IMethod Import(MethodBase methodBase, bool forceFixSignature) {
|
||
|
FixSignature = false;
|
||
|
return ImportInternal(methodBase, forceFixSignature);
|
||
|
}
|
||
|
|
||
|
IMethod ImportInternal(MethodBase methodBase) => ImportInternal(methodBase, false);
|
||
|
|
||
|
IMethod ImportInternal(MethodBase methodBase, bool forceFixSignature) {
|
||
|
if (methodBase is null)
|
||
|
return null;
|
||
|
|
||
|
if (TryToUseMethodDefs && IsThisModule(methodBase.Module) &&
|
||
|
!methodBase.IsGenericMethod && (methodBase.DeclaringType is null || !methodBase.DeclaringType.IsGenericType) &&
|
||
|
module.ResolveToken(methodBase.MetadataToken) is MethodDef md) {
|
||
|
// In same module and method and declaring type are both non-generic, directly resolve method definition.
|
||
|
// Obfuscator may rename many methods into same name then TryResolveMethod will return inconsistent method.
|
||
|
return md;
|
||
|
}
|
||
|
|
||
|
if (forceFixSignature) {
|
||
|
//TODO:
|
||
|
}
|
||
|
|
||
|
bool isMethodSpec = methodBase.IsGenericButNotGenericMethodDefinition();
|
||
|
if (isMethodSpec) {
|
||
|
IMethodDefOrRef method;
|
||
|
var origMethod = methodBase.Module.ResolveMethod(methodBase.MetadataToken);
|
||
|
if (methodBase.DeclaringType.GetElementType2() == ElementType.GenericInst)
|
||
|
method = module.UpdateRowId(new MemberRefUser(module, methodBase.Name, CreateMethodSig(origMethod), Import(methodBase.DeclaringType)));
|
||
|
else
|
||
|
method = ImportInternal(origMethod) as IMethodDefOrRef;
|
||
|
|
||
|
method = TryResolveMethod(method);
|
||
|
if (methodBase.ContainsGenericParameters)
|
||
|
return method; // Declaring type is instantiated but method itself is not
|
||
|
|
||
|
var gim = CreateGenericInstMethodSig(methodBase);
|
||
|
var methodSpec = module.UpdateRowId(new MethodSpecUser(method, gim));
|
||
|
if (FixSignature && !forceFixSignature) {
|
||
|
//TODO:
|
||
|
}
|
||
|
return methodSpec;
|
||
|
}
|
||
|
else {
|
||
|
IMemberRefParent parent;
|
||
|
if (methodBase.DeclaringType is null) {
|
||
|
// It's the global type. We can reference it with a ModuleRef token.
|
||
|
parent = GetModuleParent(methodBase.Module);
|
||
|
}
|
||
|
else
|
||
|
parent = Import(methodBase.DeclaringType);
|
||
|
if (parent is null)
|
||
|
return null;
|
||
|
|
||
|
MethodBase origMethod;
|
||
|
try {
|
||
|
// Get the original method def in case the declaring type is a generic
|
||
|
// type instance and the method uses at least one generic type parameter.
|
||
|
origMethod = methodBase.Module.ResolveMethod(methodBase.MetadataToken);
|
||
|
}
|
||
|
catch (ArgumentException) {
|
||
|
// Here if eg. the method was created by the runtime (eg. a multi-dimensional
|
||
|
// array getter/setter method). The method token is in that case 0x06000000,
|
||
|
// which is invalid.
|
||
|
origMethod = methodBase;
|
||
|
}
|
||
|
|
||
|
var methodSig = CreateMethodSig(origMethod);
|
||
|
IMethodDefOrRef methodRef = module.UpdateRowId(new MemberRefUser(module, methodBase.Name, methodSig, parent));
|
||
|
methodRef = TryResolveMethod(methodRef);
|
||
|
if (FixSignature && !forceFixSignature) {
|
||
|
//TODO:
|
||
|
}
|
||
|
return methodRef;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool IsThisModule(Module module2) => UTF8String.ToSystemStringOrEmpty(module.Name).Equals(module2.ScopeName, StringComparison.OrdinalIgnoreCase) && IsThisAssembly(module2);
|
||
|
|
||
|
MethodSig CreateMethodSig(MethodBase mb) {
|
||
|
var sig = new MethodSig(GetCallingConvention(mb));
|
||
|
|
||
|
if (mb is MethodInfo mi)
|
||
|
sig.RetType = ImportAsTypeSig(mi.ReturnParameter, mb.DeclaringType);
|
||
|
else
|
||
|
sig.RetType = module.CorLibTypes.Void;
|
||
|
|
||
|
foreach (var p in mb.GetParameters())
|
||
|
sig.Params.Add(ImportAsTypeSig(p, mb.DeclaringType));
|
||
|
|
||
|
if (mb.IsGenericMethodDefinition)
|
||
|
sig.GenParamCount = (uint)mb.GetGenericArguments().Length;
|
||
|
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
TypeSig ImportAsTypeSig(ParameterInfo p, Type declaringType) =>
|
||
|
ImportAsTypeSig(p.ParameterType, p.GetRequiredCustomModifiers(), p.GetOptionalCustomModifiers(), declaringType);
|
||
|
|
||
|
CallingConvention GetCallingConvention(MethodBase mb) {
|
||
|
CallingConvention cc = 0;
|
||
|
|
||
|
var mbcc = mb.CallingConvention;
|
||
|
if (mb.IsGenericMethodDefinition)
|
||
|
cc |= CallingConvention.Generic;
|
||
|
if ((mbcc & CallingConventions.HasThis) != 0)
|
||
|
cc |= CallingConvention.HasThis;
|
||
|
if ((mbcc & CallingConventions.ExplicitThis) != 0)
|
||
|
cc |= CallingConvention.ExplicitThis;
|
||
|
|
||
|
switch (mbcc & CallingConventions.Any) {
|
||
|
case CallingConventions.Standard:
|
||
|
cc |= CallingConvention.Default;
|
||
|
break;
|
||
|
|
||
|
case CallingConventions.VarArgs:
|
||
|
cc |= CallingConvention.VarArg;
|
||
|
break;
|
||
|
|
||
|
case CallingConventions.Any:
|
||
|
default:
|
||
|
FixSignature = true;
|
||
|
cc |= CallingConvention.Default;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return cc;
|
||
|
}
|
||
|
|
||
|
GenericInstMethodSig CreateGenericInstMethodSig(MethodBase mb) {
|
||
|
var genMethodArgs = mb.GetGenericArguments();
|
||
|
var gim = new GenericInstMethodSig(CallingConvention.GenericInst, (uint)genMethodArgs.Length);
|
||
|
foreach (var gma in genMethodArgs)
|
||
|
gim.GenericArguments.Add(ImportAsTypeSig(gma));
|
||
|
return gim;
|
||
|
}
|
||
|
|
||
|
IMemberRefParent GetModuleParent(Module module2) {
|
||
|
if (!IsThisAssembly(module2))
|
||
|
return null;
|
||
|
return module.UpdateRowId(new ModuleRefUser(module, module.Name));
|
||
|
}
|
||
|
|
||
|
bool IsThisAssembly(Module module2) {
|
||
|
// If we have no assembly, assume this is a netmodule in the same assembly as module
|
||
|
var modAsm = module.Assembly;
|
||
|
return modAsm is null || UTF8String.ToSystemStringOrEmpty(modAsm.Name).Equals(module2.Assembly.GetName().Name, StringComparison.OrdinalIgnoreCase);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="FieldInfo"/> as a <see cref="MemberRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="fieldInfo">The field</param>
|
||
|
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
|
||
|
/// or if we failed to import the field</returns>
|
||
|
public IField Import(FieldInfo fieldInfo) => Import(fieldInfo, false);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="FieldInfo"/> as a <see cref="MemberRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="fieldInfo">The field</param>
|
||
|
/// <param name="forceFixSignature">Always verify field signature to make sure the
|
||
|
/// returned reference matches the metadata in the source assembly</param>
|
||
|
/// <returns>The imported field or <c>null</c> if <paramref name="fieldInfo"/> is invalid
|
||
|
/// or if we failed to import the field</returns>
|
||
|
public IField Import(FieldInfo fieldInfo, bool forceFixSignature) {
|
||
|
FixSignature = false;
|
||
|
if (fieldInfo is null)
|
||
|
return null;
|
||
|
|
||
|
if (TryToUseFieldDefs && IsThisModule(fieldInfo.Module) &&
|
||
|
(fieldInfo.DeclaringType is null || !fieldInfo.DeclaringType.IsGenericType) &&
|
||
|
module.ResolveToken(fieldInfo.MetadataToken) is FieldDef fd) {
|
||
|
// In same module and declaring type is non-generic, directly resolve field definition.
|
||
|
// Obfuscator may rename many fields into same name then TryResolveField will return inconsistent field.
|
||
|
return fd;
|
||
|
}
|
||
|
|
||
|
if (forceFixSignature) {
|
||
|
//TODO:
|
||
|
}
|
||
|
|
||
|
IMemberRefParent parent;
|
||
|
if (fieldInfo.DeclaringType is null) {
|
||
|
// It's the global type. We can reference it with a ModuleRef token.
|
||
|
parent = GetModuleParent(fieldInfo.Module);
|
||
|
}
|
||
|
else
|
||
|
parent = Import(fieldInfo.DeclaringType);
|
||
|
if (parent is null)
|
||
|
return null;
|
||
|
|
||
|
FieldInfo origField;
|
||
|
try {
|
||
|
// Get the original field def in case the declaring type is a generic
|
||
|
// type instance and the field uses a generic type parameter.
|
||
|
origField = fieldInfo.Module.ResolveField(fieldInfo.MetadataToken);
|
||
|
}
|
||
|
catch (ArgumentException) {
|
||
|
origField = fieldInfo;
|
||
|
}
|
||
|
|
||
|
var fieldSig = new FieldSig(ImportAsTypeSig(origField.FieldType,
|
||
|
origField.GetRequiredCustomModifiers(), origField.GetOptionalCustomModifiers(), origField.DeclaringType));
|
||
|
var fieldRef = module.UpdateRowId(new MemberRefUser(module, fieldInfo.Name, fieldSig, parent));
|
||
|
|
||
|
var field = TryResolveField(fieldRef);
|
||
|
if (FixSignature && !forceFixSignature) {
|
||
|
//TODO:
|
||
|
}
|
||
|
return field;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="IType"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c></returns>
|
||
|
public IType Import(IType type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
IType result;
|
||
|
TypeDef td;
|
||
|
TypeRef tr;
|
||
|
TypeSpec ts;
|
||
|
TypeSig sig;
|
||
|
|
||
|
if ((td = type as TypeDef) is not null)
|
||
|
result = Import(td);
|
||
|
else if ((tr = type as TypeRef) is not null)
|
||
|
result = Import(tr);
|
||
|
else if ((ts = type as TypeSpec) is not null)
|
||
|
result = Import(ts);
|
||
|
else if ((sig = type as TypeSig) is not null)
|
||
|
result = Import(sig);
|
||
|
else
|
||
|
result = null;
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="TypeDef"/> as a <see cref="TypeRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c></returns>
|
||
|
public ITypeDefOrRef Import(TypeDef type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (TryToUseTypeDefs && type.Module == module)
|
||
|
return type;
|
||
|
var mapped = mapper?.Map(type);
|
||
|
if (mapped is not null)
|
||
|
return mapped;
|
||
|
return Import2(type);
|
||
|
}
|
||
|
|
||
|
TypeRef Import2(TypeDef type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
TypeRef result;
|
||
|
|
||
|
var declType = type.DeclaringType;
|
||
|
if (declType is not null)
|
||
|
result = module.UpdateRowId(new TypeRefUser(module, type.Namespace, type.Name, Import2(declType)));
|
||
|
else
|
||
|
result = module.UpdateRowId(new TypeRefUser(module, type.Namespace, type.Name, CreateScopeReference(type.DefinitionAssembly, type.Module)));
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
IResolutionScope CreateScopeReference(IAssembly defAsm, ModuleDef defMod) {
|
||
|
if (defAsm is null)
|
||
|
return null;
|
||
|
var modAsm = module.Assembly;
|
||
|
if (defMod is not null && defAsm is not null && modAsm is not null) {
|
||
|
if (UTF8String.CaseInsensitiveEquals(modAsm.Name, defAsm.Name)) {
|
||
|
if (UTF8String.CaseInsensitiveEquals(module.Name, defMod.Name))
|
||
|
return module;
|
||
|
return module.UpdateRowId(new ModuleRefUser(module, defMod.Name));
|
||
|
}
|
||
|
}
|
||
|
var pkt = PublicKeyBase.ToPublicKeyToken(defAsm.PublicKeyOrToken);
|
||
|
if (PublicKeyBase.IsNullOrEmpty2(pkt))
|
||
|
pkt = null;
|
||
|
if (TryToUseExistingAssemblyRefs && module.GetAssemblyRef(defAsm.Name) is AssemblyRef asmRef)
|
||
|
return asmRef;
|
||
|
return module.UpdateRowId(new AssemblyRefUser(defAsm.Name, defAsm.Version, pkt, defAsm.Culture) { Attributes = defAsm.Attributes & ~AssemblyAttributes.PublicKey });
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="TypeRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c></returns>
|
||
|
public ITypeDefOrRef Import(TypeRef type) {
|
||
|
var mapped = mapper?.Map(type);
|
||
|
if (mapped is not null)
|
||
|
return mapped;
|
||
|
|
||
|
return TryResolve(Import2(type));
|
||
|
}
|
||
|
|
||
|
TypeRef Import2(TypeRef type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
TypeRef result;
|
||
|
|
||
|
var declaringType = type.DeclaringType;
|
||
|
if (declaringType is not null)
|
||
|
result = module.UpdateRowId(new TypeRefUser(module, type.Namespace, type.Name, Import2(declaringType)));
|
||
|
else
|
||
|
result = module.UpdateRowId(new TypeRefUser(module, type.Namespace, type.Name, CreateScopeReference(type.DefinitionAssembly, type.Module)));
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="TypeSpec"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c></returns>
|
||
|
public TypeSpec Import(TypeSpec type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
return module.UpdateRowId(new TypeSpecUser(Import(type.TypeSig)));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="TypeSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c></returns>
|
||
|
public TypeSig Import(TypeSig type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
TypeSig result;
|
||
|
switch (type.ElementType) {
|
||
|
case ElementType.Void: result = module.CorLibTypes.Void; break;
|
||
|
case ElementType.Boolean: result = module.CorLibTypes.Boolean; break;
|
||
|
case ElementType.Char: result = module.CorLibTypes.Char; break;
|
||
|
case ElementType.I1: result = module.CorLibTypes.SByte; break;
|
||
|
case ElementType.U1: result = module.CorLibTypes.Byte; break;
|
||
|
case ElementType.I2: result = module.CorLibTypes.Int16; break;
|
||
|
case ElementType.U2: result = module.CorLibTypes.UInt16; break;
|
||
|
case ElementType.I4: result = module.CorLibTypes.Int32; break;
|
||
|
case ElementType.U4: result = module.CorLibTypes.UInt32; break;
|
||
|
case ElementType.I8: result = module.CorLibTypes.Int64; break;
|
||
|
case ElementType.U8: result = module.CorLibTypes.UInt64; break;
|
||
|
case ElementType.R4: result = module.CorLibTypes.Single; break;
|
||
|
case ElementType.R8: result = module.CorLibTypes.Double; break;
|
||
|
case ElementType.String: result = module.CorLibTypes.String; break;
|
||
|
case ElementType.TypedByRef:result = module.CorLibTypes.TypedReference; break;
|
||
|
case ElementType.I: result = module.CorLibTypes.IntPtr; break;
|
||
|
case ElementType.U: result = module.CorLibTypes.UIntPtr; break;
|
||
|
case ElementType.Object: result = module.CorLibTypes.Object; break;
|
||
|
case ElementType.Ptr: result = new PtrSig(Import(type.Next)); break;
|
||
|
case ElementType.ByRef: result = new ByRefSig(Import(type.Next)); break;
|
||
|
case ElementType.ValueType: result = CreateClassOrValueType((type as ClassOrValueTypeSig).TypeDefOrRef, true); break;
|
||
|
case ElementType.Class: result = CreateClassOrValueType((type as ClassOrValueTypeSig).TypeDefOrRef, false); break;
|
||
|
case ElementType.Var: result = new GenericVar((type as GenericVar).Number, gpContext.Type); break;
|
||
|
case ElementType.ValueArray:result = new ValueArraySig(Import(type.Next), (type as ValueArraySig).Size); break;
|
||
|
case ElementType.FnPtr: result = new FnPtrSig(Import((type as FnPtrSig).Signature)); break;
|
||
|
case ElementType.SZArray: result = new SZArraySig(Import(type.Next)); break;
|
||
|
case ElementType.MVar: result = new GenericMVar((type as GenericMVar).Number, gpContext.Method); break;
|
||
|
case ElementType.CModReqd: result = new CModReqdSig(Import((type as ModifierSig).Modifier), Import(type.Next)); break;
|
||
|
case ElementType.CModOpt: result = new CModOptSig(Import((type as ModifierSig).Modifier), Import(type.Next)); break;
|
||
|
case ElementType.Module: result = new ModuleSig((type as ModuleSig).Index, Import(type.Next)); break;
|
||
|
case ElementType.Sentinel: result = new SentinelSig(); break;
|
||
|
case ElementType.Pinned: result = new PinnedSig(Import(type.Next)); break;
|
||
|
|
||
|
case ElementType.Array:
|
||
|
var arraySig = (ArraySig)type;
|
||
|
var sizes = new List<uint>(arraySig.Sizes);
|
||
|
var lbounds = new List<int>(arraySig.LowerBounds);
|
||
|
result = new ArraySig(Import(type.Next), arraySig.Rank, sizes, lbounds);
|
||
|
break;
|
||
|
|
||
|
case ElementType.GenericInst:
|
||
|
var gis = (GenericInstSig)type;
|
||
|
var genArgs = new List<TypeSig>(gis.GenericArguments.Count);
|
||
|
foreach (var ga in gis.GenericArguments)
|
||
|
genArgs.Add(Import(ga));
|
||
|
result = new GenericInstSig(Import(gis.GenericType) as ClassOrValueTypeSig, genArgs);
|
||
|
break;
|
||
|
|
||
|
case ElementType.End:
|
||
|
case ElementType.R:
|
||
|
case ElementType.Internal:
|
||
|
default:
|
||
|
result = null;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="ITypeDefOrRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="type">The type</param>
|
||
|
/// <returns>The imported type or <c>null</c></returns>
|
||
|
public ITypeDefOrRef Import(ITypeDefOrRef type) => (ITypeDefOrRef)Import((IType)type);
|
||
|
|
||
|
TypeSig CreateClassOrValueType(ITypeDefOrRef type, bool isValueType) {
|
||
|
var corLibType = module.CorLibTypes.GetCorLibTypeSig(type);
|
||
|
if (corLibType is not null)
|
||
|
return corLibType;
|
||
|
|
||
|
if (isValueType)
|
||
|
return new ValueTypeSig(Import(type));
|
||
|
return new ClassSig(Import(type));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="CallingConventionSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="sig">The sig</param>
|
||
|
/// <returns>The imported sig or <c>null</c> if input is invalid</returns>
|
||
|
public CallingConventionSig Import(CallingConventionSig sig) {
|
||
|
if (sig is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
CallingConventionSig result;
|
||
|
|
||
|
var sigType = sig.GetType();
|
||
|
if (sigType == typeof(MethodSig))
|
||
|
result = Import((MethodSig)sig);
|
||
|
else if (sigType == typeof(FieldSig))
|
||
|
result = Import((FieldSig)sig);
|
||
|
else if (sigType == typeof(GenericInstMethodSig))
|
||
|
result = Import((GenericInstMethodSig)sig);
|
||
|
else if (sigType == typeof(PropertySig))
|
||
|
result = Import((PropertySig)sig);
|
||
|
else if (sigType == typeof(LocalSig))
|
||
|
result = Import((LocalSig)sig);
|
||
|
else
|
||
|
result = null; // Should never be reached
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="FieldSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="sig">The sig</param>
|
||
|
/// <returns>The imported sig or <c>null</c> if input is invalid</returns>
|
||
|
public FieldSig Import(FieldSig sig) {
|
||
|
if (sig is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
var result = new FieldSig(sig.GetCallingConvention(), Import(sig.Type));
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="MethodSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="sig">The sig</param>
|
||
|
/// <returns>The imported sig or <c>null</c> if input is invalid</returns>
|
||
|
public MethodSig Import(MethodSig sig) {
|
||
|
if (sig is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
var result = Import(new MethodSig(sig.GetCallingConvention()), sig);
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
T Import<T>(T sig, T old) where T : MethodBaseSig {
|
||
|
sig.RetType = Import(old.RetType);
|
||
|
foreach (var p in old.Params)
|
||
|
sig.Params.Add(Import(p));
|
||
|
sig.GenParamCount = old.GenParamCount;
|
||
|
var paramsAfterSentinel = sig.ParamsAfterSentinel;
|
||
|
if (paramsAfterSentinel is not null) {
|
||
|
foreach (var p in old.ParamsAfterSentinel)
|
||
|
paramsAfterSentinel.Add(Import(p));
|
||
|
}
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="PropertySig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="sig">The sig</param>
|
||
|
/// <returns>The imported sig or <c>null</c> if input is invalid</returns>
|
||
|
public PropertySig Import(PropertySig sig) {
|
||
|
if (sig is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
var result = Import(new PropertySig(sig.GetCallingConvention()), sig);
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="LocalSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="sig">The sig</param>
|
||
|
/// <returns>The imported sig or <c>null</c> if input is invalid</returns>
|
||
|
public LocalSig Import(LocalSig sig) {
|
||
|
if (sig is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
var result = new LocalSig(sig.GetCallingConvention(), (uint)sig.Locals.Count);
|
||
|
foreach (var l in sig.Locals)
|
||
|
result.Locals.Add(Import(l));
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="GenericInstMethodSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="sig">The sig</param>
|
||
|
/// <returns>The imported sig or <c>null</c> if input is invalid</returns>
|
||
|
public GenericInstMethodSig Import(GenericInstMethodSig sig) {
|
||
|
if (sig is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
var result = new GenericInstMethodSig(sig.GetCallingConvention(), (uint)sig.GenericArguments.Count);
|
||
|
foreach (var l in sig.GenericArguments)
|
||
|
result.GenericArguments.Add(Import(l));
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="IField"/>
|
||
|
/// </summary>
|
||
|
/// <param name="field">The field</param>
|
||
|
/// <returns>The imported type or <c>null</c> if <paramref name="field"/> is invalid</returns>
|
||
|
public IField Import(IField field) {
|
||
|
if (field is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
IField result;
|
||
|
MemberRef mr;
|
||
|
FieldDef fd;
|
||
|
|
||
|
if ((fd = field as FieldDef) is not null)
|
||
|
result = Import(fd);
|
||
|
else if ((mr = field as MemberRef) is not null)
|
||
|
result = Import(mr);
|
||
|
else
|
||
|
result = null;
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="IMethod"/>
|
||
|
/// </summary>
|
||
|
/// <param name="method">The method</param>
|
||
|
/// <returns>The imported method or <c>null</c> if <paramref name="method"/> is invalid</returns>
|
||
|
public IMethod Import(IMethod method) {
|
||
|
if (method is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
IMethod result;
|
||
|
MethodDef md;
|
||
|
MethodSpec ms;
|
||
|
MemberRef mr;
|
||
|
|
||
|
if ((md = method as MethodDef) is not null)
|
||
|
result = Import(md);
|
||
|
else if ((ms = method as MethodSpec) is not null)
|
||
|
result = Import(ms);
|
||
|
else if ((mr = method as MemberRef) is not null)
|
||
|
result = Import(mr);
|
||
|
else
|
||
|
result = null;
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="FieldDef"/> as an <see cref="IField"/>
|
||
|
/// </summary>
|
||
|
/// <param name="field">The field</param>
|
||
|
/// <returns>The imported type or <c>null</c> if <paramref name="field"/> is invalid</returns>
|
||
|
public IField Import(FieldDef field) {
|
||
|
if (field is null)
|
||
|
return null;
|
||
|
if (TryToUseFieldDefs && field.Module == module)
|
||
|
return field;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
var mapped = mapper?.Map(field);
|
||
|
if (mapped is not null) {
|
||
|
recursionCounter.Decrement();
|
||
|
return mapped;
|
||
|
}
|
||
|
|
||
|
MemberRef result = module.UpdateRowId(new MemberRefUser(module, field.Name));
|
||
|
result.Signature = Import(field.Signature);
|
||
|
result.Class = ImportParent(field.DeclaringType);
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
IMemberRefParent ImportParent(TypeDef type) {
|
||
|
if (type is null)
|
||
|
return null;
|
||
|
if (type.IsGlobalModuleType)
|
||
|
return module.UpdateRowId(new ModuleRefUser(module, type.Module?.Name));
|
||
|
return Import(type);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="MethodDef"/> as an <see cref="IMethod"/>
|
||
|
/// </summary>
|
||
|
/// <param name="method">The method</param>
|
||
|
/// <returns>The imported method or <c>null</c> if <paramref name="method"/> is invalid</returns>
|
||
|
public IMethod Import(MethodDef method) {
|
||
|
if (method is null)
|
||
|
return null;
|
||
|
if (TryToUseMethodDefs && method.Module == module)
|
||
|
return method;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
var mapped = mapper?.Map(method);
|
||
|
if (mapped is not null) {
|
||
|
recursionCounter.Decrement();
|
||
|
return mapped;
|
||
|
}
|
||
|
|
||
|
MemberRef result = module.UpdateRowId(new MemberRefUser(module, method.Name));
|
||
|
result.Signature = Import(method.Signature);
|
||
|
result.Class = ImportParent(method.DeclaringType);
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="MethodSpec"/>
|
||
|
/// </summary>
|
||
|
/// <param name="method">The method</param>
|
||
|
/// <returns>The imported method or <c>null</c> if <paramref name="method"/> is invalid</returns>
|
||
|
public MethodSpec Import(MethodSpec method) {
|
||
|
if (method is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
MethodSpec result = module.UpdateRowId(new MethodSpecUser((IMethodDefOrRef)Import(method.Method)));
|
||
|
result.Instantiation = Import(method.Instantiation);
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Imports a <see cref="MemberRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="memberRef">The member ref</param>
|
||
|
/// <returns>The imported member ref or <c>null</c> if <paramref name="memberRef"/> is invalid</returns>
|
||
|
public MemberRef Import(MemberRef memberRef) {
|
||
|
if (memberRef is null)
|
||
|
return null;
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
var mapped = mapper?.Map(memberRef);
|
||
|
if (mapped is not null) {
|
||
|
recursionCounter.Decrement();
|
||
|
return mapped;
|
||
|
}
|
||
|
|
||
|
MemberRef result = module.UpdateRowId(new MemberRefUser(module, memberRef.Name));
|
||
|
result.Signature = Import(memberRef.Signature);
|
||
|
result.Class = Import(memberRef.Class);
|
||
|
if (result.Class is null) // Will be null if memberRef.Class is null or a MethodDef
|
||
|
result = null;
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
IMemberRefParent Import(IMemberRefParent parent) {
|
||
|
if (parent is ITypeDefOrRef tdr) {
|
||
|
if (tdr is TypeDef td && td.IsGlobalModuleType)
|
||
|
return module.UpdateRowId(new ModuleRefUser(module, td.Module?.Name));
|
||
|
return Import(tdr);
|
||
|
}
|
||
|
|
||
|
if (parent is ModuleRef modRef)
|
||
|
return module.UpdateRowId(new ModuleRefUser(module, modRef.Name));
|
||
|
|
||
|
if (parent is MethodDef method) {
|
||
|
var dt = method.DeclaringType;
|
||
|
return dt is null || dt.Module != module ? null : method;
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|