<commit_before>//
// Author:
//   <NAME> (<EMAIL>)
//
// Copyright (c) 2008 - 2015 <NAME>
// Copyright (c) 2008 - 2011 Novell, Inc.
//
// Licensed under the MIT/X11 license.
//

using System;
using System.Collections.Generic;
using Mono.Collections.Generic;
using SR = System.Reflection;

using Mono.Cecil.Metadata;

namespace Mono.Cecil {

#if !READ_ONLY

	public interface IMetadataImporterProvider {
		IMetadataImporter GetMetadataImporter (ModuleDefinition module);
	}

	public interface IMetadataImporter {
		TypeReference ImportReference (TypeReference type, IGenericParameterProvider context);
		FieldReference ImportReference (FieldReference field, IGenericParameterProvider context);
		MethodReference ImportReference (MethodReference method, IGenericParameterProvider context);
	}

#if !CF

	public interface IReflectionImporterProvider {
		IReflectionImporter GetReflectionImporter (ModuleDefinition module);
	}

	public interface IReflectionImporter {
		TypeReference ImportReference (Type type, IGenericParameterProvider context);
		FieldReference ImportReference (SR.FieldInfo field, IGenericParameterProvider context);
		MethodReference ImportReference (SR.MethodBase method, IGenericParameterProvider context);
	}
#endif

	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 declTypeFullName, 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 != candidate.Name || declTypeFullName != candidate.DeclaringType.FullName)
					continue;

				return candidate.GenericParameters [position];
			}

			throw new InvalidOperationException ();
		}

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


#if !CF
	public class ReflectionImporter : IReflectionImporter {

		readonly ModuleDefinition module;

		public ReflectionImporter (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.Assembly),
				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;
		}

		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)
		{
#if !SILVERLIGHT
			return type.IsNested;
#else
			return type.DeclaringType != null;
#endif
		}

		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 (type.DeclaringType.FullName, type.DeclaringMethod.Name, type.GenericParameterPosition);
			}
			if (type.DeclaringType != null)
			{
				return  context.TypeParameter (NormalizedFullName (type.DeclaringType), type.GenericParameterPosition);
			}
			throw new InvalidOperationException();
		}

		private static string NormalizedFullName (Type type)
		{
			if (IsNestedType (type))
				return NormalizedFullName (type.DeclaringType) + "/" + type.Name;

			return type.FullName;
		}

		TypeReference ImportGenericInstance (Type type, ImportGenericContext context)
		{
			var element_type = ImportType (type.GetGenericTypeDefinition (), context, ImportGenericKind.Definition);
			var instance = new GenericInstanceType (element_type);
			var arguments = type.GetGenericArguments ();
			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;
		}

		AssemblyNameReference ImportScope (SR.Assembly assembly)
		{
			AssemblyNameReference scope;
#if !SILVERLIGHT
			var name = assembly.GetName ();

			if (TryGetAssemblyNameReference (name, out scope))
				return scope;

			scope = new AssemblyNameReference (name.Name, name.Version) {
				Culture = name.CultureInfo.Name,
				PublicKeyToken = name.GetPublicKeyToken (),
				HashAlgorithm = (AssemblyHashAlgorithm) name.HashAlgorithm,
			};

			module.AssemblyReferences.Add (scope);

			return scope;
#else
			var name = AssemblyNameReference.Parse (assembly.FullName);

			if (module.TryGetAssemblyNameReference (name, out scope))
				return scope;

			module.AssemblyReferences.Add (name);

			return name;
#endif
		}

#if !SILVERLIGHT
		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;
		}
#endif

		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)
		{
#if !SILVERLIGHT
			return field.Module.ResolveField (field.MetadataToken);
#else
			return field.DeclaringType.GetGenericTypeDefinition ().GetField (field.Name,
				SR.BindingFlags.Public
				| SR.BindingFlags.NonPublic
				| (field.IsStatic ? SR.BindingFlags.Static : SR.BindingFlags.Instance));
#endif
		}

		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 = method.Module.ResolveMethod (method.MetadataToken);

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

