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

MethodReferenceComparer.cs « Mono.Cecil - github.com/mono/cecil.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 3bf2c6eca8c0dc5ba01ef18f021271f93fe7903c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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 ();
		}
	}
}