예제 #1
0
        public static TypeReference SubstituteGenericParameters(
            this GenericInstanceType @this,
            IReadOnlyCollection <GenericParameter> genericParameters,
            ModuleDefinition moduleDefinition)
        {
            var genericType = moduleDefinition.ImportReference(@this.Resolve());

            Debug.Assert(genericType.GenericParameters.Count == @this.GenericArguments.Count);
            var substitutedGenericParameters = Enumerable
                                               .Range(0, genericType.GenericParameters.Count)
                                               .Select(i =>
            {
                var argument = @this.GenericArguments[i];
                if (argument.IsGenericParameter)
                {
                    Debug.Assert(genericParameters.Any(gp => gp.FullName == argument.FullName));
                    return(genericParameters.Single(gp => gp.FullName == argument.FullName));
                }

                if (argument is ArrayType arrayType)
                {
                    return(arrayType.SubstituteGenericParameters(genericParameters, moduleDefinition));
                }

                if (argument.IsGenericInstance && argument is GenericInstanceType genericInstanceType)
                {
                    return(SubstituteGenericParameters(genericInstanceType, genericParameters, moduleDefinition));
                }

                return(argument);
            })
                                               .ToArray();

            return(genericType.MakeGenericInstanceType(substitutedGenericParameters));
        }
예제 #2
0
        private static TypeDefinition ResolveImpl(this TypeReference reference)
        {
            try
            {
                if (reference.IsGenericInstance)
                {
                    var previous_instance = (GenericInstanceType)reference;
                    var instance          = new GenericInstanceType(previous_instance.ElementType.SmartResolve());
                    foreach (var argument in previous_instance.GenericArguments)
                    {
                        instance.GenericArguments.Add(argument.SmartResolve());
                    }
                    return(instance.Resolve());
                }

                return(reference.Resolve());
            }
            catch (AssemblyResolutionException ex)
            {
                return(null);
            }
            catch (Exception ex)
            {
                return(null);
            }
        }
예제 #3
0
        public static GenericInstanceType InflateType(GenericContext context, GenericInstanceType genericInstanceType)
        {
            var inflatedType = ConstructGenericType(context, genericInstanceType.Resolve(), genericInstanceType.GenericArguments);

            inflatedType.MetadataToken = genericInstanceType.MetadataToken;
            return(inflatedType);
        }
 private static void AddArrayIfNeeded(GenericInstanceType type, InflatedCollectionCollector generics, GenericInstanceMethod contextMethod, TypeDefinition ienumerableDefinition, TypeDefinition icollectionDefinition, TypeDefinition ilistDefinition)
 {
     TypeDefinition definition = type.Resolve();
     if (((definition == ienumerableDefinition) || (definition == icollectionDefinition)) || (definition == ilistDefinition))
     {
         ProcessArray(new ArrayType(type.GenericArguments[0]), generics, new GenericContext(type, contextMethod));
     }
 }
예제 #5
0
        private TypeReference ParametrizeSubInterface(GenericInstanceType interfaceType, TypeReference typeReference)
        {
            var gparams = interfaceType.GenericArguments
                          .Select(tr =>
                                  tr is GenericParameter gp ? _target.Module.ImportReference(((GenericInstanceType)typeReference).GenericArguments[gp.Position]) : tr)
                          .ToArray();

            return(_target.Module.ImportReference(interfaceType.Resolve()).MakeGenericInstanceType(gparams));
        }
