public ExpandedMethod(
     ExpandedType returnType, ExpandedType declaringType, MethodDefinition definition,
     ImmutableList <ExpandedType> genericArguments, ImmutableList <ExpandedType> parameters,
     ImmutableDictionary <GenericParameter, ExpandedType> genericParameterToExType
     )
 {
     this.returnType               = returnType;
     this.declaringType            = declaringType;
     this.definition               = definition;
     this.genericArguments         = genericArguments;
     this.parameters               = parameters;
     this.genericParameterToExType = genericParameterToExType;
     _name = declaringType.locally(() => {
         var sb = new StringBuilder();
         sb.Append(returnType);
         sb.Append(' ');
         sb.Append(declaringType);
         sb.Append("::");
         sb.Append(definition.Name);
         if (!genericArguments.IsEmpty)
         {
             sb.Append(genericArguments.mkString(", ", "<", ">"));
         }
         sb.Append(parameters.mkString(", ", "(", ")"));
         return(sb.ToString());
     });
 }
        public static ExpandedMethod create(
            MethodReference reference,
            ImmutableDictionary <GenericParameter, ExpandedType> callerGenericParameters
            )
        {
            var declaringType = ExpandedType.create(reference.DeclaringType, callerGenericParameters);

            return(create(declaringType, reference, callerGenericParameters));
        }
        // Optimization for when we already know the expanded declaring type.
        public static ExpandedMethod create(
            ExpandedType declaringType, MethodReference reference,
            ImmutableDictionary <GenericParameter, ExpandedType> callerGenericParameters
            )
        {
            var callerAndDeclaringGenericParameters =
                callerGenericParameters.SetItems(declaringType.genericParametersToArguments);

            var definition = reference.Resolve();

            // Generic method, like A identity<A>(A a);
            var gRef    = reference as GenericInstanceMethod;
            var gRefTpl = gRef == null
        ? F.t(ImmutableDictionary <GenericParameter, ExpandedType> .Empty, ImmutableList <ExpandedType> .Empty)
        : gRef.locally(() => {
                var methodGenericArgs = genericArgumentsDict(
                    gRef.GenericArguments, definition.GenericParameters,
                    callerAndDeclaringGenericParameters
                    );
                var elementMethodGenericArgs = genericArgumentsDict(
                    gRef.GenericArguments, gRef.ElementMethod.GenericParameters,
                    callerAndDeclaringGenericParameters
                    );
                var _dict         = methodGenericArgs.SetItems(elementMethodGenericArgs);
                var _exParameters = definition.GenericParameters.Select(p =>
                                                                        ExpandedType.create(p, _dict)
                                                                        ).ToImmutableList();
                return(F.t(_dict, _exParameters));
            });

            // Delegates have their arguments messed up somehow. The parameters take
            // form of !!0, instead of A.
            var declGRef            = reference.DeclaringType as GenericInstanceType;
            var declGRefGenericArgs = declGRef == null
        ? ImmutableDictionary <GenericParameter, ExpandedType> .Empty
        : genericArgumentsDict(
                declGRef.GenericArguments, declGRef.ElementType.GenericParameters,
                callerAndDeclaringGenericParameters
                );

            var dict = callerAndDeclaringGenericParameters.SetItems(gRefTpl._1).SetItems(declGRefGenericArgs);
            var exGenericArguments = gRefTpl._2;
            var exParameters       = reference.Parameters.Select(p => {
                var gp = p.ParameterType as GenericParameter;
                return(gp == null
          ? ExpandedType.create(p.ParameterType, dict)
          : dict[gp]);
            }).ToImmutableList();
            var exReturnType = ExpandedType.create(definition.ReturnType, dict);

            return(new ExpandedMethod(
                       exReturnType, declaringType, reference.Resolve(),
                       exGenericArguments, exParameters, dict
                       ));
        }
        /* Make a dict from generic parameter name to resolved type definition. */
        public static ImmutableDictionary <GenericParameter, ExpandedType> genericArgumentsDict(
            IList <TypeReference> genericArguments,
            IList <GenericParameter> genericParameters,
            ImmutableDictionary <GenericParameter, ExpandedType> callerGenericParameters
            )
        {
            Debug.Assert(
                genericParameters.Count == genericArguments.Count,
                "Expected generic parameter count " + genericParameters.Count +
                " to be equal to generic argument count " + genericArguments.Count
                );

            var dict = ImmutableDictionary <GenericParameter, ExpandedType> .Empty;

            for (var idx = 0; idx < genericParameters.Count; idx++)
            {
                var param = genericParameters[idx];
                var arg   = genericArguments[idx];
                dict = dict.Add(param, ExpandedType.create(arg, callerGenericParameters));
            }
            return(dict);
        }
