Beispiel #1
0
        private static bool MatchesGeneric(this MethodMember methodMember, MethodReference methodReference)
        {
            var referenceFullName = methodReference.GetElementMethod().GetFullName();
            var memberFullName    = methodMember.FullName;
            var count             = methodReference.GetElementMethod().GenericParameters.Count;

            if (methodMember.GenericParameters.Count != count)
            {
                return(false);
            }

            var parameters = new List <GenericParameter[]>();

            for (var i = 0; i < count; i++)
            {
                parameters.Add(new[]
                {
                    new GenericParameter(methodReference.GetElementMethod().GenericParameters[i].Name),
                    methodMember.GenericParameters[i]
                });
            }

            parameters = parameters.OrderByDescending(genericParameters => genericParameters[0].Name.Length).ToList();

            foreach (var genericParameters in parameters.Where(genericParameters => genericParameters[0] != null)
                     )
            {
                referenceFullName = referenceFullName.Replace(genericParameters[0].Name, genericParameters[1].Name);
                memberFullName    = memberFullName.Replace(genericParameters[0].Name, genericParameters[1].Name);
            }

            return(memberFullName.Equals(referenceFullName));
        }
        public static string GetGenericIdValue(MethodReference methodDefinition)
        {
            var spaceIndex             = methodDefinition.FullName.IndexOf(" ", StringComparison.Ordinal);
            var signature              = methodDefinition.FullName.Substring(spaceIndex + 1);
            var genericTypeMarkerIndex = signature.IndexOf("`", StringComparison.Ordinal);

            if (genericTypeMarkerIndex > -1) // is a method of a generic type and needs special logic
            {
                // has generic param but not a generic method
                var twoDotsIndex = signature.IndexOf("::", StringComparison.Ordinal);
                if (twoDotsIndex < genericTypeMarkerIndex)
                {
                    if (methodDefinition.CallingConvention == MethodCallingConvention.Generic) // generic method
                    {
                        var elementMethod = methodDefinition.GetElementMethod().FullName;
                        elementMethod = TypeService.ReplaceGenericPlaceholders(elementMethod);
                        spaceIndex    = elementMethod.IndexOf(" ", StringComparison.Ordinal);
                        signature     = elementMethod.Substring(spaceIndex + 1);

                        return(signature);
                    }

                    return(string.Empty);
                }

                // extra generic types of method name
                if (signature.IndexOf("!") > -1)
                {
                    try
                    {
                        signature = TypeService.ReplaceGenericPlaceholders(signature);

                        var fullNameWithGenTypes = signature.Substring(0, genericTypeMarkerIndex + 2) + signature.Substring(twoDotsIndex);
                        return(fullNameWithGenTypes);
                    }
                    catch (Exception ex)
                    {
                    }
                }

                return(string.Empty);
            }
            else if (methodDefinition.CallingConvention == MethodCallingConvention.Generic) // generic method
            {
                var elementMethod = methodDefinition.GetElementMethod().FullName;
                elementMethod = TypeService.ReplaceGenericPlaceholders(elementMethod);
                spaceIndex    = elementMethod.IndexOf(" ", StringComparison.Ordinal);
                signature     = elementMethod.Substring(spaceIndex + 1);

                return(signature);
            }

            return(string.Empty);
        }
        public MethodDefinition Resolve(MethodReference method)
        {
            TypeDefinition type = Resolve(method.DeclaringType);

            method = method.GetElementMethod();
            return(GetMethod(type, method));
        }
Beispiel #4
0
        public MethodDefinition Resolve(MethodReference method)
        {
            var type = Resolve(method.DeclaringType);

            if (type == null)
            {
                return(null);
            }

            method = method.GetElementMethod();

            if (!type.HasMethods)
            {
                throw new Exception("Metadata resolver--type has no methods!");
            }

            var result = GetMethod(type, method);

            if (result != null)
            {
                if (result.Module.MetadataResolver != this)
                {
                    throw new Exception("Can't be.");
                }
                return(result);
            }

            return(result);
        }