예제 #6
0
        public static TypeReference ResolveGenericParameters(this TypeReference type, GenericInstanceMethod?methodInstance, GenericInstanceType?typeInstance)
        {
            if (type is GenericParameter genericParameter)
            {
                switch (genericParameter.Owner)
                {
                case MethodReference ownerMethod: {
                    if (ownerMethod.Resolve() != methodInstance?.Resolve())
                    {
                        throw new NotSupportedException($"Generic parameter {type} comes from method {ownerMethod} which is different from provided {methodInstance}.");
                    }

                    return(methodInstance.GenericArguments[genericParameter.Position].ResolveGenericParameters(methodInstance, typeInstance));
                }

                case TypeReference ownerType: {
                    if (ownerType.Resolve() != typeInstance?.Resolve())
                    {
                        throw new NotSupportedException($"Generic parameter {type} comes from type {ownerType} which is different from provided {typeInstance}.");
                    }

                    return(typeInstance.GenericArguments[genericParameter.Position].ResolveGenericParameters(methodInstance, typeInstance));
                }

                default:
                    throw new NotSupportedException($"Unsupported generic parameter owner: {genericParameter.Owner}.");
                }
            }

            if (type is GenericInstanceType generic)
            {
                var changed = (GenericInstanceType?)null;
                for (var i = 0; i < generic.GenericArguments.Count; i++)
                {
                    var argument = generic.GenericArguments[i];
                    var resolved = argument.ResolveGenericParameters(methodInstance, typeInstance);
                    if (resolved != argument)
                    {
                        changed = changed ?? Clone(generic);
                        changed.GenericArguments[i] = resolved;
                    }
                }
                return(changed ?? type);
            }

            if (type is ByReferenceType reference)
            {
                var resolved = reference.ElementType.ResolveGenericParameters(methodInstance, typeInstance);
                if (resolved == reference.ElementType)
                {
                    return(type);
                }
                return(new ByReferenceType(resolved));
            }

            return(type);
        }
예제 #7
0
        public static GenericInstanceType ParametrizeGenericInstance(this MemberReference member, GenericInstanceType generic)
        {
            if (!generic.ContainsGenericParameter)
            {
                return(generic);
            }

            var args = generic.GenericArguments.Select(ga => member.ResolveIfGeneric(ga)).ToArray();

            return(generic.Resolve().MakeGenericInstanceType(args));
        }
        public void AddGenericInstance(GenericInstanceType ty)
        {
            if (genericInstances.ContainsKey(ty.FullName))
            {
                return;
            }

            genericInstances.Add(ty.FullName, ty);
            // recursively add generic arguments
            foreach (var arg in ty.GenericArguments)
            {
                if (arg.IsGenericInstance)
                {
                    AddGenericInstance((GenericInstanceType)arg);
                }
            }

            // build mapping from generic parameter names to instantiated types
            TypeDefinition def = ty.Resolve();
            var            genericParameterMap = new Dictionary <string, TypeReference>();

            for (int i = 0; i < def.GenericParameters.Count; i++)
            {
                genericParameterMap.Add(def.GenericParameters[i].FullName, ty.GenericArguments[i]);
            }

            // recursively add implemented interfaces
            foreach (var intf in def.Interfaces.Select(i => i.InterfaceType).Where(i => i.ContainsGenericParameter && i is GenericInstanceType).Cast <GenericInstanceType>())
            {
                var type = TypeHelpers.InstantiateType(intf, genericParameterMap);
                if (type is GenericInstanceType)
                {
                    AddGenericInstance(type as GenericInstanceType);
                }
            }

            // recursively add other instances introduced by function parameters
            foreach (var m in def.Methods)
            {
                foreach (GenericInstanceType pty in m.Parameters
                         .Select(p => p.ParameterType)
                         .Concat(Enumerable.Repeat(m.ReturnType, 1))
                         .Where(t => t.ContainsGenericParameter && t is GenericInstanceType)
                         .Cast <GenericInstanceType>())
                {
                    var type = TypeHelpers.InstantiateType(pty, genericParameterMap);
                    if (type is GenericInstanceType)
                    {
                        AddGenericInstance(type as GenericInstanceType);
                    }
                }
            }
        }
        private IEnumerable <Instruction> CastsToSupportedCollections(MethodBody body)
        {
            return(InstrumentationUtil.Where(body, delegate(Instruction candidate)
            {
                if (candidate.OpCode != OpCodes.Castclass)
                {
                    return false;
                }
                GenericInstanceType target = candidate.Operand as GenericInstanceType;

                return target != null && HasReplacement(target.Resolve().FullName);
            }));
        }
예제 #10
0
        public EmittedTypeDefinition(string name,
                                     string parentType,
                                     GenericInstanceType type)
        {
            Name       = name;
            ParentType = parentType;

            var typeDef = type.Resolve();

            Properties = typeDef
                         .Properties
                         .Zip(type.GenericArguments)
                         .Select(x => new EmittedTypeProperty(x.Item1.Name, x.Item2.Resolve()))
                         .ToArray();
        }
