@@ -2450,7 +2450,7 @@ private void ParseBlockAndExpressionBodiesWithSemicolon(
24502450
24512451 if ( this . CurrentToken . Kind == SyntaxKind . OpenBraceToken )
24522452 {
2453- blockBody = this . ParseBlock ( attributes : default , isMethodBody : true ) ;
2453+ blockBody = this . ParseMethodOrAccessorBodyBlock ( attributes : default , isAccessorBody : false ) ;
24542454 }
24552455
24562456 if ( this . CurrentToken . Kind == SyntaxKind . EqualsGreaterThanToken )
@@ -3286,7 +3286,7 @@ private AccessorDeclarationSyntax ParseAccessorDeclaration(bool isEvent)
32863286 {
32873287 if ( ! IsTerminator ( ) )
32883288 {
3289- blockBody = this . ParseBlock ( attributes : default , isMethodBody : true , isAccessorBody : true ) ;
3289+ blockBody = this . ParseMethodOrAccessorBodyBlock ( attributes : default , isAccessorBody : true ) ;
32903290 }
32913291 else
32923292 {
@@ -6423,8 +6423,10 @@ private StatementSyntax TryParseStatementNoDeclaration(
64236423 case SyntaxKind . GotoKeyword :
64246424 return this . ParseGotoStatement ( attributes ) ;
64256425 case SyntaxKind . IfKeyword :
6426- case SyntaxKind . ElseKeyword : // Including 'else' keyword to handle 'else without if' error cases
64276426 return this . ParseIfStatement ( attributes ) ;
6427+ case SyntaxKind . ElseKeyword :
6428+ // Including 'else' keyword to handle 'else without if' error cases
6429+ return this . ParseMisplacedElse ( attributes ) ;
64286430 case SyntaxKind . LockKeyword :
64296431 return this . ParseLockStatement ( attributes ) ;
64306432 case SyntaxKind . ReturnKeyword :
@@ -6947,59 +6949,72 @@ private bool IsPossibleNewExpression()
69476949 return null ;
69486950 }
69496951
6950- private BlockSyntax ParsePossiblyAttributedBlock ( bool isMethodBody = false , bool isAccessorBody = false )
6951- => ParseBlock ( this . ParseAttributeDeclarations ( ) , isMethodBody , isAccessorBody ) ;
6952+ private BlockSyntax ParsePossiblyAttributedBlock ( ) => ParseBlock ( this . ParseAttributeDeclarations ( ) ) ;
69526953
6953- // If "isMethodBody" is true, then this is the immediate body of a method/accessor.
6954- // In this case, we create a many-child list if the body is not a small single statement.
6955- // This then allows a "with many weak children" red node when the red node is created.
6956- // If "isAccessorBody" is true, then we produce a special diagnostic if the open brace is
6957- // missing. Also, "isMethodBody" must be true.
6958- private BlockSyntax ParseBlock ( SyntaxList < AttributeListSyntax > attributes , bool isMethodBody = false , bool isAccessorBody = false )
6954+ /// <summary>
6955+ /// Used to parse the block-body for a method or accessor. For blocks that appear *inside*
6956+ /// method bodies, call <see cref="ParseBlock"/>.
6957+ /// </summary>
6958+ /// <param name="isAccessorBody">If is true, then we produce a special diagnostic if the
6959+ /// open brace is missing.</param>
6960+ private BlockSyntax ParseMethodOrAccessorBodyBlock ( SyntaxList < AttributeListSyntax > attributes , bool isAccessorBody )
69596961 {
6960- // Check again for incremental re-use, since ParseBlock is called from a bunch of places
6961- // other than ParseStatementCore()
6962+ // Check again for incremental re-use. This way if a method signature is edited we can
6963+ // still quickly re-sync on the body.
69626964 if ( this . IsIncrementalAndFactoryContextMatches &&
69636965 this . CurrentNodeKind == SyntaxKind . Block &&
69646966 attributes . Count == 0 )
6965- {
69666967 return ( BlockSyntax ) this . EatNode ( ) ;
6967- }
69686968
69696969 // There's a special error code for a missing token after an accessor keyword
6970- var openBrace = isAccessorBody && this . CurrentToken . Kind != SyntaxKind . OpenBraceToken
6970+ CSharpSyntaxNode openBrace = isAccessorBody && this . CurrentToken . Kind != SyntaxKind . OpenBraceToken
69716971 ? this . AddError (
69726972 SyntaxFactory . MissingToken ( SyntaxKind . OpenBraceToken ) ,
69736973 IsFeatureEnabled ( MessageID . IDS_FeatureExpressionBodiedAccessor )
6974- ? ErrorCode . ERR_SemiOrLBraceOrArrowExpected
6975- : ErrorCode . ERR_SemiOrLBraceExpected )
6974+ ? ErrorCode . ERR_SemiOrLBraceOrArrowExpected
6975+ : ErrorCode . ERR_SemiOrLBraceExpected )
69766976 : this . EatToken ( SyntaxKind . OpenBraceToken ) ;
69776977
69786978 var statements = _pool . Allocate < StatementSyntax > ( ) ;
6979- try
6980- {
6981- CSharpSyntaxNode tmp = openBrace ;
6982- this . ParseStatements ( ref tmp , statements , stopOnSwitchSections : false ) ;
6983- openBrace = ( SyntaxToken ) tmp ;
6984- var closeBrace = this . EatToken ( SyntaxKind . CloseBraceToken ) ;
6979+ this . ParseStatements ( ref openBrace , statements , stopOnSwitchSections : false ) ;
69856980
6986- SyntaxList < StatementSyntax > statementList ;
6987- if ( isMethodBody && IsLargeEnoughNonEmptyStatementList ( statements ) )
6988- {
6989- // Force creation a many-children list, even if only 1, 2, or 3 elements in the statement list.
6990- statementList = new SyntaxList < StatementSyntax > ( SyntaxList . List ( ( ( SyntaxListBuilder ) statements ) . ToArray ( ) ) ) ;
6991- }
6992- else
6993- {
6994- statementList = statements ;
6995- }
6981+ var block = _syntaxFactory . Block (
6982+ attributes ,
6983+ ( SyntaxToken ) openBrace ,
6984+ // Force creation a many-children list, even if only 1, 2, or 3 elements in the statement list.
6985+ IsLargeEnoughNonEmptyStatementList ( statements )
6986+ ? new SyntaxList < StatementSyntax > ( SyntaxList . List ( ( ( SyntaxListBuilder ) statements ) . ToArray ( ) ) )
6987+ : statements ,
6988+ this . EatToken ( SyntaxKind . CloseBraceToken ) ) ;
69966989
6997- return _syntaxFactory . Block ( attributes , openBrace , statementList , closeBrace ) ;
6998- }
6999- finally
7000- {
7001- _pool . Free ( statements ) ;
7002- }
6990+ _pool . Free ( statements ) ;
6991+ return block ;
6992+ }
6993+
6994+ /// <summary>
6995+ /// Used to parse normal blocks that appear inside method bodies. For the top level block
6996+ /// of a method/accessor use <see cref="ParseMethodOrAccessorBodyBlock"/>.
6997+ /// </summary>
6998+ private BlockSyntax ParseBlock ( SyntaxList < AttributeListSyntax > attributes )
6999+ {
7000+ // Check again for incremental re-use, since ParseBlock is called from a bunch of places
7001+ // other than ParseStatementCore()
7002+ if ( this . IsIncrementalAndFactoryContextMatches && this . CurrentNodeKind == SyntaxKind . Block )
7003+ return ( BlockSyntax ) this . EatNode ( ) ;
7004+
7005+ CSharpSyntaxNode openBrace = this . EatToken ( SyntaxKind . OpenBraceToken ) ;
7006+
7007+ var statements = _pool . Allocate < StatementSyntax > ( ) ;
7008+ this . ParseStatements ( ref openBrace , statements , stopOnSwitchSections : false ) ;
7009+
7010+ var block = _syntaxFactory . Block (
7011+ attributes ,
7012+ ( SyntaxToken ) openBrace ,
7013+ statements ,
7014+ this . EatToken ( SyntaxKind . CloseBraceToken ) ) ;
7015+
7016+ _pool . Free ( statements ) ;
7017+ return block ;
70037018 }
70047019
70057020 // Is this statement list non-empty, and large enough to make using weak children beneficial?
@@ -7703,21 +7718,30 @@ private GotoStatementSyntax ParseGotoStatement(SyntaxList<AttributeListSyntax> a
77037718
77047719 private IfStatementSyntax ParseIfStatement ( SyntaxList < AttributeListSyntax > attributes )
77057720 {
7706- Debug . Assert ( this . CurrentToken . Kind == SyntaxKind . IfKeyword || this . CurrentToken . Kind == SyntaxKind . ElseKeyword ) ;
7721+ Debug . Assert ( this . CurrentToken . Kind == SyntaxKind . IfKeyword ) ;
77077722
7708- bool firstTokenIsElse = this . CurrentToken . Kind == SyntaxKind . ElseKeyword ;
7709- var @if = firstTokenIsElse
7710- ? this . EatToken ( SyntaxKind . IfKeyword , ErrorCode . ERR_ElseCannotStartStatement )
7711- : this . EatToken ( SyntaxKind . IfKeyword ) ;
7712- var openParen = this . EatToken ( SyntaxKind . OpenParenToken ) ;
7713- var condition = this . ParseExpressionCore ( ) ;
7714- var closeParen = this . EatToken ( SyntaxKind . CloseParenToken ) ;
7715- var statement = firstTokenIsElse
7716- ? this . ParseExpressionStatement ( attributes : default )
7717- : this . ParseEmbeddedStatement ( ) ;
7718- var elseClause = this . ParseElseClauseOpt ( ) ;
7723+ return _syntaxFactory . IfStatement (
7724+ attributes ,
7725+ this . EatToken ( SyntaxKind . IfKeyword ) ,
7726+ this . EatToken ( SyntaxKind . OpenParenToken ) ,
7727+ this . ParseExpressionCore ( ) ,
7728+ this . EatToken ( SyntaxKind . CloseParenToken ) ,
7729+ this . ParseEmbeddedStatement ( ) ,
7730+ this . ParseElseClauseOpt ( ) ) ;
7731+ }
77197732
7720- return _syntaxFactory . IfStatement ( attributes , @if , openParen , condition , closeParen , statement , elseClause ) ;
7733+ private IfStatementSyntax ParseMisplacedElse ( SyntaxList < AttributeListSyntax > attributes )
7734+ {
7735+ Debug . Assert ( this . CurrentToken . Kind == SyntaxKind . ElseKeyword ) ;
7736+
7737+ return _syntaxFactory . IfStatement (
7738+ attributes ,
7739+ this . EatToken ( SyntaxKind . IfKeyword , ErrorCode . ERR_ElseCannotStartStatement ) ,
7740+ this . EatToken ( SyntaxKind . OpenParenToken ) ,
7741+ this . ParseExpressionCore ( ) ,
7742+ this . EatToken ( SyntaxKind . CloseParenToken ) ,
7743+ this . ParseExpressionStatement ( attributes : default ) ,
7744+ this . ParseElseClauseOpt ( ) ) ;
77217745 }
77227746
77237747 private ElseClauseSyntax ParseElseClauseOpt ( )
0 commit comments