diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 19b6574e7ba86..57e4eabcdc2dc 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -2450,7 +2450,7 @@ private void ParseBlockAndExpressionBodiesWithSemicolon( if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken) { - blockBody = this.ParseBlock(isMethodBody: true); + blockBody = this.ParseMethodOrAccessorBodyBlock(isAccessorBody: false); } if (this.CurrentToken.Kind == SyntaxKind.EqualsGreaterThanToken) @@ -2477,25 +2477,6 @@ private void ParseBlockAndExpressionBodiesWithSemicolon( } } - private void ParseBodyOrSemicolon(out BlockSyntax body, out SyntaxToken semicolon) - { - if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken) - { - body = this.ParseBlock(isMethodBody: true); - - semicolon = null; - if (this.CurrentToken.Kind == SyntaxKind.SemicolonToken) - { - semicolon = this.EatTokenWithPrejudice(ErrorCode.ERR_UnexpectedSemicolon); - } - } - else - { - semicolon = this.EatToken(SyntaxKind.SemicolonToken); - body = null; - } - } - private bool IsEndOfTypeParameterList() { if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken) @@ -3305,7 +3286,7 @@ private AccessorDeclarationSyntax ParseAccessorDeclaration(bool isEvent) { if (!IsTerminator()) { - blockBody = this.ParseBlock(isMethodBody: true, isAccessorBody: true); + blockBody = this.ParseMethodOrAccessorBodyBlock(isAccessorBody: true); } else { @@ -6941,54 +6922,66 @@ private bool IsPossibleNewExpression() return null; } - // If "isMethodBody" is true, then this is the immediate body of a method/accessor. - // In this case, we create a many-child list if the body is not a small single statement. - // This then allows a "with many weak children" red node when the red node is created. - // If "isAccessorBody" is true, then we produce a special diagnostic if the open brace is - // missing. Also, "isMethodBody" must be true. - private BlockSyntax ParseBlock(bool isMethodBody = false, bool isAccessorBody = false) + /// + /// Used to parse the block-body for a method or accessor. For blocks that appear *inside* + /// method bodies, call . + /// + /// If is true, then we produce a special diagnostic if the + /// open brace is missing. + private BlockSyntax ParseMethodOrAccessorBodyBlock(bool isAccessorBody) { - // Check again for incremental re-use, since ParseBlock is called from a bunch of places - // other than ParseStatementCore() + // Check again for incremental re-use. This way if a method signature is edited we can + // still quickly re-sync on the body. if (this.IsIncrementalAndFactoryContextMatches && this.CurrentNodeKind == SyntaxKind.Block) - { return (BlockSyntax)this.EatNode(); - } // There's a special error code for a missing token after an accessor keyword - var openBrace = isAccessorBody && this.CurrentToken.Kind != SyntaxKind.OpenBraceToken + CSharpSyntaxNode openBrace = isAccessorBody && this.CurrentToken.Kind != SyntaxKind.OpenBraceToken ? this.AddError( SyntaxFactory.MissingToken(SyntaxKind.OpenBraceToken), IsFeatureEnabled(MessageID.IDS_FeatureExpressionBodiedAccessor) - ? ErrorCode.ERR_SemiOrLBraceOrArrowExpected - : ErrorCode.ERR_SemiOrLBraceExpected) + ? ErrorCode.ERR_SemiOrLBraceOrArrowExpected + : ErrorCode.ERR_SemiOrLBraceExpected) : this.EatToken(SyntaxKind.OpenBraceToken); var statements = _pool.Allocate(); - try - { - CSharpSyntaxNode tmp = openBrace; - this.ParseStatements(ref tmp, statements, stopOnSwitchSections: false); - openBrace = (SyntaxToken)tmp; - var closeBrace = this.EatToken(SyntaxKind.CloseBraceToken); + this.ParseStatements(ref openBrace, statements, stopOnSwitchSections: false); - SyntaxList statementList; - if (isMethodBody && IsLargeEnoughNonEmptyStatementList(statements)) - { - // Force creation a many-children list, even if only 1, 2, or 3 elements in the statement list. - statementList = new SyntaxList(SyntaxList.List(((SyntaxListBuilder)statements).ToArray())); - } - else - { - statementList = statements; - } + var block = _syntaxFactory.Block( + (SyntaxToken)openBrace, + // Force creation a many-children list, even if only 1, 2, or 3 elements in the statement list. + IsLargeEnoughNonEmptyStatementList(statements) + ? new SyntaxList(SyntaxList.List(((SyntaxListBuilder)statements).ToArray())) + : statements, + this.EatToken(SyntaxKind.CloseBraceToken)); - return _syntaxFactory.Block(openBrace, statementList, closeBrace); - } - finally - { - _pool.Free(statements); - } + _pool.Free(statements); + return block; + } + + /// + /// Used to parse normal blocks that appear inside method bodies. For the top level block + /// of a method/accessor use . + /// + private BlockSyntax ParseBlock() + { + // Check again for incremental re-use, since ParseBlock is called from a bunch of places + // other than ParseStatementCore() + if (this.IsIncrementalAndFactoryContextMatches && this.CurrentNodeKind == SyntaxKind.Block) + return (BlockSyntax)this.EatNode(); + + CSharpSyntaxNode openBrace = this.EatToken(SyntaxKind.OpenBraceToken); + + var statements = _pool.Allocate(); + this.ParseStatements(ref openBrace, statements, stopOnSwitchSections: false); + + var block = _syntaxFactory.Block( + (SyntaxToken)openBrace, + statements, + this.EatToken(SyntaxKind.CloseBraceToken)); + + _pool.Free(statements); + return block; } // Is this statement list non-empty, and large enough to make using weak children beneficial?