예제 #11
0
        public static MethodReference MakeGenericInstanceConstructor(this GenericInstanceType @this)
        {
            var resolvedType = @this.Resolve().GetConstructors().Single();
            var result       = new MethodReference(resolvedType.Name, resolvedType.ReturnType, @this)
            {
                HasThis           = resolvedType.HasThis,
                ExplicitThis      = resolvedType.ExplicitThis,
                CallingConvention = resolvedType.CallingConvention
            };

            result.Parameters.AddRange(resolvedType.Parameters.Select(parameter => new ParameterDefinition(parameter.ParameterType)));
            result.GenericParameters.AddRange(resolvedType.GenericParameters.Select(parameter => new GenericParameter(parameter.Name, result)));

            return(result);
        }
예제 #12
0
        private TypeReference ParametrizeSubInterface(GenericInstanceType interfaceType, TypeReference typeReference)
        {
            TypeReference LookupType(TypeReference tr)
            {
                if (tr is GenericParameter gp)
                {
                    return(((GenericInstanceType)typeReference).GenericArguments[gp.Position]);
                }

                return(tr);
            }

            var gparams = interfaceType.GenericArguments.Select(LookupType).ToArray();

            return(interfaceType.Resolve().MakeGenericInstanceType(gparams));
        }
예제 #13
0
        public Type Resolve(TypeReference type, GenericBindingContext bindingContext)
        {
            ITypeContainer container = _moduleResolver.Resolve(type.Scope);

            GenericInstanceType genericInstanceType = type as GenericInstanceType;

            if (genericInstanceType != null)
            {
                Type   genericType      = Resolve(genericInstanceType.Resolve());
                Type[] genericArguments = genericInstanceType.GenericArguments
                                          .Select(bindingContext.Resolve)
                                          .Select(argument => Resolve(argument, bindingContext)).ToArray();
                return(genericType.MakeGenericType(genericArguments));
            }

            return(container.GetType(type.FullName));
        }
예제 #14
0
        /// <summary>
        /// Takes generic argments from child class and applies them to base class
        /// <br/>
        /// eg makes `Base{T}` in <c>Child{int} : Base{int}</c> have `int` instead of `T`
        /// </summary>
        /// <param name="parentReference"></param>
        /// <param name="childReference"></param>
        /// <returns></returns>
        public static GenericInstanceType MatchGenericParameters(this GenericInstanceType parentReference, TypeReference childReference)
        {
            if (!parentReference.IsGenericInstance)
            {
                throw new InvalidOperationException("Can't make non generic type into generic");
            }

            // make new type so we can replace the args on it
            // resolve it so we have non-generic instance (eg just instance with <T> instead of <int>)
            // if we dont cecil will make it double generic (eg INVALID IL)
            var generic = new GenericInstanceType(parentReference.Resolve());

            foreach (var arg in parentReference.GenericArguments)
            {
                generic.GenericArguments.Add(arg);
            }

            for (var i = 0; i < generic.GenericArguments.Count; i++)
            {
                // if arg is not generic
                // eg List<int> would be int so not generic.
                // But List<T> would be T so is generic
                if (!generic.GenericArguments[i].IsGenericParameter)
                {
                    continue;
                }

                // get the generic name, eg T
                var name = generic.GenericArguments[i].Name;
                // find what type T is, eg turn it into `int` if `List<int>`
                var arg = FindMatchingGenericArgument(childReference, name);

                // import just to be safe
                var imported = parentReference.Module.ImportReference(arg);
                // set arg on generic, parent ref will be Base<int> instead of just Base<T>
                generic.GenericArguments[i] = imported;
            }

            return(generic);
        }