Beispiel #5
0
        /// <summary>Rewrite a method reference if needed.</summary>
        /// <param name="methodRef">The current method reference.</param>
        private bool RewriteMethodReference(MethodReference methodRef)
        {
            bool rewritten = false;

            rewritten |= this.RewriteTypeReference(methodRef.DeclaringType, newType =>
            {
                // note: generic methods are wrapped into a MethodSpecification which doesn't allow changing the
                // declaring type directly. For our purposes we want to change all generic versions of a matched
                // method anyway, so we can use GetElementMethod to get the underlying method here.
                methodRef.GetElementMethod().DeclaringType = newType;
            });
            rewritten |= this.RewriteTypeReference(methodRef.ReturnType, newType => methodRef.ReturnType = newType);

            foreach (var parameter in methodRef.Parameters)
            {
                rewritten |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType);
            }

            if (methodRef is GenericInstanceMethod genericRef)
            {
                for (int i = 0; i < genericRef.GenericArguments.Count; i++)
                {
                    rewritten |= this.RewriteTypeReference(genericRef.GenericArguments[i], newType => genericRef.GenericArguments[i] = newType);
                }
            }

            return(rewritten);
        }
Beispiel #6
0
        private StaticConstructorWrapper WrapConstructor(MethodReference methodRefHandle)
        {
            var declaringType           = MakeDeclaredType(methodRefHandle.DeclaringType);
            var declaringTypeDefnHandle = (TypeDefinition)declaringType.Handle;
            var methodDefnHandle        = FindMatchingMethod(methodRefHandle.GetElementMethod(), GetConstructors(declaringTypeDefnHandle.Methods));

            return(new StaticConstructorWrapper(this, methodDefnHandle, declaringType));
        }
        /*********
        ** Private methods
        *********/
        /// <summary>Rewrite a CIL instruction if needed.</summary>
        /// <param name="instruction">The current CIL instruction.</param>
        /// <param name="cil">The CIL instruction processor.</param>
        /// <param name="replaceWith">Replaces the CIL instruction with a new one.</param>
        private bool RewriteInstruction(Instruction instruction, ILProcessor cil, Action <Instruction> replaceWith)
        {
            bool rewritten = false;

            // field reference
            FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction);

            if (fieldRef != null)
            {
                rewritten |= this.RewriteTypeReference(fieldRef.DeclaringType, newType => fieldRef.DeclaringType = newType);
                rewritten |= this.RewriteTypeReference(fieldRef.FieldType, newType => fieldRef.FieldType = newType);
            }

            // method reference
            MethodReference methodRef = RewriteHelper.AsMethodReference(instruction);

            if (methodRef != null)
            {
                rewritten |= this.RewriteTypeReference(methodRef.DeclaringType, newType =>
                {
                    // note: generic methods are wrapped into a MethodSpecification which doesn't allow changing the
                    // declaring type directly. For our purposes we want to change all generic versions of a matched
                    // method anyway, so we can use GetElementMethod to get the underlying method here.
                    methodRef.GetElementMethod().DeclaringType = newType;
                });
                rewritten |= this.RewriteTypeReference(methodRef.ReturnType, newType => methodRef.ReturnType = newType);

                foreach (var parameter in methodRef.Parameters)
                {
                    rewritten |= this.RewriteTypeReference(parameter.ParameterType, newType => parameter.ParameterType = newType);
                }

                if (methodRef is GenericInstanceMethod genericRef)
                {
                    for (int i = 0; i < genericRef.GenericArguments.Count; i++)
                    {
                        rewritten |= this.RewriteTypeReference(genericRef.GenericArguments[i], newType => genericRef.GenericArguments[i] = newType);
                    }
                }
            }

            // type reference
            if (instruction.Operand is TypeReference typeRef)
            {
                rewritten |= this.RewriteTypeReference(typeRef, newType => replaceWith(cil.Create(instruction.OpCode, newType)));
            }

            // instruction itself
            // (should be done after the above type rewrites to ensure valid types)
            rewritten |= this.RewriteInstructionImpl(instruction, cil, newInstruction =>
            {
                rewritten = true;
                cil.Replace(instruction, newInstruction);
                instruction = newInstruction;
            });

            return(rewritten);
        }
