Ejemplo n.º 1
0
        /// <summary>
        ///   Transforms open generic types to closed instantiation using context information.
        ///   As an example, if <c>B{T}</c> inherits from <c>A{T}</c>, running it with <c>B{C}</c> as context and <c>A{B.T}</c>
        ///   as type, it will return <c>A{C}</c>.
        /// </summary>
        public static TypeReference Process(TypeReference context, TypeReference type)
        {
            if (type is null)
            {
                return(null);
            }

            var parentContext = context;
            GenericInstanceType genericInstanceTypeContext = null;

            while (parentContext != null)
            {
                genericInstanceTypeContext = parentContext as GenericInstanceType;
                if (genericInstanceTypeContext != null)
                {
                    break;
                }

                parentContext = parentContext.Resolve().BaseType;
            }

            if (genericInstanceTypeContext is null || genericInstanceTypeContext.ContainsGenericParameter)
            {
                return(type);
            }

            // Build dictionary that will map generic type to their real implementation type
            var genericTypeMapping = new Dictionary <TypeReference, TypeReference>();

            while (parentContext != null)
            {
                var resolvedType = parentContext.Resolve();
                for (int i = 0; i < resolvedType.GenericParameters.Count; ++i)
                {
                    var genericParameter = parentContext.GetElementType().Resolve().GenericParameters[i];
                    genericTypeMapping.Add(genericParameter, genericInstanceTypeContext.GenericArguments[i]);
                }
                parentContext = parentContext.Resolve().BaseType;
                if (parentContext is GenericInstanceType)
                {
                    genericInstanceTypeContext = parentContext as GenericInstanceType;
                }
            }

            var visitor = new ResolveGenericsVisitor(genericTypeMapping);
            var result  = visitor.VisitDynamic(type);

            // Make sure type is closed now
            if (result.ContainsGenericParameter)
            {
                throw new InvalidOperationException("Unsupported generic resolution.");
            }

            return(result);
        }
Ejemplo n.º 2
0
        public static void InflateGenericType(TypeDefinition genericType, TypeDefinition inflatedType, params TypeReference[] genericTypes)
        {
            // Base type
            var genericMapping = new Dictionary <TypeReference, TypeReference>();

            for (int i = 0; i < genericTypes.Length; ++i)
            {
                genericMapping.Add(genericType.GenericParameters[i], genericTypes[i]);
            }

            var resolveGenericsVisitor = new ResolveGenericsVisitor(genericMapping);

            inflatedType.BaseType = inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(genericType.BaseType));

            // Some stuff are not handled yet
            if (genericType.HasNestedTypes)
            {
                throw new NotImplementedException();
            }

            foreach (var field in genericType.Fields)
            {
                var clonedField = new FieldDefinition(field.Name, field.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(field.FieldType)));
                inflatedType.Fields.Add(clonedField);
            }

            foreach (var property in genericType.Properties)
            {
                if (property.HasParameters)
                {
                    throw new NotImplementedException();
                }

                var clonedProperty = new PropertyDefinition(property.Name, property.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(property.PropertyType)))
                {
                    HasThis   = property.HasThis,
                    GetMethod = property.GetMethod != null?InflateMethod(inflatedType, property.GetMethod, resolveGenericsVisitor) : null,
                                    SetMethod = property.SetMethod != null?InflateMethod(inflatedType, property.GetMethod, resolveGenericsVisitor) : null,
                };

                inflatedType.Properties.Add(clonedProperty);
            }

            // Clone methods
            foreach (var method in genericType.Methods)
            {
                var clonedMethod = InflateMethod(inflatedType, method, resolveGenericsVisitor);
                inflatedType.Methods.Add(clonedMethod);
            }
        }
