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); }
public UnityEntryPoint(ExpandedType type) { this.type = type; }
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) { }