#endif

	public class MetadataImporter : IMetadataImporter {

		readonly ModuleDefinition module;

		public MetadataImporter (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.Scope),
				type.IsValueType);

			MetadataSystem.TryProcessPrimitiveTypeReference (reference);

			if (type.IsNested)
				reference.DeclaringType = ImportType (type.DeclaringType, context);

			if (type.HasGenericParameters)
				ImportGenericParameters (reference, type);

			return reference;
		}

		IMetadataScope ImportScope (IMetadataScope scope)
		{
			switch (scope.MetadataScopeType) {
			case MetadataScopeType.AssemblyNameReference:
				return ImportAssemblyName ((AssemblyNameReference) scope);
			case MetadataScopeType.ModuleDefinition:
				if (scope == module) return scope;
				return ImportAssemblyName (((ModuleDefinition) scope).Assembly.Name);
			case MetadataScopeType.ModuleReference:
				throw new NotImplementedException ();
			}

			throw new NotSupportedException ();
		}

		AssemblyNameReference ImportAssemblyName (AssemblyNameReference 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
			};

			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;

			module.AssemblyReferences.Add (reference);

			return reference;
		}

		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 imported_instance = new GenericInstanceType (element_type);

				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;
			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 (((MethodReference)mvar_parameter.Owner).DeclaringType.FullName, mvar_parameter.DeclaringMethod.Name, mvar_parameter.Position);
			case ElementType.FnPtr:
				var funcPtr = (FunctionPointerType)type;
				var imported = new FunctionPointerType() {
					HasThis = funcPtr.HasThis,
					ExplicitThis = funcPtr.ExplicitThis,
					CallingConvention = funcPtr.CallingConvention,
					ReturnType = ImportType (funcPtr.ReturnType, context)
				};
                var parameters = funcPtr.Parameters;
				for (int i = 0; i < parameters.Count; i++)
                    imported.Parameters.Add(
						new ParameterDefinition (ImportType (parameters [i].ParameterType, context)));
                return imported;
			}

			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 reference_parameters = reference.Parameters;

				var parameters = method.Parameters;
				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 ("module");
		}

		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 (name_reference.FullName != reference.FullName) // TODO compare field by field
					continue;

				assembly_reference = reference;
				return true;
			}

			assembly_reference = null;
			return false;
		}
	}

#endif
}<commit_msg>Faster AssemblyNameReference comparison<commit_after>//
// Author:
//   <NAME> (<EMAIL>)
//
// Copyright (c) 2008 - 2015 <NAME>
// Copyright (c) 2008 - 2011 Novell, Inc.
//
// Licensed under the MIT/X11 license.
//

using System;
using System.Collections.Generic;
using Mono.Collections.Generic;
using SR = System.Reflection;

using Mono.Cecil.Metadata;

namespace Mono.Cecil {

#if !READ_ONLY

	public interface IMetadataImporterProvider {
		IMetadataImporter GetMetadataImporter (ModuleDefinition module);
	}

	public interface IMetadataImporter {
		TypeReference ImportReference (TypeReference type, IGenericParameterProvider context);
		FieldReference ImportReference (FieldReference field, IGenericParameterProvider context);
		MethodReference ImportReference (MethodReference method, IGenericParameterProvider context);
	}

#if !CF

	public interface IReflectionImporterProvider {
		IReflectionImporter GetReflectionImporter (ModuleDefinition module);
	}

	public interface IReflectionImporter {
		TypeReference ImportReference (Type type, IGenericParameterProvider context);
		FieldReference ImportReference (SR.FieldInfo field, IGenericParameterProvider context);
		MethodReference ImportReference (SR.MethodBase method, IGenericParameterProvider context);
	}
#endif

	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 declTypeFullName, 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 != candidate.Name || declTypeFullName != candidate.DeclaringType.FullName)
					continue;

				return candidate.GenericParameters [position];
			}

			throw new InvalidOperationException ();
		}

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


