File: Lowering\LocalRewriter\PipelinePhaseValidator.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// 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.Diagnostics;
 
namespace Microsoft.CodeAnalysis.CSharp;
 
#if DEBUG
internal enum PipelinePhase
{
    InitialBinding,
    LocalRewriting,
    Spilling,
    ClosureConversion,
    StateMachineRewriting,
    Emit
}
#endif
 
internal sealed partial class PipelinePhaseValidator
#if DEBUG
     : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
#endif
{
 
#if DEBUG
    private readonly PipelinePhase _completedPhase;
#endif
 
#if DEBUG
    private PipelinePhaseValidator(PipelinePhase completedPhase)
    {
        _completedPhase = completedPhase;
    }
#endif
 
    [Conditional("DEBUG")]
    public static void AssertAfterInitialBinding(BoundNode node)
    {
#if DEBUG
        Assert(node, PipelinePhase.InitialBinding);
#endif
    }
 
    [Conditional("DEBUG")]
    public static void AssertAfterLocalRewriting(BoundNode node)
    {
#if DEBUG
        Assert(node, PipelinePhase.LocalRewriting);
#endif
    }
 
    [Conditional("DEBUG")]
    public static void AssertAfterSpilling(BoundNode node)
    {
#if DEBUG
        Assert(node, PipelinePhase.Spilling);
#endif
    }
 
    [Conditional("DEBUG")]
    public static void AssertAfterClosureConversion(BoundNode node)
    {
#if DEBUG
        Assert(node, PipelinePhase.ClosureConversion);
#endif
    }
 
    [Conditional("DEBUG")]
    public static void AssertAfterStateMachineRewriting(BoundNode node)
    {
#if DEBUG
        Assert(node, PipelinePhase.StateMachineRewriting);
#endif
    }
 
#if DEBUG
    /// <summary>
    /// Asserts that no unexpected nodes survived a given phase of rewriting.
    /// </summary>
    public static void Assert(BoundNode node, PipelinePhase completedPhase)
    {
        try
        {
            new PipelinePhaseValidator(completedPhase).Visit(node);
        }
        catch (InsufficientExecutionStackException)
        {
            // Intentionally ignored to let the overflow get caught in a more crucial visitor
        }
    }
 
    public override BoundNode? Visit(BoundNode? node)
    {
        if (node is null || node.HasErrors)
            return null;
 
        if (_completedPhase >= DoesNotSurvive(node.Kind))
            Debug.Assert(false, $"Bound nodes of kind {node.Kind} should not survive past {DoesNotSurvive(node.Kind)}");
 
        return base.Visit(node);
    }
#endif
}