예제 #15
0
        public override TypeReference Visit(GenericParameter type)
        {
            if (type.Type == GenericParameterType.Method)
            {
                if (genericContextMethod != null && type.Position < genericContextMethod.GenericArguments.Count)
                {
                    // Look for generic parameter in both resolved and element method
                    var genericContext1   = genericContextMethod.ElementMethod;
                    var genericContext2   = genericContextMethod.Resolve();
                    var genericParameter1 = genericContext1.GenericParameters[type.Position];
                    var genericParameter2 = genericContext2.GenericParameters[type.Position];

                    if (resolveOnlyReferences)
                    {
                        if (genericParameter1.Name == type.Name)
                        {
                            return(genericParameter2);
                        }
                    }
                    else
                    {
                        if (genericParameter1.Name == type.Name)
                        {
                            return(genericContextMethod.GenericArguments[type.Position]);
                        }

                        if (genericParameter2.Name == type.Name)
                        {
                            return(genericContextMethod.GenericArguments[type.Position]);
                        }
                    }
                }
            }
            else
            {
                if (genericContextType != null && type.Position < genericContextType.GenericArguments.Count)
                {
                    // Look for generic parameter in both resolved and element method
                    var genericContext1   = genericContextType.ElementType;
                    var genericContext2   = genericContextType.Resolve();
                    var genericParameter1 = genericContext1.GenericParameters[type.Position];
                    var genericParameter2 = genericContext2.GenericParameters[type.Position];

                    if (resolveOnlyReferences)
                    {
                        if (genericParameter1.Name == type.Name)
                        {
                            return(genericParameter2);
                        }
                    }
                    else
                    {
                        if (genericParameter1.Name == type.Name)
                        {
                            return(genericContextType.GenericArguments[type.Position]);
                        }

                        if (genericParameter2.Name == type.Name)
                        {
                            return(genericContextType.GenericArguments[type.Position]);
                        }
                    }
                }
            }

            return(base.Visit(type));
        }
예제 #16
0
    void DecorateMethod(MethodDefinition playableMethod, MethodDefinition originalMethod, TypeDefinition requestIdentifier, TypeDefinition responseIdentifier)
    {
        var reqResTypes = new List <TypeReference>();

        foreach (var pType in playableMethod.Parameters)
        {
            var module = GetModuleForReferencedType(pType.ParameterType);
            var def    = module.ImportReference(pType.ParameterType);
            reqResTypes.Add(ModuleDefinition.ImportReference(def.Resolve()));
        }

        var resModule = GetModuleForReferencedType(playableMethod.ReturnType);

        var responseType = ModuleDefinition.ImportReference(resModule.ImportReference(playableMethod.ReturnType).Resolve());

        bool isFunc = responseType.FullName != "System.Void"; //this is to determine if original method is a function or an action

        if (isFunc)
        {
            reqResTypes.Add(responseType);
        }

        var reqResArray = reqResTypes.ToArray();

        var dynPlayerTypeDef = TestFlaskAspectsModule.GetType(GetPlayerType(playableMethod.Parameters.Count, isFunc).FullName);
        var dynPlayerTypeRef = ModuleDefinition.ImportReference(dynPlayerTypeDef);

        TypeDefinition playerTypeDef;
        TypeReference  playerTypeRef;

        bool isPlayerGeneric = isFunc || playableMethod.Parameters.Count > 0; //if the player is instance is generic somehow (usually it is)

        if (isPlayerGeneric)
        {
            playerTypeRef = dynPlayerTypeRef.MakeGenericInstanceType(reqResArray);
            playerTypeDef = playerTypeRef.Resolve();
        }
        else //this is method with no args and no response (it is not generic at all)
        {
            playerTypeRef = dynPlayerTypeRef;
            playerTypeDef = dynPlayerTypeDef;
        }

        var dynTestModesDef = TestFlaskAspectsModule.GetType(typeof(TestModes).FullName);
        var dynTestModesRef = ModuleDefinition.ImportReference(dynTestModesDef);
        var testModesDef    = dynTestModesRef.Resolve();

        MethodReference playerCtorRef;
        MethodReference startInvocationMethodRef;
        MethodReference determineTestModeMethodRef;
        MethodReference playMethodRef;
        MethodReference recordMethodRef;
        MethodReference callOriginalMethodRef;

        if (isPlayerGeneric)
        {
            playerCtorRef              = ModuleDefinition.ImportReference(playerTypeDef.GetConstructors().First().MakeHostInstanceGeneric(reqResArray));
            startInvocationMethodRef   = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "StartInvocation").MakeHostInstanceGeneric(reqResArray));
            determineTestModeMethodRef = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "DetermineTestMode").MakeHostInstanceGeneric(reqResArray));
            playMethodRef              = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "Play").MakeHostInstanceGeneric(reqResArray));
            recordMethodRef            = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "Record").MakeHostInstanceGeneric(reqResArray));
            callOriginalMethodRef      = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "CallOriginal").MakeHostInstanceGeneric(reqResArray));
        }
        else //this is method with no args and no response (it is not generic at all)
        {
            playerCtorRef              = ModuleDefinition.ImportReference(playerTypeDef.GetConstructors().First());
            startInvocationMethodRef   = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "StartInvocation"));
            determineTestModeMethodRef = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "DetermineTestMode"));
            playMethodRef              = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "Play"));
            recordMethodRef            = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "Record"));
            callOriginalMethodRef      = ModuleDefinition.ImportReference(playerTypeDef.Methods.First(m => m.Name == "CallOriginal"));
        }

        var orgMethodRef = ModuleDefinition.ImportReference(GetOrgMethodType(playableMethod.Parameters.Count, isFunc));

        MethodReference orgMethodCtorRef;

        if (isPlayerGeneric)
        {
            GenericInstanceType orgMethodType = orgMethodRef.MakeGenericInstanceType(reqResArray);
            var genericOrgMethodTypeDef       = orgMethodType.Resolve();

            orgMethodCtorRef = ModuleDefinition.ImportReference(genericOrgMethodTypeDef.GetConstructors()
                                                                .Where(c => c.Parameters.Count == 2) //(object, IntPtr)
                                                                .First().MakeHostInstanceGeneric(reqResArray));
        }
        else
        {
            orgMethodCtorRef = ModuleDefinition.ImportReference(orgMethodRef.Resolve().GetConstructors()
                                                                .Where(c => c.Parameters.Count == 2) //(object, IntPtr)
                                                                .First());
        }

        MethodReference requestIdentifierCtorRef = null;

        if (requestIdentifier != null)
        {
            requestIdentifierCtorRef = requestIdentifier != null?ModuleDefinition.ImportReference(requestIdentifier.GetConstructors().First()) : null;
        }

        MethodReference responseIdentifierCtorRef = null;

        if (responseIdentifier != null)
        {
            responseIdentifierCtorRef = responseIdentifier != null?ModuleDefinition.ImportReference(responseIdentifier.GetConstructors().First()) : null;
        }

        if (isFunc)
        {
            DecorateFunc(playableMethod, originalMethod, playerTypeRef,
                         testModesDef, responseType, requestIdentifierCtorRef, responseIdentifierCtorRef, playerCtorRef, startInvocationMethodRef,
                         determineTestModeMethodRef, orgMethodCtorRef, callOriginalMethodRef, recordMethodRef, playMethodRef);
        }
        else
        {
            DecorateAction(playableMethod, originalMethod, playerTypeRef,
                           testModesDef, responseType, requestIdentifierCtorRef, responseIdentifierCtorRef, playerCtorRef, startInvocationMethodRef,
                           determineTestModeMethodRef, orgMethodCtorRef, callOriginalMethodRef, recordMethodRef, playMethodRef);
        }
    }
