diff options
-rw-r--r-- | Mono.Cecil/AssemblyReader.cs | 4 | ||||
-rw-r--r-- | Mono.Cecil/AssemblyWriter.cs | 8 | ||||
-rw-r--r-- | Mono.Cecil/FieldDefinition.cs | 2 | ||||
-rw-r--r-- | Mono.Cecil/GenericParameterResolver.cs | 175 | ||||
-rw-r--r-- | Mono.Cecil/MemberReference.cs | 5 | ||||
-rw-r--r-- | Mono.Cecil/MethodDefinition.cs | 2 | ||||
-rw-r--r-- | Mono.Cecil/MethodReferenceComparer.cs | 143 | ||||
-rw-r--r-- | Mono.Cecil/Treatments.cs | 7 | ||||
-rw-r--r-- | Mono.Cecil/TypeComparisonMode.cs | 12 | ||||
-rw-r--r-- | Mono.Cecil/TypeReference.cs | 2 | ||||
-rw-r--r-- | Mono.Cecil/TypeReferenceEqualityComparer.cs | 253 | ||||
-rw-r--r-- | Mono.Cecil/TypeResolver.cs | 220 | ||||
-rw-r--r-- | Mono.Cecil/WindowsRuntimeProjections.cs | 248 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/LoadAssemblyDefinitionForTestsBaseSimple.cs | 16 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/MethodReferenceComparerTests.cs | 135 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/TypeDefinitionUtils.cs | 41 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/TypeReferenceComparisonTests.cs | 84 | ||||
-rw-r--r-- | Test/Mono.Cecil.Tests/WindowsRuntimeProjectionsTests.cs | 144 | ||||
-rw-r--r-- | Test/Resources/assemblies/NativeWinmd.winmd | bin | 3584 -> 4608 bytes |
19 files changed, 1401 insertions, 100 deletions
diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs index 3dae1e4..d18a51e 100644 --- a/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/AssemblyReader.cs @@ -2326,10 +2326,6 @@ namespace Mono.Cecil { } member.token = new MetadataToken (TokenType.MemberRef, rid); - - if (module.IsWindowsMetadata ()) - WindowsRuntimeProjections.Project (member); - return member; } diff --git a/Mono.Cecil/AssemblyWriter.cs b/Mono.Cecil/AssemblyWriter.cs index 3ea1088..4fba786 100644 --- a/Mono.Cecil/AssemblyWriter.cs +++ b/Mono.Cecil/AssemblyWriter.cs @@ -1277,6 +1277,8 @@ namespace Mono.Cecil { void AttachTypeToken (TypeDefinition type) { + var treatment = WindowsRuntimeProjections.RemoveProjection (type); + type.token = new MetadataToken (TokenType.TypeDef, type_rid++); type.fields_range.Start = field_rid; type.methods_range.Start = method_rid; @@ -1289,6 +1291,8 @@ namespace Mono.Cecil { if (type.HasNestedTypes) AttachNestedTypesToken (type); + + WindowsRuntimeProjections.ApplyProjection (type, treatment); } void AttachNestedTypesToken (TypeDefinition type) @@ -1990,16 +1994,12 @@ namespace Mono.Cecil { MetadataToken GetMemberRefToken (MemberReference member) { - var projection = WindowsRuntimeProjections.RemoveProjection (member); - var row = CreateMemberRefRow (member); MetadataToken token; if (!member_ref_map.TryGetValue (row, out token)) token = AddMemberReference (member, row); - WindowsRuntimeProjections.ApplyProjection (member, projection); - return token; } diff --git a/Mono.Cecil/FieldDefinition.cs b/Mono.Cecil/FieldDefinition.cs index 242e04e..15b7720 100644 --- a/Mono.Cecil/FieldDefinition.cs +++ b/Mono.Cecil/FieldDefinition.cs @@ -68,7 +68,7 @@ namespace Mono.Cecil { set { offset = value; } } - internal new FieldDefinitionProjection WindowsRuntimeProjection { + internal FieldDefinitionProjection WindowsRuntimeProjection { get { return (FieldDefinitionProjection) projection; } set { projection = value; } } 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; + } + } +} diff --git a/Mono.Cecil/MemberReference.cs b/Mono.Cecil/MemberReference.cs index 84fd38c..8276a66 100644 --- a/Mono.Cecil/MemberReference.cs +++ b/Mono.Cecil/MemberReference.cs @@ -48,11 +48,6 @@ namespace Mono.Cecil { get { return projection != null; } } - internal MemberReferenceProjection WindowsRuntimeProjection { - get { return (MemberReferenceProjection) projection; } - set { projection = value; } - } - internal bool HasImage { get { var module = Module; diff --git a/Mono.Cecil/MethodDefinition.cs b/Mono.Cecil/MethodDefinition.cs index 42bd8f3..b4b88d9 100644 --- a/Mono.Cecil/MethodDefinition.cs +++ b/Mono.Cecil/MethodDefinition.cs @@ -81,7 +81,7 @@ namespace Mono.Cecil { set { sem_attrs = value; } } - internal new MethodDefinitionProjection WindowsRuntimeProjection { + internal MethodDefinitionProjection WindowsRuntimeProjection { get { return (MethodDefinitionProjection) projection; } set { projection = value; } } diff --git a/Mono.Cecil/MethodReferenceComparer.cs b/Mono.Cecil/MethodReferenceComparer.cs new file mode 100644 index 0000000..3bf2c6e --- /dev/null +++ b/Mono.Cecil/MethodReferenceComparer.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; + +namespace Mono.Cecil { + internal sealed class MethodReferenceComparer : EqualityComparer<MethodReference> { + // Initialized lazily for each thread + [ThreadStatic] + static List<MethodReference> xComparisonStack = null; + + [ThreadStatic] + static List<MethodReference> yComparisonStack = null; + + public override bool Equals (MethodReference x, MethodReference y) + { + return AreEqual (x, y); + } + + public override int GetHashCode (MethodReference obj) + { + return GetHashCodeFor (obj); + } + + public static bool AreEqual (MethodReference x, MethodReference y) + { + if (ReferenceEquals (x, y)) + return true; + + if (x.HasThis != y.HasThis) + return false; + + if (x.HasParameters != y.HasParameters) + return false; + + if (x.HasGenericParameters != y.HasGenericParameters) + return false; + + if (x.Parameters.Count != y.Parameters.Count) + return false; + + if (x.Name != y.Name) + return false; + + if (!TypeReferenceEqualityComparer.AreEqual (x.DeclaringType, y.DeclaringType)) + return false; + + var xGeneric = x as GenericInstanceMethod; + var yGeneric = y as GenericInstanceMethod; + if (xGeneric != null || yGeneric != null) { + if (xGeneric == null || yGeneric == null) + return false; + + if (xGeneric.GenericArguments.Count != yGeneric.GenericArguments.Count) + return false; + + for (int i = 0; i < xGeneric.GenericArguments.Count; i++) + if (!TypeReferenceEqualityComparer.AreEqual (xGeneric.GenericArguments[i], yGeneric.GenericArguments[i])) + return false; + } + + var xResolved = x.Resolve (); + var yResolved = y.Resolve (); + + if (xResolved != yResolved) + return false; + + if (xResolved == null) + { + // We couldn't resolve either method. In order for them to be equal, their parameter types _must_ match. But wait, there's a twist! + // There exists a situation where we might get into a recursive state: parameter type comparison might lead to comparing the same + // methods again if the parameter types are generic parameters whose owners are these methods. We guard against these by using a + // thread static list of all our comparisons carried out in the stack so far, and if we're in progress of comparing them already, + // we'll just say that they match. + + if (xComparisonStack == null) + xComparisonStack = new List<MethodReference> (); + + if (yComparisonStack == null) + yComparisonStack = new List<MethodReference> (); + + for (int i = 0; i < xComparisonStack.Count; i++) { + if (xComparisonStack[i] == x && yComparisonStack[i] == y) + return true; + } + + xComparisonStack.Add (x); + + try { + yComparisonStack.Add (y); + + try { + for (int i = 0; i < x.Parameters.Count; i++) { + if (!TypeReferenceEqualityComparer.AreEqual (x.Parameters[i].ParameterType, y.Parameters[i].ParameterType)) + return false; + } + } finally { + yComparisonStack.RemoveAt (yComparisonStack.Count - 1); + } + } finally { + xComparisonStack.RemoveAt (xComparisonStack.Count - 1); + } + } + + return true; + } + + public static bool AreSignaturesEqual (MethodReference x, MethodReference y, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (x.HasThis != y.HasThis) + return false; + + if (x.Parameters.Count != y.Parameters.Count) + return false; + + if (x.GenericParameters.Count != y.GenericParameters.Count) + return false; + + for (var i = 0; i < x.Parameters.Count; i++) + if (!TypeReferenceEqualityComparer.AreEqual (x.Parameters[i].ParameterType, y.Parameters[i].ParameterType, comparisonMode)) + return false; + + if (!TypeReferenceEqualityComparer.AreEqual (x.ReturnType, y.ReturnType, comparisonMode)) + return false; + + return true; + } + + public static int GetHashCodeFor (MethodReference obj) + { + // a very good prime number + const int hashCodeMultiplier = 486187739; + + var genericInstanceMethod = obj as GenericInstanceMethod; + if (genericInstanceMethod != null) { + var hashCode = GetHashCodeFor (genericInstanceMethod.ElementMethod); + for (var i = 0; i < genericInstanceMethod.GenericArguments.Count; i++) + hashCode = hashCode * hashCodeMultiplier + TypeReferenceEqualityComparer.GetHashCodeFor (genericInstanceMethod.GenericArguments[i]); + return hashCode; + } + + return TypeReferenceEqualityComparer.GetHashCodeFor (obj.DeclaringType) * hashCodeMultiplier + obj.Name.GetHashCode (); + } + } +} diff --git a/Mono.Cecil/Treatments.cs b/Mono.Cecil/Treatments.cs index 4ceaebf..21c1768 100644 --- a/Mono.Cecil/Treatments.cs +++ b/Mono.Cecil/Treatments.cs @@ -23,6 +23,7 @@ namespace Mono.Cecil { PrefixWindowsRuntimeName = 0x4, RedirectToClrType = 0x5, RedirectToClrAttribute = 0x6, + RedirectImplementedMethods = 0x7, Abstract = 0x10, Internal = 0x20, @@ -38,7 +39,6 @@ namespace Mono.Cecil { [Flags] enum MethodDefinitionTreatment { None = 0x0, - Dispose = 0x1, Abstract = 0x2, Private = 0x4, Public = 0x8, @@ -51,11 +51,6 @@ namespace Mono.Cecil { Public = 0x1, } - enum MemberReferenceTreatment { - None = 0x0, - Dispose = 0x1, - } - enum CustomAttributeValueTreatment { None = 0x0, AllowSingle = 0x1, diff --git a/Mono.Cecil/TypeComparisonMode.cs b/Mono.Cecil/TypeComparisonMode.cs new file mode 100644 index 0000000..f69d98a --- /dev/null +++ b/Mono.Cecil/TypeComparisonMode.cs @@ -0,0 +1,12 @@ +namespace Mono.Cecil +{ + internal enum TypeComparisonMode { + Exact, + SignatureOnly, + + /// <summary> + /// Types can be in different assemblies, as long as the module, assembly, and type names match they will be considered equal + /// </summary> + SignatureOnlyLoose + } +} diff --git a/Mono.Cecil/TypeReference.cs b/Mono.Cecil/TypeReference.cs index e3fb5c5..701f83b 100644 --- a/Mono.Cecil/TypeReference.cs +++ b/Mono.Cecil/TypeReference.cs @@ -100,7 +100,7 @@ namespace Mono.Cecil { } } - internal new TypeReferenceProjection WindowsRuntimeProjection { + internal TypeReferenceProjection WindowsRuntimeProjection { get { return (TypeReferenceProjection) projection; } set { projection = value; } } diff --git a/Mono.Cecil/TypeReferenceEqualityComparer.cs b/Mono.Cecil/TypeReferenceEqualityComparer.cs new file mode 100644 index 0000000..29c2ee2 --- /dev/null +++ b/Mono.Cecil/TypeReferenceEqualityComparer.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; + +namespace Mono.Cecil { + internal sealed class TypeReferenceEqualityComparer : EqualityComparer<TypeReference> { + public override bool Equals (TypeReference x, TypeReference y) + { + return AreEqual (x, y); + } + + public override int GetHashCode (TypeReference obj) + { + return GetHashCodeFor (obj); + } + + public static bool AreEqual (TypeReference a, TypeReference b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (ReferenceEquals (a, b)) + return true; + + if (a == null || b == null) + return false; + + var aMetadataType = a.MetadataType; + var bMetadataType = b.MetadataType; + + if (aMetadataType == MetadataType.GenericInstance || bMetadataType == MetadataType.GenericInstance) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual ((GenericInstanceType)a, (GenericInstanceType)b, comparisonMode); + } + + if (aMetadataType == MetadataType.Array || bMetadataType == MetadataType.Array) { + if (aMetadataType != bMetadataType) + return false; + + var a1 = (ArrayType)a; + var b1 = (ArrayType)b; + if (a1.Rank != b1.Rank) + return false; + + return AreEqual (a1.ElementType, b1.ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Var || bMetadataType == MetadataType.Var) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual ((GenericParameter)a, (GenericParameter)b, comparisonMode); + } + + if (aMetadataType == MetadataType.MVar || bMetadataType == MetadataType.MVar) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual ((GenericParameter)a, (GenericParameter)b, comparisonMode); + } + + if (aMetadataType == MetadataType.ByReference || bMetadataType == MetadataType.ByReference) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((ByReferenceType)a).ElementType, ((ByReferenceType)b).ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Pointer || bMetadataType == MetadataType.Pointer) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((PointerType)a).ElementType, ((PointerType)b).ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.RequiredModifier || bMetadataType == MetadataType.RequiredModifier) { + if (aMetadataType != bMetadataType) + return false; + + var a1 = (RequiredModifierType)a; + var b1 = (RequiredModifierType)b; + + return AreEqual (a1.ModifierType, b1.ModifierType, comparisonMode) && AreEqual (a1.ElementType, b1.ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.OptionalModifier || bMetadataType == MetadataType.OptionalModifier) { + if (aMetadataType != bMetadataType) + return false; + + var a1 = (OptionalModifierType)a; + var b1 = (OptionalModifierType)b; + + return AreEqual (a1.ModifierType, b1.ModifierType, comparisonMode) && AreEqual (a1.ElementType, b1.ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Pinned || bMetadataType == MetadataType.Pinned) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((PinnedType)a).ElementType, ((PinnedType)b).ElementType, comparisonMode); + } + + if (aMetadataType == MetadataType.Sentinel || bMetadataType == MetadataType.Sentinel) { + if (aMetadataType != bMetadataType) + return false; + + return AreEqual (((SentinelType)a).ElementType, ((SentinelType)b).ElementType, comparisonMode); + } + + if (!a.Name.Equals (b.Name) || !a.Namespace.Equals (b.Namespace)) + return false; + + var xDefinition = a.Resolve (); + var yDefinition = b.Resolve (); + + // For loose signature the types could be in different assemblies, as long as the type names match we will consider them equal + if (comparisonMode == TypeComparisonMode.SignatureOnlyLoose) { + if (xDefinition.Module.Name != yDefinition.Module.Name) + return false; + + if (xDefinition.Module.Assembly.Name.Name != yDefinition.Module.Assembly.Name.Name) + return false; + + return xDefinition.FullName == yDefinition.FullName; + } + + return xDefinition == yDefinition; + } + + static bool AreEqual (GenericParameter a, GenericParameter b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (ReferenceEquals (a, b)) + return true; + + if (a.Position != b.Position) + return false; + + if (a.Type != b.Type) + return false; + + var aOwnerType = a.Owner as TypeReference; + if (aOwnerType != null && AreEqual (aOwnerType, b.Owner as TypeReference, comparisonMode)) + return true; + + var aOwnerMethod = a.Owner as MethodReference; + if (aOwnerMethod != null && comparisonMode != TypeComparisonMode.SignatureOnlyLoose && MethodReferenceComparer.AreEqual (aOwnerMethod, b.Owner as MethodReference)) + return true; + + return comparisonMode == TypeComparisonMode.SignatureOnly || comparisonMode == TypeComparisonMode.SignatureOnlyLoose; + } + + static bool AreEqual (GenericInstanceType a, GenericInstanceType b, TypeComparisonMode comparisonMode = TypeComparisonMode.Exact) + { + if (ReferenceEquals (a, b)) + return true; + + var aGenericArgumentsCount = a.GenericArguments.Count; + if (aGenericArgumentsCount != b.GenericArguments.Count) + return false; + + if (!AreEqual (a.ElementType, b.ElementType, comparisonMode)) + return false; + + for (int i = 0; i < aGenericArgumentsCount; i++) + if (!AreEqual (a.GenericArguments[i], b.GenericArguments[i], comparisonMode)) + return false; + + return true; + } + + public static int GetHashCodeFor (TypeReference obj) + { + // a very good prime number + const int hashCodeMultiplier = 486187739; + // prime numbers + const int genericInstanceTypeMultiplier = 31; + const int byReferenceMultiplier = 37; + const int pointerMultiplier = 41; + const int requiredModifierMultiplier = 43; + const int optionalModifierMultiplier = 47; + const int pinnedMultiplier = 53; + const int sentinelMultiplier = 59; + + var metadataType = obj.MetadataType; + + if (metadataType == MetadataType.GenericInstance) { + var genericInstanceType = (GenericInstanceType)obj; + var hashCode = GetHashCodeFor (genericInstanceType.ElementType) * hashCodeMultiplier + genericInstanceTypeMultiplier; + for (var i = 0; i < genericInstanceType.GenericArguments.Count; i++) + hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor (genericInstanceType.GenericArguments[i]); + return hashCode; + } + + if (metadataType == MetadataType.Array) { + var arrayType = (ArrayType)obj; + return GetHashCodeFor (arrayType.ElementType) * hashCodeMultiplier + arrayType.Rank.GetHashCode (); + } + + if (metadataType == MetadataType.Var || metadataType == MetadataType.MVar) { + var genericParameter = (GenericParameter)obj; + var hashCode = genericParameter.Position.GetHashCode () * hashCodeMultiplier + ((int)metadataType).GetHashCode (); + + var ownerTypeReference = genericParameter.Owner as TypeReference; + if (ownerTypeReference != null) + return hashCode * hashCodeMultiplier + GetHashCodeFor (ownerTypeReference); + + var ownerMethodReference = genericParameter.Owner as MethodReference; + if (ownerMethodReference != null) + return hashCode * hashCodeMultiplier + MethodReferenceComparer.GetHashCodeFor (ownerMethodReference); + + throw new InvalidOperationException ("Generic parameter encountered with invalid owner"); + } + + if (metadataType == MetadataType.ByReference) { + var byReferenceType = (ByReferenceType)obj; + return GetHashCodeFor (byReferenceType.ElementType) * hashCodeMultiplier * byReferenceMultiplier; + } + + if (metadataType == MetadataType.Pointer) { + var pointerType = (PointerType)obj; + return GetHashCodeFor (pointerType.ElementType) * hashCodeMultiplier * pointerMultiplier; + } + + if (metadataType == MetadataType.RequiredModifier) { + var requiredModifierType = (RequiredModifierType)obj; + var hashCode = GetHashCodeFor (requiredModifierType.ElementType) * requiredModifierMultiplier; + hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor (requiredModifierType.ModifierType); + return hashCode; + } + + if (metadataType == MetadataType.OptionalModifier) { + var optionalModifierType = (OptionalModifierType)obj; + var hashCode = GetHashCodeFor (optionalModifierType.ElementType) * optionalModifierMultiplier; + hashCode = hashCode * hashCodeMultiplier + GetHashCodeFor (optionalModifierType.ModifierType); + return hashCode; + } + + if (metadataType == MetadataType.Pinned) { + var pinnedType = (PinnedType)obj; + return GetHashCodeFor (pinnedType.ElementType) * hashCodeMultiplier * pinnedMultiplier; + } + + if (metadataType == MetadataType.Sentinel) { + var sentinelType = (SentinelType)obj; + return GetHashCodeFor (sentinelType.ElementType) * hashCodeMultiplier * sentinelMultiplier; + } + + if (metadataType == MetadataType.FunctionPointer) { + throw new NotImplementedException ("We currently don't handle function pointer types."); + } + + return obj.Namespace.GetHashCode () * hashCodeMultiplier + obj.FullName.GetHashCode (); + } + } +} diff --git a/Mono.Cecil/TypeResolver.cs b/Mono.Cecil/TypeResolver.cs new file mode 100644 index 0000000..95b0f3a --- /dev/null +++ b/Mono.Cecil/TypeResolver.cs @@ -0,0 +1,220 @@ +using Mono.Cecil.Cil; +using System; + +namespace Mono.Cecil { + internal sealed class TypeResolver { + private readonly IGenericInstance _typeDefinitionContext; + private readonly IGenericInstance _methodDefinitionContext; + + public static TypeResolver For (TypeReference typeReference) + { + return typeReference.IsGenericInstance ? new TypeResolver ((GenericInstanceType)typeReference) : new TypeResolver (); + } + + public static TypeResolver For (TypeReference typeReference, MethodReference methodReference) + { + return new TypeResolver (typeReference as GenericInstanceType, methodReference as GenericInstanceMethod); + } + + public TypeResolver () + { + + } + + public TypeResolver (GenericInstanceType typeDefinitionContext) + { + _typeDefinitionContext = typeDefinitionContext; + } + + public TypeResolver (GenericInstanceMethod methodDefinitionContext) + { + _methodDefinitionContext = methodDefinitionContext; + } + + public TypeResolver (GenericInstanceType typeDefinitionContext, GenericInstanceMethod methodDefinitionContext) + { + _typeDefinitionContext = typeDefinitionContext; + _methodDefinitionContext = methodDefinitionContext; + } + + public MethodReference Resolve (MethodReference method) + { + var methodReference = method; + if (IsDummy ()) + return methodReference; + + var declaringType = Resolve (method.DeclaringType); + + var genericInstanceMethod = method as GenericInstanceMethod; + if (genericInstanceMethod != null) { + methodReference = new MethodReference (method.Name, method.ReturnType, declaringType); + + foreach (var p in method.Parameters) + methodReference.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, p.ParameterType)); + + foreach (var gp in genericInstanceMethod.ElementMethod.GenericParameters) + methodReference.GenericParameters.Add (new GenericParameter (gp.Name, methodReference)); + + methodReference.HasThis = method.HasThis; + + var m = new GenericInstanceMethod (methodReference); + foreach (var ga in genericInstanceMethod.GenericArguments) { + m.GenericArguments.Add (Resolve (ga)); + } + + methodReference = m; + } else { + methodReference = new MethodReference (method.Name, method.ReturnType, declaringType); + + foreach (var gp in method.GenericParameters) + methodReference.GenericParameters.Add (new GenericParameter (gp.Name, methodReference)); + + foreach (var p in method.Parameters) + methodReference.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, p.ParameterType)); + + methodReference.HasThis = method.HasThis; + } + + + return methodReference; + } + + public FieldReference Resolve (FieldReference field) + { + var declaringType = Resolve (field.DeclaringType); + + if (declaringType == field.DeclaringType) + return field; + + return new FieldReference (field.Name, field.FieldType, declaringType); + } + + public TypeReference ResolveReturnType (MethodReference method) + { + return Resolve (GenericParameterResolver.ResolveReturnTypeIfNeeded (method)); + } + + public TypeReference ResolveParameterType (MethodReference method, ParameterReference parameter) + { + return Resolve (GenericParameterResolver.ResolveParameterTypeIfNeeded (method, parameter)); + } + + public TypeReference ResolveVariableType (MethodReference method, VariableReference variable) + { + return Resolve (GenericParameterResolver.ResolveVariableTypeIfNeeded (method, variable)); + } + + public TypeReference ResolveFieldType (FieldReference field) + { + return Resolve (GenericParameterResolver.ResolveFieldTypeIfNeeded (field)); + } + + public TypeReference Resolve (TypeReference typeReference) + { + return Resolve (typeReference, true); + } + + public TypeReference Resolve (TypeReference typeReference, bool includeTypeDefinitions) + { + if (IsDummy ()) + return typeReference; + + if (_typeDefinitionContext != null && _typeDefinitionContext.GenericArguments.Contains (typeReference)) + return typeReference; + if (_methodDefinitionContext != null && _methodDefinitionContext.GenericArguments.Contains (typeReference)) + return typeReference; + + var genericParameter = typeReference as GenericParameter; + if (genericParameter != null) { + if (_typeDefinitionContext != null && _typeDefinitionContext.GenericArguments.Contains (genericParameter)) + return genericParameter; + if (_methodDefinitionContext != null && _methodDefinitionContext.GenericArguments.Contains (genericParameter)) + return genericParameter; + return ResolveGenericParameter (genericParameter); + } + + var arrayType = typeReference as ArrayType; + if (arrayType != null) + return new ArrayType (Resolve (arrayType.ElementType), arrayType.Rank); + + var pointerType = typeReference as PointerType; + if (pointerType != null) + return new PointerType (Resolve (pointerType.ElementType)); + + var byReferenceType = typeReference as ByReferenceType; + if (byReferenceType != null) + return new ByReferenceType (Resolve (byReferenceType.ElementType)); + + var pinnedType = typeReference as PinnedType; + if (pinnedType != null) + return new PinnedType (Resolve (pinnedType.ElementType)); + + var genericInstanceType = typeReference as GenericInstanceType; + if (genericInstanceType != null) { + var newGenericInstanceType = new GenericInstanceType (genericInstanceType.ElementType); + foreach (var genericArgument in genericInstanceType.GenericArguments) + newGenericInstanceType.GenericArguments.Add (Resolve (genericArgument)); + return newGenericInstanceType; + } + + var requiredModType = typeReference as RequiredModifierType; + if (requiredModType != null) + return Resolve (requiredModType.ElementType, includeTypeDefinitions); + + + if (includeTypeDefinitions) { + var typeDefinition = typeReference as TypeDefinition; + if (typeDefinition != null && typeDefinition.HasGenericParameters) { + var newGenericInstanceType = new GenericInstanceType (typeDefinition); + foreach (var gp in typeDefinition.GenericParameters) + newGenericInstanceType.GenericArguments.Add (Resolve (gp)); + return newGenericInstanceType; + } + } + + if (typeReference is TypeSpecification) + throw new NotSupportedException (string.Format ("The type {0} cannot be resolved correctly.", typeReference.FullName)); + + return typeReference; + } + + internal TypeResolver Nested (GenericInstanceMethod genericInstanceMethod) + { + return new TypeResolver (_typeDefinitionContext as GenericInstanceType, genericInstanceMethod); + } + + private TypeReference ResolveGenericParameter (GenericParameter genericParameter) + { + if (genericParameter.Owner == null) + return HandleOwnerlessInvalidILCode (genericParameter); + + var memberReference = genericParameter.Owner as MemberReference; + if (memberReference == null) + throw new NotSupportedException (); + + return genericParameter.Type == GenericParameterType.Type + ? _typeDefinitionContext.GenericArguments[genericParameter.Position] + : (_methodDefinitionContext != null ? _methodDefinitionContext.GenericArguments[genericParameter.Position] : genericParameter); + } + + private TypeReference HandleOwnerlessInvalidILCode (GenericParameter genericParameter) + { + // NOTE: If owner is null and we have a method parameter, then we'll assume that the method parameter + // is actually a type parameter, and we'll use the type parameter from the corresponding position. I think + // this assumption is valid, but if you're visiting this code then I might have been proven wrong. + if (genericParameter.Type == GenericParameterType.Method && (_typeDefinitionContext != null && genericParameter.Position < _typeDefinitionContext.GenericArguments.Count)) + return _typeDefinitionContext.GenericArguments[genericParameter.Position]; + + // NOTE: Owner cannot be null, but sometimes the Mono compiler generates invalid IL and we + // end up in this situation. + // When we do, we assume that the runtime doesn't care about the resolved type of the GenericParameter, + // thus we return a reference to System.Object. + return genericParameter.Module.TypeSystem.Object; + } + + private bool IsDummy () + { + return _typeDefinitionContext == null && _methodDefinitionContext == null; + } + } +} diff --git a/Mono.Cecil/WindowsRuntimeProjections.cs b/Mono.Cecil/WindowsRuntimeProjections.cs index 5ecd53c..946116b 100644 --- a/Mono.Cecil/WindowsRuntimeProjections.cs +++ b/Mono.Cecil/WindowsRuntimeProjections.cs @@ -15,29 +15,21 @@ using Mono.Collections.Generic; namespace Mono.Cecil { - sealed class MemberReferenceProjection { - - public readonly string Name; - public readonly MemberReferenceTreatment Treatment; - - public MemberReferenceProjection (MemberReference member, MemberReferenceTreatment treatment) - { - Name = member.Name; - Treatment = treatment; - } - } - sealed class TypeDefinitionProjection { public readonly TypeAttributes Attributes; public readonly string Name; public readonly TypeDefinitionTreatment Treatment; + public readonly Collection<MethodDefinition> RedirectedMethods; + public readonly Collection<KeyValuePair<InterfaceImplementation, InterfaceImplementation>> RedirectedInterfaces; - public TypeDefinitionProjection (TypeDefinition type, TypeDefinitionTreatment treatment) + public TypeDefinitionProjection (TypeDefinition type, TypeDefinitionTreatment treatment, Collection<MethodDefinition> redirectedMethods, Collection<KeyValuePair<InterfaceImplementation, InterfaceImplementation>> redirectedInterfaces) { Attributes = type.Attributes; Name = type.Name; Treatment = treatment; + RedirectedMethods = redirectedMethods; + RedirectedInterfaces = redirectedInterfaces; } } @@ -106,16 +98,14 @@ namespace Mono.Cecil { public readonly string ClrName; public readonly string ClrAssembly; public readonly bool Attribute; - public readonly bool Disposable; - public ProjectionInfo (string winrt_namespace, string clr_namespace, string clr_name, string clr_assembly, bool attribute = false, bool disposable = false) + public ProjectionInfo (string winrt_namespace, string clr_namespace, string clr_name, string clr_assembly, bool attribute = false) { WinRTNamespace = winrt_namespace; ClrNamespace = clr_namespace; ClrName = clr_name; ClrAssembly = clr_assembly; Attribute = attribute; - Disposable = disposable; } } @@ -163,7 +153,7 @@ namespace Mono.Cecil { { "HResult", new ProjectionInfo ("Windows.Foundation", "System", "Exception", "System.Runtime") }, { "IBindableIterable", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections", "IEnumerable", "System.Runtime") }, { "IBindableVector", new ProjectionInfo ("Windows.UI.Xaml.Interop", "System.Collections", "IList", "System.Runtime") }, - { "IClosable", new ProjectionInfo ("Windows.Foundation", "System", "IDisposable", "System.Runtime", disposable: true) }, + { "IClosable", new ProjectionInfo ("Windows.Foundation", "System", "IDisposable", "System.Runtime") }, { "ICommand", new ProjectionInfo ("Windows.UI.Xaml.Input", "System.Windows.Input", "ICommand", "System.ObjectModel") }, { "IIterable`1", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "IEnumerable`1", "System.Runtime") }, { "IKeyValuePair`2", new ProjectionInfo ("Windows.Foundation.Collections", "System.Collections.Generic", "KeyValuePair`2", "System.Runtime") }, @@ -229,21 +219,24 @@ namespace Mono.Cecil { { var treatment = TypeDefinitionTreatment.None; var metadata_kind = type.Module.MetadataKind; + Collection<MethodDefinition> redirectedMethods = null; + Collection<KeyValuePair<InterfaceImplementation, InterfaceImplementation>> redirectedInterfaces = null; if (type.IsWindowsRuntime) { if (metadata_kind == MetadataKind.WindowsMetadata) { treatment = GetWellKnownTypeDefinitionTreatment (type); if (treatment != TypeDefinitionTreatment.None) { - ApplyProjection (type, new TypeDefinitionProjection (type, treatment)); + ApplyProjection (type, new TypeDefinitionProjection (type, treatment, redirectedMethods, redirectedInterfaces)); return; } var base_type = type.BaseType; - if (base_type != null && IsAttribute (base_type)) + if (base_type != null && IsAttribute (base_type)) { treatment = TypeDefinitionTreatment.NormalAttribute; - else - treatment = TypeDefinitionTreatment.NormalType; - } + } else { + treatment = GenerateRedirectionInformation (type, out redirectedMethods, out redirectedInterfaces); + } + } else if (metadata_kind == MetadataKind.ManagedWindowsMetadata && NeedsWindowsRuntimePrefix (type)) treatment = TypeDefinitionTreatment.PrefixWindowsRuntimeName; @@ -255,7 +248,7 @@ namespace Mono.Cecil { treatment = TypeDefinitionTreatment.UnmangleWindowsRuntimeName; if (treatment != TypeDefinitionTreatment.None) - ApplyProjection (type, new TypeDefinitionProjection (type, treatment)); + ApplyProjection (type, new TypeDefinitionProjection (type, treatment, redirectedMethods, redirectedInterfaces)); } static TypeDefinitionTreatment GetWellKnownTypeDefinitionTreatment (TypeDefinition type) @@ -275,6 +268,106 @@ namespace Mono.Cecil { return TypeDefinitionTreatment.None; } + private static TypeDefinitionTreatment GenerateRedirectionInformation (TypeDefinition type, out Collection<MethodDefinition> redirectedMethods, out Collection<KeyValuePair<InterfaceImplementation, InterfaceImplementation>> redirectedInterfaces) + { + bool implementsProjectedInterface = false; + redirectedMethods = null; + redirectedInterfaces = null; + + foreach (var implementedInterface in type.Interfaces) { + if (IsRedirectedType (implementedInterface.InterfaceType)) { + implementsProjectedInterface = true; + break; + } + } + + if (!implementsProjectedInterface) + return TypeDefinitionTreatment.NormalType; + + var allImplementedInterfaces = new HashSet<TypeReference> (new TypeReferenceEqualityComparer ()); + redirectedMethods = new Collection<MethodDefinition> (); + redirectedInterfaces = new Collection<KeyValuePair<InterfaceImplementation, InterfaceImplementation>> (); + + foreach (var @interface in type.Interfaces) { + var interfaceType = @interface.InterfaceType; + + if (IsRedirectedType (interfaceType)) { + allImplementedInterfaces.Add (interfaceType); + CollectImplementedInterfaces (interfaceType, allImplementedInterfaces); + } + } + + foreach (var implementedInterface in type.Interfaces) { + var interfaceType = implementedInterface.InterfaceType; + if (IsRedirectedType (implementedInterface.InterfaceType)) { + var etype = interfaceType.GetElementType (); + var unprojectedType = new TypeReference (etype.Namespace, etype.Name, etype.Module, etype.Scope) { + DeclaringType = etype.DeclaringType, + projection = etype.projection + }; + + RemoveProjection (unprojectedType); + + var genericInstanceType = interfaceType as GenericInstanceType; + if (genericInstanceType != null) { + var genericUnprojectedType = new GenericInstanceType (unprojectedType); + foreach (var genericArgument in genericInstanceType.GenericArguments) + genericUnprojectedType.GenericArguments.Add (genericArgument); + + unprojectedType = genericUnprojectedType; + } + + var unprojectedInterface = new InterfaceImplementation (unprojectedType); + redirectedInterfaces.Add (new KeyValuePair<InterfaceImplementation, InterfaceImplementation> (implementedInterface, unprojectedInterface)); + } + } + + // Interfaces don't inherit methods of the interfaces they implement + if (!type.IsInterface) { + foreach (var implementedInterface in allImplementedInterfaces) { + RedirectInterfaceMethods (implementedInterface, redirectedMethods); + } + } + + return TypeDefinitionTreatment.RedirectImplementedMethods; + } + + private static void CollectImplementedInterfaces (TypeReference type, HashSet<TypeReference> results) + { + var typeResolver = TypeResolver.For (type); + var typeDef = type.Resolve (); + + foreach (var implementedInterface in typeDef.Interfaces) { + var interfaceType = typeResolver.Resolve (implementedInterface.InterfaceType); + results.Add (interfaceType); + CollectImplementedInterfaces (interfaceType, results); + } + } + + private static void RedirectInterfaceMethods (TypeReference interfaceType, Collection<MethodDefinition> redirectedMethods) + { + var typeResolver = TypeResolver.For (interfaceType); + var typeDef = interfaceType.Resolve (); + + foreach (var method in typeDef.Methods) { + var redirectedMethod = new MethodDefinition (method.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot, typeResolver.Resolve (method.ReturnType)); + redirectedMethod.ImplAttributes = MethodImplAttributes.Runtime; + + foreach (var parameter in method.Parameters) { + redirectedMethod.Parameters.Add (new ParameterDefinition (parameter.Name, parameter.Attributes, typeResolver.Resolve (parameter.ParameterType))); + } + + redirectedMethod.Overrides.Add (typeResolver.Resolve (method)); + redirectedMethods.Add (redirectedMethod); + } + } + + private static bool IsRedirectedType (TypeReference type) + { + var typeRefProjection = type.GetElementType ().projection as TypeReferenceProjection; + return typeRefProjection != null && typeRefProjection.Treatment == TypeReferenceTreatment.UseProjectionInfo; + } + static bool NeedsWindowsRuntimePrefix (TypeDefinition type) { if ((type.Attributes & (TypeAttributes.VisibilityMask | TypeAttributes.Interface)) != TypeAttributes.Public) @@ -336,6 +429,32 @@ namespace Mono.Cecil { case TypeDefinitionTreatment.RedirectToClrAttribute: type.Attributes = type.Attributes & ~TypeAttributes.Public; break; + + case TypeDefinitionTreatment.RedirectImplementedMethods: { + type.Attributes |= TypeAttributes.WindowsRuntime | TypeAttributes.Import; + + foreach (var redirectedInterfacePair in projection.RedirectedInterfaces) { + type.Interfaces.Add (redirectedInterfacePair.Value); + + foreach (var customAttribute in redirectedInterfacePair.Key.CustomAttributes) + redirectedInterfacePair.Value.CustomAttributes.Add (customAttribute); + + redirectedInterfacePair.Key.CustomAttributes.Clear (); + + foreach (var method in type.Methods) { + foreach (var @override in method.Overrides) { + if (TypeReferenceEqualityComparer.AreEqual (@override.DeclaringType, redirectedInterfacePair.Key.InterfaceType)) { + @override.DeclaringType = redirectedInterfacePair.Value.InterfaceType; + } + } + } + } + + foreach (var method in projection.RedirectedMethods) { + type.Methods.Add (method); + } + } + break; } if ((treatment & TypeDefinitionTreatment.Abstract) != 0) @@ -358,6 +477,28 @@ namespace Mono.Cecil { type.Attributes = projection.Attributes; type.Name = projection.Name; + if (projection.Treatment == TypeDefinitionTreatment.RedirectImplementedMethods) { + foreach (var method in projection.RedirectedMethods) { + type.Methods.Remove (method); + } + + foreach (var redirectedInterfacePair in projection.RedirectedInterfaces) { + foreach (var method in type.Methods) { + foreach (var @override in method.Overrides) { + if (TypeReferenceEqualityComparer.AreEqual (@override.DeclaringType, redirectedInterfacePair.Value.InterfaceType)) { + @override.DeclaringType = redirectedInterfacePair.Key.InterfaceType; + } + } + } + + foreach (var customAttribute in redirectedInterfacePair.Value.CustomAttributes) + redirectedInterfacePair.Key.CustomAttributes.Add (customAttribute); + + redirectedInterfacePair.Value.CustomAttributes.Clear (); + type.Interfaces.Remove (redirectedInterfacePair.Value); + } + } + return projection; } @@ -482,27 +623,16 @@ namespace Mono.Cecil { { var seen_redirected = false; var seen_non_redirected = false; - var disposable = false; - foreach (var @override in method.Overrides) - { - if (@override.MetadataToken.TokenType == TokenType.MemberRef && ImplementsRedirectedInterface (@override, out disposable)) - { + foreach (var @override in method.Overrides) { + if (@override.MetadataToken.TokenType == TokenType.MemberRef && ImplementsRedirectedInterface (@override)) { seen_redirected = true; - if (disposable) - break; - } - else + } else { seen_non_redirected = true; + } } - if (disposable) - { - treatment = MethodDefinitionTreatment.Dispose; - other = false; - } - else if (seen_redirected && !seen_non_redirected) - { + if (seen_redirected && !seen_non_redirected) { treatment = MethodDefinitionTreatment.Runtime | MethodDefinitionTreatment.InternalCall | MethodDefinitionTreatment.Private; other = false; } @@ -540,9 +670,6 @@ namespace Mono.Cecil { var treatment = projection.Treatment; - if ((treatment & MethodDefinitionTreatment.Dispose) != 0) - method.Name = "Dispose"; - if ((treatment & MethodDefinitionTreatment.Abstract) != 0) method.Attributes |= MethodAttributes.Abstract; @@ -615,19 +742,8 @@ namespace Mono.Cecil { return projection; } - public static void Project (MemberReference member) + static bool ImplementsRedirectedInterface (MemberReference member) { - bool disposable; - if (!ImplementsRedirectedInterface (member, out disposable) || !disposable) - return; - - ApplyProjection (member, new MemberReferenceProjection (member, MemberReferenceTreatment.Dispose)); - } - - static bool ImplementsRedirectedInterface (MemberReference member, out bool disposable) - { - disposable = false; - var declaring_type = member.DeclaringType; TypeReference type; switch (declaring_type.MetadataToken.TokenType) { @@ -655,7 +771,6 @@ namespace Mono.Cecil { ProjectionInfo info; if (Projections.TryGetValue (type.Name, out info) && type.Namespace == info.WinRTNamespace) { - disposable = info.Disposable; found = true; } @@ -664,29 +779,6 @@ namespace Mono.Cecil { return found; } - public static void ApplyProjection (MemberReference member, MemberReferenceProjection projection) - { - if (projection == null) - return; - - if (projection.Treatment == MemberReferenceTreatment.Dispose) - member.Name = "Dispose"; - - member.WindowsRuntimeProjection = projection; - } - - public static MemberReferenceProjection RemoveProjection (MemberReference member) - { - if (!member.IsWindowsRuntimeProjection) - return null; - - var projection = member.WindowsRuntimeProjection; - member.WindowsRuntimeProjection = null; - - member.Name = projection.Name; - - return projection; - } public void AddVirtualReferences (Collection<AssemblyNameReference> references) { diff --git a/Test/Mono.Cecil.Tests/LoadAssemblyDefinitionForTestsBaseSimple.cs b/Test/Mono.Cecil.Tests/LoadAssemblyDefinitionForTestsBaseSimple.cs new file mode 100644 index 0000000..5c3b713 --- /dev/null +++ b/Test/Mono.Cecil.Tests/LoadAssemblyDefinitionForTestsBaseSimple.cs @@ -0,0 +1,16 @@ +using System.Reflection; + +namespace Mono.Cecil.Tests { + + public class LoadAssemblyDefinitionForTestsBaseSimple { + + protected AssemblyDefinition _assembly; + protected AssemblyDefinition _mscorlib; + + public void SetupAssemblyDefinitions (Assembly testAssembly) + { + _assembly = AssemblyDefinition.ReadAssembly (testAssembly.Location); + _mscorlib = _assembly.MainModule.TypeSystem.Object.Resolve ().Module.Assembly; + } + } +} diff --git a/Test/Mono.Cecil.Tests/MethodReferenceComparerTests.cs b/Test/Mono.Cecil.Tests/MethodReferenceComparerTests.cs new file mode 100644 index 0000000..92e5de3 --- /dev/null +++ b/Test/Mono.Cecil.Tests/MethodReferenceComparerTests.cs @@ -0,0 +1,135 @@ +using NUnit.Framework; +using System; +using System.Linq; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class MethodReferenceComparerTests : LoadAssemblyDefinitionForTestsBaseSimple { + + private TypeDefinition _class1; + private TypeDefinition _class2; + + [SetUp] + public void SetUp () + { + SetupAssemblyDefinitions (typeof (MethodReferenceComparerTests).Assembly); + _class1 = TypeDefinitionUtils.TypeDefinitionFor (typeof (Class1), _assembly); + _class2 = TypeDefinitionUtils.TypeDefinitionFor (typeof (Class2), _assembly); + } + + [Test] + public void MethodReferenceEqualsMethodDefinition () + { + var typeDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib); + var method = typeDefinition.Methods.Single (m => m.Name == "GetHashCode"); + var methodReference = new MethodReference (method.Name, method.ReturnType, method.DeclaringType); + methodReference.HasThis = method.HasThis; + + Assert.That (MethodReferenceComparer.AreEqual (method, methodReference), Is.True); + } + + [Test] + public void VerifyMethodSignatureMatches () + { + Assert.IsTrue (CompareSignatures ("MethodWithNoParametersOrReturn")); + Assert.IsTrue (CompareSignatures ("GenericMethodWithNoParametersOrReturn")); + Assert.IsFalse (CompareSignatures ("MethodWithNoParametersOrReturn", "GenericMethodWithNoParametersOrReturn")); + + Assert.IsTrue (CompareSignatures ("MethodWithIntParameterAndVoidReturn")); + } + + [Test] + public void VerifySignatureComparisonConsidersStatic () + { + Assert.IsTrue (CompareSignatures ("StaticMethodWithNoParametersOrReturn")); + Assert.IsTrue (CompareSignatures ("StaticMethodWithNoParametersOrReturn")); + Assert.IsFalse (CompareSignatures ("MethodWithNoParametersOrReturn", "StaticMethodWithNoParametersOrReturn")); + Assert.IsFalse (CompareSignatures ("GenericMethodWithNoParametersOrReturn", "GenericStaticMethodWithNoParametersOrReturn")); + } + + [Test] + public void VerifyMethodSignatureWithGenericParameters () + { + Assert.IsTrue (CompareSignatures ("GenericMethodWithGenericParameter")); + Assert.IsTrue (CompareSignatures ("GenericMethodWithGenericParameterArray")); + Assert.IsTrue (CompareSignatures ("GenericMethodWithByReferenceGenericParameter")); + Assert.IsTrue (CompareSignatures ("GenericMethodWithGenericInstanceGenericParameter")); + } + + [Test] + public void VerifyNonResolvableMethodReferencesWithDifferentParameterTypesAreNotEqual () + { + var method1 = new MethodReference ("TestMethod", _class1.Module.TypeSystem.Void, _class1); + method1.Parameters.Add (new ParameterDefinition (new ByReferenceType (_class1.Module.TypeSystem.Int16))); + + var method2 = new MethodReference ("TestMethod", _class1.Module.TypeSystem.Void, _class1); + method2.Parameters.Add (new ParameterDefinition (new ByReferenceType (_class1.Module.TypeSystem.Char))); + + Assert.IsFalse (MethodReferenceComparer.AreEqual (method1, method2)); + } + + [Test] + public void VerifyNonResolvableRecursiveMethodsDontStackOverflow () + { + var method1 = new MethodReference ("TestMethod", _class1.Module.TypeSystem.Void, _class1); + method1.GenericParameters.Add (new GenericParameter (method1)); + method1.Parameters.Add (new ParameterDefinition (method1.GenericParameters[0])); + + var method2 = new MethodReference ("TestMethod", _class1.Module.TypeSystem.Void, _class1); + method2.GenericParameters.Add (new GenericParameter (method2)); + method2.Parameters.Add (new ParameterDefinition (method2.GenericParameters[0])); + + Assert.IsTrue (MethodReferenceComparer.AreEqual (method1, method2)); + } + + bool CompareSignatures (string name) + { + return CompareSignatures (name, name); + } + + bool CompareSignatures (string name1, string name2) + { + return MethodReferenceComparer.AreSignaturesEqual (GetMethod (_class1, name1), GetMethod (_class2, name2), TypeComparisonMode.SignatureOnly); + } + + static MethodDefinition GetMethod (TypeDefinition type, string name) + { + return type.Methods.Single (m => m.Name == name); + } + + class GenericClass<T> { + + } + + class Class1 { + + void MethodWithNoParametersOrReturn () {} + void GenericMethodWithNoParametersOrReturn<T> () {} + static void StaticMethodWithNoParametersOrReturn () {} + static void GenericStaticMethodWithNoParametersOrReturn<T> () {} + + void MethodWithIntParameterAndVoidReturn (int a) {} + + void GenericMethodWithGenericParameter<T> (T t) {} + void GenericMethodWithGenericParameterArray<T> (T[] t) {} + void GenericMethodWithByReferenceGenericParameter<T> (ref T a) {} + void GenericMethodWithGenericInstanceGenericParameter<T> (GenericClass<T> a) {} + } + + class Class2 { + + void MethodWithNoParametersOrReturn () {} + void GenericMethodWithNoParametersOrReturn<T> () {} + static void StaticMethodWithNoParametersOrReturn () {} + static void GenericStaticMethodWithNoParametersOrReturn<T> () {} + + void MethodWithIntParameterAndVoidReturn (int a) {} + + void GenericMethodWithGenericParameter<T> (T t) {} + void GenericMethodWithGenericParameterArray<T> (T[] t) {} + void GenericMethodWithByReferenceGenericParameter<T> (ref T a) {} + void GenericMethodWithGenericInstanceGenericParameter<T> (GenericClass<T> a) {} + } + } +} diff --git a/Test/Mono.Cecil.Tests/TypeDefinitionUtils.cs b/Test/Mono.Cecil.Tests/TypeDefinitionUtils.cs new file mode 100644 index 0000000..7324584 --- /dev/null +++ b/Test/Mono.Cecil.Tests/TypeDefinitionUtils.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Mono.Cecil { + + public static class TypeDefinitionUtils { + + public static TypeReference TypeDefinitionForGeneric ( + Type genericType, AssemblyDefinition genericAssemblyDefinition, + Type paramterType, AssemblyDefinition parameterAssemblyDefinition) + { + var paramDefinition = TypeDefinitionUtils.TypeDefinitionFor (paramterType, parameterAssemblyDefinition); + var genericDefinition = TypeDefinitionUtils.TypeDefinitionFor (genericType, genericAssemblyDefinition); + var genericInstance = new GenericInstanceType (genericDefinition); + genericInstance.GenericArguments.Add (paramDefinition); + return genericInstance; + } + + public static TypeDefinition TypeDefinitionFor (Type type, AssemblyDefinition assemblyDefinition) + { + var stack = new Stack<string> (); + var currentType = type; + while (currentType != null) { + stack.Push ( (currentType.DeclaringType == null ? currentType.Namespace + "." : "") + currentType.Name); + currentType = currentType.DeclaringType; + } + + var typeDefinition = assemblyDefinition.MainModule.GetType (stack.Pop ()); + if (typeDefinition == null) + return null; + + while (stack.Count > 0) { + var name = stack.Pop (); + typeDefinition = typeDefinition.NestedTypes.Single (t => t.Name == name); + } + + return typeDefinition; + } + } +} diff --git a/Test/Mono.Cecil.Tests/TypeReferenceComparisonTests.cs b/Test/Mono.Cecil.Tests/TypeReferenceComparisonTests.cs new file mode 100644 index 0000000..d8332eb --- /dev/null +++ b/Test/Mono.Cecil.Tests/TypeReferenceComparisonTests.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using Mono.Cecil; +using NUnit.Framework; + +namespace Mono.Cecil.Tests { + + [TestFixture] + public class TypeReferenceComparisonTests : LoadAssemblyDefinitionForTestsBaseSimple { + + [SetUp] + public void SetUp () + { + SetupAssemblyDefinitions (typeof (TypeReferenceComparisonTests).Assembly); + } + + [Test] + public void TypeReferenceEqualsTypeDefinition () + { + var typeDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib); + var typeReference = new TypeReference (typeDefinition.Namespace, typeDefinition.Name, typeDefinition.Module, typeDefinition.Scope); + + Assert.That (TypeReferenceEqualityComparer.AreEqual (typeDefinition, typeReference), Is.True); + } + + [Test] + public void GenericParametersFromTwoTypesAreNotEqual () + { + var listDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (List<>), _mscorlib); + var stackDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (Comparer<>), _mscorlib); + + Assert.That (TypeReferenceEqualityComparer.AreEqual (listDefinition.GenericParameters[0], stackDefinition.GenericParameters[0]), Is.False); + } + + [Test] + public void ArrayTypesDoNotMatchIfRankIsDifferent () + { + var elementType = TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib); + + Assert.That (TypeReferenceEqualityComparer.AreEqual (new ArrayType (elementType, 1), new ArrayType (elementType, 2)), Is.False, "Two array types with different ranks match, which is not expected."); + } + + [Test] + public void ArrayTypesDoNotMatchIfElementTypeIsDifferent () + { + Assert.That (TypeReferenceEqualityComparer.AreEqual (new ArrayType (TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib), 1), new ArrayType (TypeDefinitionUtils.TypeDefinitionFor (typeof (Int64), _mscorlib), 1)), Is.False, "Two array types with different element types match, which is not expected."); + } + + [Test] + public void ArrayTypesWithDifferentRanksToNotMatch () + { + var elementType = TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib); + + Assert.That (TypeReferenceEqualityComparer.AreEqual ( (TypeSpecification) new ArrayType (elementType, 1), (TypeSpecification) new ArrayType (elementType, 2)), Is.False, "Two type specifications that are array types with different ranks match, which is not expected."); + } + + [Test] + public void GenericInstanceTypeFromTwoTypesAreNotEqual () + { + var int32Definition = TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib); + var listDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (List<>), _mscorlib); + var listGenericInstance = new GenericInstanceType (listDefinition); + listGenericInstance.GenericArguments.Add (int32Definition); + var stackDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (Comparer<>), _mscorlib); + var stackGenericInstance = new GenericInstanceType (stackDefinition); + stackGenericInstance.GenericArguments.Add (int32Definition); + + Assert.That (TypeReferenceEqualityComparer.AreEqual (listGenericInstance, stackGenericInstance), Is.False); + } + + [Test] + public void GenericInstanceTypeForSameTypeIsEqual () + { + var int32Definition = TypeDefinitionUtils.TypeDefinitionFor (typeof (Int32), _mscorlib); + var listDefinition = TypeDefinitionUtils.TypeDefinitionFor (typeof (List<>), _mscorlib); + var listGenericInstance = new GenericInstanceType (listDefinition); + listGenericInstance.GenericArguments.Add (int32Definition); + var listGenericInstance2 = new GenericInstanceType (listDefinition); + listGenericInstance2.GenericArguments.Add (int32Definition); + + Assert.That (TypeReferenceEqualityComparer.AreEqual (listGenericInstance, listGenericInstance2), Is.True); + } + } +} diff --git a/Test/Mono.Cecil.Tests/WindowsRuntimeProjectionsTests.cs b/Test/Mono.Cecil.Tests/WindowsRuntimeProjectionsTests.cs index 9b10fd5..bac85cf 100644 --- a/Test/Mono.Cecil.Tests/WindowsRuntimeProjectionsTests.cs +++ b/Test/Mono.Cecil.Tests/WindowsRuntimeProjectionsTests.cs @@ -8,8 +8,10 @@ using System.Linq; using System.Text; namespace Mono.Cecil.Tests { + [TestFixture] public abstract class BaseWindowsRuntimeProjectionsTests : BaseTestFixture { + protected abstract string ModuleName { get; } protected abstract MetadataKind ExpectedMetadataKind { get; } protected abstract string [] ManagedClassTypeNames { get; } @@ -96,6 +98,7 @@ namespace Mono.Cecil.Tests { [TestFixture] public class ManagedWindowsRuntimeProjectionsTests : BaseWindowsRuntimeProjectionsTests { + protected override string ModuleName { get { return "ManagedWinmd.winmd"; } } protected override MetadataKind ExpectedMetadataKind { get { return MetadataKind.ManagedWindowsMetadata; } } @@ -132,6 +135,7 @@ namespace Mono.Cecil.Tests { [TestFixture] public class NativeWindowsRuntimeProjectionsTests : BaseWindowsRuntimeProjectionsTests { + protected override string ModuleName { get { return "NativeWinmd.winmd"; } } protected override MetadataKind ExpectedMetadataKind { get { return MetadataKind.WindowsMetadata; } } @@ -139,6 +143,146 @@ namespace Mono.Cecil.Tests { protected override string [] ManagedClassTypeNames { get { return new [] { "ManagedClass" }; } } protected override string [] CustomListTypeNames { get { return new [] { "CustomList" }; } } + + [Test] + public void CanProjectAndRedirectInterfaces () + { + if (Platform.OnMono) + return; + + TestModule (ModuleName, (module) => { + var customListClass = module.Types.Single (t => t.Name == "CustomList"); + Assert.AreEqual (5, customListClass.Interfaces.Count); + + Assert.AreEqual (1, customListClass.Interfaces[0].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Metadata.DefaultAttribute", customListClass.Interfaces[0].CustomAttributes[0].AttributeType.FullName); + Assert.AreEqual ("NativeWinmd.__ICustomListPublicNonVirtuals", customListClass.Interfaces[0].InterfaceType.FullName); + + Assert.AreEqual (0, customListClass.Interfaces[1].CustomAttributes.Count); + Assert.AreEqual ("System.Collections.Generic.IList`1<System.Int32>", customListClass.Interfaces[1].InterfaceType.FullName); + + Assert.AreEqual (0, customListClass.Interfaces[2].CustomAttributes.Count); + Assert.AreEqual ("System.Collections.Generic.IEnumerable`1<System.Int32>", customListClass.Interfaces[2].InterfaceType.FullName); + + Assert.AreEqual (0, customListClass.Interfaces[3].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Collections.IVector`1<System.Int32>", customListClass.Interfaces[3].InterfaceType.FullName); + + Assert.AreEqual (0, customListClass.Interfaces[4].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Collections.IIterable`1<System.Int32>", customListClass.Interfaces[4].InterfaceType.FullName); + + var customPropertySetClass = module.Types.Single (t => t.Name == "CustomPropertySet"); + Assert.AreEqual (7, customPropertySetClass.Interfaces.Count); + + Assert.AreEqual (0, customPropertySetClass.Interfaces[0].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Collections.IPropertySet", customPropertySetClass.Interfaces[0].InterfaceType.FullName); + + Assert.AreEqual (1, customPropertySetClass.Interfaces[1].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Metadata.DefaultAttribute", customPropertySetClass.Interfaces[1].CustomAttributes[0].AttributeType.FullName); + Assert.AreEqual ("NativeWinmd.__ICustomPropertySetPublicNonVirtuals", customPropertySetClass.Interfaces[1].InterfaceType.FullName); + + Assert.AreEqual (0, customPropertySetClass.Interfaces[2].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Collections.IObservableMap`2<System.String,System.Object>", customPropertySetClass.Interfaces[2].InterfaceType.FullName); + + Assert.AreEqual (0, customPropertySetClass.Interfaces[3].CustomAttributes.Count); + Assert.AreEqual ("System.Collections.Generic.IDictionary`2<System.String,System.Object>", customPropertySetClass.Interfaces[3].InterfaceType.FullName); + + Assert.AreEqual (0, customPropertySetClass.Interfaces[4].CustomAttributes.Count); + Assert.AreEqual ("System.Collections.Generic.IEnumerable`1<System.Collections.Generic.KeyValuePair`2<System.String,System.Object>>", customPropertySetClass.Interfaces[4].InterfaceType.FullName); + + Assert.AreEqual (0, customPropertySetClass.Interfaces[5].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Collections.IMap`2<System.String,System.Object>", customPropertySetClass.Interfaces[5].InterfaceType.FullName); + + Assert.AreEqual (0, customPropertySetClass.Interfaces[6].CustomAttributes.Count); + Assert.AreEqual ("Windows.Foundation.Collections.IIterable`1<System.Collections.Generic.KeyValuePair`2<System.String,System.Object>>", customPropertySetClass.Interfaces[6].InterfaceType.FullName); + + }, verify: false, assemblyResolver: WindowsRuntimeAssemblyResolver.CreateInstance (), applyWindowsRuntimeProjections: true); + } + + [Test] + public void CanProjectInterfaceMethods () + { + if (Platform.OnMono) + return; + + TestModule (ModuleName, (module) => { + var customListClass = module.Types.Single (t => t.Name == "CustomList"); + Assert.AreEqual (28, customListClass.Methods.Count); + Assert.AreEqual (TypeDefinitionTreatment.RedirectImplementedMethods, customListClass.WindowsRuntimeProjection.Treatment); + + // Verify that projections add implementations for all projected interfaces methods + Assert.AreEqual (customListClass.Methods[0].FullName, "System.Void NativeWinmd.CustomList::.ctor()"); + Assert.AreEqual (customListClass.Methods[1].FullName, "Windows.Foundation.Collections.IIterator`1<System.Int32> NativeWinmd.CustomList::First()"); + Assert.AreEqual (customListClass.Methods[2].FullName, "System.UInt32 NativeWinmd.CustomList::get_Size()"); + Assert.AreEqual (customListClass.Methods[3].FullName, "System.Int32 NativeWinmd.CustomList::GetAt(System.UInt32)"); + Assert.AreEqual (customListClass.Methods[4].FullName, "System.Collections.Generic.IReadOnlyList`1<System.Int32> NativeWinmd.CustomList::GetView()"); + Assert.AreEqual (customListClass.Methods[5].FullName, "System.Boolean NativeWinmd.CustomList::IndexOf(System.Int32,System.UInt32&)"); + Assert.AreEqual (customListClass.Methods[6].FullName, "System.Void NativeWinmd.CustomList::SetAt(System.UInt32,System.Int32)"); + Assert.AreEqual (customListClass.Methods[7].FullName, "System.Void NativeWinmd.CustomList::InsertAt(System.UInt32,System.Int32)"); + Assert.AreEqual (customListClass.Methods[8].FullName, "System.Void NativeWinmd.CustomList::RemoveAt(System.UInt32)"); + Assert.AreEqual (customListClass.Methods[9].FullName, "System.Void NativeWinmd.CustomList::Append(System.Int32)"); + Assert.AreEqual (customListClass.Methods[10].FullName, "System.Void NativeWinmd.CustomList::RemoveAtEnd()"); + Assert.AreEqual (customListClass.Methods[11].FullName, "System.Void NativeWinmd.CustomList::Clear()"); + Assert.AreEqual (customListClass.Methods[12].FullName, "System.UInt32 NativeWinmd.CustomList::GetMany(System.UInt32,System.Int32[])"); + Assert.AreEqual (customListClass.Methods[13].FullName, "System.Void NativeWinmd.CustomList::ReplaceAll(System.Int32[])"); + Assert.AreEqual (customListClass.Methods[14].FullName, "System.Int32 NativeWinmd.CustomList::get_Item(System.Int32)"); + Assert.AreEqual (customListClass.Methods[15].FullName, "System.Void NativeWinmd.CustomList::set_Item(System.Int32,System.Int32)"); + Assert.AreEqual (customListClass.Methods[16].FullName, "System.Int32 NativeWinmd.CustomList::IndexOf(System.Int32)"); + Assert.AreEqual (customListClass.Methods[17].FullName, "System.Void NativeWinmd.CustomList::Insert(System.Int32,System.Int32)"); + Assert.AreEqual (customListClass.Methods[18].FullName, "System.Void NativeWinmd.CustomList::RemoveAt(System.Int32)"); + Assert.AreEqual (customListClass.Methods[19].FullName, "System.Int32 NativeWinmd.CustomList::get_Count()"); + Assert.AreEqual (customListClass.Methods[20].FullName, "System.Boolean NativeWinmd.CustomList::get_IsReadOnly()"); + Assert.AreEqual (customListClass.Methods[21].FullName, "System.Void NativeWinmd.CustomList::Add(System.Int32)"); + Assert.AreEqual (customListClass.Methods[22].FullName, "System.Void NativeWinmd.CustomList::Clear()"); + Assert.AreEqual (customListClass.Methods[23].FullName, "System.Boolean NativeWinmd.CustomList::Contains(System.Int32)"); + Assert.AreEqual (customListClass.Methods[24].FullName, "System.Void NativeWinmd.CustomList::CopyTo(System.Int32[],System.Int32)"); + Assert.AreEqual (customListClass.Methods[25].FullName, "System.Boolean NativeWinmd.CustomList::Remove(System.Int32)"); + Assert.AreEqual (customListClass.Methods[26].FullName, "System.Collections.Generic.IEnumerator`1<System.Int32> NativeWinmd.CustomList::GetEnumerator()"); + Assert.AreEqual (customListClass.Methods[27].FullName, "System.Collections.IEnumerator NativeWinmd.CustomList::GetEnumerator()"); + }, verify: false, assemblyResolver: WindowsRuntimeAssemblyResolver.CreateInstance (), applyWindowsRuntimeProjections: true); + } + + [Test] + public void CanProjectMethodOverrides () + { + if (Platform.OnMono) + return; + + TestModule (ModuleName, (module) => { + var customListClass = module.Types.Single (t => t.Name == "CustomList"); + + for (int i = 1; i < customListClass.Methods.Count; i++) + Assert.AreEqual (1, customListClass.Methods[i].Overrides.Count); + + Assert.AreEqual (customListClass.Methods[1].Overrides[0].FullName, "Windows.Foundation.Collections.IIterator`1<!0> Windows.Foundation.Collections.IIterable`1<System.Int32>::First()"); + Assert.AreEqual (customListClass.Methods[2].Overrides[0].FullName, "System.UInt32 Windows.Foundation.Collections.IVector`1<System.Int32>::get_Size()"); + Assert.AreEqual (customListClass.Methods[3].Overrides[0].FullName, "!0 Windows.Foundation.Collections.IVector`1<System.Int32>::GetAt(System.UInt32)"); + Assert.AreEqual (customListClass.Methods[4].Overrides[0].FullName, "System.Collections.Generic.IReadOnlyList`1<!0> Windows.Foundation.Collections.IVector`1<System.Int32>::GetView()"); + Assert.AreEqual (customListClass.Methods[5].Overrides[0].FullName, "System.Boolean Windows.Foundation.Collections.IVector`1<System.Int32>::IndexOf(!0,System.UInt32&)"); + Assert.AreEqual (customListClass.Methods[6].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::SetAt(System.UInt32,!0)"); + Assert.AreEqual (customListClass.Methods[7].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::InsertAt(System.UInt32,!0)"); + Assert.AreEqual (customListClass.Methods[8].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::RemoveAt(System.UInt32)"); + Assert.AreEqual (customListClass.Methods[9].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::Append(!0)"); + Assert.AreEqual (customListClass.Methods[10].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::RemoveAtEnd()"); + Assert.AreEqual (customListClass.Methods[11].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::Clear()"); + Assert.AreEqual (customListClass.Methods[12].Overrides[0].FullName, "System.UInt32 Windows.Foundation.Collections.IVector`1<System.Int32>::GetMany(System.UInt32,!0[])"); + Assert.AreEqual (customListClass.Methods[13].Overrides[0].FullName, "System.Void Windows.Foundation.Collections.IVector`1<System.Int32>::ReplaceAll(!0[])"); + Assert.AreEqual (customListClass.Methods[14].Overrides[0].FullName, "T System.Collections.Generic.IList`1<System.Int32>::get_Item(System.Int32)"); + Assert.AreEqual (customListClass.Methods[15].Overrides[0].FullName, "System.Void System.Collections.Generic.IList`1<System.Int32>::set_Item(System.Int32,T)"); + Assert.AreEqual (customListClass.Methods[16].Overrides[0].FullName, "System.Int32 System.Collections.Generic.IList`1<System.Int32>::IndexOf(T)"); + Assert.AreEqual (customListClass.Methods[17].Overrides[0].FullName, "System.Void System.Collections.Generic.IList`1<System.Int32>::Insert(System.Int32,T)"); + Assert.AreEqual (customListClass.Methods[18].Overrides[0].FullName, "System.Void System.Collections.Generic.IList`1<System.Int32>::RemoveAt(System.Int32)"); + Assert.AreEqual (customListClass.Methods[19].Overrides[0].FullName, "System.Int32 System.Collections.Generic.ICollection`1<System.Int32>::get_Count()"); + Assert.AreEqual (customListClass.Methods[20].Overrides[0].FullName, "System.Boolean System.Collections.Generic.ICollection`1<System.Int32>::get_IsReadOnly()"); + Assert.AreEqual (customListClass.Methods[21].Overrides[0].FullName, "System.Void System.Collections.Generic.ICollection`1<System.Int32>::Add(T)"); + Assert.AreEqual (customListClass.Methods[22].Overrides[0].FullName, "System.Void System.Collections.Generic.ICollection`1<System.Int32>::Clear()"); + Assert.AreEqual (customListClass.Methods[23].Overrides[0].FullName, "System.Boolean System.Collections.Generic.ICollection`1<System.Int32>::Contains(T)"); + Assert.AreEqual (customListClass.Methods[24].Overrides[0].FullName, "System.Void System.Collections.Generic.ICollection`1<System.Int32>::CopyTo(T[],System.Int32)"); + Assert.AreEqual (customListClass.Methods[25].Overrides[0].FullName, "System.Boolean System.Collections.Generic.ICollection`1<System.Int32>::Remove(T)"); + Assert.AreEqual (customListClass.Methods[26].Overrides[0].FullName, "System.Collections.Generic.IEnumerator`1<T> System.Collections.Generic.IEnumerable`1<System.Int32>::GetEnumerator()"); + Assert.AreEqual (customListClass.Methods[27].Overrides[0].FullName, "System.Collections.IEnumerator System.Collections.IEnumerable::GetEnumerator()"); + + }, verify: false, assemblyResolver: WindowsRuntimeAssemblyResolver.CreateInstance (), applyWindowsRuntimeProjections: true); + } } } #endif diff --git a/Test/Resources/assemblies/NativeWinmd.winmd b/Test/Resources/assemblies/NativeWinmd.winmd Binary files differindex 53fedff..b6417cf 100644 --- a/Test/Resources/assemblies/NativeWinmd.winmd +++ b/Test/Resources/assemblies/NativeWinmd.winmd |