File: src\Analyzers\Core\Analyzers\OrderModifiers\OrderModifiersHelpers.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// 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;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
 
namespace Microsoft.CodeAnalysis.OrderModifiers;
 
internal abstract class AbstractOrderModifiersHelpers
{
    private static readonly char[] s_comma = [','];
 
    /// <remarks>
    /// Reference type so we can read/write atomically.
    /// </remarks>
    private Tuple<string, Dictionary<int, int>>? _lastParsed;
 
    protected abstract int GetKeywordKind(string trimmed);
 
    public static bool IsOrdered(Dictionary<int, int> preferredOrder, SyntaxTokenList modifiers)
    {
        if (modifiers.Count >= 2)
        {
            var lastOrder = int.MinValue;
            foreach (var modifier in modifiers)
            {
                var currentOrder = preferredOrder.TryGetValue(modifier.RawKind, out var value) ? value : int.MaxValue;
                if (currentOrder < lastOrder)
                {
                    return false;
                }
 
                lastOrder = currentOrder;
            }
        }
 
        return true;
    }
 
    public bool TryGetOrComputePreferredOrder(string value, [NotNullWhen(true)] out Dictionary<int, int>? preferredOrder)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            preferredOrder = null;
            return false;
        }
 
        var lastParsed = Volatile.Read(ref _lastParsed);
        if (lastParsed?.Item1 != value)
        {
            if (!TryParse(value, out var parsed))
            {
                preferredOrder = null;
                return false;
            }
 
            lastParsed = Tuple.Create(value, parsed);
            Volatile.Write(ref _lastParsed, lastParsed);
        }
 
        preferredOrder = lastParsed.Item2;
        return true;
    }
 
    protected virtual bool TryParse(string value, [NotNullWhen(true)] out Dictionary<int, int>? parsed)
    {
        var result = new Dictionary<int, int>();
 
        var index = 0;
        foreach (var piece in value.Split(s_comma, StringSplitOptions.RemoveEmptyEntries))
        {
            var trimmed = piece.Trim();
            var kind = GetKeywordKind(trimmed);
 
            if (kind == 0)
            {
                parsed = null;
                return false;
            }
 
            result[kind] = index;
            index++;
        }
 
        if (result.Count == 0)
        {
            parsed = null;
            return false;
        }
 
        parsed = result;
        return true;
    }
}