diff options
Diffstat (limited to 'main/src/addins/CSharpBinding/Util/TokenComparer.cs')
-rw-r--r-- | main/src/addins/CSharpBinding/Util/TokenComparer.cs | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/main/src/addins/CSharpBinding/Util/TokenComparer.cs b/main/src/addins/CSharpBinding/Util/TokenComparer.cs new file mode 100644 index 0000000000..2fe8d6f412 --- /dev/null +++ b/main/src/addins/CSharpBinding/Util/TokenComparer.cs @@ -0,0 +1,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); + } + } +} |