File: Microsoft.NetCore.Analyzers\Performance\CSharpUseStringMethodCharOverloadWithSingleCharacters.Fixer.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\src\Microsoft.CodeAnalysis.CSharp.NetAnalyzers\Microsoft.CodeAnalysis.CSharp.NetAnalyzers.csproj (Microsoft.CodeAnalysis.CSharp.NetAnalyzers)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Composition;
using System.Linq;
using Analyzer.Utilities.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Operations;
using Microsoft.NetCore.Analyzers.Performance;
 
namespace Microsoft.NetCore.CSharp.Analyzers.Performance
{
    [ExportCodeFixProvider(LanguageNames.CSharp), Shared]
    public sealed class CSharpUseStringMethodCharOverloadWithSingleCharactersFixer : UseStringMethodCharOverloadWithSingleCharactersFixer
    {
        protected override bool TryGetChar(SemanticModel model, SyntaxNode argumentListNode, out char c)
        {
            c = default;
 
            if (argumentListNode is not ArgumentListSyntax argumentList)
            {
                return false;
            }
 
            ArgumentSyntax? stringArgumentNode = null;
            foreach (var argument in argumentList.Arguments)
            {
                var argumentOperation = model.GetOperation(argument) as IArgumentOperation;
                if (argumentOperation?.Parameter != null && argumentOperation.Parameter.Ordinal == 0)
                {
                    stringArgumentNode = argument;
                    break;
                }
            }
 
            if (stringArgumentNode != null &&
                stringArgumentNode.Expression is LiteralExpressionSyntax containedLiteralExpressionSyntax)
            {
                return TryGetCharFromLiteralExpressionSyntax(containedLiteralExpressionSyntax, out c);
            }
 
            return false;
 
            static bool TryGetCharFromLiteralExpressionSyntax(LiteralExpressionSyntax sourceLiteralExpressionSyntax, out char parsedCharLiteral)
            {
                parsedCharLiteral = default;
                if (sourceLiteralExpressionSyntax.Token.Value is string sourceLiteralValue && char.TryParse(sourceLiteralValue, out parsedCharLiteral))
                {
                    return true;
                }
 
                return false;
            }
        }
 
        protected override CodeAction CreateCodeAction(Document document, SyntaxNode argumentListNode, char sourceCharLiteral)
        {
            return new CSharpReplaceStringLiteralWithCharLiteralCodeAction(document, argumentListNode, sourceCharLiteral);
        }
 
        private sealed class CSharpReplaceStringLiteralWithCharLiteralCodeAction(
            Document document, SyntaxNode argumentListNode, char sourceCharLiteral)
            : ReplaceStringLiteralWithCharLiteralCodeAction(document, argumentListNode, sourceCharLiteral)
        {
            protected override void ApplyFix(
                DocumentEditor editor,
                SemanticModel model,
                SyntaxNode oldArgumentListNode,
                char c)
            {
                var argumentNode = (ArgumentSyntax)editor.Generator.Argument(editor.Generator.LiteralExpression(c));
                var arguments = new[] { argumentNode }.Concat(((ArgumentListSyntax)oldArgumentListNode).Arguments
                        .Select(arg => (arg, operation: model.GetOperation(arg) as IArgumentOperation))
                        .Where(t => PreserveArgument(t.operation))
                        .Select(t => t.arg));
                var argumentListNode = SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(arguments));
 
                editor.ReplaceNode(oldArgumentListNode, argumentListNode.WithTriviaFrom(oldArgumentListNode));
            }
        }
    }
}