|
5 | 5 | using System; |
6 | 6 | using System.Collections.Generic; |
7 | 7 | using System.Diagnostics; |
| 8 | +using System.Runtime.CompilerServices; |
8 | 9 | using System.Threading; |
9 | 10 | using Microsoft.CodeAnalysis.CSharp.Symbols; |
10 | 11 | using Microsoft.CodeAnalysis.Text; |
@@ -7146,35 +7147,44 @@ private bool IsEndOfFixedStatement() |
7146 | 7147 |
|
7147 | 7148 | private StatementSyntax ParseEmbeddedStatement() |
7148 | 7149 | { |
7149 | | - // The consumers of embedded statements are expecting to receive a non-null statement |
7150 | | - // yet there are several error conditions that can lead ParseStatementCore to return |
7151 | | - // null. When that occurs create an error empty Statement and return it to the caller. |
7152 | | - StatementSyntax statement = this.ParseStatementCore() ?? SyntaxFactory.EmptyStatement(EatToken(SyntaxKind.SemicolonToken)); |
| 7150 | + // ParseEmbeddedStatement is called through many recursive statement parsing cases. We |
| 7151 | + // keep the body exceptionally simple, and we optimize for the common case, to ensure it |
| 7152 | + // is inlined into the callers. Otherwise the overhead of this single method can have a |
| 7153 | + // deep impact on the number of recursive calls we can make (more than a hundred during |
| 7154 | + // empirical testing). |
7153 | 7155 |
|
7154 | | - switch (statement.Kind) |
| 7156 | + return parseEmbeddedStatementRest(this.ParseStatementCore()); |
| 7157 | + |
| 7158 | + StatementSyntax parseEmbeddedStatementRest(StatementSyntax statement) |
7155 | 7159 | { |
| 7160 | + if (statement == null) |
| 7161 | + { |
| 7162 | + // The consumers of embedded statements are expecting to receive a non-null statement |
| 7163 | + // yet there are several error conditions that can lead ParseStatementCore to return |
| 7164 | + // null. When that occurs create an error empty Statement and return it to the caller. |
| 7165 | + return SyntaxFactory.EmptyStatement(EatToken(SyntaxKind.SemicolonToken)); |
| 7166 | + } |
| 7167 | + |
7156 | 7168 | // In scripts, stand-alone expression statements may not be followed by semicolons. |
7157 | 7169 | // ParseExpressionStatement hides the error. |
7158 | 7170 | // However, embedded expression statements are required to be followed by semicolon. |
7159 | | - case SyntaxKind.ExpressionStatement: |
7160 | | - if (IsScript) |
7161 | | - { |
7162 | | - var expressionStatementSyntax = (ExpressionStatementSyntax)statement; |
7163 | | - var semicolonToken = expressionStatementSyntax.SemicolonToken; |
| 7171 | + if (statement.Kind == SyntaxKind.ExpressionStatement && |
| 7172 | + IsScript) |
| 7173 | + { |
| 7174 | + var expressionStatementSyntax = (ExpressionStatementSyntax)statement; |
| 7175 | + var semicolonToken = expressionStatementSyntax.SemicolonToken; |
7164 | 7176 |
|
7165 | | - // Do not add a new error if the same error was already added. |
7166 | | - if (semicolonToken.IsMissing && |
7167 | | - !semicolonToken.GetDiagnostics().Contains(diagnosticInfo => (ErrorCode)diagnosticInfo.Code == ErrorCode.ERR_SemicolonExpected)) |
7168 | | - { |
7169 | | - semicolonToken = this.AddError(semicolonToken, ErrorCode.ERR_SemicolonExpected); |
7170 | | - statement = expressionStatementSyntax.Update(expressionStatementSyntax.Expression, semicolonToken); |
7171 | | - } |
| 7177 | + // Do not add a new error if the same error was already added. |
| 7178 | + if (semicolonToken.IsMissing && |
| 7179 | + !semicolonToken.GetDiagnostics().Contains(diagnosticInfo => (ErrorCode)diagnosticInfo.Code == ErrorCode.ERR_SemicolonExpected)) |
| 7180 | + { |
| 7181 | + semicolonToken = this.AddError(semicolonToken, ErrorCode.ERR_SemicolonExpected); |
| 7182 | + return expressionStatementSyntax.Update(expressionStatementSyntax.Expression, semicolonToken); |
7172 | 7183 | } |
| 7184 | + } |
7173 | 7185 |
|
7174 | | - break; |
| 7186 | + return statement; |
7175 | 7187 | } |
7176 | | - |
7177 | | - return statement; |
7178 | 7188 | } |
7179 | 7189 |
|
7180 | 7190 | private BreakStatementSyntax ParseBreakStatement() |
|
0 commit comments