From a803035d82e65a917e76eab24be3ddc06617d26f Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 5 Mar 2020 17:17:15 -0800 Subject: [PATCH 1/4] Add parsing for the with-expression form --- .../Portable/Generated/CSharp.Generated.g4 | 5 + .../Syntax.xml.Internal.Generated.cs | 187 ++++++ .../Generated/Syntax.xml.Main.Generated.cs | 27 + .../Generated/Syntax.xml.Syntax.Generated.cs | 67 +++ .../CSharp/Portable/Parser/LanguageParser.cs | 32 +- .../CSharp/Portable/PublicAPI.Unshipped.txt | 23 + .../CSharp/Portable/Syntax/Syntax.xml | 16 + .../CSharp/Portable/Syntax/SyntaxKind.cs | 3 + .../CSharp/Portable/Syntax/SyntaxKindFacts.cs | 5 + .../DiagnosticAnalyzerTests.AllInOne.cs | 2 + .../Generated/Syntax.Test.xml.Generated.cs | 86 +++ .../Syntax/Parsing/DeclarationParsingTests.cs | 213 ------- .../Test/Syntax/Parsing/ParsingTests.cs | 2 +- .../Test/Syntax/Parsing/RecordParsing.cs | 544 ++++++++++++++++++ .../DiagnosticAnalyzerDriverTests.cs | 2 + 15 files changed, 999 insertions(+), 215 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 47c320aa048e0..0b551bd708154 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -655,6 +655,7 @@ expression | tuple_expression | type | type_of_expression + | with_expression ; anonymous_function_expression @@ -955,6 +956,10 @@ type_of_expression : 'typeof' '(' type ')' ; +with_expression + : expression 'with' '{' (anonymous_object_member_declarator (',' anonymous_object_member_declarator)* ','?)? '}' + ; + xml_node : xml_c_data_section | xml_comment diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs index 69f0ae251a83d..915ef20ec9cde 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs @@ -2180,6 +2180,157 @@ static PostfixUnaryExpressionSyntax() } } + internal sealed partial class WithExpressionSyntax : ExpressionSyntax + { + internal readonly ExpressionSyntax receiver; + internal readonly SyntaxToken withKeyword; + internal readonly SyntaxToken openBraceToken; + internal readonly GreenNode? initializers; + internal readonly SyntaxToken closeBraceToken; + + internal WithExpressionSyntax(SyntaxKind kind, ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, GreenNode? initializers, SyntaxToken closeBraceToken, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 5; + this.AdjustFlagsAndWidth(receiver); + this.receiver = receiver; + this.AdjustFlagsAndWidth(withKeyword); + this.withKeyword = withKeyword; + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + if (initializers != null) + { + this.AdjustFlagsAndWidth(initializers); + this.initializers = initializers; + } + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + + internal WithExpressionSyntax(SyntaxKind kind, ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, GreenNode? initializers, SyntaxToken closeBraceToken, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 5; + this.AdjustFlagsAndWidth(receiver); + this.receiver = receiver; + this.AdjustFlagsAndWidth(withKeyword); + this.withKeyword = withKeyword; + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + if (initializers != null) + { + this.AdjustFlagsAndWidth(initializers); + this.initializers = initializers; + } + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + + internal WithExpressionSyntax(SyntaxKind kind, ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, GreenNode? initializers, SyntaxToken closeBraceToken) + : base(kind) + { + this.SlotCount = 5; + this.AdjustFlagsAndWidth(receiver); + this.receiver = receiver; + this.AdjustFlagsAndWidth(withKeyword); + this.withKeyword = withKeyword; + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + if (initializers != null) + { + this.AdjustFlagsAndWidth(initializers); + this.initializers = initializers; + } + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + + public ExpressionSyntax Receiver => this.receiver; + public SyntaxToken WithKeyword => this.withKeyword; + public SyntaxToken OpenBraceToken => this.openBraceToken; + public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList Initializers => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.initializers)); + public SyntaxToken CloseBraceToken => this.closeBraceToken; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.receiver, + 1 => this.withKeyword, + 2 => this.openBraceToken, + 3 => this.initializers, + 4 => this.closeBraceToken, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.WithExpressionSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitWithExpression(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitWithExpression(this); + + public WithExpressionSyntax Update(ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList initializers, SyntaxToken closeBraceToken) + { + if (receiver != this.Receiver || withKeyword != this.WithKeyword || openBraceToken != this.OpenBraceToken || initializers != this.Initializers || closeBraceToken != this.CloseBraceToken) + { + var newNode = SyntaxFactory.WithExpression(receiver, withKeyword, openBraceToken, initializers, closeBraceToken); + var diags = GetDiagnostics(); + if (diags?.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = GetAnnotations(); + if (annotations?.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; + } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) + => new WithExpressionSyntax(this.Kind, this.receiver, this.withKeyword, this.openBraceToken, this.initializers, this.closeBraceToken, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new WithExpressionSyntax(this.Kind, this.receiver, this.withKeyword, this.openBraceToken, this.initializers, this.closeBraceToken, GetDiagnostics(), annotations); + + internal WithExpressionSyntax(ObjectReader reader) + : base(reader) + { + this.SlotCount = 5; + var receiver = (ExpressionSyntax)reader.ReadValue(); + AdjustFlagsAndWidth(receiver); + this.receiver = receiver; + var withKeyword = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(withKeyword); + this.withKeyword = withKeyword; + var openBraceToken = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + var initializers = (GreenNode?)reader.ReadValue(); + if (initializers != null) + { + AdjustFlagsAndWidth(initializers); + this.initializers = initializers; + } + var closeBraceToken = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + + internal override void WriteTo(ObjectWriter writer) + { + base.WriteTo(writer); + writer.WriteValue(this.receiver); + writer.WriteValue(this.withKeyword); + writer.WriteValue(this.openBraceToken); + writer.WriteValue(this.initializers); + writer.WriteValue(this.closeBraceToken); + } + + static WithExpressionSyntax() + { + ObjectBinder.RegisterTypeReader(typeof(WithExpressionSyntax), r => new WithExpressionSyntax(r)); + } + } + /// Class which represents the syntax node for member access expression. internal sealed partial class MemberAccessExpressionSyntax : ExpressionSyntax { @@ -30973,6 +31124,7 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitAwaitExpression(AwaitExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitWithExpression(WithExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitMemberAccessExpression(MemberAccessExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitConditionalAccessExpression(ConditionalAccessExpressionSyntax node) => this.DefaultVisit(node); public virtual TResult VisitMemberBindingExpression(MemberBindingExpressionSyntax node) => this.DefaultVisit(node); @@ -31192,6 +31344,7 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitPrefixUnaryExpression(PrefixUnaryExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitAwaitExpression(AwaitExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) => this.DefaultVisit(node); + public virtual void VisitWithExpression(WithExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitMemberAccessExpression(MemberAccessExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitConditionalAccessExpression(ConditionalAccessExpressionSyntax node) => this.DefaultVisit(node); public virtual void VisitMemberBindingExpression(MemberBindingExpressionSyntax node) => this.DefaultVisit(node); @@ -31449,6 +31602,9 @@ public override CSharpSyntaxNode VisitAwaitExpression(AwaitExpressionSyntax node public override CSharpSyntaxNode VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) => node.Update((ExpressionSyntax)Visit(node.Operand), (SyntaxToken)Visit(node.OperatorToken)); + public override CSharpSyntaxNode VisitWithExpression(WithExpressionSyntax node) + => node.Update((ExpressionSyntax)Visit(node.Receiver), (SyntaxToken)Visit(node.WithKeyword), (SyntaxToken)Visit(node.OpenBraceToken), VisitList(node.Initializers), (SyntaxToken)Visit(node.CloseBraceToken)); + public override CSharpSyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) => node.Update((ExpressionSyntax)Visit(node.Expression), (SyntaxToken)Visit(node.OperatorToken), (SimpleNameSyntax)Visit(node.Name)); @@ -32525,6 +32681,21 @@ public PostfixUnaryExpressionSyntax PostfixUnaryExpression(SyntaxKind kind, Expr return result; } + public WithExpressionSyntax WithExpression(ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList initializers, SyntaxToken closeBraceToken) + { + #if DEBUG + if (receiver == null) throw new ArgumentNullException(nameof(receiver)); + if (withKeyword == null) throw new ArgumentNullException(nameof(withKeyword)); + if (withKeyword.Kind != SyntaxKind.WithKeyword) throw new ArgumentException(nameof(withKeyword)); + if (openBraceToken == null) throw new ArgumentNullException(nameof(openBraceToken)); + if (openBraceToken.Kind != SyntaxKind.OpenBraceToken) throw new ArgumentException(nameof(openBraceToken)); + if (closeBraceToken == null) throw new ArgumentNullException(nameof(closeBraceToken)); + if (closeBraceToken.Kind != SyntaxKind.CloseBraceToken) throw new ArgumentException(nameof(closeBraceToken)); + #endif + + return new WithExpressionSyntax(SyntaxKind.WithExpression, receiver, withKeyword, openBraceToken, initializers.Node, closeBraceToken, this.context); + } + public MemberAccessExpressionSyntax MemberAccessExpression(SyntaxKind kind, ExpressionSyntax expression, SyntaxToken operatorToken, SimpleNameSyntax name) { switch (kind) @@ -37077,6 +37248,21 @@ public static PostfixUnaryExpressionSyntax PostfixUnaryExpression(SyntaxKind kin return result; } + public static WithExpressionSyntax WithExpression(ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList initializers, SyntaxToken closeBraceToken) + { + #if DEBUG + if (receiver == null) throw new ArgumentNullException(nameof(receiver)); + if (withKeyword == null) throw new ArgumentNullException(nameof(withKeyword)); + if (withKeyword.Kind != SyntaxKind.WithKeyword) throw new ArgumentException(nameof(withKeyword)); + if (openBraceToken == null) throw new ArgumentNullException(nameof(openBraceToken)); + if (openBraceToken.Kind != SyntaxKind.OpenBraceToken) throw new ArgumentException(nameof(openBraceToken)); + if (closeBraceToken == null) throw new ArgumentNullException(nameof(closeBraceToken)); + if (closeBraceToken.Kind != SyntaxKind.CloseBraceToken) throw new ArgumentException(nameof(closeBraceToken)); + #endif + + return new WithExpressionSyntax(SyntaxKind.WithExpression, receiver, withKeyword, openBraceToken, initializers.Node, closeBraceToken); + } + public static MemberAccessExpressionSyntax MemberAccessExpression(SyntaxKind kind, ExpressionSyntax expression, SyntaxToken operatorToken, SimpleNameSyntax name) { switch (kind) @@ -41168,6 +41354,7 @@ internal static IEnumerable GetNodeTypes() typeof(PrefixUnaryExpressionSyntax), typeof(AwaitExpressionSyntax), typeof(PostfixUnaryExpressionSyntax), + typeof(WithExpressionSyntax), typeof(MemberAccessExpressionSyntax), typeof(ConditionalAccessExpressionSyntax), typeof(MemberBindingExpressionSyntax), diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs index b00580bd8bf66..f2d622370ac50 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs @@ -70,6 +70,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a PostfixUnaryExpressionSyntax node. public virtual TResult VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a WithExpressionSyntax node. + public virtual TResult VisitWithExpression(WithExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a MemberAccessExpressionSyntax node. public virtual TResult VisitMemberAccessExpression(MemberAccessExpressionSyntax node) => this.DefaultVisit(node); @@ -718,6 +721,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a PostfixUnaryExpressionSyntax node. public virtual void VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a WithExpressionSyntax node. + public virtual void VisitWithExpression(WithExpressionSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a MemberAccessExpressionSyntax node. public virtual void VisitMemberAccessExpression(MemberAccessExpressionSyntax node) => this.DefaultVisit(node); @@ -1366,6 +1372,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor public override SyntaxNode? VisitPostfixUnaryExpression(PostfixUnaryExpressionSyntax node) => node.Update((ExpressionSyntax?)Visit(node.Operand) ?? throw new ArgumentNullException("operand"), VisitToken(node.OperatorToken)); + public override SyntaxNode? VisitWithExpression(WithExpressionSyntax node) + => node.Update((ExpressionSyntax?)Visit(node.Receiver) ?? throw new ArgumentNullException("receiver"), VisitToken(node.WithKeyword), VisitToken(node.OpenBraceToken), VisitList(node.Initializers), VisitToken(node.CloseBraceToken)); + public override SyntaxNode? VisitMemberAccessExpression(MemberAccessExpressionSyntax node) => node.Update((ExpressionSyntax?)Visit(node.Expression) ?? throw new ArgumentNullException("expression"), VisitToken(node.OperatorToken), (SimpleNameSyntax?)Visit(node.Name) ?? throw new ArgumentNullException("name")); @@ -2281,6 +2290,24 @@ private static SyntaxKind GetPostfixUnaryExpressionOperatorTokenKind(SyntaxKind _ => throw new ArgumentOutOfRangeException(), }; + /// Creates a new WithExpressionSyntax instance. + public static WithExpressionSyntax WithExpression(ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, SeparatedSyntaxList initializers, SyntaxToken closeBraceToken) + { + if (receiver == null) throw new ArgumentNullException(nameof(receiver)); + if (withKeyword.Kind() != SyntaxKind.WithKeyword) throw new ArgumentException(nameof(withKeyword)); + if (openBraceToken.Kind() != SyntaxKind.OpenBraceToken) throw new ArgumentException(nameof(openBraceToken)); + if (closeBraceToken.Kind() != SyntaxKind.CloseBraceToken) throw new ArgumentException(nameof(closeBraceToken)); + return (WithExpressionSyntax)Syntax.InternalSyntax.SyntaxFactory.WithExpression((Syntax.InternalSyntax.ExpressionSyntax)receiver.Green, (Syntax.InternalSyntax.SyntaxToken)withKeyword.Node!, (Syntax.InternalSyntax.SyntaxToken)openBraceToken.Node!, initializers.Node.ToGreenSeparatedList(), (Syntax.InternalSyntax.SyntaxToken)closeBraceToken.Node!).CreateRed(); + } + + /// Creates a new WithExpressionSyntax instance. + public static WithExpressionSyntax WithExpression(ExpressionSyntax receiver, SeparatedSyntaxList initializers) + => SyntaxFactory.WithExpression(receiver, SyntaxFactory.Token(SyntaxKind.WithKeyword), SyntaxFactory.Token(SyntaxKind.OpenBraceToken), initializers, SyntaxFactory.Token(SyntaxKind.CloseBraceToken)); + + /// Creates a new WithExpressionSyntax instance. + public static WithExpressionSyntax WithExpression(ExpressionSyntax receiver) + => SyntaxFactory.WithExpression(receiver, SyntaxFactory.Token(SyntaxKind.WithKeyword), SyntaxFactory.Token(SyntaxKind.OpenBraceToken), default, SyntaxFactory.Token(SyntaxKind.CloseBraceToken)); + /// Creates a new MemberAccessExpressionSyntax instance. public static MemberAccessExpressionSyntax MemberAccessExpression(SyntaxKind kind, ExpressionSyntax expression, SyntaxToken operatorToken, SimpleNameSyntax name) { diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs index 59db5c854a649..8fdbd56632232 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs @@ -893,6 +893,73 @@ public PostfixUnaryExpressionSyntax Update(ExpressionSyntax operand, SyntaxToken public PostfixUnaryExpressionSyntax WithOperatorToken(SyntaxToken operatorToken) => Update(this.Operand, operatorToken); } + public sealed partial class WithExpressionSyntax : ExpressionSyntax + { + private ExpressionSyntax? receiver; + private SyntaxNode? initializers; + + internal WithExpressionSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + public ExpressionSyntax Receiver => GetRedAtZero(ref this.receiver)!; + + public SyntaxToken WithKeyword => new SyntaxToken(this, ((Syntax.InternalSyntax.WithExpressionSyntax)this.Green).withKeyword, GetChildPosition(1), GetChildIndex(1)); + + public SyntaxToken OpenBraceToken => new SyntaxToken(this, ((Syntax.InternalSyntax.WithExpressionSyntax)this.Green).openBraceToken, GetChildPosition(2), GetChildIndex(2)); + + public SeparatedSyntaxList Initializers + { + get + { + var red = GetRed(ref this.initializers, 3); + return red != null ? new SeparatedSyntaxList(red, GetChildIndex(3)) : default; + } + } + + public SyntaxToken CloseBraceToken => new SyntaxToken(this, ((Syntax.InternalSyntax.WithExpressionSyntax)this.Green).closeBraceToken, GetChildPosition(4), GetChildIndex(4)); + + internal override SyntaxNode? GetNodeSlot(int index) + => index switch + { + 0 => GetRedAtZero(ref this.receiver)!, + 3 => GetRed(ref this.initializers, 3)!, + _ => null, + }; + + internal override SyntaxNode? GetCachedSlot(int index) + => index switch + { + 0 => this.receiver, + 3 => this.initializers, + _ => null, + }; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitWithExpression(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitWithExpression(this); + + public WithExpressionSyntax Update(ExpressionSyntax receiver, SyntaxToken withKeyword, SyntaxToken openBraceToken, SeparatedSyntaxList initializers, SyntaxToken closeBraceToken) + { + if (receiver != this.Receiver || withKeyword != this.WithKeyword || openBraceToken != this.OpenBraceToken || initializers != this.Initializers || closeBraceToken != this.CloseBraceToken) + { + var newNode = SyntaxFactory.WithExpression(receiver, withKeyword, openBraceToken, initializers, closeBraceToken); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + public WithExpressionSyntax WithReceiver(ExpressionSyntax receiver) => Update(receiver, this.WithKeyword, this.OpenBraceToken, this.Initializers, this.CloseBraceToken); + public WithExpressionSyntax WithWithKeyword(SyntaxToken withKeyword) => Update(this.Receiver, withKeyword, this.OpenBraceToken, this.Initializers, this.CloseBraceToken); + public WithExpressionSyntax WithOpenBraceToken(SyntaxToken openBraceToken) => Update(this.Receiver, this.WithKeyword, openBraceToken, this.Initializers, this.CloseBraceToken); + public WithExpressionSyntax WithInitializers(SeparatedSyntaxList initializers) => Update(this.Receiver, this.WithKeyword, this.OpenBraceToken, initializers, this.CloseBraceToken); + public WithExpressionSyntax WithCloseBraceToken(SyntaxToken closeBraceToken) => Update(this.Receiver, this.WithKeyword, this.OpenBraceToken, this.Initializers, closeBraceToken); + + public WithExpressionSyntax AddInitializers(params AnonymousObjectMemberDeclaratorSyntax[] items) => WithInitializers(this.Initializers.AddRange(items)); + } + /// Class which represents the syntax node for member access expression. public sealed partial class MemberAccessExpressionSyntax : ExpressionSyntax { diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index a0cde627a8ecf..dd0148e53989b 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -8892,6 +8892,8 @@ private static Precedence GetPrecedence(SyntaxKind op) case SyntaxKind.ThisExpression: case SyntaxKind.TrueLiteralExpression: case SyntaxKind.TupleExpression: + // PROTOTYPE: Is this the right precedence? + case SyntaxKind.WithExpression: return Precedence.Primary; default: throw ExceptionUtilities.UnexpectedValue(op); @@ -8931,9 +8933,11 @@ private bool IsAwaitExpression() // If we see an await followed by a token that cannot follow an identifier, parse await as a unop. // BindAwait() catches the cases where await successfully parses as a unop but is not in an async // function, and reports an appropriate ERR_BadAwaitWithoutAsync* error. - switch (this.PeekToken(1).Kind) + var next = PeekToken(1); + switch (next.Kind) { case SyntaxKind.IdentifierToken: + return next.ContextualKind != SyntaxKind.WithKeyword; // Keywords case SyntaxKind.NewKeyword: @@ -9091,6 +9095,10 @@ private ExpressionSyntax ParseExpressionContinued(ExpressionSyntax leftOperand, { opKind = SyntaxKind.SwitchExpression; } + else if (tk == SyntaxKind.WithKeyword && this.PeekToken(1).Kind == SyntaxKind.OpenBraceToken) + { + opKind = SyntaxKind.WithExpression; + } else { break; @@ -9189,6 +9197,10 @@ private ExpressionSyntax ParseExpressionContinued(ExpressionSyntax leftOperand, { leftOperand = ParseSwitchExpression(leftOperand, opToken); } + else if (opKind == SyntaxKind.WithExpression) + { + leftOperand = ParseWithExpression(leftOperand, opToken); + } else if (tk == SyntaxKind.DotDotToken) { // Operator ".." here can either be a binary or a postfix unary operator: @@ -10405,6 +10417,24 @@ private AnonymousObjectCreationExpressionSyntax ParseAnonymousTypeExpression() return result; } + private ExpressionSyntax ParseWithExpression(ExpressionSyntax receiverExpression, SyntaxToken withKeyword) + { + var openBrace = this.EatToken(SyntaxKind.OpenBraceToken); + var expressions = _pool.AllocateSeparated(); + this.ParseAnonymousTypeMemberInitializers(ref openBrace, ref expressions); + var closeBrace = this.EatToken(SyntaxKind.CloseBraceToken); + withKeyword = CheckFeatureAvailability(withKeyword, MessageID.IDS_FeatureRecords); + var result = _syntaxFactory.WithExpression( + receiverExpression, + withKeyword, + openBrace, + expressions, + closeBrace); + _pool.Free(expressions); + + return result; + } + private void ParseAnonymousTypeMemberInitializers(ref SyntaxToken openBrace, ref SeparatedSyntaxListBuilder list) { if (this.CurrentToken.Kind != SyntaxKind.CloseBraceToken) diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 0f3e403dc553a..8370599d9d85f 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -107,6 +107,19 @@ Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.AddParameterListPar Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax baseList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.StructDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.AddInitializers(params Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousObjectMemberDeclaratorSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.CloseBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.Initializers.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.OpenBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.Receiver.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.Update(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax receiver, Microsoft.CodeAnalysis.SyntaxToken withKeyword, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SeparatedSyntaxList initializers, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.WithInitializers(Microsoft.CodeAnalysis.SeparatedSyntaxList initializers) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.WithKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.WithOpenBraceToken(Microsoft.CodeAnalysis.SyntaxToken openBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.WithReceiver(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax receiver) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.WithWithKeyword(Microsoft.CodeAnalysis.SyntaxToken withKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax Microsoft.CodeAnalysis.CSharp.SyntaxKind.DataKeyword = 8438 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax @@ -133,9 +146,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.WhileStatementSyntax.WithAttributeLists(Mic Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxToken yieldKeyword, Microsoft.CodeAnalysis.SyntaxToken returnOrBreakKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax +Microsoft.CodeAnalysis.CSharp.SyntaxKind.WithExpression = 9060 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.WithKeyword = 8439 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax abstract Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitWithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList @@ -166,6 +182,8 @@ override Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax.AttributeLists. override Microsoft.CodeAnalysis.CSharp.Syntax.UnsafeStatementSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.UsingStatementSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList override Microsoft.CodeAnalysis.CSharp.Syntax.WhileStatementSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options = null, string path = "", System.Text.Encoding encoding = null, System.Collections.Immutable.ImmutableDictionary diagnosticOptions = null, bool? isGeneratedCode = null) -> Microsoft.CodeAnalysis.SyntaxTree static Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.Create(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode root, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options, string path, System.Text.Encoding encoding, System.Collections.Immutable.ImmutableDictionary diagnosticOptions) -> Microsoft.CodeAnalysis.SyntaxTree @@ -233,5 +251,10 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingStatement(Microsoft.Code static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UsingStatement(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxToken awaitKeyword, Microsoft.CodeAnalysis.SyntaxToken usingKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax declaration, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.UsingStatementSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WhileStatement(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax condition, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.WhileStatementSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WhileStatement(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxToken whileKeyword, Microsoft.CodeAnalysis.SyntaxToken openParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax condition, Microsoft.CodeAnalysis.SyntaxToken closeParenToken, Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax statement) -> Microsoft.CodeAnalysis.CSharp.Syntax.WhileStatementSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax receiver) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax receiver, Microsoft.CodeAnalysis.SeparatedSyntaxList initializers) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax receiver, Microsoft.CodeAnalysis.SyntaxToken withKeyword, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SeparatedSyntaxList initializers, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.YieldStatement(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.YieldStatement(Microsoft.CodeAnalysis.CSharp.SyntaxKind kind, Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxToken yieldKeyword, Microsoft.CodeAnalysis.SyntaxToken returnOrBreakKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.YieldStatementSyntax +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitWithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitWithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.WithExpressionSyntax node) -> TResult diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index afeb5a7932042..dc64174105f47 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -451,6 +451,22 @@ Creates a PostfixUnaryExpressionSyntax node. + + + + + + + + + + + + + + + + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index e9c1b4148369e..6825c5a837975 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -197,6 +197,7 @@ public enum SyntaxKind : ushort AwaitKeyword = 8436, WhenKeyword = 8437, DataKeyword = 8438, + WithKeyword = 8439, /// when adding a contextual keyword following functions must be adapted: /// /// @@ -597,5 +598,7 @@ public enum SyntaxKind : ushort ImplicitStackAllocArrayCreationExpression = 9053, SuppressNullableWarningExpression = 9054, NullableDirectiveTrivia = 9055, + + WithExpression = 9060, } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index 0379cf4a99cb6..e28846760a3a6 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1109,6 +1109,7 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.UnderscoreToken: case SyntaxKind.VarKeyword: case SyntaxKind.DataKeyword: + case SyntaxKind.WithKeyword: return true; default: return false; @@ -1214,6 +1215,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.VarKeyword; case "data": return SyntaxKind.DataKeyword; + case "with": + return SyntaxKind.WithKeyword; default: return SyntaxKind.None; } @@ -1635,6 +1638,8 @@ public static string GetText(SyntaxKind kind) return "var"; case SyntaxKind.DataKeyword: return "data"; + case SyntaxKind.WithKeyword: + return "with"; default: return string.Empty; } diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs index faa7f816905ba..2a56dadcb477a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs @@ -28,6 +28,8 @@ public void DiagnosticAnalyzerAllInOne() // Add nodes that are not yet in AllInOneCSharpCode to this list. var missingSyntaxKinds = new HashSet(); + // PROTOTYPE: Add to all in one + missingSyntaxKinds.Add(SyntaxKind.WithExpression); var analyzer = new CSharpTrackingDiagnosticAnalyzer(); CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { analyzer }); diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index aa628386388ee..89cff17e90e5e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -67,6 +67,9 @@ private static Syntax.InternalSyntax.AwaitExpressionSyntax GenerateAwaitExpressi private static Syntax.InternalSyntax.PostfixUnaryExpressionSyntax GeneratePostfixUnaryExpression() => InternalSyntaxFactory.PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.PlusPlusToken)); + private static Syntax.InternalSyntax.WithExpressionSyntax GenerateWithExpression() + => InternalSyntaxFactory.WithExpression(GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.WithKeyword), InternalSyntaxFactory.Token(SyntaxKind.OpenBraceToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.CloseBraceToken)); + private static Syntax.InternalSyntax.MemberAccessExpressionSyntax GenerateMemberAccessExpression() => InternalSyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.DotToken), GenerateIdentifierName()); @@ -871,6 +874,20 @@ public void TestPostfixUnaryExpressionFactoryAndProperties() AttachAndCheckDiagnostics(node); } + [Fact] + public void TestWithExpressionFactoryAndProperties() + { + var node = GenerateWithExpression(); + + Assert.NotNull(node.Receiver); + Assert.Equal(SyntaxKind.WithKeyword, node.WithKeyword.Kind); + Assert.Equal(SyntaxKind.OpenBraceToken, node.OpenBraceToken.Kind); + Assert.Equal(default, node.Initializers); + Assert.Equal(SyntaxKind.CloseBraceToken, node.CloseBraceToken.Kind); + + AttachAndCheckDiagnostics(node); + } + [Fact] public void TestMemberAccessExpressionFactoryAndProperties() { @@ -3918,6 +3935,32 @@ public void TestPostfixUnaryExpressionIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestWithExpressionTokenDeleteRewriter() + { + var oldNode = GenerateWithExpression(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestWithExpressionIdentityRewriter() + { + var oldNode = GenerateWithExpression(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestMemberAccessExpressionTokenDeleteRewriter() { @@ -9076,6 +9119,9 @@ private static AwaitExpressionSyntax GenerateAwaitExpression() private static PostfixUnaryExpressionSyntax GeneratePostfixUnaryExpression() => SyntaxFactory.PostfixUnaryExpression(SyntaxKind.PostIncrementExpression, GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.PlusPlusToken)); + private static WithExpressionSyntax GenerateWithExpression() + => SyntaxFactory.WithExpression(GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.WithKeyword), SyntaxFactory.Token(SyntaxKind.OpenBraceToken), new SeparatedSyntaxList(), SyntaxFactory.Token(SyntaxKind.CloseBraceToken)); + private static MemberAccessExpressionSyntax GenerateMemberAccessExpression() => SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.DotToken), GenerateIdentifierName()); @@ -9880,6 +9926,20 @@ public void TestPostfixUnaryExpressionFactoryAndProperties() Assert.Equal(node, newNode); } + [Fact] + public void TestWithExpressionFactoryAndProperties() + { + var node = GenerateWithExpression(); + + Assert.NotNull(node.Receiver); + Assert.Equal(SyntaxKind.WithKeyword, node.WithKeyword.Kind()); + Assert.Equal(SyntaxKind.OpenBraceToken, node.OpenBraceToken.Kind()); + Assert.Equal(default, node.Initializers); + Assert.Equal(SyntaxKind.CloseBraceToken, node.CloseBraceToken.Kind()); + var newNode = node.WithReceiver(node.Receiver).WithWithKeyword(node.WithKeyword).WithOpenBraceToken(node.OpenBraceToken).WithInitializers(node.Initializers).WithCloseBraceToken(node.CloseBraceToken); + Assert.Equal(node, newNode); + } + [Fact] public void TestMemberAccessExpressionFactoryAndProperties() { @@ -12927,6 +12987,32 @@ public void TestPostfixUnaryExpressionIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestWithExpressionTokenDeleteRewriter() + { + var oldNode = GenerateWithExpression(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestWithExpressionIdentityRewriter() + { + var oldNode = GenerateWithExpression(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestMemberAccessExpressionTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index b7a8c45765852..31bbbf02c96c5 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -23,219 +23,6 @@ protected override SyntaxTree ParseTree(string text, CSharpParseOptions options) return SyntaxFactory.ParseSyntaxTree(text, options ?? TestOptions.Regular); } - [Fact] - public void RecordParsing01() - { - var text = "data class C(int X, int Y);"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.DataKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "X"); - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "Y"); - } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing02() - { - var text = "class C(int X, int Y);"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "X"); - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "Y"); - } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing03() - { - var text = "data class C;"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.DataKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing04() - { - var text = "class C { public int data; }"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.FieldDeclaration); - { - N(SyntaxKind.PublicKeyword); - N(SyntaxKind.VariableDeclaration); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "data"); - } - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.CloseBraceToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing05() - { - var tree = ParseTree("class Point;", options: null); - tree.GetDiagnostics().Verify( - // (1,12): error CS8652: The feature 'records' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - // class Point; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ";").WithArguments("records").WithLocation(1, 12) - ); - - UsingNode((CSharpSyntaxNode)tree.GetRoot()); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "Point"); - N(SyntaxKind.SemicolonToken); - } - N(SyntaxKind.EndOfFileToken); - } - EOF(); - } - - [Fact] - public void RecordParsing06() - { - var tree = ParseTree("interface P;", options: null); - tree.GetDiagnostics().Verify( - // (1,12): error CS1514: { expected - // interface P; - Diagnostic(ErrorCode.ERR_LbraceExpected, ";").WithLocation(1, 12), - // (1,12): error CS1513: } expected - // interface P; - Diagnostic(ErrorCode.ERR_RbraceExpected, ";").WithLocation(1, 12) - ); - - UsingNode((CSharpSyntaxNode)tree.GetRoot()); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.InterfaceDeclaration); - { - N(SyntaxKind.InterfaceKeyword); - N(SyntaxKind.IdentifierToken, "P"); - M(SyntaxKind.OpenBraceToken); - M(SyntaxKind.CloseBraceToken); - N(SyntaxKind.SemicolonToken); - } - N(SyntaxKind.EndOfFileToken); - } - EOF(); - } - - [Fact] - public void RecordParsing07() - { - var tree = ParseTree("interface P(int x, int y);", options: null); - tree.GetDiagnostics().Verify( - // (1,12): error CS1514: { expected - // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(1, 12), - // (1,12): error CS1513: } expected - // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(1, 12), - // (1,25): error CS0116: A namespace cannot directly contain members such as fields or methods - // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_NamespaceUnexpected, ")").WithLocation(1, 25), - // (1,26): error CS1022: Type or namespace definition, or end-of-file expected - // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(1, 26) - ); - } [Fact] public void TestExternAlias() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index a23aea8864af9..97e74e0a6cf66 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -123,7 +123,7 @@ internal void UsingExpression(string text, ParseOptions? options, params Diagnos UsingNode(text, SyntaxFactory.ParseExpression(text, options: options), expectedErrors); } - private void UsingNode(string text, CSharpSyntaxNode node, DiagnosticDescription[] expectedErrors) + protected void UsingNode(string text, CSharpSyntaxNode node, DiagnosticDescription[] expectedErrors) { // we validate the text roundtrips Assert.Equal(text, node.ToFullString()); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs new file mode 100644 index 0000000000000..cd8bbed70619a --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -0,0 +1,544 @@ +// 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 enable + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public sealed class RecordParsingTests : ParsingTests + { + private SyntaxTree UsingTree(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedErrors) + { + var tree = SyntaxFactory.ParseSyntaxTree(text, options); + UsingNode(text, tree.GetCompilationUnitRoot(), expectedErrors); + return tree; + } + + private SyntaxTree UsingTree(string text, params DiagnosticDescription[] expectedErrors) + => UsingTree(text, TestOptions.RegularPreview, expectedErrors); + + private new void UsingExpression(string text, params DiagnosticDescription[] expectedErrors) + => UsingExpression(text, TestOptions.RegularPreview, expectedErrors); + + public RecordParsingTests(ITestOutputHelper output) : base(output) { } + + [Fact] + public void WithParsingLangVer() + { + var text = @" +class C +{ + int x = 0 with {}; +}"; + var tree = SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Regular8); + tree.GetDiagnostics().Verify( + // (4,15): error CS8652: The feature 'records' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // int x = 0 with {}; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "with").WithArguments("records").WithLocation(4, 15) + ); + } + + [Fact] + public void WithParsing1() + { + var text = @" +class C +{ + with { }; + x with { }; + int x = with { }; + int x = 0 with { }; +}"; + UsingTree(text, + // (4,10): error CS1519: Invalid token '{' in class, struct, or interface member declaration + // with { }; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(4, 10), + // (4,10): error CS1519: Invalid token '{' in class, struct, or interface member declaration + // with { }; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(4, 10), + // (5,15): error CS1597: Semicolon after method or accessor block is not valid + // x with { }; + Diagnostic(ErrorCode.ERR_UnexpectedSemicolon, ";").WithLocation(5, 15), + // (6,18): error CS1002: ; expected + // int x = with { }; + Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(6, 18), + // (6,18): error CS1022: Type or namespace definition, or end-of-file expected + // int x = with { }; + Diagnostic(ErrorCode.ERR_EOFExpected, "{").WithLocation(6, 18), + // (6,20): error CS1022: Type or namespace definition, or end-of-file expected + // int x = with { }; + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(6, 20), + // (6,21): error CS1022: Type or namespace definition, or end-of-file expected + // int x = with { }; + Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(6, 21), + // (8,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(8, 1) + ); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "with"); + } + } + N(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IdentifierToken, "with"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "with"); + } + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithParsing2() + { + var text = @" +class C +{ + int M() + { + int x = M() with { } + 3; + } +}"; + UsingTree(text); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.AddExpression); + { + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.PlusToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "3"); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithParsing3() + { + var text = "0 with {"; + + UsingExpression(text, + // (1,9): error CS1513: } expected + // 0 with { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 9) + ); + + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing4() + { + var text = "0 with { X"; + + UsingExpression(text, + // (1,11): error CS1513: } expected + // 0 with { X + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 11) + ); + + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AnonymousObjectMemberDeclarator); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + M(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing5() + { + var text = "0 with { X 3 =,"; + + UsingExpression(text, + // (1,12): error CS1003: Syntax error, ',' expected + // 0 with { X 3 =, + Diagnostic(ErrorCode.ERR_SyntaxError, "3").WithArguments(",", "").WithLocation(1, 12), + // (1,15): error CS1525: Invalid expression term ',' + // 0 with { X 3 =, + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ",").WithArguments(",").WithLocation(1, 15), + // (1,16): error CS1513: } expected + // 0 with { X 3 =, + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 16) + ); + + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AnonymousObjectMemberDeclarator); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.AnonymousObjectMemberDeclarator); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "3"); + } + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing6() + { + var text = @"M() with { } switch { }"; + + UsingExpression(text); + + N(SyntaxKind.SwitchExpression); + { + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing7() + { + var text = @"M() with { } + 3"; + + UsingExpression(text); + + N(SyntaxKind.AddExpression); + { + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.PlusToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "3"); + } + } + EOF(); + } + + [Fact] + public void WithParsing8() + { + var text = @"M() with { }.ToString()"; + + UsingExpression(text, + // (1,1): error CS1073: Unexpected token '.' + // M() with { }.ToString() + Diagnostic(ErrorCode.ERR_UnexpectedToken, "M() with { }").WithArguments(".").WithLocation(1, 1) + ); + + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing9() + { + var text = @"M() with { } with { }"; + + UsingExpression(text); + + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing10() + { + UsingStatement("int x = await with { };", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + } +} \ No newline at end of file diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index 126fc0c775227..26bf2d10c93ec 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -34,6 +34,8 @@ public async Task DiagnosticAnalyzerDriverAllInOne() symbolKindsWithNoCodeBlocks.Add(SymbolKind.NamedType); var missingSyntaxNodes = new HashSet(); + // PROTOTYPE: Add to all in one + missingSyntaxNodes.Add(SyntaxKind.WithExpression); var analyzer = new CSharpTrackingDiagnosticAnalyzer(); using var workspace = TestWorkspace.CreateCSharp(source, TestOptions.Regular); From 0a11e25781b2e43306d56adfb7c9839f12f8b753 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 10 Mar 2020 16:20:05 -0700 Subject: [PATCH 2/4] Respond to PR comments --- .../CSharp/Portable/Parser/LanguageParser.cs | 4 +- .../Test/Syntax/Parsing/RecordParsing.cs | 343 ++++++++++++++++++ 2 files changed, 345 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index dd0148e53989b..bf2e4d29933d8 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -8821,6 +8821,8 @@ private static Precedence GetPrecedence(SyntaxKind op) case SyntaxKind.IsPatternExpression: return Precedence.Relational; case SyntaxKind.SwitchExpression: + // PROTOTYPE: Is this the right precedence? + case SyntaxKind.WithExpression: return Precedence.Switch; case SyntaxKind.LeftShiftExpression: case SyntaxKind.RightShiftExpression: @@ -8892,8 +8894,6 @@ private static Precedence GetPrecedence(SyntaxKind op) case SyntaxKind.ThisExpression: case SyntaxKind.TrueLiteralExpression: case SyntaxKind.TupleExpression: - // PROTOTYPE: Is this the right precedence? - case SyntaxKind.WithExpression: return Precedence.Primary; default: throw ExceptionUtilities.UnexpectedValue(op); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index cd8bbed70619a..8f7c83998e1fe 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -29,6 +29,220 @@ private SyntaxTree UsingTree(string text, params DiagnosticDescription[] expecte public RecordParsingTests(ITestOutputHelper output) : base(output) { } + [Fact] + public void RecordParsing01() + { + var text = "data class C(int X, int Y);"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.DataKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing02() + { + var text = "class C(int X, int Y);"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing03() + { + var text = "data class C;"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.DataKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing04() + { + var text = "class C { public int data; }"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "data"); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing05() + { + var tree = ParseTree("class Point;", options: null); + tree.GetDiagnostics().Verify( + // (1,12): error CS8652: The feature 'records' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // class Point; + Diagnostic(ErrorCode.ERR_FeatureInPreview, ";").WithArguments("records").WithLocation(1, 12) + ); + + UsingNode((CSharpSyntaxNode)tree.GetRoot()); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Point"); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void RecordParsing06() + { + var tree = ParseTree("interface P;", options: null); + tree.GetDiagnostics().Verify( + // (1,12): error CS1514: { expected + // interface P; + Diagnostic(ErrorCode.ERR_LbraceExpected, ";").WithLocation(1, 12), + // (1,12): error CS1513: } expected + // interface P; + Diagnostic(ErrorCode.ERR_RbraceExpected, ";").WithLocation(1, 12) + ); + + UsingNode((CSharpSyntaxNode)tree.GetRoot()); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.InterfaceDeclaration); + { + N(SyntaxKind.InterfaceKeyword); + N(SyntaxKind.IdentifierToken, "P"); + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void RecordParsing07() + { + var tree = ParseTree("interface P(int x, int y);", options: null); + tree.GetDiagnostics().Verify( + // (1,12): error CS1514: { expected + // interface P(int x, int y); + Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(1, 12), + // (1,12): error CS1513: } expected + // interface P(int x, int y); + Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(1, 12), + // (1,25): error CS0116: A namespace cannot directly contain members such as fields or methods + // interface P(int x, int y); + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, ")").WithLocation(1, 25), + // (1,26): error CS1022: Type or namespace definition, or end-of-file expected + // interface P(int x, int y); + Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(1, 26) + ); + } + [Fact] public void WithParsingLangVer() { @@ -540,5 +754,134 @@ public void WithParsing10() } EOF(); } + + [Fact] + public void WithParsing11() + { + UsingStatement("await with;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "with"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void WithParsing12() + { + var text = @"M() switch { } with { }"; + + UsingExpression(text); + + N(SyntaxKind.SwitchExpression); + { + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void WithParsing13() + { + var text = @"M(out await with)"; + UsingExpression(text); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.OutKeyword); + N(SyntaxKind.DeclarationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "with"); + } + } + } + N(SyntaxKind.CloseParenToken); + } + } + EOF(); + } + + [Fact] + public void WithParsing14() + { + // Precedence inversion + var text = @"x is int y with {}"; + UsingExpression(text, + // (1,12): error CS1073: Unexpected token 'with' + // x is int y with {} + Diagnostic(ErrorCode.ERR_UnexpectedToken, "with").WithArguments("with").WithLocation(1, 12) + ); + N(SyntaxKind.WithExpression); + { + N(SyntaxKind.IsPatternExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.DeclarationPattern); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + } + N(SyntaxKind.WithKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } } } \ No newline at end of file From 451103acde8e77cb6cd0e5c8fabb1a4b243f33e7 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 10 Mar 2020 18:10:24 -0700 Subject: [PATCH 3/4] Fix test baseline --- src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index 8f7c83998e1fe..82f45230d446e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -784,9 +784,9 @@ public void WithParsing12() UsingExpression(text); - N(SyntaxKind.SwitchExpression); + N(SyntaxKind.WithExpression); { - N(SyntaxKind.WithExpression); + N(SyntaxKind.SwitchExpression); { N(SyntaxKind.InvocationExpression); { @@ -800,11 +800,11 @@ public void WithParsing12() N(SyntaxKind.CloseParenToken); } } - N(SyntaxKind.WithKeyword); + N(SyntaxKind.SwitchKeyword); N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } - N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.WithKeyword); N(SyntaxKind.OpenBraceToken); N(SyntaxKind.CloseBraceToken); } From f312d93819e4d72b4cd508a9bab2b0c66269292e Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 11 Mar 2020 14:45:42 -0700 Subject: [PATCH 4/4] Fix formatting --- .../Test/Syntax/Parsing/RecordParsing.cs | 398 +++++++++--------- 1 file changed, 199 insertions(+), 199 deletions(-) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs index 82f45230d446e..6821ff737fed3 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RecordParsing.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -30,217 +30,217 @@ private SyntaxTree UsingTree(string text, params DiagnosticDescription[] expecte public RecordParsingTests(ITestOutputHelper output) : base(output) { } [Fact] - public void RecordParsing01() - { - var text = "data class C(int X, int Y);"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.DataKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "X"); - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "Y"); - } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing02() - { - var text = "class C(int X, int Y);"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.ParameterList); - { - N(SyntaxKind.OpenParenToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "X"); - } - N(SyntaxKind.CommaToken); - N(SyntaxKind.Parameter); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.IdentifierToken, "Y"); - } - N(SyntaxKind.CloseParenToken); - } - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing03() - { - var text = "data class C;"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.DataKeyword); - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing04() - { - var text = "class C { public int data; }"; - UsingTree(text); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "C"); - N(SyntaxKind.OpenBraceToken); - N(SyntaxKind.FieldDeclaration); - { - N(SyntaxKind.PublicKeyword); - N(SyntaxKind.VariableDeclaration); - { - N(SyntaxKind.PredefinedType); - { - N(SyntaxKind.IntKeyword); - } - N(SyntaxKind.VariableDeclarator); - { - N(SyntaxKind.IdentifierToken, "data"); - } - N(SyntaxKind.SemicolonToken); - } - } - N(SyntaxKind.CloseBraceToken); - } - } - N(SyntaxKind.EndOfFileToken); - EOF(); - } - - [Fact] - public void RecordParsing05() - { - var tree = ParseTree("class Point;", options: null); - tree.GetDiagnostics().Verify( + public void RecordParsing01() + { + var text = "data class C(int X, int Y);"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.DataKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing02() + { + var text = "class C(int X, int Y);"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Y"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing03() + { + var text = "data class C;"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.DataKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing04() + { + var text = "class C { public int data; }"; + UsingTree(text); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "data"); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + EOF(); + } + + [Fact] + public void RecordParsing05() + { + var tree = ParseTree("class Point;", options: null); + tree.GetDiagnostics().Verify( // (1,12): error CS8652: The feature 'records' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // class Point; - Diagnostic(ErrorCode.ERR_FeatureInPreview, ";").WithArguments("records").WithLocation(1, 12) - ); - - UsingNode((CSharpSyntaxNode)tree.GetRoot()); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.ClassDeclaration); - { - N(SyntaxKind.ClassKeyword); - N(SyntaxKind.IdentifierToken, "Point"); - N(SyntaxKind.SemicolonToken); - } - N(SyntaxKind.EndOfFileToken); - } - EOF(); - } - - [Fact] - public void RecordParsing06() - { - var tree = ParseTree("interface P;", options: null); - tree.GetDiagnostics().Verify( + Diagnostic(ErrorCode.ERR_FeatureInPreview, ";").WithArguments("records").WithLocation(1, 12) + ); + + UsingNode((CSharpSyntaxNode)tree.GetRoot()); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Point"); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void RecordParsing06() + { + var tree = ParseTree("interface P;", options: null); + tree.GetDiagnostics().Verify( // (1,12): error CS1514: { expected // interface P; - Diagnostic(ErrorCode.ERR_LbraceExpected, ";").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_LbraceExpected, ";").WithLocation(1, 12), // (1,12): error CS1513: } expected // interface P; - Diagnostic(ErrorCode.ERR_RbraceExpected, ";").WithLocation(1, 12) - ); - - UsingNode((CSharpSyntaxNode)tree.GetRoot()); - - N(SyntaxKind.CompilationUnit); - { - N(SyntaxKind.InterfaceDeclaration); - { - N(SyntaxKind.InterfaceKeyword); - N(SyntaxKind.IdentifierToken, "P"); - M(SyntaxKind.OpenBraceToken); - M(SyntaxKind.CloseBraceToken); - N(SyntaxKind.SemicolonToken); - } - N(SyntaxKind.EndOfFileToken); - } - EOF(); - } - - [Fact] - public void RecordParsing07() - { - var tree = ParseTree("interface P(int x, int y);", options: null); - tree.GetDiagnostics().Verify( + Diagnostic(ErrorCode.ERR_RbraceExpected, ";").WithLocation(1, 12) + ); + + UsingNode((CSharpSyntaxNode)tree.GetRoot()); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.InterfaceDeclaration); + { + N(SyntaxKind.InterfaceKeyword); + N(SyntaxKind.IdentifierToken, "P"); + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void RecordParsing07() + { + var tree = ParseTree("interface P(int x, int y);", options: null); + tree.GetDiagnostics().Verify( // (1,12): error CS1514: { expected // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(1, 12), // (1,12): error CS1513: } expected // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(1, 12), + Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(1, 12), // (1,25): error CS0116: A namespace cannot directly contain members such as fields or methods // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_NamespaceUnexpected, ")").WithLocation(1, 25), + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, ")").WithLocation(1, 25), // (1,26): error CS1022: Type or namespace definition, or end-of-file expected // interface P(int x, int y); - Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(1, 26) - ); + Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(1, 26) + ); } [Fact] @@ -884,4 +884,4 @@ public void WithParsing14() EOF(); } } -} \ No newline at end of file +}