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:
Diffstat (limited to 'Mono.Cecil/MethodReferenceComparer.cs')
-rw-r--r--Mono.Cecil/MethodReferenceComparer.cs143
1 files changed, 143 insertions, 0 deletions
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 ();
+ }
+ }
+}