File: Microsoft.CodeQuality.Analyzers\Maintainability\UseCrossPlatformIntrinsicsFixer.cs
Web Access
Project: src\sdk\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.NetAnalyzers\Microsoft.CodeAnalysis.NetAnalyzers.csproj (Microsoft.CodeAnalysis.NetAnalyzers)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.NetAnalyzers;

namespace Microsoft.CodeQuality.Analyzers.Maintainability
{
    using static MicrosoftCodeQualityAnalyzersResources;
    using RuleKind = UseCrossPlatformIntrinsicsAnalyzer.RuleKind;

    public abstract class UseCrossPlatformIntrinsicsFixer : OrderedCodeFixProvider
    {
        public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(UseCrossPlatformIntrinsicsAnalyzer.RuleId);

        protected sealed override string CodeActionTitle => UseCrossPlatformIntrinsicsTitle;

        protected sealed override string CodeActionEquivalenceKey => nameof(UseCrossPlatformIntrinsicsFixer);

        protected sealed override Task FixAllCoreAsync(SyntaxEditor editor, SyntaxGenerator generator, Diagnostic diagnostic, CancellationToken cancellationToken)
        {
            SyntaxNode node = editor.OriginalRoot.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);

            // We shouldn't get here for a diagnostic that doesn't have the expected properties.

            if (!diagnostic.Properties.TryGetValue(nameof(RuleKind), out string? ruleKindName))
            {
                Debug.Fail($"Found diagnostic without an associated {nameof(RuleKind)} property.");
                return Task.CompletedTask;
            }

            if (!Enum.TryParse(ruleKindName, out RuleKind ruleKind))
            {
                Debug.Fail($"Found diagnostic with an unrecognized {nameof(RuleKind)} property: {ruleKindName}.");
                return Task.CompletedTask;
            }

            editor.ReplaceNode(node, (currentNode, generator) => ReplaceNode(currentNode, generator, ruleKind));
            return Task.CompletedTask;
        }

        protected virtual SyntaxNode ReplaceNode(SyntaxNode currentNode, SyntaxGenerator generator, RuleKind ruleKind)
        {
            return ruleKind switch
            {
                RuleKind.op_Addition => ReplaceWithBinaryOperator(currentNode, generator, isCommutative: true, generator.AddExpression),
                RuleKind.op_BitwiseAnd => ReplaceWithBinaryOperator(currentNode, generator, isCommutative: true, generator.BitwiseAndExpression),
                RuleKind.op_BitwiseOr => ReplaceWithBinaryOperator(currentNode, generator, isCommutative: true, generator.BitwiseOrExpression),
                RuleKind.op_Division => ReplaceWithBinaryOperator(currentNode, generator, isCommutative: false, generator.DivideExpression),
                RuleKind.op_Multiply => ReplaceWithBinaryOperator(currentNode, generator, isCommutative: true, generator.MultiplyExpression),
                RuleKind.op_OnesComplement => ReplaceWithUnaryOperator(currentNode, generator, generator.BitwiseNotExpression),
                RuleKind.op_Subtraction => ReplaceWithBinaryOperator(currentNode, generator, isCommutative: false, generator.SubtractExpression),
                RuleKind.op_UnaryNegation => ReplaceWithUnaryOperator(currentNode, generator, generator.NegateExpression),
                _ => currentNode,
            };
        }

        protected abstract SyntaxNode ReplaceWithUnaryOperator(SyntaxNode currentNode, SyntaxGenerator generator, Func<SyntaxNode, SyntaxNode?> unaryOpFunc);

        protected abstract SyntaxNode ReplaceWithBinaryOperator(SyntaxNode currentNode, SyntaxGenerator generator, bool isCommutative, Func<SyntaxNode, SyntaxNode, SyntaxNode?> binaryOpFunc);
    }
}