Ejemplo n.º 3
0
        private static MethodDefinition InflateMethod(TypeDefinition inflatedType, MethodDefinition method, ResolveGenericsVisitor resolveGenericsVisitor)
        {
            var clonedMethod = new MethodDefinition(method.Name, method.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(method.ReturnType)));

            clonedMethod.Parameters.AddRange(
                method.Parameters.Select(x => new ParameterDefinition(x.Name, x.Attributes, inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(x.ParameterType)))));

            if (method.Body != null)
            {
                clonedMethod.Body.Variables.AddRange(
                    method.Body.Variables.Select(x => new VariableDefinition(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(x.VariableType)))));


                clonedMethod.Body.InitLocals = method.Body.InitLocals;

                var mappedInstructions = new Dictionary <Instruction, Instruction>();
                foreach (var instruction in method.Body.Instructions)
                {
                    // Create nop instructions to start with (if we use actual opcode, it would do an operand check)
                    var mappedInstruction = Instruction.Create(OpCodes.Nop);
                    mappedInstruction.OpCode        = instruction.OpCode;
                    mappedInstruction.Operand       = instruction.Operand;
                    mappedInstructions[instruction] = mappedInstruction;
                }

                foreach (var instruction in method.Body.Instructions)
                {
                    // Fix operand
                    var mappedInstruction = mappedInstructions[instruction];
                    if (mappedInstruction.Operand is Instruction)
                    {
                        mappedInstruction.Operand = mappedInstructions[(Instruction)instruction.Operand];
                    }
                    else if (mappedInstruction.Operand is ParameterDefinition)
                    {
                        var parameterIndex = method.Parameters.IndexOf((ParameterDefinition)instruction.Operand);
                        mappedInstruction.Operand = clonedMethod.Parameters[parameterIndex];
                    }
                    else if (mappedInstruction.Operand is VariableDefinition)
                    {
                        var variableIndex = method.Body.Variables.IndexOf((VariableDefinition)instruction.Operand);
                        mappedInstruction.Operand = clonedMethod.Body.Variables[variableIndex];
                    }
                    else if (mappedInstruction.Operand is TypeReference)
                    {
                        var newTypeReference = resolveGenericsVisitor.VisitDynamic((TypeReference)mappedInstruction.Operand);
                        newTypeReference          = inflatedType.Module.ImportReference(newTypeReference);
                        mappedInstruction.Operand = newTypeReference;
                    }
                    else if (mappedInstruction.Operand is FieldReference)
                    {
                        var fieldReference    = (FieldReference)mappedInstruction.Operand;
                        var newFieldReference = new FieldReference(fieldReference.Name,
                                                                   inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(fieldReference.FieldType)),
                                                                   inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(fieldReference.DeclaringType)));
                        mappedInstruction.Operand = newFieldReference;
                    }
                    else if (mappedInstruction.Operand is MethodReference)
                    {
                        var methodReference = (MethodReference)mappedInstruction.Operand;

                        var genericInstanceMethod = methodReference as GenericInstanceMethod;
                        if (genericInstanceMethod != null)
                        {
                            methodReference = genericInstanceMethod.ElementMethod;
                        }

                        methodReference = methodReference.GetElementMethod();
                        var newMethodReference = new MethodReference(methodReference.Name,
                                                                     inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(methodReference.ReturnType)),
                                                                     inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(methodReference.DeclaringType)))
                        {
                            HasThis           = methodReference.HasThis,
                            ExplicitThis      = methodReference.ExplicitThis,
                            CallingConvention = methodReference.CallingConvention,
                        };

                        foreach (var parameter in methodReference.Parameters)
                        {
                            newMethodReference.Parameters.Add(new ParameterDefinition(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(parameter.ParameterType))));
                        }

                        if (methodReference.HasGenericParameters)
                        {
                            CopyGenericParameters(methodReference, newMethodReference);
                        }

                        if (genericInstanceMethod != null)
                        {
                            newMethodReference = newMethodReference.MakeGenericMethod(genericInstanceMethod.GenericArguments.Select(x => inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(x))).ToArray());
                        }

                        mappedInstruction.Operand = newMethodReference;
                    }
                    else if (mappedInstruction.Operand is Mono.Cecil.CallSite)
                    {
                        var callSite    = (Mono.Cecil.CallSite)mappedInstruction.Operand;
                        var newCallSite = new Mono.Cecil.CallSite(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(callSite.ReturnType)))
                        {
                            HasThis           = callSite.HasThis,
                            ExplicitThis      = callSite.ExplicitThis,
                            CallingConvention = callSite.CallingConvention,
                        };

                        foreach (var parameter in callSite.Parameters)
                        {
                            newCallSite.Parameters.Add(new ParameterDefinition(inflatedType.Module.ImportReference(resolveGenericsVisitor.VisitDynamic(parameter.ParameterType))));
                        }

                        mappedInstruction.Operand = newCallSite;
                    }
                    else if (mappedInstruction.Operand is Instruction[])
                    {
                        // Not used in UpdatableProperty<T>
                        throw new NotImplementedException();
                    }
                }

                clonedMethod.Body.Instructions.AddRange(method.Body.Instructions.Select(x => mappedInstructions[x]));
            }
            return(clonedMethod);
        }