diff options
Diffstat (limited to 'Mono.Cecil/GenericParameterResolver.cs')
-rw-r--r-- | Mono.Cecil/GenericParameterResolver.cs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/Mono.Cecil/GenericParameterResolver.cs b/Mono.Cecil/GenericParameterResolver.cs new file mode 100644 index 0000000..86525c5 --- /dev/null +++ b/Mono.Cecil/GenericParameterResolver.cs @@ -0,0 +1,175 @@ +using Mono.Cecil.Cil; +using System; + +namespace Mono.Cecil { + internal sealed class GenericParameterResolver { + internal static TypeReference ResolveReturnTypeIfNeeded (MethodReference methodReference) + { + if (methodReference.DeclaringType.IsArray && methodReference.Name == "Get") + return methodReference.ReturnType; + + var genericInstanceMethod = methodReference as GenericInstanceMethod; + var declaringGenericInstanceType = methodReference.DeclaringType as GenericInstanceType; + + if (genericInstanceMethod == null && declaringGenericInstanceType == null) + return methodReference.ReturnType; + + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, methodReference.ReturnType); + } + + internal static TypeReference ResolveFieldTypeIfNeeded (FieldReference fieldReference) + { + return ResolveIfNeeded (null, fieldReference.DeclaringType as GenericInstanceType, fieldReference.FieldType); + } + + internal static TypeReference ResolveParameterTypeIfNeeded (MethodReference method, ParameterReference parameter) + { + var genericInstanceMethod = method as GenericInstanceMethod; + var declaringGenericInstanceType = method.DeclaringType as GenericInstanceType; + + if (genericInstanceMethod == null && declaringGenericInstanceType == null) + return parameter.ParameterType; + + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, parameter.ParameterType); + } + + internal static TypeReference ResolveVariableTypeIfNeeded (MethodReference method, VariableReference variable) + { + var genericInstanceMethod = method as GenericInstanceMethod; + var declaringGenericInstanceType = method.DeclaringType as GenericInstanceType; + + if (genericInstanceMethod == null && declaringGenericInstanceType == null) + return variable.VariableType; + + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, variable.VariableType); + } + + private static TypeReference ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance declaringGenericInstanceType, TypeReference parameterType) + { + var byRefType = parameterType as ByReferenceType; + if (byRefType != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, byRefType); + + var arrayType = parameterType as ArrayType; + if (arrayType != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, arrayType); + + var genericInstanceType = parameterType as GenericInstanceType; + if (genericInstanceType != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, genericInstanceType); + + var genericParameter = parameterType as GenericParameter; + if (genericParameter != null) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, genericParameter); + + var requiredModifierType = parameterType as RequiredModifierType; + if (requiredModifierType != null && ContainsGenericParameters (requiredModifierType)) + return ResolveIfNeeded (genericInstanceMethod, declaringGenericInstanceType, requiredModifierType.ElementType); + + if (ContainsGenericParameters (parameterType)) + throw new Exception ("Unexpected generic parameter."); + + return parameterType; + } + + private static TypeReference ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, GenericParameter genericParameterElement) + { + return (genericParameterElement.MetadataType == MetadataType.MVar) + ? (genericInstanceMethod != null ? genericInstanceMethod.GenericArguments[genericParameterElement.Position] : genericParameterElement) + : genericInstanceType.GenericArguments[genericParameterElement.Position]; + } + + private static ArrayType ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, ArrayType arrayType) + { + return new ArrayType (ResolveIfNeeded (genericInstanceMethod, genericInstanceType, arrayType.ElementType), arrayType.Rank); + } + + private static ByReferenceType ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, ByReferenceType byReferenceType) + { + return new ByReferenceType (ResolveIfNeeded (genericInstanceMethod, genericInstanceType, byReferenceType.ElementType)); + } + + private static GenericInstanceType ResolveIfNeeded (IGenericInstance genericInstanceMethod, IGenericInstance genericInstanceType, GenericInstanceType genericInstanceType1) + { + if (!ContainsGenericParameters (genericInstanceType1)) + return genericInstanceType1; + + var newGenericInstance = new GenericInstanceType (genericInstanceType1.ElementType); + + foreach (var genericArgument in genericInstanceType1.GenericArguments) { + if (!genericArgument.IsGenericParameter) { + newGenericInstance.GenericArguments.Add (ResolveIfNeeded (genericInstanceMethod, genericInstanceType, genericArgument)); + continue; + } + + var genParam = (GenericParameter)genericArgument; + + switch (genParam.Type) { + case GenericParameterType.Type: { + if (genericInstanceType == null) + throw new NotSupportedException (); + + newGenericInstance.GenericArguments.Add (genericInstanceType.GenericArguments[genParam.Position]); + } + break; + + case GenericParameterType.Method: { + if (genericInstanceMethod == null) + newGenericInstance.GenericArguments.Add (genParam); + else + newGenericInstance.GenericArguments.Add (genericInstanceMethod.GenericArguments[genParam.Position]); + } + break; + } + } + + return newGenericInstance; + } + + private static bool ContainsGenericParameters (TypeReference typeReference) + { + var genericParameter = typeReference as GenericParameter; + if (genericParameter != null) + return true; + + var arrayType = typeReference as ArrayType; + if (arrayType != null) + return ContainsGenericParameters (arrayType.ElementType); + + var pointerType = typeReference as PointerType; + if (pointerType != null) + return ContainsGenericParameters (pointerType.ElementType); + + var byRefType = typeReference as ByReferenceType; + if (byRefType != null) + return ContainsGenericParameters (byRefType.ElementType); + + var sentinelType = typeReference as SentinelType; + if (sentinelType != null) + return ContainsGenericParameters (sentinelType.ElementType); + + var pinnedType = typeReference as PinnedType; + if (pinnedType != null) + return ContainsGenericParameters (pinnedType.ElementType); + + var requiredModifierType = typeReference as RequiredModifierType; + if (requiredModifierType != null) + return ContainsGenericParameters (requiredModifierType.ElementType); + + var genericInstance = typeReference as GenericInstanceType; + if (genericInstance != null) { + foreach (var genericArgument in genericInstance.GenericArguments) { + if (ContainsGenericParameters (genericArgument)) + return true; + } + + return false; + } + + if (typeReference is TypeSpecification) + throw new NotSupportedException (); + + return false; + } + } +} |