Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/cecil.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTautvydas Žilys <tautvydas.zilys@gmail.com>2020-09-16 01:48:36 +0300
committerGitHub <noreply@github.com>2020-09-16 01:48:36 +0300
commit1e3bbed3ef66b79be7818f6c6ecf2ac639ffeb19 (patch)
treefaa9bd53158a19546066706747c9f3c739251b24
parente94d04f9196e3bdec9226bcfb89571249f62b6f3 (diff)
Unity's Windows Runtime changes (#394)
* Implemented Windows Runtime projections for implemented interface overrides. * Don't redirect Windows Runtime projected methods on interfaces. * Add additional test cases for Windows Runtime interface projection. * Fix reading interface impl attributes when using immediate reading mode. * Do not project for windows runtime during read. A type will not be fully initialized during read, so don't attempt to project for Windows runtime until after all of the metadata reading is correct. If a type reading for a module is no completed, a call to BinaryRangeSearch in MetadataSystem can fail, because some of the entries in the types array will still be null. * Fix build warnings. * Remove method that got duplicated during a cherry pick. * Fixed an issue with MethodReferenceComparer where it would incorrectly identify two method references to be the same if they had the same declaring types, the same parameter counts and were both unresolvable. * Sync up latest changes to MethodReferenceComparer and TypeReferenceEquality comparer and also add tests for them. * Fix code formatting. * Remove extra char * Style fix Co-authored-by: Ignas Ziberkas <ignas@unity3d.com> Co-authored-by: Josh Peterson <petersonjm1@gmail.com> Co-authored-by: Jb Evain <jb@evain.net>
-rw-r--r--Mono.Cecil/AssemblyReader.cs4
-rw-r--r--Mono.Cecil/AssemblyWriter.cs8
-rw-r--r--Mono.Cecil/FieldDefinition.cs2
-rw-r--r--Mono.Cecil/GenericParameterResolver.cs175
-rw-r--r--Mono.Cecil/MemberReference.cs5
-rw-r--r--Mono.Cecil/MethodDefinition.cs2
-rw-r--r--Mono.Cecil/MethodReferenceComparer.cs143
-rw-r--r--Mono.Cecil/Treatments.cs7
-rw-r--r--Mono.Cecil/TypeComparisonMode.cs12
-rw-r--r--Mono.Cecil/TypeReference.cs2
-rw-r--r--Mono.Cecil/TypeReferenceEqualityComparer.cs253
-rw-r--r--Mono.Cecil/TypeResolver.cs220
-rw-r--r--Mono.Cecil/WindowsRuntimeProjections.cs248
-rw-r--r--Test/Mono.Cecil.Tests/LoadAssemblyDefinitionForTestsBaseSimple.cs16
-rw-r--r--Test/Mono.Cecil.Tests/MethodReferenceComparerTests.cs135
-rw-r--r--Test/Mono.Cecil.Tests/TypeDefinitionUtils.cs41
-rw-r--r--Test/Mono.Cecil.Tests/TypeReferenceComparisonTests.cs84
-rw-r--r--Test/Mono.Cecil.Tests/WindowsRuntimeProjectionsTests.cs144
-rw-r--r--Test/Resources/assemblies/NativeWinmd.winmdbin3584 -> 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
index 53fedff..b6417cf 100644
--- a/Test/Resources/assemblies/NativeWinmd.winmd
+++ b/Test/Resources/assemblies/NativeWinmd.winmd
Binary files differ