859 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			859 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //
 | |
| // Author:
 | |
| //   Jb Evain (jbevain@gmail.com)
 | |
| //
 | |
| // Copyright (c) 2008 - 2015 Jb Evain
 | |
| // Copyright (c) 2008 - 2011 Novell, Inc.
 | |
| //
 | |
| // Licensed under the MIT/X11 license.
 | |
| //
 | |
| 
 | |
| using MonoFN.Cecil.Metadata;
 | |
| using MonoFN.Collections.Generic;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using SR = System.Reflection;
 | |
| 
 | |
| namespace MonoFN.Cecil
 | |
| {
 | |
| 
 | |
|     public interface IMetadataImporterProvider
 | |
|     {
 | |
|         IMetadataImporter GetMetadataImporter(ModuleDefinition module);
 | |
|     }
 | |
| 
 | |
|     public interface IMetadataImporter
 | |
|     {
 | |
|         AssemblyNameReference ImportReference(AssemblyNameReference reference);
 | |
|         TypeReference ImportReference(TypeReference type, IGenericParameterProvider context);
 | |
|         FieldReference ImportReference(FieldReference field, IGenericParameterProvider context);
 | |
|         MethodReference ImportReference(MethodReference method, IGenericParameterProvider context);
 | |
|     }
 | |
| 
 | |
|     public interface IReflectionImporterProvider
 | |
|     {
 | |
|         IReflectionImporter GetReflectionImporter(ModuleDefinition module);
 | |
|     }
 | |
| 
 | |
|     public interface IReflectionImporter
 | |
|     {
 | |
|         AssemblyNameReference ImportReference(SR.AssemblyName reference);
 | |
|         TypeReference ImportReference(Type type, IGenericParameterProvider context);
 | |
|         FieldReference ImportReference(SR.FieldInfo field, IGenericParameterProvider context);
 | |
|         MethodReference ImportReference(SR.MethodBase method, IGenericParameterProvider context);
 | |
|     }
 | |
| 
 | |
|     struct ImportGenericContext
 | |
|     {
 | |
| 
 | |
|         Collection<IGenericParameterProvider> stack;
 | |
| 
 | |
|         public bool IsEmpty { get { return stack == null; } }
 | |
| 
 | |
|         public ImportGenericContext(IGenericParameterProvider provider)
 | |
|         {
 | |
|             if (provider == null)
 | |
|                 throw new ArgumentNullException("provider");
 | |
| 
 | |
|             stack = null;
 | |
| 
 | |
|             Push(provider);
 | |
|         }
 | |
| 
 | |
|         public void Push(IGenericParameterProvider provider)
 | |
|         {
 | |
|             if (stack == null)
 | |
|                 stack = new Collection<IGenericParameterProvider>(1) { provider };
 | |
|             else
 | |
|                 stack.Add(provider);
 | |
|         }
 | |
| 
 | |
|         public void Pop()
 | |
|         {
 | |
|             stack.RemoveAt(stack.Count - 1);
 | |
|         }
 | |
| 
 | |
|         public TypeReference MethodParameter(string method, int position)
 | |
|         {
 | |
|             for (int i = stack.Count - 1; i >= 0; i--)
 | |
|             {
 | |
|                 var candidate = stack[i] as MethodReference;
 | |
|                 if (candidate == null)
 | |
|                     continue;
 | |
| 
 | |
|                 if (method != NormalizeMethodName(candidate))
 | |
|                     continue;
 | |
| 
 | |
|                 return candidate.GenericParameters[position];
 | |
|             }
 | |
| 
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public string NormalizeMethodName(MethodReference method)
 | |
|         {
 | |
|             return method.DeclaringType.GetElementType().FullName + "." + method.Name;
 | |
|         }
 | |
| 
 | |
|         public TypeReference TypeParameter(string type, int position)
 | |
|         {
 | |
|             for (int i = stack.Count - 1; i >= 0; i--)
 | |
|             {
 | |
|                 var candidate = GenericTypeFor(stack[i]);
 | |
| 
 | |
|                 if (candidate.FullName != type)
 | |
|                     continue;
 | |
| 
 | |
|                 return candidate.GenericParameters[position];
 | |
|             }
 | |
| 
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         static TypeReference GenericTypeFor(IGenericParameterProvider context)
 | |
|         {
 | |
|             var type = context as TypeReference;
 | |
|             if (type != null)
 | |
|                 return type.GetElementType();
 | |
| 
 | |
|             var method = context as MethodReference;
 | |
|             if (method != null)
 | |
|                 return method.DeclaringType.GetElementType();
 | |
| 
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         public static ImportGenericContext For(IGenericParameterProvider context)
 | |
|         {
 | |
|             return context != null ? new ImportGenericContext(context) : default(ImportGenericContext);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public class DefaultReflectionImporter : IReflectionImporter
 | |
|     {
 | |
| 
 | |
|         readonly protected ModuleDefinition module;
 | |
| 
 | |
|         public DefaultReflectionImporter(ModuleDefinition module)
 | |
|         {
 | |
|             Mixin.CheckModule(module);
 | |
|             this.module = module;
 | |
|         }
 | |
| 
 | |
|         enum ImportGenericKind
 | |
|         {
 | |
|             Definition,
 | |
|             Open,
 | |
|         }
 | |
| 
 | |
|         static readonly Dictionary<Type, ElementType> type_etype_mapping = new Dictionary<Type, ElementType>(18) {
 | |
|             { typeof (void), ElementType.Void },
 | |
|             { typeof (bool), ElementType.Boolean },
 | |
|             { typeof (char), ElementType.Char },
 | |
|             { typeof (sbyte), ElementType.I1 },
 | |
|             { typeof (byte), ElementType.U1 },
 | |
|             { typeof (short), ElementType.I2 },
 | |
|             { typeof (ushort), ElementType.U2 },
 | |
|             { typeof (int), ElementType.I4 },
 | |
|             { typeof (uint), ElementType.U4 },
 | |
|             { typeof (long), ElementType.I8 },
 | |
|             { typeof (ulong), ElementType.U8 },
 | |
|             { typeof (float), ElementType.R4 },
 | |
|             { typeof (double), ElementType.R8 },
 | |
|             { typeof (string), ElementType.String },
 | |
|             { typeof (TypedReference), ElementType.TypedByRef },
 | |
|             { typeof (IntPtr), ElementType.I },
 | |
|             { typeof (UIntPtr), ElementType.U },
 | |
|             { typeof (object), ElementType.Object },
 | |
|         };
 | |
| 
 | |
|         TypeReference ImportType(Type type, ImportGenericContext context)
 | |
|         {
 | |
|             return ImportType(type, context, ImportGenericKind.Open);
 | |
|         }
 | |
| 
 | |
|         TypeReference ImportType(Type type, ImportGenericContext context, ImportGenericKind import_kind)
 | |
|         {
 | |
|             if (IsTypeSpecification(type) || ImportOpenGenericType(type, import_kind))
 | |
|                 return ImportTypeSpecification(type, context);
 | |
| 
 | |
|             var reference = new TypeReference(
 | |
|                 string.Empty,
 | |
|                 type.Name,
 | |
|                 module,
 | |
|                 ImportScope(type),
 | |
|                 type.IsValueType);
 | |
| 
 | |
|             reference.etype = ImportElementType(type);
 | |
| 
 | |
|             if (IsNestedType(type))
 | |
|                 reference.DeclaringType = ImportType(type.DeclaringType, context, import_kind);
 | |
|             else
 | |
|                 reference.Namespace = type.Namespace ?? string.Empty;
 | |
| 
 | |
|             if (type.IsGenericType)
 | |
|                 ImportGenericParameters(reference, type.GetGenericArguments());
 | |
| 
 | |
|             return reference;
 | |
|         }
 | |
| 
 | |
|         protected virtual IMetadataScope ImportScope(Type type)
 | |
|         {
 | |
|             return ImportScope(type.Assembly);
 | |
|         }
 | |
| 
 | |
|         static bool ImportOpenGenericType(Type type, ImportGenericKind import_kind)
 | |
|         {
 | |
|             return type.IsGenericType && type.IsGenericTypeDefinition && import_kind == ImportGenericKind.Open;
 | |
|         }
 | |
| 
 | |
|         static bool ImportOpenGenericMethod(SR.MethodBase method, ImportGenericKind import_kind)
 | |
|         {
 | |
|             return method.IsGenericMethod && method.IsGenericMethodDefinition && import_kind == ImportGenericKind.Open;
 | |
|         }
 | |
| 
 | |
|         static bool IsNestedType(Type type)
 | |
|         {
 | |
|             return type.IsNested;
 | |
|         }
 | |
| 
 | |
|         TypeReference ImportTypeSpecification(Type type, ImportGenericContext context)
 | |
|         {
 | |
|             if (type.IsByRef)
 | |
|                 return new ByReferenceType(ImportType(type.GetElementType(), context));
 | |
| 
 | |
|             if (type.IsPointer)
 | |
|                 return new PointerType(ImportType(type.GetElementType(), context));
 | |
| 
 | |
|             if (type.IsArray)
 | |
|                 return new ArrayType(ImportType(type.GetElementType(), context), type.GetArrayRank());
 | |
| 
 | |
|             if (type.IsGenericType)
 | |
|                 return ImportGenericInstance(type, context);
 | |
| 
 | |
|             if (type.IsGenericParameter)
 | |
|                 return ImportGenericParameter(type, context);
 | |
| 
 | |
|             throw new NotSupportedException(type.FullName);
 | |
|         }
 | |
| 
 | |
|         static TypeReference ImportGenericParameter(Type type, ImportGenericContext context)
 | |
|         {
 | |
|             if (context.IsEmpty)
 | |
|                 throw new InvalidOperationException();
 | |
| 
 | |
|             if (type.DeclaringMethod != null)
 | |
|                 return context.MethodParameter(NormalizeMethodName(type.DeclaringMethod), type.GenericParameterPosition);
 | |
| 
 | |
|             if (type.DeclaringType != null)
 | |
|                 return context.TypeParameter(NormalizeTypeFullName(type.DeclaringType), type.GenericParameterPosition);
 | |
| 
 | |
|             throw new InvalidOperationException();
 | |
|         }
 | |
| 
 | |
|         static string NormalizeMethodName(SR.MethodBase method)
 | |
|         {
 | |
|             return NormalizeTypeFullName(method.DeclaringType) + "." + method.Name;
 | |
|         }
 | |
| 
 | |
|         static string NormalizeTypeFullName(Type type)
 | |
|         {
 | |
|             if (IsNestedType(type))
 | |
|                 return NormalizeTypeFullName(type.DeclaringType) + "/" + type.Name;
 | |
| 
 | |
|             return type.FullName;
 | |
|         }
 | |
| 
 | |
|         TypeReference ImportGenericInstance(Type type, ImportGenericContext context)
 | |
|         {
 | |
|             var element_type = ImportType(type.GetGenericTypeDefinition(), context, ImportGenericKind.Definition);
 | |
|             var arguments = type.GetGenericArguments();
 | |
|             var instance = new GenericInstanceType(element_type, arguments.Length);
 | |
|             var instance_arguments = instance.GenericArguments;
 | |
| 
 | |
|             context.Push(element_type);
 | |
|             try
 | |
|             {
 | |
|                 for (int i = 0; i < arguments.Length; i++)
 | |
|                     instance_arguments.Add(ImportType(arguments[i], context));
 | |
| 
 | |
|                 return instance;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 context.Pop();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         static bool IsTypeSpecification(Type type)
 | |
|         {
 | |
|             return type.HasElementType
 | |
|                 || IsGenericInstance(type)
 | |
|                 || type.IsGenericParameter;
 | |
|         }
 | |
| 
 | |
|         static bool IsGenericInstance(Type type)
 | |
|         {
 | |
|             return type.IsGenericType && !type.IsGenericTypeDefinition;
 | |
|         }
 | |
| 
 | |
|         static ElementType ImportElementType(Type type)
 | |
|         {
 | |
|             ElementType etype;
 | |
|             if (!type_etype_mapping.TryGetValue(type, out etype))
 | |
|                 return ElementType.None;
 | |
| 
 | |
|             return etype;
 | |
|         }
 | |
| 
 | |
|         protected AssemblyNameReference ImportScope(SR.Assembly assembly)
 | |
|         {
 | |
|             return ImportReference(assembly.GetName());
 | |
|         }
 | |
| 
 | |
|         public virtual AssemblyNameReference ImportReference(SR.AssemblyName name)
 | |
|         {
 | |
|             Mixin.CheckName(name);
 | |
| 
 | |
|             AssemblyNameReference reference;
 | |
|             if (TryGetAssemblyNameReference(name, out reference))
 | |
|                 return reference;
 | |
| 
 | |
|             reference = new AssemblyNameReference(name.Name, name.Version)
 | |
|             {
 | |
|                 PublicKeyToken = name.GetPublicKeyToken(),
 | |
|                 Culture = name.CultureInfo.Name,
 | |
|                 HashAlgorithm = (AssemblyHashAlgorithm)name.HashAlgorithm,
 | |
|             };
 | |
| 
 | |
|             module.AssemblyReferences.Add(reference);
 | |
|             return reference;
 | |
|         }
 | |
| 
 | |
|         bool TryGetAssemblyNameReference(SR.AssemblyName name, out AssemblyNameReference assembly_reference)
 | |
|         {
 | |
|             var references = module.AssemblyReferences;
 | |
| 
 | |
|             for (int i = 0; i < references.Count; i++)
 | |
|             {
 | |
|                 var reference = references[i];
 | |
|                 if (name.FullName != reference.FullName) // TODO compare field by field
 | |
|                     continue;
 | |
| 
 | |
|                 assembly_reference = reference;
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             assembly_reference = null;
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         FieldReference ImportField(SR.FieldInfo field, ImportGenericContext context)
 | |
|         {
 | |
|             var declaring_type = ImportType(field.DeclaringType, context);
 | |
| 
 | |
|             if (IsGenericInstance(field.DeclaringType))
 | |
|                 field = ResolveFieldDefinition(field);
 | |
| 
 | |
|             context.Push(declaring_type);
 | |
|             try
 | |
|             {
 | |
|                 return new FieldReference
 | |
|                 {
 | |
|                     Name = field.Name,
 | |
|                     DeclaringType = declaring_type,
 | |
|                     FieldType = ImportType(field.FieldType, context),
 | |
|                 };
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 context.Pop();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         static SR.FieldInfo ResolveFieldDefinition(SR.FieldInfo field)
 | |
|         {
 | |
|             return field.Module.ResolveField(field.MetadataToken);
 | |
|         }
 | |
| 
 | |
|         static SR.MethodBase ResolveMethodDefinition(SR.MethodBase method)
 | |
|         {
 | |
|             return method.Module.ResolveMethod(method.MetadataToken);
 | |
|         }
 | |
| 
 | |
|         MethodReference ImportMethod(SR.MethodBase method, ImportGenericContext context, ImportGenericKind import_kind)
 | |
|         {
 | |
|             if (IsMethodSpecification(method) || ImportOpenGenericMethod(method, import_kind))
 | |
|                 return ImportMethodSpecification(method, context);
 | |
| 
 | |
|             var declaring_type = ImportType(method.DeclaringType, context);
 | |
| 
 | |
|             if (IsGenericInstance(method.DeclaringType))
 | |
|                 method = ResolveMethodDefinition(method);
 | |
| 
 | |
|             var reference = new MethodReference
 | |
|             {
 | |
|                 Name = method.Name,
 | |
|                 HasThis = HasCallingConvention(method, SR.CallingConventions.HasThis),
 | |
|                 ExplicitThis = HasCallingConvention(method, SR.CallingConventions.ExplicitThis),
 | |
|                 DeclaringType = ImportType(method.DeclaringType, context, ImportGenericKind.Definition),
 | |
|             };
 | |
| 
 | |
|             if (HasCallingConvention(method, SR.CallingConventions.VarArgs))
 | |
|                 reference.CallingConvention &= MethodCallingConvention.VarArg;
 | |
| 
 | |
|             if (method.IsGenericMethod)
 | |
|                 ImportGenericParameters(reference, method.GetGenericArguments());
 | |
| 
 | |
|             context.Push(reference);
 | |
|             try
 | |
|             {
 | |
|                 var method_info = method as SR.MethodInfo;
 | |
|                 reference.ReturnType = method_info != null
 | |
|                     ? ImportType(method_info.ReturnType, context)
 | |
|                     : ImportType(typeof(void), default(ImportGenericContext));
 | |
| 
 | |
|                 var parameters = method.GetParameters();
 | |
|                 var reference_parameters = reference.Parameters;
 | |
| 
 | |
|                 for (int i = 0; i < parameters.Length; i++)
 | |
|                     reference_parameters.Add(
 | |
|                         new ParameterDefinition(ImportType(parameters[i].ParameterType, context)));
 | |
| 
 | |
|                 reference.DeclaringType = declaring_type;
 | |
| 
 | |
|                 return reference;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 context.Pop();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         static void ImportGenericParameters(IGenericParameterProvider provider, Type[] arguments)
 | |
|         {
 | |
|             var provider_parameters = provider.GenericParameters;
 | |
| 
 | |
|             for (int i = 0; i < arguments.Length; i++)
 | |
|                 provider_parameters.Add(new GenericParameter(arguments[i].Name, provider));
 | |
|         }
 | |
| 
 | |
|         static bool IsMethodSpecification(SR.MethodBase method)
 | |
|         {
 | |
|             return method.IsGenericMethod && !method.IsGenericMethodDefinition;
 | |
|         }
 | |
| 
 | |
|         MethodReference ImportMethodSpecification(SR.MethodBase method, ImportGenericContext context)
 | |
|         {
 | |
|             var method_info = method as SR.MethodInfo;
 | |
|             if (method_info == null)
 | |
|                 throw new InvalidOperationException();
 | |
| 
 | |
|             var element_method = ImportMethod(method_info.GetGenericMethodDefinition(), context, ImportGenericKind.Definition);
 | |
|             var instance = new GenericInstanceMethod(element_method);
 | |
|             var arguments = method.GetGenericArguments();
 | |
|             var instance_arguments = instance.GenericArguments;
 | |
| 
 | |
|             context.Push(element_method);
 | |
|             try
 | |
|             {
 | |
|                 for (int i = 0; i < arguments.Length; i++)
 | |
|                     instance_arguments.Add(ImportType(arguments[i], context));
 | |
| 
 | |
|                 return instance;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 context.Pop();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         static bool HasCallingConvention(SR.MethodBase method, SR.CallingConventions conventions)
 | |
|         {
 | |
|             return (method.CallingConvention & conventions) != 0;
 | |
|         }
 | |
| 
 | |
|         public virtual TypeReference ImportReference(Type type, IGenericParameterProvider context)
 | |
|         {
 | |
|             Mixin.CheckType(type);
 | |
|             return ImportType(
 | |
|                 type,
 | |
|                 ImportGenericContext.For(context),
 | |
|                 context != null ? ImportGenericKind.Open : ImportGenericKind.Definition);
 | |
|         }
 | |
| 
 | |
|         public virtual FieldReference ImportReference(SR.FieldInfo field, IGenericParameterProvider context)
 | |
|         {
 | |
|             Mixin.CheckField(field);
 | |
|             return ImportField(field, ImportGenericContext.For(context));
 | |
|         }
 | |
| 
 | |
|         public virtual MethodReference ImportReference(SR.MethodBase method, IGenericParameterProvider context)
 | |
|         {
 | |
|             Mixin.CheckMethod(method);
 | |
|             return ImportMethod(method,
 | |
|                 ImportGenericContext.For(context),
 | |
|                 context != null ? ImportGenericKind.Open : ImportGenericKind.Definition);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public class DefaultMetadataImporter : IMetadataImporter
 | |
|     {
 | |
| 
 | |
|         readonly protected ModuleDefinition module;
 | |
| 
 | |
|         public DefaultMetadataImporter(ModuleDefinition module)
 | |
|         {
 | |
|             Mixin.CheckModule(module);
 | |
| 
 | |
|             this.module = module;
 | |
|         }
 | |
| 
 | |
|         TypeReference ImportType(TypeReference type, ImportGenericContext context)
 | |
|         {
 | |
|             if (type.IsTypeSpecification())
 | |
|                 return ImportTypeSpecification(type, context);
 | |
| 
 | |
|             var reference = new TypeReference(
 | |
|                 type.Namespace,
 | |
|                 type.Name,
 | |
|                 module,
 | |
|                 ImportScope(type),
 | |
|                 type.IsValueType);
 | |
| 
 | |
|             MetadataSystem.TryProcessPrimitiveTypeReference(reference);
 | |
| 
 | |
|             if (type.IsNested)
 | |
|                 reference.DeclaringType = ImportType(type.DeclaringType, context);
 | |
| 
 | |
|             if (type.HasGenericParameters)
 | |
|                 ImportGenericParameters(reference, type);
 | |
| 
 | |
|             return reference;
 | |
|         }
 | |
| 
 | |
|         protected virtual IMetadataScope ImportScope(TypeReference type)
 | |
|         {
 | |
|             return ImportScope(type.Scope);
 | |
|         }
 | |
| 
 | |
|         protected IMetadataScope ImportScope(IMetadataScope scope)
 | |
|         {
 | |
|             switch (scope.MetadataScopeType)
 | |
|             {
 | |
|                 case MetadataScopeType.AssemblyNameReference:
 | |
|                     return ImportReference((AssemblyNameReference)scope);
 | |
|                 case MetadataScopeType.ModuleDefinition:
 | |
|                     if (scope == module) return scope;
 | |
|                     return ImportReference(((ModuleDefinition)scope).Assembly.Name);
 | |
|                 case MetadataScopeType.ModuleReference:
 | |
|                     throw new NotImplementedException();
 | |
|             }
 | |
| 
 | |
|             throw new NotSupportedException();
 | |
|         }
 | |
| 
 | |
|         public virtual AssemblyNameReference ImportReference(AssemblyNameReference name)
 | |
|         {
 | |
|             Mixin.CheckName(name);
 | |
| 
 | |
|             AssemblyNameReference reference;
 | |
|             if (module.TryGetAssemblyNameReference(name, out reference))
 | |
|                 return reference;
 | |
| 
 | |
|             reference = new AssemblyNameReference(name.Name, name.Version)
 | |
|             {
 | |
|                 Culture = name.Culture,
 | |
|                 HashAlgorithm = name.HashAlgorithm,
 | |
|                 IsRetargetable = name.IsRetargetable,
 | |
|                 IsWindowsRuntime = name.IsWindowsRuntime,
 | |
|             };
 | |
| 
 | |
|             var pk_token = !name.PublicKeyToken.IsNullOrEmpty()
 | |
|                 ? new byte[name.PublicKeyToken.Length]
 | |
|                 : Empty<byte>.Array;
 | |
| 
 | |
|             if (pk_token.Length > 0)
 | |
|                 Buffer.BlockCopy(name.PublicKeyToken, 0, pk_token, 0, pk_token.Length);
 | |
| 
 | |
|             reference.PublicKeyToken = pk_token;
 | |
| 
 | |
|             //Only add if not self.
 | |
|             if (CanAddAssemblyNameReference(module, reference))
 | |
|                 module.AssemblyReferences.Add(reference);
 | |
| 
 | |
|             return reference;
 | |
|         }
 | |
| 
 | |
|         private bool CanAddAssemblyNameReference(ModuleDefinition module, AssemblyNameReference nameRef)
 | |
|         {
 | |
|             return true;
 | |
|             //return (module.assembly.FullName != nameRef.FullName);
 | |
|         }
 | |
| 
 | |
|         static void ImportGenericParameters(IGenericParameterProvider imported, IGenericParameterProvider original)
 | |
|         {
 | |
|             var parameters = original.GenericParameters;
 | |
|             var imported_parameters = imported.GenericParameters;
 | |
| 
 | |
|             for (int i = 0; i < parameters.Count; i++)
 | |
|                 imported_parameters.Add(new GenericParameter(parameters[i].Name, imported));
 | |
|         }
 | |
| 
 | |
|         TypeReference ImportTypeSpecification(TypeReference type, ImportGenericContext context)
 | |
|         {
 | |
|             switch (type.etype)
 | |
|             {
 | |
|                 case ElementType.SzArray:
 | |
|                     var vector = (ArrayType)type;
 | |
|                     return new ArrayType(ImportType(vector.ElementType, context));
 | |
|                 case ElementType.Ptr:
 | |
|                     var pointer = (PointerType)type;
 | |
|                     return new PointerType(ImportType(pointer.ElementType, context));
 | |
|                 case ElementType.ByRef:
 | |
|                     var byref = (ByReferenceType)type;
 | |
|                     return new ByReferenceType(ImportType(byref.ElementType, context));
 | |
|                 case ElementType.Pinned:
 | |
|                     var pinned = (PinnedType)type;
 | |
|                     return new PinnedType(ImportType(pinned.ElementType, context));
 | |
|                 case ElementType.Sentinel:
 | |
|                     var sentinel = (SentinelType)type;
 | |
|                     return new SentinelType(ImportType(sentinel.ElementType, context));
 | |
|                 case ElementType.FnPtr:
 | |
|                     var fnptr = (FunctionPointerType)type;
 | |
|                     var imported_fnptr = new FunctionPointerType()
 | |
|                     {
 | |
|                         HasThis = fnptr.HasThis,
 | |
|                         ExplicitThis = fnptr.ExplicitThis,
 | |
|                         CallingConvention = fnptr.CallingConvention,
 | |
|                         ReturnType = ImportType(fnptr.ReturnType, context),
 | |
|                     };
 | |
| 
 | |
|                     if (!fnptr.HasParameters)
 | |
|                         return imported_fnptr;
 | |
| 
 | |
|                     for (int i = 0; i < fnptr.Parameters.Count; i++)
 | |
|                         imported_fnptr.Parameters.Add(new ParameterDefinition(
 | |
|                             ImportType(fnptr.Parameters[i].ParameterType, context)));
 | |
| 
 | |
|                     return imported_fnptr;
 | |
|                 case ElementType.CModOpt:
 | |
|                     var modopt = (OptionalModifierType)type;
 | |
|                     return new OptionalModifierType(
 | |
|                         ImportType(modopt.ModifierType, context),
 | |
|                         ImportType(modopt.ElementType, context));
 | |
|                 case ElementType.CModReqD:
 | |
|                     var modreq = (RequiredModifierType)type;
 | |
|                     return new RequiredModifierType(
 | |
|                         ImportType(modreq.ModifierType, context),
 | |
|                         ImportType(modreq.ElementType, context));
 | |
|                 case ElementType.Array:
 | |
|                     var array = (ArrayType)type;
 | |
|                     var imported_array = new ArrayType(ImportType(array.ElementType, context));
 | |
|                     if (array.IsVector)
 | |
|                         return imported_array;
 | |
| 
 | |
|                     var dimensions = array.Dimensions;
 | |
|                     var imported_dimensions = imported_array.Dimensions;
 | |
| 
 | |
|                     imported_dimensions.Clear();
 | |
| 
 | |
|                     for (int i = 0; i < dimensions.Count; i++)
 | |
|                     {
 | |
|                         var dimension = dimensions[i];
 | |
| 
 | |
|                         imported_dimensions.Add(new ArrayDimension(dimension.LowerBound, dimension.UpperBound));
 | |
|                     }
 | |
| 
 | |
|                     return imported_array;
 | |
|                 case ElementType.GenericInst:
 | |
|                     var instance = (GenericInstanceType)type;
 | |
|                     var element_type = ImportType(instance.ElementType, context);
 | |
|                     var arguments = instance.GenericArguments;
 | |
|                     var imported_instance = new GenericInstanceType(element_type, arguments.Count);
 | |
|                     var imported_arguments = imported_instance.GenericArguments;
 | |
| 
 | |
|                     for (int i = 0; i < arguments.Count; i++)
 | |
|                         imported_arguments.Add(ImportType(arguments[i], context));
 | |
| 
 | |
|                     return imported_instance;
 | |
|                 case ElementType.Var:
 | |
|                     var var_parameter = (GenericParameter)type;
 | |
|                     if (var_parameter.DeclaringType == null)
 | |
|                         throw new InvalidOperationException();
 | |
|                     return context.TypeParameter(var_parameter.DeclaringType.FullName, var_parameter.Position);
 | |
|                 case ElementType.MVar:
 | |
|                     var mvar_parameter = (GenericParameter)type;
 | |
|                     if (mvar_parameter.DeclaringMethod == null)
 | |
|                         throw new InvalidOperationException();
 | |
|                     return context.MethodParameter(context.NormalizeMethodName(mvar_parameter.DeclaringMethod), mvar_parameter.Position);
 | |
|             }
 | |
| 
 | |
|             throw new NotSupportedException(type.etype.ToString());
 | |
|         }
 | |
| 
 | |
|         FieldReference ImportField(FieldReference field, ImportGenericContext context)
 | |
|         {
 | |
|             var declaring_type = ImportType(field.DeclaringType, context);
 | |
| 
 | |
|             context.Push(declaring_type);
 | |
|             try
 | |
|             {
 | |
|                 return new FieldReference
 | |
|                 {
 | |
|                     Name = field.Name,
 | |
|                     DeclaringType = declaring_type,
 | |
|                     FieldType = ImportType(field.FieldType, context),
 | |
|                 };
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 context.Pop();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         MethodReference ImportMethod(MethodReference method, ImportGenericContext context)
 | |
|         {
 | |
|             if (method.IsGenericInstance)
 | |
|                 return ImportMethodSpecification(method, context);
 | |
| 
 | |
|             var declaring_type = ImportType(method.DeclaringType, context);
 | |
| 
 | |
|             var reference = new MethodReference
 | |
|             {
 | |
|                 Name = method.Name,
 | |
|                 HasThis = method.HasThis,
 | |
|                 ExplicitThis = method.ExplicitThis,
 | |
|                 DeclaringType = declaring_type,
 | |
|                 CallingConvention = method.CallingConvention,
 | |
|             };
 | |
| 
 | |
|             if (method.HasGenericParameters)
 | |
|                 ImportGenericParameters(reference, method);
 | |
| 
 | |
|             context.Push(reference);
 | |
|             try
 | |
|             {
 | |
|                 reference.ReturnType = ImportType(method.ReturnType, context);
 | |
| 
 | |
|                 if (!method.HasParameters)
 | |
|                     return reference;
 | |
| 
 | |
|                 var parameters = method.Parameters;
 | |
|                 var reference_parameters = reference.parameters = new ParameterDefinitionCollection(reference, parameters.Count);
 | |
|                 for (int i = 0; i < parameters.Count; i++)
 | |
|                     reference_parameters.Add(
 | |
|                         new ParameterDefinition(ImportType(parameters[i].ParameterType, context)));
 | |
| 
 | |
|                 return reference;
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 context.Pop();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         MethodSpecification ImportMethodSpecification(MethodReference method, ImportGenericContext context)
 | |
|         {
 | |
|             if (!method.IsGenericInstance)
 | |
|                 throw new NotSupportedException();
 | |
| 
 | |
|             var instance = (GenericInstanceMethod)method;
 | |
|             var element_method = ImportMethod(instance.ElementMethod, context);
 | |
|             var imported_instance = new GenericInstanceMethod(element_method);
 | |
| 
 | |
|             var arguments = instance.GenericArguments;
 | |
|             var imported_arguments = imported_instance.GenericArguments;
 | |
| 
 | |
|             for (int i = 0; i < arguments.Count; i++)
 | |
|                 imported_arguments.Add(ImportType(arguments[i], context));
 | |
| 
 | |
|             return imported_instance;
 | |
|         }
 | |
| 
 | |
|         public virtual TypeReference ImportReference(TypeReference type, IGenericParameterProvider context)
 | |
|         {
 | |
|             Mixin.CheckType(type);
 | |
|             return ImportType(type, ImportGenericContext.For(context));
 | |
|         }
 | |
| 
 | |
|         public virtual FieldReference ImportReference(FieldReference field, IGenericParameterProvider context)
 | |
|         {
 | |
|             Mixin.CheckField(field);
 | |
|             return ImportField(field, ImportGenericContext.For(context));
 | |
|         }
 | |
| 
 | |
|         public virtual MethodReference ImportReference(MethodReference method, IGenericParameterProvider context)
 | |
|         {
 | |
|             Mixin.CheckMethod(method);
 | |
|             return ImportMethod(method, ImportGenericContext.For(context));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static partial class Mixin
 | |
|     {
 | |
| 
 | |
|         public static void CheckModule(ModuleDefinition module)
 | |
|         {
 | |
|             if (module == null)
 | |
|                 throw new ArgumentNullException(Argument.module.ToString());
 | |
|         }
 | |
| 
 | |
|         public static bool TryGetAssemblyNameReference(this ModuleDefinition module, AssemblyNameReference name_reference, out AssemblyNameReference assembly_reference)
 | |
|         {
 | |
|             var references = module.AssemblyReferences;
 | |
| 
 | |
|             for (int i = 0; i < references.Count; i++)
 | |
|             {
 | |
|                 var reference = references[i];
 | |
|                 if (!Equals(name_reference, reference))
 | |
|                     continue;
 | |
| 
 | |
|                 assembly_reference = reference;
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|             assembly_reference = null;
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         static bool Equals(byte[] a, byte[] b)
 | |
|         {
 | |
|             if (ReferenceEquals(a, b))
 | |
|                 return true;
 | |
|             if (a == null)
 | |
|                 return false;
 | |
|             if (a.Length != b.Length)
 | |
|                 return false;
 | |
|             for (int i = 0; i < a.Length; i++)
 | |
|                 if (a[i] != b[i])
 | |
|                     return false;
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         static bool Equals<T>(T a, T b) where T : class, IEquatable<T>
 | |
|         {
 | |
|             if (ReferenceEquals(a, b))
 | |
|                 return true;
 | |
|             if (a == null)
 | |
|                 return false;
 | |
|             return a.Equals(b);
 | |
|         }
 | |
| 
 | |
|         static bool Equals(AssemblyNameReference a, AssemblyNameReference b)
 | |
|         {
 | |
|             if (ReferenceEquals(a, b))
 | |
|                 return true;
 | |
|             if (a.Name != b.Name)
 | |
|                 return false;
 | |
|             if (!Equals(a.Version, b.Version))
 | |
|                 return false;
 | |
|             if (a.Culture != b.Culture)
 | |
|                 return false;
 | |
|             if (!Equals(a.PublicKeyToken, b.PublicKeyToken))
 | |
|                 return false;
 | |
|             return true;
 | |
|         }
 | |
|     }
 | |
| }
 |