File: src\Analyzers\CSharp\CodeFixes\UseCollectionExpression\CSharpUseCollectionExpressionForStackAllocCodeFixProvider.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;
using System.Collections.Immutable;
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.UseCollectionExpression;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.UseCollectionExpression;
 
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.UseCollectionExpressionForStackAlloc), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed partial class CSharpUseCollectionExpressionForStackAllocCodeFixProvider()
    : AbstractUseCollectionExpressionCodeFixProvider<ExpressionSyntax>(
        CSharpCodeFixesResources.Use_collection_expression,
        IDEDiagnosticIds.UseCollectionExpressionForStackAllocDiagnosticId)
{
    public override ImmutableArray<string> FixableDiagnosticIds { get; } = [IDEDiagnosticIds.UseCollectionExpressionForStackAllocDiagnosticId];
 
    protected sealed override async Task FixAsync(
        Document document,
        SyntaxEditor editor,
        ExpressionSyntax stackAllocExpression,
        ImmutableDictionary<string, string?> properties,
        CancellationToken cancellationToken)
    {
        if (stackAllocExpression is not StackAllocArrayCreationExpressionSyntax and not ImplicitStackAllocArrayCreationExpressionSyntax)
            return;
 
        var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
        var expressionType = semanticModel.Compilation.ExpressionOfTType();
        var matches = GetMatches();
        if (matches.IsDefault)
            return;
 
        var collectionExpression = await CSharpCollectionExpressionRewriter.CreateCollectionExpressionAsync(
            document,
            stackAllocExpression,
            preMatches: [],
            matches,
            static e => e switch
            {
                StackAllocArrayCreationExpressionSyntax arrayCreation => arrayCreation.Initializer,
                ImplicitStackAllocArrayCreationExpressionSyntax implicitArrayCreation => implicitArrayCreation.Initializer,
                _ => throw ExceptionUtilities.Unreachable(),
            },
            static (e, i) => e switch
            {
                StackAllocArrayCreationExpressionSyntax arrayCreation => arrayCreation.WithInitializer(i),
                ImplicitStackAllocArrayCreationExpressionSyntax implicitArrayCreation => implicitArrayCreation.WithInitializer(i),
                _ => throw ExceptionUtilities.Unreachable(),
            },
            cancellationToken).ConfigureAwait(false);
 
        editor.ReplaceNode(stackAllocExpression, collectionExpression);
 
        foreach (var match in matches)
            editor.RemoveNode(match.Node);
 
        return;
 
        ImmutableArray<CollectionMatch<StatementSyntax>> GetMatches()
            => stackAllocExpression switch
            {
                // if we have `stackalloc[] { ... }` we have no subsequent matches to add to the collection. All values come
                // from within the initializer.
                ImplicitStackAllocArrayCreationExpressionSyntax
                    => [],
 
                // we have `stackalloc T[...] ...;` defer to analyzer to find the items that follow that may need to
                // be added to the collection expression.
                StackAllocArrayCreationExpressionSyntax arrayCreation
                    => CSharpUseCollectionExpressionForStackAllocDiagnosticAnalyzer.TryGetMatches(
                        semanticModel, arrayCreation, expressionType, allowSemanticsChange: true, cancellationToken),
 
                // We validated this is unreachable in the caller.
                _ => throw ExceptionUtilities.Unreachable(),
            };
    }
}