Beispiel #8
0
        private MethodReference CloneMethodWithDeclaringType(MethodReference methodRef, TypeReference declaringTypeRef)
        {
            // If the input method reference is generic, it will be wrapped in a GenericInstanceMethod object
            var genericRef = methodRef as GenericInstanceMethod;

            if (genericRef != null)
            {
                // The actual method data we need to replicate is the ElementMethod
                // Replace the method reference with the element method from the generic wrapper
                methodRef = methodRef.GetElementMethod();
            }

            // Build a new method reference that matches the original exactly, but with a different declaring type
            var newRef = new MethodReference(methodRef.Name, methodRef.ReturnType, declaringTypeRef)
            {
                CallingConvention = methodRef.CallingConvention,
                HasThis           = methodRef.HasThis,
                ExplicitThis      = methodRef.ExplicitThis,
                MethodReturnType  = methodRef.MethodReturnType,
            };

            // Clone method input parameters
            foreach (var p in methodRef.Parameters)
            {
                newRef.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, p.ParameterType));
            }

            // Clone method generic parameters
            foreach (var p in methodRef.GenericParameters)
            {
                newRef.GenericParameters.Add(new GenericParameter(p.Name, newRef));
            }

            if (genericRef == null)
            {
                // For non-generic methods, we can simply return the new method reference
                return(newRef);
            }
            else
            {
                // For generic methods, copy the generic arguments into the new method refernce
                var newGenericRef = new GenericInstanceMethod(newRef);
                foreach (var typeDef in genericRef.GenericArguments)
                {
                    newGenericRef.GenericArguments.Add(typeDef);
                }

                // Done
                return(newGenericRef);
            }
        }
Beispiel #9
0
        private StaticMethodWrapper WrapMethod(MethodReference methodRefHandle)
        {
            var declaringType           = MakeDeclaredType(methodRefHandle.DeclaringType);
            var declaringTypeDefnHandle = (TypeDefinition)declaringType.Handle;
            var methodDefnHandle        = FindMatchingMethod(methodRefHandle.GetElementMethod(), declaringTypeDefnHandle.Methods);
            var method = new StaticMethodWrapper(this, methodDefnHandle, declaringType, declaringType, declaringType.Substitution);

            var genericInstance = methodRefHandle as GenericInstanceMethod;

            if (genericInstance != null)
            {
                var genericArguments = CollectionUtils.ConvertAllToArray <TypeReference, ITypeInfo>(genericInstance.GenericArguments, MakeType);
                method = method.MakeGenericMethod(genericArguments);
            }

            return(method);
        }
Beispiel #10
0
 public IMethod Resolve(MethodReference methodReference)
 {
     if (methodReference == null)
     {
         throw new ArgumentNullException(nameof(methodReference));
     }
     lock (methodLookupCache) {
         IMethod method;
         if (!methodLookupCache.TryGetValue(methodReference, out method))
         {
             method = FindNonGenericMethod(methodReference.GetElementMethod());
             if (method == null)
             {
                 method = CreateFakeMethod(methodReference);
             }
             if (methodReference.CallingConvention == MethodCallingConvention.VarArg)
             {
                 method = new VarArgInstanceMethod(
                     method,
                     methodReference.Parameters.SkipWhile(p => !p.ParameterType.IsSentinel).Select(p => Resolve(p.ParameterType))
                     );
             }
             else if (methodReference.IsGenericInstance || methodReference.DeclaringType.IsGenericInstance)
             {
                 IList <IType> classTypeArguments  = null;
                 IList <IType> methodTypeArguments = null;
                 if (methodReference.IsGenericInstance)
                 {
                     var gim = ((GenericInstanceMethod)methodReference);
                     methodTypeArguments = gim.GenericArguments.SelectArray(Resolve);
                 }
                 if (methodReference.DeclaringType.IsGenericInstance)
                 {
                     var git = (GenericInstanceType)methodReference.DeclaringType;
                     classTypeArguments = git.GenericArguments.SelectArray(Resolve);
                 }
                 method = method.Specialize(new TypeParameterSubstitution(classTypeArguments, methodTypeArguments));
             }
             methodLookupCache.Add(methodReference, method);
         }
         return(method);
     }
 }
        public virtual MethodDefinition ResolveMethod(MethodReference methodRef)
        {
            var declaringType = ResolveType(methodRef.DeclaringType);

            methodRef = methodRef.GetElementMethod();

            if (declaringType != null && declaringType.HasMethods)
            {
                foreach (var method in declaringType.Methods)
                {
                    if (MethodRefsAreEqual(method, methodRef))
                    {
                        return(method);
                    }
                }
            }

            return(null);
        }
