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 /Mono.Cecil
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>
Diffstat (limited to 'Mono.Cecil')
-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
13 files changed, 981 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)
{