예제 #17
0
        private static MethodDefinition GetImplementedMethodFromGenericInstanceType(this MethodDefinition self, GenericInstanceType type)
        {
            TypeDefinition typeDef = type.Resolve();

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

            foreach (MethodDefinition method in typeDef.Methods)
            {
                if (method.Name == self.Name)
                {
                    if (method.HasParameters && self.HasParameters && method.Parameters.Count == self.Parameters.Count)
                    {
                        if (method.ReturnType.IsGenericParameter)
                        {
                            int parameterPosition = (method.ReturnType as GenericParameter).Position;

                            TypeReference genericArgument;
                            if (!type.PostionToArgument.TryGetValue(parameterPosition, out genericArgument))
                            {
                                continue;
                            }

                            if (genericArgument.FullName != self.ReturnType.FullName)
                            {
                                continue;
                            }
                        }
                        else if (method.ReturnType.FullName != self.ReturnType.FullName)
                        {
                            continue;
                        }

                        for (int i = 0; i < method.Parameters.Count; i++)
                        {
                            TypeReference parameterType = method.Parameters[i].ParameterType;

                            if (parameterType.IsGenericParameter)
                            {
                                int parameterPosition = (parameterType as GenericParameter).Position;

                                TypeReference genericArgument;
                                if (!type.PostionToArgument.TryGetValue(parameterPosition, out genericArgument))
                                {
                                    continue;
                                }

                                if (genericArgument.FullName != self.Parameters[i].ParameterType.FullName)
                                {
                                    continue;
                                }
                            }
                            else if (parameterType.FullName != self.Parameters[i].ParameterType.FullName)
                            {
                                continue;
                            }
                        }
                    }

                    return(method);
                }
            }

            return(null);
        }
		private static MethodDefinition GetImplementedMethodFromGenericInstanceType(this MethodDefinition self, GenericInstanceType type)
		{
			TypeDefinition typeDef = type.Resolve();

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

			foreach (MethodDefinition method in typeDef.Methods)
			{
				if (method.Name == self.Name)
				{
					if (method.HasParameters && self.HasParameters && method.Parameters.Count == self.Parameters.Count)
					{
						if (method.ReturnType.IsGenericParameter)
						{
							int parameterPosition = (method.ReturnType as GenericParameter).Position;

							TypeReference genericArgument;
							if (!type.PostionToArgument.TryGetValue(parameterPosition, out genericArgument))
							{
								continue;
							}

							if (genericArgument.FullName != self.ReturnType.FullName)
							{
								continue;
							}
						}
						else if (method.ReturnType.FullName != self.ReturnType.FullName)
						{
							continue;
						}

						for (int i = 0; i < method.Parameters.Count; i++)
						{
							TypeReference parameterType = method.Parameters[i].ParameterType;

							if (parameterType.IsGenericParameter)
							{
								int parameterPosition = (parameterType as GenericParameter).Position;

								TypeReference genericArgument;
								if (!type.PostionToArgument.TryGetValue(parameterPosition, out genericArgument))
								{
									continue;
								}

								if (genericArgument.FullName != self.Parameters[i].ParameterType.FullName)
								{
									continue;
								}
							}
							else if (parameterType.FullName != self.Parameters[i].ParameterType.FullName)
							{
								continue;
							}
						}
					}

					return method;
				}
			}

			return null;
		}
