| File: BoundTree\BoundTreeVisitors.cs | Web Access |
| Project: src\roslyn\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. #nullable disable using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using System; using Roslyn.Utilities; using System.Linq; namespace Microsoft.CodeAnalysis.CSharp { internal abstract partial class BoundTreeVisitor<A, R> { protected BoundTreeVisitor() { } public virtual R Visit(BoundNode node, A arg) { if (node == null) { return default(R); } // this switch contains fewer than 50 of the most common node kinds switch (node.Kind) { case BoundKind.TypeExpression: return VisitTypeExpression(node as BoundTypeExpression, arg); case BoundKind.NamespaceExpression: return VisitNamespaceExpression(node as BoundNamespaceExpression, arg); case BoundKind.UnaryOperator: return VisitUnaryOperator(node as BoundUnaryOperator, arg); case BoundKind.IncrementOperator: return VisitIncrementOperator(node as BoundIncrementOperator, arg); case BoundKind.BinaryOperator: return VisitBinaryOperator(node as BoundBinaryOperator, arg); case BoundKind.CompoundAssignmentOperator: return VisitCompoundAssignmentOperator(node as BoundCompoundAssignmentOperator, arg); case BoundKind.AssignmentOperator: return VisitAssignmentOperator(node as BoundAssignmentOperator, arg); case BoundKind.NullCoalescingOperator: return VisitNullCoalescingOperator(node as BoundNullCoalescingOperator, arg); case BoundKind.ConditionalOperator: return VisitConditionalOperator(node as BoundConditionalOperator, arg); case BoundKind.ArrayAccess: return VisitArrayAccess(node as BoundArrayAccess, arg); case BoundKind.TypeOfOperator: return VisitTypeOfOperator(node as BoundTypeOfOperator, arg); case BoundKind.DefaultLiteral: return VisitDefaultLiteral(node as BoundDefaultLiteral, arg); case BoundKind.DefaultExpression: return VisitDefaultExpression(node as BoundDefaultExpression, arg); case BoundKind.IsOperator: return VisitIsOperator(node as BoundIsOperator, arg); case BoundKind.AsOperator: return VisitAsOperator(node as BoundAsOperator, arg); case BoundKind.Conversion: return VisitConversion(node as BoundConversion, arg); case BoundKind.SequencePointExpression: return VisitSequencePointExpression(node as BoundSequencePointExpression, arg); case BoundKind.SequencePoint: return VisitSequencePoint(node as BoundSequencePoint, arg); case BoundKind.SequencePointWithSpan: return VisitSequencePointWithSpan(node as BoundSequencePointWithSpan, arg); case BoundKind.Block: return VisitBlock(node as BoundBlock, arg); case BoundKind.LocalDeclaration: return VisitLocalDeclaration(node as BoundLocalDeclaration, arg); case BoundKind.MultipleLocalDeclarations: return VisitMultipleLocalDeclarations(node as BoundMultipleLocalDeclarations, arg); case BoundKind.Sequence: return VisitSequence(node as BoundSequence, arg); case BoundKind.NoOpStatement: return VisitNoOpStatement(node as BoundNoOpStatement, arg); case BoundKind.ReturnStatement: return VisitReturnStatement(node as BoundReturnStatement, arg); case BoundKind.ThrowStatement: return VisitThrowStatement(node as BoundThrowStatement, arg); case BoundKind.ExpressionStatement: return VisitExpressionStatement(node as BoundExpressionStatement, arg); case BoundKind.BreakStatement: return VisitBreakStatement(node as BoundBreakStatement, arg); case BoundKind.ContinueStatement: return VisitContinueStatement(node as BoundContinueStatement, arg); case BoundKind.IfStatement: return VisitIfStatement(node as BoundIfStatement, arg); case BoundKind.ForEachStatement: return VisitForEachStatement(node as BoundForEachStatement, arg); case BoundKind.TryStatement: return VisitTryStatement(node as BoundTryStatement, arg); case BoundKind.Literal: return VisitLiteral(node as BoundLiteral, arg); case BoundKind.ThisReference: return VisitThisReference(node as BoundThisReference, arg); case BoundKind.Local: return VisitLocal(node as BoundLocal, arg); case BoundKind.Parameter: return VisitParameter(node as BoundParameter, arg); case BoundKind.LabelStatement: return VisitLabelStatement(node as BoundLabelStatement, arg); case BoundKind.GotoStatement: return VisitGotoStatement(node as BoundGotoStatement, arg); case BoundKind.LabeledStatement: return VisitLabeledStatement(node as BoundLabeledStatement, arg); case BoundKind.StatementList: return VisitStatementList(node as BoundStatementList, arg); case BoundKind.ConditionalGoto: return VisitConditionalGoto(node as BoundConditionalGoto, arg); case BoundKind.Call: return VisitCall(node as BoundCall, arg); case BoundKind.ObjectCreationExpression: return VisitObjectCreationExpression(node as BoundObjectCreationExpression, arg); case BoundKind.DelegateCreationExpression: return VisitDelegateCreationExpression(node as BoundDelegateCreationExpression, arg); case BoundKind.FieldAccess: return VisitFieldAccess(node as BoundFieldAccess, arg); case BoundKind.PropertyAccess: return VisitPropertyAccess(node as BoundPropertyAccess, arg); case BoundKind.Lambda: return VisitLambda(node as BoundLambda, arg); case BoundKind.NameOfOperator: return VisitNameOfOperator(node as BoundNameOfOperator, arg); } return VisitInternal(node, arg); } public virtual R DefaultVisit(BoundNode node, A arg) { return default(R); } } internal abstract partial class BoundTreeVisitor { protected BoundTreeVisitor() { } [DebuggerHidden] public virtual BoundNode Visit(BoundNode node) { if (node != null) { return node.Accept(this); } return null; } [DebuggerHidden] public virtual BoundNode DefaultVisit(BoundNode node) { return null; } public class CancelledByStackGuardException : Exception { public readonly BoundNode Node; public CancelledByStackGuardException(Exception inner, BoundNode node) : base(inner.Message, inner) { Node = node; } public void AddAnError(DiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InsufficientStack, GetTooLongOrComplexExpressionErrorLocation(Node)); } public void AddAnError(BindingDiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_InsufficientStack, GetTooLongOrComplexExpressionErrorLocation(Node)); } public static Location GetTooLongOrComplexExpressionErrorLocation(BoundNode node) { SyntaxNode syntax = node.Syntax; if (syntax is not (ExpressionSyntax or PatternSyntax)) { syntax = syntax.DescendantNodes(n => n is not (ExpressionSyntax or PatternSyntax)).FirstOrDefault(n => n is ExpressionSyntax or PatternSyntax) ?? syntax; } return syntax.GetFirstToken().GetLocation(); } } /// <summary> /// Consumers must provide implementation for <see cref="VisitExpressionOrPatternWithoutStackGuard"/>. /// </summary> [DebuggerStepThrough] protected BoundNode VisitExpressionOrPatternWithStackGuard(ref int recursionDepth, BoundNode node) { Debug.Assert(node is BoundExpression or BoundPattern); BoundNode result; recursionDepth++; #if DEBUG int saveRecursionDepth = recursionDepth; #endif if (recursionDepth > 1 || !ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException()) { EnsureSufficientExecutionStack(recursionDepth); result = VisitExpressionOrPatternWithoutStackGuard(node); } else { result = VisitExpressionOrPatternWithStackGuard(node); } #if DEBUG Debug.Assert(saveRecursionDepth == recursionDepth); #endif recursionDepth--; return result; } [DebuggerStepThrough] protected virtual void EnsureSufficientExecutionStack(int recursionDepth) { StackGuard.EnsureSufficientExecutionStack(recursionDepth); } protected virtual bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException() { return true; } #nullable enable [DebuggerStepThrough] private BoundNode? VisitExpressionOrPatternWithStackGuard(BoundNode node) { try { return VisitExpressionOrPatternWithoutStackGuard(node); } catch (InsufficientExecutionStackException ex) { throw new CancelledByStackGuardException(ex, node); } } /// <summary> /// We should be intentional about behavior of derived classes regarding guarding against stack overflow. /// </summary> protected abstract BoundNode? VisitExpressionOrPatternWithoutStackGuard(BoundNode node); } }