private void AddNestedTypes(TypeDefinition type, GenericInstanceTypeMap genericInstanceTypeMap) { foreach (TypeDefinition nestedType in type.NestedTypes) { AddType(nestedType, genericInstanceTypeMap); } }
private FieldInfo[] GetFields(TypeDefinition type, bool isGenericInstance, GenericInstanceTypeMap genericInstanceTypeMap) { var fields = new List <FieldInfo>(); foreach (FieldDefinition field in type.Fields) { var fieldInfo = GetFieldInfo(type, field, isGenericInstance, genericInstanceTypeMap); if (fieldInfo != null) { fields.Add(fieldInfo.Value); } } return(fields.ToArray()); }
private void AddBaseType(TypeReference typeRef, GenericInstanceTypeMap genericInstanceTypeMap) { var baseType = typeRef.Resolve().BaseType; if (baseType != null) { /* If we are processing generic instance type and * its base type happens to be a generic instance class as well, * we want to forward our generic arguments to the base. Consider: * * class One<T> * { * T one; * } * * class Two<T1, T2> : One<T2> * { * } * * class Three : Two<int, float> * { * } * * In this case, three is inheriting from Two<int, float>, * so we want Two<int, float> to inherit from One<float>, * however, cecil will tell us that base of Two<T1, T2> is One<T2>, * therefore we have to create the generic instance type of One<float> ourselves */ if (typeRef.IsGenericInstance && baseType.IsGenericInstance) { var genericInstance = ((GenericInstanceType)baseType); baseType = MakeGenericInstance(genericInstance.ElementType, genericInstance.GenericArguments, genericInstanceTypeMap); } AddType(baseType, genericInstanceTypeMap); } }
private FieldInfo?GetFieldInfo(TypeDefinition type, FieldDefinition field, bool isDeclaringTypeGenericInstance, GenericInstanceTypeMap genericInstanceTypeMap) { if (!WillSerialize(field)) { return(null); } var ti = new FieldInfo(); ti.name = field.Name; TypeReference fieldType; if (isDeclaringTypeGenericInstance) { fieldType = ResolveGenericInstanceType(field.FieldType, genericInstanceTypeMap); } else { fieldType = field.FieldType; } ti.type = GetMonoEmbeddedFullTypeNameFor(fieldType); ti.flags = FieldInfoFlags.None; var fixedBufferAttribute = GetFixedBufferAttribute(field); if (fixedBufferAttribute != null) { ti.flags |= FieldInfoFlags.FixedBuffer; ti.fixedBufferLength = GetFixedBufferLength(fixedBufferAttribute); ti.fixedBufferTypename = GetFixedBufferTypename(fixedBufferAttribute); } return(ti); }
private TypeReference MakeGenericInstance(TypeReference genericClass, IEnumerable <TypeReference> arguments, GenericInstanceTypeMap genericInstanceTypeMap) { var genericInstance = new GenericInstanceType(genericClass); foreach (var argument in arguments.Select(x => ResolveGenericInstanceType(x, genericInstanceTypeMap))) { genericInstance.GenericArguments.Add(argument); } return(genericInstance); }
private void AddType(TypeReference typeRef, GenericInstanceTypeMap genericInstanceTypeMap) { // Prevent duplicates if (classes_.Any(x => x.name == GetMonoEmbeddedFullTypeNameFor(typeRef))) { return; } TypeDefinition type; try { type = typeRef.Resolve(); } // This will happen for types which we don't have access to, like Windows.Foundation.IAsyncOperation<int> catch (AssemblyResolutionException) { return; } catch (NotSupportedException) // "NotSupportedException: Version not supported: 255.255.255.255" is thrown when assembly references WinRT assembly (e.g. mscorlib) { return; } if (type == null) { return; } if (typeRef.IsGenericInstance) { var arguments = ((GenericInstanceType)typeRef).GenericArguments; var parameters = type.GenericParameters; for (int i = 0; i < arguments.Count; i++) { if (parameters[i] != arguments[i]) { genericInstanceTypeMap[parameters[i]] = arguments[i]; } } typeResolver.Add((GenericInstanceType)typeRef); } /* Process class itself before nested/base types in case user does something evil, for example: * * class Outer * { * class Inner : Child * { * } * } * * class Child : Outer * { * } */ bool shouldImplementDeserializable = false; try { shouldImplementDeserializable = UnitySerializationLogic.ShouldImplementIDeserializable(type); } catch { // If assembly has unknown reference (for ex., see tests VariousPlugins, where Metro plugins are used), skip field } if (!shouldImplementDeserializable) { // In this case we only take care of processing the nested types, if any. AddNestedTypes(type, genericInstanceTypeMap); } else { var ci = new ClassInfo(); ci.name = GetMonoEmbeddedFullTypeNameFor(typeRef); ci.fields = GetFields(type, typeRef.IsGenericInstance, genericInstanceTypeMap); classes_.Add(ci); // Fetch info for inner types AddNestedTypes(type, genericInstanceTypeMap); // Add base type AddBaseType(typeRef, genericInstanceTypeMap); } if (typeRef.IsGenericInstance) { typeResolver.Remove((GenericInstanceType)typeRef); } }
/* We use this GenericInstanceTypeMap to map generic types to their generic instance types, * This is needed for correctly assess inheritance in cases like this: * * class One<T> * { * public T one; * } * * class Two : One<int> * { * } * * In this case, we look at type Two, and see that it inherits from type One<int>, * so we map T -> int. When we come across looking at field "one", we see that its * declaring type is a generic instance type and that T maps to int, so it writes down * that class One<int> has a field "int one". * * We use a new map for going through each type instance (check GatherClassInfo()). */ private TypeReference ResolveGenericInstanceType(TypeReference typeToResolve, GenericInstanceTypeMap genericInstanceTypeMap) { var arrayType = typeToResolve as ArrayType; if (arrayType != null) { typeToResolve = new ArrayType(ResolveGenericInstanceType(arrayType.ElementType, genericInstanceTypeMap), arrayType.Rank); } while (genericInstanceTypeMap.ContainsKey(typeToResolve)) { typeToResolve = genericInstanceTypeMap[typeToResolve]; } if (typeToResolve.IsGenericInstance) { // Handle the case of nested generics, like List<Dictionary<int, List<string>>> var genericInstance = ((GenericInstanceType)typeToResolve); typeToResolve = MakeGenericInstance(genericInstance.ElementType, genericInstance.GenericArguments, genericInstanceTypeMap); } return(typeToResolve); }