Exemple #5
0
 public UnityEntryPoint(ExpandedType type)
 {
     this.type = type;
 }
Exemple #6
0
 public static Option <IEntryPoint> create(TypeDefinition type)
 {
     return(isEntryPoint(type).opt <IEntryPoint>(() => new UnityEntryPoint(
                                                     ExpandedType.create(type, ExpandedType.EMPTY_GENERIC_LOOKUP)
                                                     )));
 }
        public static AnalyzerData analyze(
            IEnumerable <MethodDefinition> entryPoints,
            AnalyserLogger log
            )
        {
            var data = new AnalyzerData(
                ImmutableHashSet <ExpandedType> .Empty, ImmutableHashSet <ExpandedMethod> .Empty,
                ImmutableHashSet <VirtualMethod> .Empty, ImmutableHashSet <VirtualMethod> .Empty
                );

            foreach (var entryMethod in entryPoints)
            {
                var exEntryMethod = ExpandedMethod.create(
                    entryMethod, ExpandedType.EMPTY_GENERIC_LOOKUP
                    );
                data = data.addType(exEntryMethod.declaringType);
                if (!data.hasMethod(exEntryMethod))
                {
                    log.log("Entry", exEntryMethod);
                    data = analyze(data, exEntryMethod, log);
                }
            }

            // Once we know all used types, resolve the called virtual methods.
            // Iterate in a loop because expanding virtual method bodies might invoke additional
            // virtual methods.
            while (!data.virtualMethodsToAnalyze.IsEmpty)
            {
                foreach (var virtualMethod in data.virtualMethodsToAnalyze)
                {
                    var declaring = virtualMethod.method.declaringType;
                    foreach (var _usedType in data.usedTypes.Where(et => et.implements(declaring)))
                    {
                        var usedType = _usedType;
                        MethodDefinition matching = null;
                        while (matching == null)
                        {
                            matching = VirtualMethods.GetMethod(
                                usedType.definition.Methods, virtualMethod.method.definition
                                );
                            if (matching == null)
                            {
                                if (usedType.definition.BaseType == null)
                                {
                                    throw new Exception(
                                              "Can't find implementation for [" + virtualMethod + "] in [" + _usedType + "]!"
                                              );
                                }
                                usedType = ExpandedType.create(
                                    usedType.definition.BaseType,
                                    usedType.genericParametersToArguments
                                    );
                            }
                        }

                        var generics = usedType.genericParametersToArguments.AddRange(
                            ExpandedMethod.genericArgumentsDict(
                                virtualMethod.method.genericArguments.Select(t => (TypeReference)t.definition).ToList(),
                                matching.GenericParameters,
                                usedType.genericParametersToArguments
                                )
                            );
                        var exMatching = new ExpandedMethod(
                            virtualMethod.method.returnType, usedType, matching,
                            virtualMethod.method.genericArguments,
                            virtualMethod.method.parameters, generics
                            );
                        data = analyze(data, exMatching, log);
                    }
                    data = data.analyzedVirtualMethod(virtualMethod);
                }
            }
            return(data);
        }
 public AnalyzerData addType(ExpandedType type)
 {
     return(hasType(type)
 ? this : new AnalyzerData(usedTypes.Add(type), analyzedMethods, virtualMethodsToAnalyze, analyzedVirtualMethods));
 }
 public bool hasType(ExpandedType type)
 {
     return(usedTypes.Contains(type));
 }
        static AnalyzerData analyze(
            AnalyzerData data, ExpandedMethod method, AnalyserLogger log
            )
        {
            if (data.hasMethod(method))
            {
                return(data);
            }
            log.log("method", method);
            log.incIndent();

            data = data.addMethod(method);

            if (method.definition.IsConstructor)
            {
                data = data.addType(method.declaringType);
            }
            data = data.addType(method.returnType);
            data = method.parameters.Aggregate(data, (current, parameter) => current.addType(parameter));

            if (method.definition.IsVirtual && method.definition.Body == null)
            {
                // Because we don't know with what concrete types the implementation classes
                // of virtual methods will be instantiated, we will need to do a separate
                // analyzing stage once we know all the concrete types.
                data = data.addType(method.declaringType);
                data = data.addVirtualMethod(new VirtualMethod(method));
            }
            else if (method.definition.Body != null)
            {
                var body = method.definition.Body;
                foreach (var varDef in body.Variables)
                {
                    var exVar = ExpandedType.create(varDef.VariableType, method.genericParameterToExType);
                    data = data.addType(exVar);
                }
                foreach (var instruction in body.Instructions)
                {
                    if (
                        instruction.OpCode == OpCodes.Stfld || instruction.OpCode == OpCodes.Stsfld ||
                        instruction.OpCode == OpCodes.Ldsfld
                        )
                    {
                        var fieldDef      = (FieldReference)instruction.Operand;
                        var fieldGenerics = method.genericParameterToExType;
                        var gFieldType    = fieldDef.FieldType as GenericInstanceType;

                        if (fieldDef.FieldType.DeclaringType != null /*fieldDef.FieldType.IsNested*/)
                        {
                            if (fieldDef.FieldType.IsGenericParameter)
                            {
                                var generics = ExpandedMethod.genericArgumentsDict(
                                    ((GenericInstanceType)fieldDef.DeclaringType).GenericArguments,
                                    fieldDef.FieldType.DeclaringType.GenericParameters,
                                    fieldGenerics
                                    );
                                fieldGenerics = fieldGenerics.AddRange(generics);
                            }
                            if (gFieldType != null)
                            {
                                var tpl =
                                    gFieldType.GenericArguments.SequenceEqual(gFieldType.ElementType.GenericParameters)
                  ? F.t(
                                        (IList <TypeReference>)gFieldType.ElementType.DeclaringType.GenericParameters.Cast <TypeReference>().ToList(),
                                        (IList <GenericParameter>)gFieldType.GenericArguments.Cast <GenericParameter>().ToList()
                                        )
                  : gFieldType.ElementType.DeclaringType.HasGenericParameters
                    ? F.t(
                                        (IList <TypeReference>)gFieldType.GenericArguments,
                                        (IList <GenericParameter>)gFieldType.ElementType.DeclaringType.GenericParameters
                                        )
                    : F.t(
                                        (IList <TypeReference>) new TypeReference[0],
                                        (IList <GenericParameter>) new GenericParameter[0]
                                        );

                                var generics =
                                    ExpandedMethod.genericArgumentsDict(tpl._1, tpl._2, fieldGenerics);
                                fieldGenerics = fieldGenerics.AddRange(generics);
                            }
                        }
                        var exFieldDef      = ExpandedType.create(fieldDef.FieldType, fieldGenerics);
                        var exDeclaringType = ExpandedType.create(fieldDef.DeclaringType, method.genericParameterToExType);
                        data = data.addType(exFieldDef).addType(exDeclaringType);
                    }
                    else if (
                        instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Calli ||
                        instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj
                        )
                    {
                        var methodRef = (MethodReference)instruction.Operand;
                        if (instruction.OpCode == OpCodes.Newobj && methodRef.DeclaringType.Resolve().isDelegate())
                        {
                            methodRef = (MethodReference)instruction.Previous.Operand;
                        }
                        var expanded = ExpandedMethod.create(methodRef, method.genericParameterToExType);
                        data = analyze(data, expanded, log);
                    }
                }
            }
            else if (!(method.definition.IsInternalCall || method.definition.IsPInvokeImpl))
            {
                throw new Exception("Method body null when not expected: " + method);
            }
            log.decIndent();
            return(data);
        }
 public void log(ExpandedType type, string msg)
 {
     log("[" + type.name + "] " + msg);
 }
 public void log(ExpandedType type, string msg)
 {
 }