#if !CF
	public class ReflectionImporter : IReflectionImporter {

		readonly ModuleDefinition module;

		public ReflectionImporter (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.Assembly),
				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;
		}

		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)
		{
#if !SILVERLIGHT
			return type.IsNested;
#else
			return type.DeclaringType != null;
#endif
		}

		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 (type.DeclaringType.FullName, type.DeclaringMethod.Name, type.GenericParameterPosition);
			}
			if (type.DeclaringType != null)
			{
				return  context.TypeParameter (NormalizedFullName (type.DeclaringType), type.GenericParameterPosition);
			}
			throw new InvalidOperationException();
		}

		private static string NormalizedFullName (Type type)
		{
			if (IsNestedType (type))
				return NormalizedFullName (type.DeclaringType) + "/" + type.Name;

			return type.FullName;
		}

		TypeReference ImportGenericInstance (Type type, ImportGenericContext context)
		{
			var element_type = ImportType (type.GetGenericTypeDefinition (), context, ImportGenericKind.Definition);
			var instance = new GenericInstanceType (element_type);
			var arguments = type.GetGenericArguments ();
			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;
		}

		AssemblyNameReference ImportScope (SR.Assembly assembly)
		{
			AssemblyNameReference scope;
#if !SILVERLIGHT
			var name = assembly.GetName ();

			if (TryGetAssemblyNameReference (name, out scope))
				return scope;

			scope = new AssemblyNameReference (name.Name, name.Version) {
				Culture = name.CultureInfo.Name,
				PublicKeyToken = name.GetPublicKeyToken (),
				HashAlgorithm = (AssemblyHashAlgorithm) name.HashAlgorithm,
			};

			module.AssemblyReferences.Add (scope);

			return scope;
#else
			var name = AssemblyNameReference.Parse (assembly.FullName);

			if (module.TryGetAssemblyNameReference (name, out scope))
				return scope;

			module.AssemblyReferences.Add (name);

			return name;
#endif
		}

#if !SILVERLIGHT
		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;
		}
#endif

		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)
		{
#if !SILVERLIGHT
			return field.Module.ResolveField (field.MetadataToken);
#else
			return field.DeclaringType.GetGenericTypeDefinition ().GetField (field.Name,
				SR.BindingFlags.Public
				| SR.BindingFlags.NonPublic
				| (field.IsStatic ? SR.BindingFlags.Static : SR.BindingFlags.Instance));
#endif
		}

		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 = method.Module.ResolveMethod (method.MetadataToken);

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

#endif

	public class MetadataImporter : IMetadataImporter {

		readonly ModuleDefinition module;

		public MetadataImporter (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.Scope),
				type.IsValueType);

			MetadataSystem.TryProcessPrimitiveTypeReference (reference);

			if (type.IsNested)
				reference.DeclaringType = ImportType (type.DeclaringType, context);

			if (type.HasGenericParameters)
				ImportGenericParameters (reference, type);

			return reference;
		}

		IMetadataScope ImportScope (IMetadataScope scope)
		{
			switch (scope.MetadataScopeType) {
			case MetadataScopeType.AssemblyNameReference:
				return ImportAssemblyName ((AssemblyNameReference) scope);
			case MetadataScopeType.ModuleDefinition:
				if (scope == module) return scope;
				return ImportAssemblyName (((ModuleDefinition) scope).Assembly.Name);
			case MetadataScopeType.ModuleReference:
				throw new NotImplementedException ();
			}

			throw new NotSupportedException ();
		}

		AssemblyNameReference ImportAssemblyName (AssemblyNameReference 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
			};

			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;

			module.AssemblyReferences.Add (reference);

			return reference;
		}

		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 imported_instance = new GenericInstanceType (element_type);

				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;
			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 (((MethodReference)mvar_parameter.Owner).DeclaringType.FullName, mvar_parameter.DeclaringMethod.Name, mvar_parameter.Position);
			case ElementType.FnPtr:
				var funcPtr = (FunctionPointerType)type;
				var imported = new FunctionPointerType() {
					HasThis = funcPtr.HasThis,
					ExplicitThis = funcPtr.ExplicitThis,
					CallingConvention = funcPtr.CallingConvention,
					ReturnType = ImportType (funcPtr.ReturnType, context)
				};
                var parameters = funcPtr.Parameters;
				for (int i = 0; i < parameters.Count; i++)
                    imported.Parameters.Add(
						new ParameterDefinition (ImportType (parameters [i].ParameterType, context)));
                return imported;
			}

			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 reference_parameters = reference.Parameters;

				var parameters = method.Parameters;
				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 ("module");
		}

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

		private static bool Equals(byte[] a, byte[] b)
		{
			if (a == b) return true;
			if (a.Length != b.Length) return false;
			for (int i = 0; i < a.Length; i++)
				if (a[i] != b[i]) return false;
			return true;
		}

		private static bool Equals<T>(T a, T b) where T : class, IEquatable<T>
		{
			if (a == b) return true;
			if (a == null) return false;
			return a.Equals(b);
		}

		private static bool Equals(AssemblyNameReference a, AssemblyNameReference b)
		{
			if (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;
		}
	}

#endif
}
{'fraction_non_alphanumeric': 0.09358644180443632, 'fraction_numerical': 0.0022223145301985543, 'mean_word_length': 4.094593164744471, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4291606', 'n_tokens_mistral': 16132, 'n_tokens_neox': 13150, 'n_words': 3483}