예제 #19
0
        TypeDefinition ExpandGenericType(GenericInstanceType genericType)
        {
            var genericName = GetGenericName(genericType);

            if (m_genericTypeCache.ContainsKey(genericName))
            {
                return(m_genericTypeCache[genericName]);
            }

            var ot = genericType.Resolve();
            var nt = new TypeDefinition("", genericName, TypeAttributes.Class);

            m_genericTypeCache[genericName] = nt;

            nt.BaseType = ot.BaseType;

            // update fields
            foreach (var f in ot.Fields)
            {
                var ft = f.FieldType;
                ft = ResolveGenericParameter(ft, genericType);

                var nf = new FieldDefinition(f.Name, f.Attributes, ft);
                nt.Fields.Add(nf);
            }

            // update Methods
            foreach (var m in ot.Methods)
            {
                var rt = ResolveGenericParameter(m.ReturnType, genericType);

                var nm = new MethodDefinition(m.Name, m.Attributes, rt);
                nt.Methods.Add(nm);
                foreach (var p in m.Parameters)
                {
                    nm.Parameters.Add(new ParameterDefinition(p.Name, p.Attributes, ResolveGenericParameter(p.ParameterType, genericType)));
                }


                if (m.HasBody)
                {
                    CopyTypeHelper.CopyMethodBody(m, nm);
                    foreach (var v in nm.Body.Variables)
                    {
                        if (v.VariableType.ContainsGenericParameter)
                        {
                            v.VariableType = ResolveGenericParameter(v.VariableType, genericType);
                            if (v.VariableType.ContainsGenericParameter || v.VariableType.IsGenericInstance)
                            {
                                v.VariableType = ExpandGenericType((GenericInstanceType)v.VariableType);
                            }
                        }
                    }

                    var ilp = nm.Body.GetILProcessor();
                    foreach (var i in nm.Body.Instructions)
                    {
                        if (i.Operand is MemberReference fr && fr.ContainsGenericParameter)
                        {
                            if (fr.DeclaringType.ContainsGenericParameter)
                            {
                                fr.DeclaringType = ResolveGenericParameter(fr.DeclaringType, genericType);
                                if (fr.DeclaringType.ContainsGenericParameter || fr.DeclaringType.IsGenericInstance)
                                {
                                    fr.DeclaringType = ExpandGenericType((GenericInstanceType)fr.DeclaringType);
                                }
                            }
                        }
                    }
                }
            }

            return(nt);
        }
