Repository navigation
Expand file tree
/
Copy pathCXNodeEqualityComparer.cs
More file actions
104 lines (87 loc) · 3.09 KB
/
Copy pathCXNodeEqualityComparer.cs
File metadata and controls
104 lines (87 loc) · 3.09 KB
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
using System.Collections.Generic;
using System.Linq;
using Discord.CX.Util;
namespace Discord.CX.Parser;
/// <summary>
/// Represents an equality comparer for <see cref="ICXNode"/>.
/// </summary>
/// <param name="flags">
/// The flags used to compare equality between <see cref="ICXNode"/>.
/// </param>
public sealed class CXNodeEqualityComparer(
SyntaxEqualityFlags flags = SyntaxEqualityFlags.All
) : IEqualityComparer<ICXNode>
{
/// <summary>
/// The default equality comparer instance.
/// </summary>
public static readonly CXNodeEqualityComparer Default = new();
/// <inheritdoc/>
public bool Equals(ICXNode? x, ICXNode? y)
{
if (x is null) return y is null;
if (y is null) return false;
if (ReferenceEquals(x, y)) return true;
if (
(flags & SyntaxEqualityFlags.CompareSourceDocument) != 0 &&
!ReferenceEquals(x.Document, y.Document)
)
{
return false;
}
if (
(flags & SyntaxEqualityFlags.CompareTrivia) != 0 &&
(
!x.LeadingTrivia.Equals(y.LeadingTrivia) ||
!x.TrailingTrivia.Equals(y.LeadingTrivia)
)
) return false;
if (
(flags & SyntaxEqualityFlags.CompareDiagnostics) != 0 &&
!x.Diagnostics.SequenceEqual(y.Diagnostics)
) return false;
if (
(flags & SyntaxEqualityFlags.CompareFlags) != 0 &&
x is CXToken a && y is CXToken b &&
a.Flags != b.Flags
) return false;
if (
(flags & SyntaxEqualityFlags.CompareLocation) != 0 &&
!x.Span.Equals(y.Span)
) return false;
return (x, y) switch
{
(CXToken t1, CXToken t2) =>
t1.Kind == t2.Kind &&
t1.RawValue == t2.RawValue,
(CXNode n1, CXNode n2) =>
n1.Slots.SequenceEqual(n2.Slots, this),
// 'CXNode' should handle this case, but add it just in case.
(ICXCollection c1, ICXCollection c2) =>
c1.ToList().SequenceEqual(c2.ToList(), this),
// no matching types, they don't equal
_ => false
};
}
/// <inheritdoc/>
public int GetHashCode(ICXNode obj)
{
var hash = 0;
if ((flags & SyntaxEqualityFlags.CompareLocation) != 0)
hash = Hash.Combine(hash, obj.Span);
if ((flags & SyntaxEqualityFlags.CompareTrivia) != 0)
hash = Hash.Combine(hash, obj.LeadingTrivia, obj.TrailingTrivia);
if ((flags & SyntaxEqualityFlags.CompareDiagnostics) != 0)
hash = Hash.Combine(hash, obj.Diagnostics.Aggregate(0, Hash.Combine));
return Hash.Combine(
hash,
obj switch
{
CXToken token => Hash.Combine(token.Kind, token.RawValue),
CXNode node => node.Slots.Aggregate(0, Hash.Combine),
ICXCollection col => col.ToList().Aggregate(0, Hash.Combine),
_ => 0
}
);
}
}