File: src\Analyzers\CSharp\CodeFixes\UseObjectInitializer\CSharpUseObjectInitializerCodeFixProvider.cs
Web Access
Project: src\src\CodeStyle\CSharp\CodeFixes\Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle.Fixes)
// 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.Collections.Immutable;
using System.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.LanguageService;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.UseObjectInitializer;
 
namespace Microsoft.CodeAnalysis.CSharp.UseObjectInitializer;
 
using static CSharpSyntaxTokens;
using static SyntaxFactory;
using ObjectInitializerMatch = Match<ExpressionSyntax, StatementSyntax, MemberAccessExpressionSyntax, ExpressionStatementSyntax>;
 
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseObjectInitializer), Shared]
[method: ImportingConstructor]
[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
internal sealed class CSharpUseObjectInitializerCodeFixProvider() :
    AbstractUseObjectInitializerCodeFixProvider<
        SyntaxKind,
        ExpressionSyntax,
        StatementSyntax,
        BaseObjectCreationExpressionSyntax,
        MemberAccessExpressionSyntax,
        ExpressionStatementSyntax,
        LocalDeclarationStatementSyntax,
        VariableDeclaratorSyntax,
        CSharpUseNamedMemberInitializerAnalyzer>
{
    protected override CSharpUseNamedMemberInitializerAnalyzer GetAnalyzer()
        => CSharpUseNamedMemberInitializerAnalyzer.Allocate();
 
    protected override ISyntaxFormatting SyntaxFormatting => CSharpSyntaxFormatting.Instance;
 
    protected override ISyntaxKinds SyntaxKinds => CSharpSyntaxKinds.Instance;
 
    protected override SyntaxTrivia Whitespace(string text)
        => SyntaxFactory.Whitespace(text);
 
    protected override StatementSyntax GetNewStatement(
        StatementSyntax statement,
        BaseObjectCreationExpressionSyntax objectCreation,
        SyntaxFormattingOptions options,
        ImmutableArray<ObjectInitializerMatch> matches)
    {
        return statement.ReplaceNode(
            objectCreation,
            GetNewObjectCreation(objectCreation, options, matches));
    }
 
    private BaseObjectCreationExpressionSyntax GetNewObjectCreation(
        BaseObjectCreationExpressionSyntax objectCreation,
        SyntaxFormattingOptions options,
        ImmutableArray<ObjectInitializerMatch> matches)
    {
        return UseInitializerHelpers.GetNewObjectCreation(
            objectCreation,
            CreateExpressions(objectCreation, options, matches));
    }
 
    private SeparatedSyntaxList<ExpressionSyntax> CreateExpressions(
        BaseObjectCreationExpressionSyntax objectCreation,
        SyntaxFormattingOptions options,
        ImmutableArray<ObjectInitializerMatch> matches)
    {
        using var _ = ArrayBuilder<SyntaxNodeOrToken>.GetInstance(out var nodesAndTokens);
 
        UseInitializerHelpers.AddExistingItems<ObjectInitializerMatch, ExpressionSyntax>(
            objectCreation, nodesAndTokens, addTrailingComma: true, static (_, e) => e);
 
        for (var i = 0; i < matches.Length; i++)
        {
            var match = matches[i];
            var expressionStatement = match.Statement;
            var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;
            var trivia = match.MemberAccessExpression.GetLeadingTrivia();
 
            var newTrivia = i == 0 ? trivia.WithoutLeadingBlankLines() : trivia;
 
            var newAssignment = assignment
                .WithLeft(match.MemberAccessExpression.Name.WithLeadingTrivia(newTrivia))
                .WithRight(Indent(assignment.Right, options));
 
            if (i < matches.Length - 1)
            {
                nodesAndTokens.Add(newAssignment);
                nodesAndTokens.Add(CommaToken.WithTriviaFrom(expressionStatement.SemicolonToken));
            }
            else
            {
                newAssignment = newAssignment.WithTrailingTrivia(
                    expressionStatement.GetTrailingTrivia());
                nodesAndTokens.Add(newAssignment);
            }
        }
 
        return SeparatedList<ExpressionSyntax>(nodesAndTokens);
    }
}