|
// 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.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.OrderModifiers;
internal abstract class AbstractOrderModifiersCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
private readonly ISyntaxFacts _syntaxFacts;
private readonly AbstractOrderModifiersHelpers _helpers;
protected AbstractOrderModifiersCodeFixProvider(
ISyntaxFacts syntaxFacts,
AbstractOrderModifiersHelpers helpers)
{
_syntaxFacts = syntaxFacts;
_helpers = helpers;
}
protected abstract ImmutableArray<string> FixableCompilerErrorIds { get; }
protected abstract CodeStyleOption2<string> GetCodeStyleOption(AnalyzerOptionsProvider options);
public sealed override ImmutableArray<string> FixableDiagnosticIds
=> FixableCompilerErrorIds.Add(IDEDiagnosticIds.OrderModifiersDiagnosticId);
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var syntaxTree = await context.Document.GetRequiredSyntaxTreeAsync(context.CancellationToken).ConfigureAwait(false);
var syntaxNode = Location.Create(syntaxTree, context.Span).FindNode(context.CancellationToken);
if (_syntaxFacts.GetModifiers(syntaxNode) != default)
{
RegisterCodeFix(context, AnalyzersResources.Order_modifiers, nameof(AnalyzersResources.Order_modifiers));
}
}
protected override async Task FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
{
var options = await document.GetAnalyzerOptionsProviderAsync(cancellationToken).ConfigureAwait(false);
var option = GetCodeStyleOption(options);
if (!_helpers.TryGetOrComputePreferredOrder(option.Value, out var preferredOrder))
{
return;
}
foreach (var diagnostic in diagnostics)
{
var memberDeclaration = diagnostic.Location.FindNode(cancellationToken);
editor.ReplaceNode(memberDeclaration, (currentNode, _) =>
{
var modifiers = _syntaxFacts.GetModifiers(currentNode);
var orderedModifiers = new SyntaxTokenList(
modifiers.OrderBy(CompareModifiers)
.Select((t, i) => t.WithTriviaFrom(modifiers[i])));
var updatedMemberDeclaration = _syntaxFacts.WithModifiers(currentNode, orderedModifiers);
return updatedMemberDeclaration;
});
}
return;
// Local functions
int CompareModifiers(SyntaxToken t1, SyntaxToken t2)
=> GetOrder(t1) - GetOrder(t2);
int GetOrder(SyntaxToken token)
=> preferredOrder.TryGetValue(token.RawKind, out var value) ? value : int.MaxValue;
}
}
|