Beispiel #12
0
        /// <summary>
        /// Check the given method reference.
        /// </summary>
        private void Check(MethodReference method, string context)
        {
            if (!Check(method.DeclaringType, context))
            {
                return;
            }
            var error = false;

            try
            {
                if (method.IsGenericInstance)
                {
                    Check((GenericInstanceMethod)method, context);
                }
                else
                {
                    var typeDef   = method.DeclaringType.GetElementType().Resolve();
                    var emethod   = method.GetElementMethod();
                    var methodDef = (typeDef != null) ? typeDef.Methods.FirstOrDefault(x => x.AreSameExcludingGenericArguments(emethod, null)) : null;
                    error = (methodDef == null);
                }
            }
            catch (Exception)
            {
                error = true;
            }
            CheckResolveData data;
            var key = method.FullName;

            if (!resolveErrorMethodNames.TryGetValue(key, out data))
            {
                data = new CheckResolveData {
                    IsAvailable = !error
                };
                resolveErrorMethodNames.Add(key, data);
                if (error)
                {
                    Error(MessageTypes.MissingMethod, Format(method, false), method.DeclaringType.Scope, context);
                }
            }
            data.CheckCount++;
        }
Beispiel #13
0
        private MethodDefinition ResolveManually(MethodReference method)
        {
            var metadataResolver = method.Module.MetadataResolver;
            var type             = metadataResolver.Resolve(method.DeclaringType);

            if (type == null || !type.HasMethods)
            {
                return(null);
            }

            method = method.GetElementMethod();

            Func <IEnumerable <MethodDefinition>, MethodReference, MethodDefinition>[] finderMethods =
            { GetMethodDefinition, GetCompatibleMethodDefinition };

            for (int i = 0; i < finderMethods.Length; i++)
            {
                while (type != null)
                {
                    var methodDefinition = finderMethods[i](type.Methods, method);

                    if (methodDefinition != null)
                    {
                        return(methodDefinition);
                    }

                    if (type.BaseType == null)
                    {
                        break;
                    }
                    type = metadataResolver.Resolve(type.BaseType);
                }
                type = metadataResolver.Resolve(method.DeclaringType);
            }

            return(null);
        }
Beispiel #14
0
 private static ulong GetToken(MethodReference method)
 {
     return((ulong)method.DeclaringType.Module.Assembly.GetHashCode() << 32 | method.GetElementMethod().MetadataToken.ToUInt32());
 }
Beispiel #15
0
        private MethodMemberInstance CreateMethodMemberFromMethodReference(
            [NotNull] ITypeInstance <IType> typeInstance, [NotNull] MethodReference methodReference)
        {
            if (methodReference.IsGenericInstance)
            {
                var elementMethod =
                    CreateMethodMemberFromMethodReference(typeInstance, methodReference.GetElementMethod()).Member;

                var genericInstanceMethod = (GenericInstanceMethod)methodReference;
                var genericArguments      = genericInstanceMethod.GenericArguments
                                            .Select(CreateGenericArgumentFromTypeReference)
                                            .Where(argument => !argument.Type.IsCompilerGenerated);

                return(new MethodMemberInstance(elementMethod, typeInstance.GenericArguments, genericArguments));
            }

            var returnTypeReference = methodReference.ReturnType;
            var returnType          = GetOrCreateStubTypeInstanceFromTypeReference(returnTypeReference);

            var        name                = methodReference.BuildMethodMemberName();
            var        fullName            = methodReference.BuildFullName();
            var        isGeneric           = methodReference.HasGenericParameters;
            var        isCompilerGenerated = methodReference.IsCompilerGenerated();
            MethodForm methodForm;
            Visibility visibility;
            bool       isStub;

            MethodDefinition methodDefinition;

            try
            {
                methodDefinition = methodReference.Resolve();
            }
            catch (AssemblyResolutionException)
            {
                methodDefinition = null;
            }

            if (methodDefinition == null)
            {
                visibility = Public;
                methodForm = methodReference.HasConstructorName() ? MethodForm.Constructor : MethodForm.Normal;
                isStub     = true;
            }
            else
            {
                visibility = methodDefinition.GetVisibility();
                methodForm = methodDefinition.GetMethodForm();
                isStub     = false;
            }

            var methodMember = new MethodMember(name, fullName, typeInstance.Type, visibility, returnType,
                                                false, methodForm, isGeneric, isStub, isCompilerGenerated);

            var parameters = methodReference.GetParameters(this).ToList();

            methodMember.ParameterInstances.AddRange(parameters);

            var genericParameters = GetGenericParameters(methodReference);

            methodMember.GenericParameters.AddRange(genericParameters);

            return(new MethodMemberInstance(methodMember, typeInstance.GenericArguments,
                                            Enumerable.Empty <GenericArgument>()));
        }
