/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Utilities/NameSyntaxComparer.cs
127 строк
5 KB
Cyrus Najmabadi
use recursive patterns
18 сен 2025, 23:32
18 сен 2025, 23:32
d58db64
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Microsoft.CodeAnalysis.CSharp.Utilities; internal sealed class NameSyntaxComparer : IComparer<NameSyntax?> { private readonly IComparer<SyntaxToken> _tokenComparer; internal readonly TypeSyntaxComparer TypeComparer; internal NameSyntaxComparer(IComparer<SyntaxToken> tokenComparer) { _tokenComparer = tokenComparer; TypeComparer = new TypeSyntaxComparer(tokenComparer, this); } public static IComparer<NameSyntax?> Create() => Create(TokenComparer.NormalInstance); public static IComparer<NameSyntax?> Create(IComparer<SyntaxToken> tokenComparer) => new NameSyntaxComparer(tokenComparer); public int Compare(NameSyntax? x, NameSyntax? y) { if (x == y) return 0; return (x, y) switch { (null, null) => 0, (null, _) => -1, (_, null) => 1, ({ IsMissing: true }, { IsMissing: true }) => 0, ({ IsMissing: true }, _) => -1, (_, { IsMissing: true }) => 1, (IdentifierNameSyntax identifierX, IdentifierNameSyntax identifierY) => _tokenComparer.Compare(identifierX.Identifier, identifierY.Identifier), (GenericNameSyntax genericX, GenericNameSyntax genericY) => Compare(genericX, genericY), (IdentifierNameSyntax identifierX, GenericNameSyntax genericY) => _tokenComparer.Compare(identifierX.Identifier, genericY.Identifier) is var diff and not 0 ? diff : -1, // Goo goes before Goo<T> (GenericNameSyntax genericX, IdentifierNameSyntax identifierY) => _tokenComparer.Compare(genericX.Identifier, identifierY.Identifier) is var diff and not 0 ? diff : -1, // Goo<T> goes after Goo (_, _) => DecomposeCompare(x, y), }; int DecomposeCompare(NameSyntax x, NameSyntax y) { // At this point one or both of the nodes is a dotted name or // aliased name. Break them apart into individual pieces and // compare those. var xNameParts = DecomposeNameParts(x); var yNameParts = DecomposeNameParts(y); for (var i = 0; i < xNameParts.Count && i < yNameParts.Count; i++) { var compare = Compare(xNameParts[i], yNameParts[i]); if (compare != 0) return compare; } // they matched up to this point. The shorter one should come // first. return xNameParts.Count - yNameParts.Count; } } private static IList<SimpleNameSyntax> DecomposeNameParts(NameSyntax name) { var result = new List<SimpleNameSyntax>(); DecomposeNameParts(name, result); return result; } private static void DecomposeNameParts(NameSyntax name, List<SimpleNameSyntax> result) { switch (name.Kind()) { case SyntaxKind.QualifiedName: var dottedName = (QualifiedNameSyntax)name; DecomposeNameParts(dottedName.Left, result); DecomposeNameParts(dottedName.Right, result); break; case SyntaxKind.AliasQualifiedName: var aliasedName = (AliasQualifiedNameSyntax)name; result.Add(aliasedName.Alias); DecomposeNameParts(aliasedName.Name, result); break; case SyntaxKind.IdentifierName: result.Add((IdentifierNameSyntax)name); break; case SyntaxKind.GenericName: result.Add((GenericNameSyntax)name); break; } } private int Compare(GenericNameSyntax x, GenericNameSyntax y) { var compare = _tokenComparer.Compare(x.Identifier, y.Identifier); if (compare != 0) return compare; // The one with less type params comes first. compare = x.Arity - y.Arity; if (compare != 0) return compare; // Same name, same parameter count. Compare each parameter. for (var i = 0; i < x.Arity; i++) { var xArg = x.TypeArgumentList.Arguments[i]; var yArg = y.TypeArgumentList.Arguments[i]; compare = TypeComparer.Compare(xArg, yArg); if (compare != 0) return compare; } return 0; } }