File: src\Analyzers\Core\Analyzers\UseCollectionInitializer\UseCollectionInitializerHelpers.cs
Web Access
Project: src\src\CodeStyle\Core\Analyzers\Microsoft.CodeAnalysis.CodeStyle.csproj (Microsoft.CodeAnalysis.CodeStyle)
// 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.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.UseCollectionExpression;
 
namespace Microsoft.CodeAnalysis.UseCollectionInitializer;
 
internal static class UseCollectionInitializerHelpers
{
    public const string UseCollectionExpressionName = nameof(UseCollectionExpressionName);
    public const string ChangesSemanticsName = nameof(ChangesSemanticsName);
 
    public static readonly ImmutableDictionary<string, string?> UseCollectionExpressionProperties =
        ImmutableDictionary<string, string?>.Empty.Add(UseCollectionExpressionName, UseCollectionExpressionName);
 
    public static ImmutableArray<Location> GetLocationsToFade(
        ISyntaxFacts syntaxFacts,
        CollectionMatch<SyntaxNode> matchInfo)
    {
        var match = matchInfo.Node;
        var syntaxTree = match.SyntaxTree;
        if (syntaxFacts.IsExpressionStatement(match))
        {
            var expression = syntaxFacts.GetExpressionOfExpressionStatement(match);
 
            if (syntaxFacts.IsInvocationExpression(expression))
            {
                var arguments = syntaxFacts.GetArgumentsOfInvocationExpression(expression);
                var additionalUnnecessaryLocations = ImmutableArray.Create(
                    syntaxTree.GetLocation(TextSpan.FromBounds(match.SpanStart, arguments[0].SpanStart)),
                    syntaxTree.GetLocation(TextSpan.FromBounds(arguments.Last().FullSpan.End, match.Span.End)));
 
                return additionalUnnecessaryLocations;
            }
        }
        else if (syntaxFacts.IsForEachStatement(match))
        {
            // For a `foreach (var x in expr) ...` statement, fade out the parts before and after `expr`.
 
            var expression = syntaxFacts.GetExpressionOfForeachStatement(match);
            var additionalUnnecessaryLocations = ImmutableArray.Create(
                syntaxTree.GetLocation(TextSpan.FromBounds(match.SpanStart, expression.SpanStart)),
                syntaxTree.GetLocation(TextSpan.FromBounds(expression.FullSpan.End, match.Span.End)));
 
            return additionalUnnecessaryLocations;
        }
 
        return [];
    }
 
    public static IEnumerable<TStatementSyntax> GetSubsequentStatements<TStatementSyntax>(
        ISyntaxFacts syntaxFacts,
        TStatementSyntax initialStatement) where TStatementSyntax : SyntaxNode
    {
        // If containing statement is inside a block (e.g. method), than we need to iterate through its child
        // statements. If containing statement is in top-level code, than we need to iterate through child statements of
        // containing compilation unit.
        var containingBlockOrCompilationUnit = initialStatement.GetRequiredParent();
 
        // In case of top-level code parent of the statement will be GlobalStatementSyntax, so we need to get its parent
        // in order to get CompilationUnitSyntax
        if (syntaxFacts.IsGlobalStatement(containingBlockOrCompilationUnit))
            containingBlockOrCompilationUnit = containingBlockOrCompilationUnit.Parent!;
 
        var foundStatement = false;
        foreach (var child in containingBlockOrCompilationUnit.ChildNodesAndTokens())
        {
            if (child.IsToken)
                continue;
 
            var childNode = child.AsNode()!;
            var extractedChild = syntaxFacts.IsGlobalStatement(childNode)
                ? syntaxFacts.GetStatementOfGlobalStatement(childNode)
                : childNode;
 
            if (!foundStatement)
            {
                if (extractedChild == initialStatement)
                {
                    foundStatement = true;
                }
 
                continue;
            }
 
            if (extractedChild is not TStatementSyntax childStatement)
                break;
 
            yield return childStatement;
        }
    }
 
    public static bool ChangesSemantics(Diagnostic diagnostic)
        => diagnostic.Properties.ContainsKey(ChangesSemanticsName);
}