-
Notifications
You must be signed in to change notification settings - Fork 4k
/
BoundTreeVisitors.cs
251 lines (226 loc) · 10.6 KB
/
BoundTreeVisitors.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// 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 ExpressionSyntax))
{
syntax = syntax.DescendantNodes(n => !(n is ExpressionSyntax)).OfType<ExpressionSyntax>().FirstOrDefault() ?? syntax;
}
return syntax.GetFirstToken().GetLocation();
}
}
/// <summary>
/// Consumers must provide implementation for <see cref="VisitExpressionWithoutStackGuard"/>.
/// </summary>
[DebuggerStepThrough]
protected BoundExpression VisitExpressionWithStackGuard(ref int recursionDepth, BoundExpression node)
{
BoundExpression result;
recursionDepth++;
#if DEBUG
int saveRecursionDepth = recursionDepth;
#endif
if (recursionDepth > 1 || !ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException())
{
StackGuard.EnsureSufficientExecutionStack(recursionDepth);
result = VisitExpressionWithoutStackGuard(node);
}
else
{
result = VisitExpressionWithStackGuard(node);
}
#if DEBUG
Debug.Assert(saveRecursionDepth == recursionDepth);
#endif
recursionDepth--;
return result;
}
protected virtual bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException()
{
return true;
}
#nullable enable
[DebuggerStepThrough]
private BoundExpression? VisitExpressionWithStackGuard(BoundExpression node)
{
try
{
return VisitExpressionWithoutStackGuard(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 BoundExpression? VisitExpressionWithoutStackGuard(BoundExpression node);
#nullable disable
}
}