예제 #20
0
    private WeaveResult WeaveProperty(PropertyDefinition prop, TypeDefinition type, Dictionary <string, Tuple <MethodReference, MethodReference> > methodTable)
    {
        var columnName     = prop.Name;
        var mapToAttribute = prop.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name == "MapToAttribute");

        if (mapToAttribute != null)
        {
            columnName = (string)mapToAttribute.ConstructorArguments[0].Value;
        }

        var backingField = prop.GetBackingField();
        var isIndexed    = prop.CustomAttributes.Any(a => a.AttributeType.Name == "IndexedAttribute");

        if (isIndexed && (!_indexableTypes.Contains(prop.PropertyType.FullName)))
        {
            return(WeaveResult.Error($"{type.Name}.{prop.Name} is marked as [Indexed] which is only allowed on integral types as well as string, bool and DateTimeOffset, not on {prop.PropertyType.FullName}."));
        }

        var isPrimaryKey = prop.CustomAttributes.Any(a => a.AttributeType.Name == "PrimaryKeyAttribute");

        if (isPrimaryKey && (!_primaryKeyTypes.Contains(prop.PropertyType.FullName)))
        {
            return(WeaveResult.Error($"{type.Name}.{prop.Name} is marked as [PrimaryKey] which is only allowed on integral and string types, not on {prop.PropertyType.FullName}."));
        }

        if (!prop.IsAutomatic())
        {
            if (prop.PropertyType.Resolve().BaseType.IsSameAs(_realmObject))
            {
                return(WeaveResult.Warning($"{type.Name}.{columnName} is not an automatic property but its type is a RealmObject which normally indicates a relationship."));
            }

            return(WeaveResult.Skipped());
        }

        if (_typeTable.ContainsKey(prop.PropertyType.FullName))
        {
            // If the property is automatic but doesn't have a setter, we should still ignore it.
            if (prop.SetMethod == null)
            {
                return(WeaveResult.Skipped());
            }

            var typeId = prop.PropertyType.FullName + (isPrimaryKey ? " unique" : string.Empty);
            if (!methodTable.ContainsKey(typeId))
            {
                var getter = _realmObject.LookupMethodReference("Get" + _typeTable[prop.PropertyType.FullName] + "Value", ModuleDefinition);
                var setter = _realmObject.LookupMethodReference("Set" + _typeTable[prop.PropertyType.FullName] + "Value" + (isPrimaryKey ? "Unique" : string.Empty), ModuleDefinition);
                methodTable[typeId] = Tuple.Create(getter, setter);
            }

            ReplaceGetter(prop, columnName, methodTable[typeId].Item1);
            ReplaceSetter(prop, backingField, columnName, methodTable[typeId].Item2);
        }

        // treat IList and RealmList similarly but IList gets a default so is useable as standalone
        // IList or RealmList allows people to declare lists only of _realmObject due to the class definition
        else if (prop.IsIList())
        {
            var elementType = ((GenericInstanceType)prop.PropertyType).GenericArguments.Single();
            if (!elementType.Resolve().BaseType.IsSameAs(_realmObject))
            {
                return(WeaveResult.Warning($"SKIPPING {type.Name}.{columnName} because it is an IList but its generic type is not a RealmObject subclass, so will not persist."));
            }

            if (prop.SetMethod != null)
            {
                return(WeaveResult.Error($"{type.Name}.{columnName} has a setter but its type is a IList which only supports getters."));
            }

            var concreteListType = new GenericInstanceType(_system_IList)
            {
                GenericArguments = { elementType }
            };
            var listConstructor         = concreteListType.Resolve().GetConstructors().Single(c => c.IsPublic && c.Parameters.Count == 0);
            var concreteListConstructor = listConstructor.MakeHostInstanceGeneric(elementType);

            // weaves list getter which also sets backing to List<T>, forcing it to accept us setting it post-init
            var backingDef = backingField as FieldDefinition;
            if (backingDef != null)
            {
                backingDef.Attributes &= ~FieldAttributes.InitOnly;  // without a set; auto property has this flag we must clear
            }

            ReplaceListGetter(prop, backingField, columnName,
                              new GenericInstanceMethod(_genericGetListValueReference)
            {
                GenericArguments = { elementType }
            },
                              ModuleDefinition.ImportReference(concreteListConstructor));
        }
        else if (prop.PropertyType.Resolve().BaseType.IsSameAs(_realmObject))
        {
            if (!prop.IsAutomatic())
            {
                return(WeaveResult.Warning($"{type.Name}.{columnName} is not an automatic property but its type is a RealmObject which normally indicates a relationship."));
            }

            // with casting in the _realmObject methods, should just work
            ReplaceGetter(prop, columnName,
                          new GenericInstanceMethod(_genericGetObjectValueReference)
            {
                GenericArguments = { prop.PropertyType }
            });
            ReplaceSetter(prop, backingField, columnName,
                          new GenericInstanceMethod(_genericSetObjectValueReference)
            {
                GenericArguments = { prop.PropertyType }
            });
        }
        else if (prop.PropertyType.FullName == "System.DateTime")
        {
            return(WeaveResult.Error($"Class '{type.Name}' field '{prop.Name}' is a DateTime which is not supported - use DateTimeOffset instead."));
        }
        else if (prop.PropertyType.FullName == "System.Nullable`1<System.DateTime>")
        {
            return(WeaveResult.Error($"Class '{type.Name}' field '{prop.Name}' is a DateTime? which is not supported - use DateTimeOffset? instead."));
        }
        else
        {
            return(WeaveResult.Error($"Class '{type.Name}' field '{columnName}' is a '{prop.PropertyType}' which is not yet supported."));
        }

        var preserveAttribute = new CustomAttribute(_preserveAttributeConstructor);

        prop.CustomAttributes.Add(preserveAttribute);

        var wovenPropertyAttribute = new CustomAttribute(_wovenPropertyAttributeConstructor);

        prop.CustomAttributes.Add(wovenPropertyAttribute);

        Debug.WriteLine(string.Empty);

        var primaryKeyMsg = isPrimaryKey ? "[PrimaryKey]" : string.Empty;
        var indexedMsg    = isIndexed ? "[Indexed]" : string.Empty;

        LogDebug($"Woven {type.Name}.{prop.Name} as a {prop.PropertyType.FullName} {primaryKeyMsg} {indexedMsg}.");
        return(WeaveResult.Success(prop, backingField, isPrimaryKey));
    }
