// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Reflection;
namespace dnlib.DotNet {
///
/// options
///
[Flags]
public enum ImporterOptions {
///
/// Use s whenever possible if the is located
/// in this module.
///
TryToUseTypeDefs = 1,
///
/// Use s whenever possible if the is located
/// in this module.
///
TryToUseMethodDefs = 2,
///
/// Use s whenever possible if the is located
/// in this module.
///
TryToUseFieldDefs = 4,
///
/// Use s, s and s
/// whenever possible if the definition is located in this module.
///
///
///
///
TryToUseDefs = TryToUseTypeDefs | TryToUseMethodDefs | TryToUseFieldDefs,
///
/// Use already existing s whenever possible
///
TryToUseExistingAssemblyRefs = 8,
///
/// Don't set this flag. For internal use only.
///
FixSignature = int.MinValue,
}
///
/// Re-maps entities that were renamed in the target module
///
public abstract class ImportMapper {
///
/// Matches source to the one that is already present in the target module under a different name.
///
/// referenced by the entity that is being imported.
/// matching or null if there's no match.
public virtual ITypeDefOrRef Map(ITypeDefOrRef source) => null;
///
/// Matches source to the one that is already present in the target module under a different name.
///
/// referenced by the entity that is being imported.
/// matching or null if there's no match.
public virtual IField Map(FieldDef source) => null;
///
/// Matches source to the one that is already present in the target module under a different name.
///
/// referenced by the entity that is being imported.
/// matching or null if there's no match.
public virtual IMethod Map(MethodDef source) => null;
///
/// Matches source to the one that is already present in the target module under a different name.
///
/// referenced by the entity that is being imported.
/// matching or null if there's no match.
public virtual MemberRef Map(MemberRef source) => null;
///
/// Overrides default behavior of
/// May be used to use reference assemblies for resolution, for example.
///
/// to create for. is non-generic type or generic type without generic arguments.
/// or null to use default 's type resolution
public virtual ITypeDefOrRef Map(Type source) => null;
}
///
/// Imports s, s, s
/// and s as references
///
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;
}
}
///
/// Constructor
///
/// The module that will own all references
public Importer(ModuleDef module)
: this(module, 0, new GenericParamContext(), null) {
}
///
/// Constructor
///
/// The module that will own all references
/// Generic parameter context
public Importer(ModuleDef module, GenericParamContext gpContext)
: this(module, 0, gpContext, null) {
}
///
/// Constructor
///
/// The module that will own all references
/// Importer options
public Importer(ModuleDef module, ImporterOptions options)
: this(module, options, new GenericParamContext(), null) {
}
///
/// Constructor
///
/// The module that will own all references
/// Importer options
/// Generic parameter context
public Importer(ModuleDef module, ImporterOptions options, GenericParamContext gpContext)
: this(module, options, gpContext, null) {
}
///
/// Constructor
///
/// The module that will own all references
/// Importer options
/// Generic parameter context
/// Mapper for renamed entities
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;
}
///
/// Imports a as a .
///
/// The type
/// The imported type or null if is invalid
public ITypeDefOrRef Import(Type type) => module.UpdateRowId(ImportAsTypeSig(type).ToTypeDefOrRef());
///
/// Imports a as a . See also
///
/// The type
///
[Obsolete("Use 'Import(Type)' instead.")]
public ITypeDefOrRef ImportDeclaringType(Type type) => Import(type);
///
/// Imports a as a
///
/// The type
/// A list of all required modifiers or null
/// A list of all optional modifiers or null
/// The imported type or null if is invalid
public ITypeDefOrRef Import(Type type, IList requiredModifiers, IList optionalModifiers) =>
module.UpdateRowId(ImportAsTypeSig(type, requiredModifiers, optionalModifiers).ToTypeDefOrRef());
///
/// Imports a as a
///
/// The type
/// The imported type or null if is invalid
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();
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));
}
///
/// Imports a as a
///
/// The type
/// A list of all required modifiers or null
/// A list of all optional modifiers or null
/// The imported type or null if is invalid
public TypeSig ImportAsTypeSig(Type type, IList requiredModifiers, IList optionalModifiers) =>
ImportAsTypeSig(type, requiredModifiers, optionalModifiers, null);
TypeSig ImportAsTypeSig(Type type, IList requiredModifiers, IList 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(IList list) => list is null || list.Count == 0;
///
/// Imports a as a . This will be either
/// a or a .
///
/// The method
/// The imported method or null if is invalid
/// or if we failed to import the method
public IMethod Import(MethodBase methodBase) => Import(methodBase, false);
///
/// Imports a as a . This will be either
/// a or a .
///
/// The method
/// Always verify method signature to make sure the
/// returned reference matches the metadata in the source assembly
/// The imported method or null if is invalid
/// or if we failed to import the method
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);
}
///
/// Imports a as a
///
/// The field
/// The imported field or null if is invalid
/// or if we failed to import the field
public IField Import(FieldInfo fieldInfo) => Import(fieldInfo, false);
///
/// Imports a as a
///
/// The field
/// Always verify field signature to make sure the
/// returned reference matches the metadata in the source assembly
/// The imported field or null if is invalid
/// or if we failed to import the field
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;
}
///
/// Imports a
///
/// The type
/// The imported type or null
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;
}
///
/// Imports a as a
///
/// The type
/// The imported type or null
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 });
}
///
/// Imports a
///
/// The type
/// The imported type or null
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;
}
///
/// Imports a
///
/// The type
/// The imported type or null
public TypeSpec Import(TypeSpec type) {
if (type is null)
return null;
return module.UpdateRowId(new TypeSpecUser(Import(type.TypeSig)));
}
///
/// Imports a
///
/// The type
/// The imported type or null
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(arraySig.Sizes);
var lbounds = new List(arraySig.LowerBounds);
result = new ArraySig(Import(type.Next), arraySig.Rank, sizes, lbounds);
break;
case ElementType.GenericInst:
var gis = (GenericInstSig)type;
var genArgs = new List(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;
}
///
/// Imports a
///
/// The type
/// The imported type or null
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));
}
///
/// Imports a
///
/// The sig
/// The imported sig or null if input is invalid
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;
}
///
/// Imports a
///
/// The sig
/// The imported sig or null if input is invalid
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;
}
///
/// Imports a
///
/// The sig
/// The imported sig or null if input is invalid
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 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;
}
///
/// Imports a
///
/// The sig
/// The imported sig or null if input is invalid
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;
}
///
/// Imports a
///
/// The sig
/// The imported sig or null if input is invalid
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;
}
///
/// Imports a
///
/// The sig
/// The imported sig or null if input is invalid
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;
}
///
/// Imports a
///
/// The field
/// The imported type or null if is invalid
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;
}
///
/// Imports a
///
/// The method
/// The imported method or null if is invalid
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;
}
///
/// Imports a as an
///
/// The field
/// The imported type or null if is invalid
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);
}
///
/// Imports a as an
///
/// The method
/// The imported method or null if is invalid
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;
}
///
/// Imports a
///
/// The method
/// The imported method or null if is invalid
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;
}
///
/// Imports a
///
/// The member ref
/// The imported member ref or null if is invalid
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;
}
}
}