private static ImmutableArray <OperationReplacer> GetOperationReplacers(RequiredSymbols symbols)
 {
     return(ImmutableArray.Create <OperationReplacer>(
                new StringStringCaseReplacer(symbols),
                new StringStringBoolReplacer(symbols),
                new StringStringStringComparisonReplacer(symbols)));
 }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document      = context.Document;
            var token         = context.CancellationToken;
            var semanticModel = await document.GetSemanticModelAsync(token).ConfigureAwait(false);

            _ = RequiredSymbols.TryGetSymbols(semanticModel.Compilation, out var symbols);
            RoslynDebug.Assert(symbols is not null);

            var root = await document.GetSyntaxRootAsync(token).ConfigureAwait(false);

            var node = root.FindNode(context.Span, getInnermostNodeForTie: true);

            if (semanticModel.GetOperation(node, token) is not IBinaryOperation violation)
            {
                return;
            }

            //  Get the replacer that applies to the reported violation.
            var replacer = GetOperationReplacers(symbols).First(x => x.IsMatch(violation));

            var codeAction = CodeAction.Create(
                Resx.UseStringEqualsOverStringCompareCodeFixTitle,
                CreateChangedDocument,
                nameof(Resx.UseStringEqualsOverStringCompareCodeFixTitle));

            context.RegisterCodeFix(codeAction, context.Diagnostics);
            return;

            //  Local functions

            async Task <Document> CreateChangedDocument(CancellationToken token)
            {
                var editor = await DocumentEditor.CreateAsync(document, token).ConfigureAwait(false);

                var replacementNode = replacer.CreateReplacementExpression(violation, editor.Generator);

                editor.ReplaceNode(violation.Syntax, replacementNode);

                return(editor.GetChangedDocument());
            }
        }
 protected OperationReplacer(RequiredSymbols symbols)
 {
     Symbols = symbols;
 }
 public StringStringStringComparisonReplacer(RequiredSymbols symbols)
     : base(symbols)
 {
 }
 public StringStringBoolReplacer(RequiredSymbols symbols)
     : base(symbols)
 {
 }