예제 #21
0
 public void WriteDefinition(GenericInstanceType type, IMetadataCollection metadataCollection)
 {
     if (GenericsUtilities.CheckForMaximumRecursion(type))
     {
         object[] args = new object[] { MetadataWriter.Naming.ForGenericClass(type) };
         base.Writer.WriteLine("Il2CppGenericClass {0} = {{ -1, {{ NULL, NULL }}, NULL }};", args);
     }
     else
     {
         base.Writer.WriteExternForIl2CppGenericInst(type.GenericArguments);
         object[] objArray2 = new object[] { MetadataWriter.Naming.ForGenericClass(type), metadataCollection.GetTypeInfoIndex(type.Resolve()), MetadataWriter.Naming.ForGenericInst(type.GenericArguments), MetadataWriter.Naming.Null, MetadataWriter.Naming.Null };
         base.WriteLine("Il2CppGenericClass {0} = {{ {1}, {{ &{2}, {3} }}, {4} }};", objArray2);
     }
 }
예제 #22
0
        private void ReplaceContructorWithConstructorFrom(Instruction newObj)
        {
            MethodReference originalCtor = (MethodReference)newObj.Operand;

            GenericInstanceType originalList  = (GenericInstanceType)originalCtor.DeclaringType;
            GenericInstanceType declaringType = new GenericInstanceType(Context.Import(_collectionReplacements[originalList.Resolve().FullName]));

            foreach (TypeReference argument in originalList.GenericArguments)
            {
                declaringType.GenericArguments.Add(argument);
            }

            MethodReference newCtor = new MethodReference(".ctor", Context.Import(typeof(void)));

            newCtor.DeclaringType = declaringType;
            newCtor.HasThis       = true;

            foreach (ParameterDefinition parameter in originalCtor.Parameters)
            {
                newCtor.Parameters.Add(parameter);
            }

            newObj.Operand = newCtor;
        }
예제 #23
0
 public static GenericInstanceType InflateType(GenericContext context, GenericInstanceType genericInstanceType) =>
 ConstructGenericType(context, genericInstanceType.Resolve(), genericInstanceType.GenericArguments);