File: Language\Intermediate\IntermediateNodeExtensions.cs
Web Access
Project: src\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.PooledObjects;
 
namespace Microsoft.AspNetCore.Razor.Language.Intermediate;
 
public static class IntermediateNodeExtensions
{
    public static ImmutableArray<RazorDiagnostic> GetAllDiagnostics(this IntermediateNode node)
    {
        ArgHelper.ThrowIfNull(node);
 
        var diagnostics = new PooledHashSet<RazorDiagnostic>();
        try
        {
            CollectDiagnostics(node, ref diagnostics);
 
            return diagnostics.OrderByAsArray(static d => d.Span.AbsoluteIndex);
        }
        finally
        {
            diagnostics.ClearAndFree();
        }
 
        static void CollectDiagnostics(IntermediateNode node, ref PooledHashSet<RazorDiagnostic> diagnostics)
        {
            if (node.HasDiagnostics)
            {
                diagnostics.UnionWith(node.Diagnostics);
            }
 
            foreach (var childNode in node.Children)
            {
                CollectDiagnostics(childNode, ref diagnostics);
            }
        }
    }
 
    public static ImmutableArray<TNode> FindDescendantNodes<TNode>(this IntermediateNode node)
        where TNode : IntermediateNode
    {
        using var results = new PooledArrayBuilder<TNode>();
        node.CollectDescendantNodes(ref results.AsRef());
 
        return results.ToImmutableAndClear();
    }
 
    internal static void CollectDescendantNodes<TNode>(this IntermediateNode root, ref PooledArrayBuilder<TNode> results)
        where TNode : IntermediateNode
    {
        using var stack = new PooledArrayBuilder<IntermediateNode>();
        ref var stackRef = ref stack.AsRef();
 
        PushChildren(root, ref stackRef);
 
        while (stack.Count > 0)
        {
            var node = stack.Pop();
 
            if (node is TNode target)
            {
                results.Add(target);
            }
 
            PushChildren(node, ref stackRef);
        }
 
        static void PushChildren(IntermediateNode node, ref PooledArrayBuilder<IntermediateNode> stack)
        {
            // Push children in reverse order so we process them in original order.
            var children = node.Children;
            for (var i = children.Count - 1; i >= 0; i--)
            {
                stack.Push(children[i]);
            }
        }
    }
}