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
|
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Globalization;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace ICSharpCode.NRefactory6.CSharp
{
internal class TokenComparer : IComparer<SyntaxToken>
{
private const string SystemNamespace = "System";
public static readonly IComparer<SyntaxToken> NormalInstance = new TokenComparer(specialCaseSystem: false);
public static readonly IComparer<SyntaxToken> SystemFirstInstance = new TokenComparer(specialCaseSystem: true);
private readonly bool _specialCaseSystem;
private TokenComparer(bool specialCaseSystem)
{
_specialCaseSystem = specialCaseSystem;
}
private static bool IsSystem(string s)
{
return s == SystemNamespace;
}
public int Compare(SyntaxToken x, SyntaxToken y)
{
if (_specialCaseSystem &&
x.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.UsingKeyword, SyntaxKind.StaticKeyword) &&
y.GetPreviousToken(includeSkipped: true).IsKind(SyntaxKind.UsingKeyword, SyntaxKind.StaticKeyword))
{
var token1IsSystem = IsSystem(x.ValueText);
var token2IsSystem = IsSystem(y.ValueText);
if (token1IsSystem && !token2IsSystem)
{
return -1;
}
else if (!token1IsSystem && token2IsSystem)
{
return 1;
}
}
return CompareWorker(x, y);
}
private int CompareWorker(SyntaxToken x, SyntaxToken y)
{
if (x == y)
{
return 0;
}
// By using 'ValueText' we get the value that is normalized. i.e.
// @class will be 'class', and unicode escapes will be converted
// to actual unicode. This allows sorting to work properly across
// tokens that have different source representations, but which
// mean the same thing.
var string1 = x.ValueText;
var string2 = y.ValueText;
// First check in a case insensitive manner. This will put
// everything that starts with an 'a' or 'A' above everything
// that starts with a 'b' or 'B'.
var compare = CultureInfo.InvariantCulture.CompareInfo.Compare(string1, string2,
CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth);
if (compare != 0)
{
return compare;
}
// Now, once we've grouped such that 'a' words and 'A' words are
// together, sort such that 'a' words come before 'A' words.
return CultureInfo.InvariantCulture.CompareInfo.Compare(string1, string2,
CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth);
}
}
}
|