Beispiel #16
0
        private bool TryToResolveInSupport(MethodReference method)
        {
            if (string.IsNullOrEmpty(Context.SupportModulePartialNamespace))
            {
                return(false);
            }

            method = method.GetElementMethod();

            var originalType = method.DeclaringType;

            if (originalType.IsGenericInstance || originalType.HasGenericParameters)
            {
                return(false);
            }

            var support = SupportAssemblyReference();

            var ns = Context.SupportModulePartialNamespace;

            if (!string.IsNullOrEmpty(originalType.Namespace))
            {
                ns += '.' + originalType.Namespace;
            }
            method.DeclaringType = new TypeReference(ns, originalType.Name, Context.TargetModule, support, originalType.IsValueType);

            MethodDefinition resolved = null;

            // We can only change declaring type like this for static methods
            if (!method.HasThis)
            {
                resolved = method.Resolve();
            }

            // If our method is instance, we can have a static method in support module that has explicit "this" parameter
            if (resolved == null && method.HasThis)
            {
                method.HasThis = false;
                method.Parameters.Insert(0, new ParameterDefinition(originalType));
                resolved = method.Resolve();

                // Our explicit "this" parameter can be of type System.Object
                if (resolved == null)
                {
                    method.Parameters[0] = new ParameterDefinition(method.DeclaringType.Module.TypeSystem.Object.Resolve());
                    resolved             = method.Resolve();
                }

                if (resolved == null)
                {
                    method.HasThis = true;
                    method.Parameters.RemoveAt(0);
                }
            }

            if (resolved != null)
            {
                Context.RewriteTarget = true;
                AddSupportReferenceIfNeeded(support);
                return(true);
            }

            method.DeclaringType = originalType;
            return(false);
        }
        public void OnMethod(MethodDefinition method)
        {
            if (method.DeclaringType.IsInterface)
            {
                return;
            }
            if (!method.HasBody)
            {
                if (Verbosity >= 9)
                {
                    Console.WriteLine("method has no body: " + method.FullName);
                }
                return;
            }

            if (method.GenericParameters.Count > 0)
            {
                if (Verbosity >= Verbosities.SkippingVerbose)
                {
                    Console.WriteLine(" . Skipping generic method: " + method.FullName);
                }
                return;
            }

            var processor = method.Body.GetILProcessor();

            foreach (var i in method.Body.Instructions.ToArray())
            {
                if (i.OpCode != OpCodes.Callvirt &&
                    i.OpCode != OpCodes.Call &&
                    i.OpCode != OpCodes.Calli
                    )
                {
                    continue;
                }

                Mono.Cecil.GenericParameter genPar = null;

                MethodReference mr = i.Operand as MethodReference;
                if (mr == null)
                {
                    throw new Exception("Call method does not have MethodReference as Operand.");
                }
                if (!mr.IsGenericInstance)
                {
                    continue;
                }
                if (!mr.FullName.Contains("<"))
                {
//					if(Verbosity >= 8) - shouldn't be reached
                    Console.WriteLine("Skipping method that contains no <");
                    continue;
                }

                if (mr.FullName.Contains(" System."))
                {
                    if (Verbosity >= Verbosities.Skipping)
                    {
                        Console.WriteLine("Skipping method invocation that contains ' System.': "
                                          + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name);
                    }
                    continue;
                }

#if CUSTOM // Custom blacklist
                if (!mr.FullName.Contains(" LionFire.") && !mr.FullName.Contains(" Dycen."))
                {
                    if (Verbosity >= Verbosities.Skipping)
                    {
                        Console.WriteLine("Skipping method that is not LionFire or Dycen:"
                                          + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name);
                    }
                    continue;
                }
#endif

                var genPars = mr.Resolve().GenericParameters;
                //					Console.WriteLine("TEMP2 - " + genPars.Count);
                //				var genPars = mr.GetGenericParameters(method.Module);
                //				Console.WriteLine("TEMP " + mr.Name);
                //				Console.WriteLine("TEMP genPars.Count " + genPars.Count);

                if (genPars.Count != 1)
                {
                    if (Verbosity >= Verbosities.Warning)
                    {
                        Console.WriteLine("[NS] Replacing methods with more than 1 generic parameter not supported: " + genPars.Count + ": " + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name);
                    }
                    continue;
                }
                else
                {
                    genPar = genPars[0];
//					var resolved = genPar.Resolve();
//					Console.WriteLine("NEW -- <" + (resolved == null ? "null" : resolved.Name) + ">");
                    if (Verbosity >= 10)
                    {
                        Console.WriteLine("NEW |- <" + genPar + ">");
                    }
                }


                #region string genericParameter = ...;
                string         genericParameter;
                Type           genericTypeParameter;
                TypeDefinition genericTypeParameterDefinition = null;
                {
                    string n = mr.FullName.Split(' ')[1];
                    n = n.Split(new string[] { "::" }, StringSplitOptions.RemoveEmptyEntries)[1];
                    int startI = n.IndexOf('<') + 1;
                    int stack  = 0;
                    int endI   = startI + 1;
                    while (stack > 0 || n[endI] != '>')
                    {
                        if (n[endI] == '<')
                        {
                            stack++;
                        }
                        if (n[endI] == '>')
                        {
                            stack--;
                        }
                        endI++;
                    }

                    int length = endI - startI;
                    genericParameter = n.Substring(startI, length);

//					if(genericParameter.StartsWith("!!"))
//					{
//						int genParAliasIndex = Convert.ToInt32(genericParameter.Substring(2));
//
//						var genParAlias = genPars[genParAliasIndex];
//
//
//						genericParameter = genParAlias.FullName;
//						Console.WriteLine("NEW - Generic method alias param: " + genericParameter);
//					}
                    //				if(genericParameter.Contains("<") || genericParameter.Contains(">"))
                    //				{
                    //					Console.WriteLine("Unsupported generic method ("+mr.FullName+") with generic parameter: " + genericParameter);
                    //					skipped++;
                    //					continue;
                    //				}

                    if (Verbosity >= 8)
                    {
                        Console.WriteLine("Generic method param: " + genericParameter);
                    }

                    genericTypeParameter = Type.GetType(genericParameter, false);

                    //if(genericTypeParameter == null)
                    {
                        foreach (ModuleDefinition modDef in ads.SelectMany(assDef => assDef.Modules))
                        {
                            //						foreach(var modType in modDef.Types)
                            //						{
                            //							Console.WriteLine("ccc - " + modType);
                            //						}
                            genericTypeParameterDefinition = modDef.Types.Where(td => td.FullName == genericParameter
                                                                                //							                      && !td.IsGenericInstance
                                                                                ).FirstOrDefault();

                            if (genericTypeParameterDefinition != null)
                            {
                                if (Verbosity >= 9)
                                {
                                    Console.WriteLine("TODO - got genTD: " + genericTypeParameterDefinition);
                                }
                                break;
                            }
                        }
                        if (genericTypeParameterDefinition == null)
                        {
                            if (Verbosity >= 8)
                            {
                                Console.WriteLine(" x Could not get TypeDefinition for " + genericParameter);
                            }
                            // No continue, this is not a problem
                        }

                        if (genericTypeParameter == null && genericTypeParameterDefinition == null)
                        {
                            if (Verbosity >= Verbosities.Error)
                            {
                                Console.WriteLine(" x - Failed to get Type for " + genericParameter + " in invocation: " + mr.FullName + " in method " + method.FullName);
                            }
                            skipped++;
                            continue;
                        }
                    }
                }
                #endregion

#if ONLY_VOID_OR_GENPARM // OLD, now other return types are supported if they are the same as replaced method
                string matchingReturnType = "!!0";
//				genericTypeParameter.FullName;


                if (mr.ReturnType.FullName != "System.Void" &&
                    mr.ReturnType.FullName != matchingReturnType)
//				   && mr.ReturnType.FullName != genericTypeParameter.FullName)
                {
                    if (Verbosity >= 3)
                    {
                        Console.WriteLine("   x generic method doesn't return System.Void or '"
                                          + matchingReturnType +
                                          "': " + mr.FullName + ", but instead: " + mr.ReturnType.FullName);
                    }
                    continue;
                }
#endif

//				if(Verbosity >= 9) Console.WriteLine("mr: " + mr.Name);

                TypeDefinition tr = mr.DeclaringType.Resolve();

                MethodDefinition replacementMethod = null;
//				if(mr.DeclaringType.Name == "MultiType")
//				{
//					foreach(MethodDefinition replacementMethod_ in
//						tr.Methods)
//					{
//						Console.WriteLine("z " + replacementMethod_.Name + "    " + replacementMethod_.FullName);
//					}
//				}

                bool noCast = false;

                foreach (MethodDefinition replacementMethod_ in
                         tr.Methods.Where(mr_ => mr_.Name == mr.Name && !mr_.HasGenericParameters))
                {
                    noCast = false;
                    // TODO: Verify parameters
                    if (!replacementMethod_.HasParameters)
                    {
                        continue;
                    }
                    if (replacementMethod_.Parameters.Count != mr.Parameters.Count + 1)
                    {
                        if (Verbosity >= 8)
                        {
                            Console.WriteLine("   x - (alt) candidate replacement method has wrong parameter count: " + replacementMethod_.FullName);
                        }
                        continue;
                    }
//					Console.WriteLine("Replacement param type: "+ replacementMethod_.Parameters[0].ParameterType.FullName);

                    if (replacementMethod_.Parameters[replacementMethod_.Parameters.Count - 1].ParameterType.FullName != "System.Type")
                    {
                        if (Verbosity >= 8)
                        {
                            Console.WriteLine("   x - (alt) candidate replacement does not have Type parameter at the end of parameters : " + replacementMethod_.FullName);
                        }
                        continue;
                    }


                    if (mr.ReturnType.FullName == replacementMethod_.ReturnType.Resolve().FullName)
                    {
                        noCast = true;
                        if (Verbosity >= 9)
                        {
                            Console.WriteLine("   - (alt) generic method and alt method return same type:: " + mr.ReturnType.FullName);
                        }
                    }
                    else if (mr.ReturnType.FullName != "System.Void")                      // Replacement must return object
                    {
                        if (replacementMethod_.ReturnType.Resolve().FullName != "System.Object")
                        {
                            if (Verbosity >= 3)
                            {
                                Console.WriteLine(" [x?] (alt) generic method returns T but candidate replacement method does not return System.Object: " + replacementMethod_.FullName
                                                  + " [[" + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name + "]]");
                            }
                            continue;
                        }
                    }
                    if (Verbosity >= 8)
                    {
                        Console.WriteLine("FOUND ALTERNATE METHOD: " + replacementMethod_);
                    }
                    replacementMethod = replacementMethod_;
                    break;                     // FUTURE: don't break here, keep going to see if there are multiple (ambiguous) matches and throw/output error
                }
                if (replacementMethod == null)
                {
                    if (!(" " + mr.FullName).Contains(" System."))
                    {
                        if (Verbosity >= Verbosities.Warning)
                        {
                            Console.WriteLine("[__] No alternate found for "
                                              + mr.FullName + " in " + method.DeclaringType.FullName + "." + method.Name);
                        }
//						                  + mr.DeclaringType.FullName+"." +mr.Name + "(...)");
                    }
                    skipped++;
                    continue;
                }

//				if(mr.Name != "TestMethod") continue; // TEMP
                if (Verbosity >= Verbosities.Success)
                {
                    Console.WriteLine(" O Replacing " + mr.FullName
                                      + " " + mr.GenericParameters.Count + " generic parameters"
                                      + " " + mr.Parameters.Count + " parameters"
                                      + " | " + mr.GetElementMethod().FullName + ""
                                      + " | " + mr.GetElementMethod().HasGenericParameters + ""
                                      + " | " + mr.GetElementMethod().GenericParameters[0].Name + ""
                                      );
                }

//				if(Verbosity >= 6)
//					Console.WriteLine("Resolved non-specific generic method: " + mr.FullName);

//				if(Verbosity >= 8) Console.WriteLine("RESOLVED TYPE: " + genericTypeParameter);

//				var typeModuleDefinition = ModuleDefinition.ReadModule(type.Module.Assembly.Location);
//				var typeDefinition = typeModuleDefinition.Types.Where(td => td.FullName == genericParameter).FirstOrDefault();
//				if(typeDefinition != null && Verbosity >= 5)
//				{
//					Console.WriteLine("Resolved typeDefinition: " + typeDefinition);
//				}
//				else
//				{
//					Console.WriteLine("Failed to resolve typeDefinition: " + type.FullName);
////					foreach(var td in ModuleDefinition.ReadModule(type.Module.Assembly.Location).Types)
////					{
////						Console.WriteLine(" ... " + td.FullName);
////					}
//					continue;
//				}

//				method.Module.Import(type); // try removing this

//				IMetadataScope scope = method.Module;
//				var typeRef = new TypeReference(type.Namespace, type.Name, typeModuleDefinition, scope, type.IsValueType);
//				Console.WriteLine("TypeRef: "+ typeRef);

//				method.Module.Import(type);
                var replacementMethodImported = method.Module.Import(replacementMethod);

                // IL_0000:  ldtoken Rewriter.TestClass

                if (genericTypeParameter != null)
                {
                    processor.InsertBefore(i, processor.Create(OpCodes.Ldtoken, method.Module.Import(genericTypeParameter)));
                }
                else
                {
                    processor.InsertBefore(i, processor.Create(OpCodes.Ldtoken, method.Module.Import(genericTypeParameterDefinition)));
                }

                // IL_0005:  call class [mscorlib]System.Type class
                //              [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)

                var             gtfh    = typeof(Type).GetMethod("GetTypeFromHandle");
                MethodReference gtfhRef = method.Module.Import(gtfh, mr);

                processor.InsertBefore(i, processor.Create(OpCodes.Call, gtfhRef));

                // IL_000a:  call void class Rewriter.TestClass::TestMethod(class [mscorlib]System.Type)
                var callMethod = processor.Create(i.OpCode, replacementMethodImported);
                processor.InsertAfter(i, callMethod);

                #region Cast the result, if it exists

                if (mr.ReturnType.FullName != "System.Void" && !noCast)
                {
                    string castAssembly;
                    string castType;

                    if (genericTypeParameter != null)
                    {
                        castAssembly = genericTypeParameter.Assembly.GetName(false).Name;
                        castType     = "[" + castAssembly + "]" + genericTypeParameter.FullName;
                    }
                    else if (genericTypeParameterDefinition != null)
                    {
                        castAssembly = "";
                        castType     = genericTypeParameterDefinition.ToString();
//						var resolvedGTPD = genericTypeParameterDefinition.Resolve();
//						resolvedGTPD.FullName
                    }
                    else
                    {
                        castType = "???";
                        Console.WriteLine("INTERNAL ERROR - genericTypeParameter not set for " + mr.FullName + ". genericTypeParameterDefinition:" + genericTypeParameterDefinition.Resolve());
                        continue;
                    }

                    //					castAssembly = castAssembly.Substring(castAssembly.IndexOf(","));
                    if (Verbosity > 8)
                    {
                        Console.WriteLine("CAST to " + castType + " | " + genericTypeParameterDefinition);
                    }
                    var importedGenericType = mr.Module.Import(genericTypeParameterDefinition);
                    processor.InsertAfter(callMethod,
                                          processor.Create(OpCodes.Castclass, importedGenericType));
                }

                #endregion

                processor.Remove(i);
                replaced++;

//				if(Verbosity >= Verbosities.Success)
//					Console.WriteLine(" - " + ((MethodReference)i.Operand).Name + " replaced with " + replacementMethod.FullName);


//				mr.GetGenericParameters(null);
//
//			if(method.GenericParameters.Count == 0) return;
//
//			if(method.GenericParameters.Count > 1)
//			{
//				Console.WriteLine("Warning: cannot handle more than one generic parameter yet: " +
//				                  method.DeclaringType.FullName + "." + method.Name);
//				return;
//			}
//
//			var body = method.Body;
//			body.Instructions
//			if(method.GenericParameters.Count == 1)
//			{
//			}
            }
        }