diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md index 6075637771e03..3058c6165f03b 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 10.md @@ -291,3 +291,29 @@ unsafe record struct R( public bool Equals(R other) => true; } ``` + +## `extension` treated as a contextual keyword + +PROTOTYPE record which version this break is introduced in + +Starting with C# 14, the `extension` keyword serves a special purpose in denoting extension containers. +This changes how the compiler interprets certain code constructs. + +If you need to use "extension" as an identifier rather than a keyword, escape it with the `@` prefix: `@extension`. This tells the compiler to treat it as a regular identifier instead of a keyword. + +The compiler will parse this as an extension container rather than a constructor. +```csharp +class extension +{ + extension(object o) { } // parsed as an extension container +} +``` + +The compiler will fail to parse this as a method with return type `extension`. +```csharp +class extension +{ + extension M() { } // will not compile +} +``` + diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 13c398af16501..424ae43759e4f 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -2600,7 +2600,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep Invalid preprocessor expression - Invalid token '{0}' in class, record, struct, or interface member declaration + Invalid token '{0}' in a member declaration Method must have a return type @@ -8047,4 +8047,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 'InterceptsLocationAttribute(string, int, int)' is not supported. Move to 'InterceptableLocation'-based generation of these attributes instead. (https://github.com/dotnet/roslyn/issues/72133) + + extensions + + + Extension declarations may not have a name. + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 83f128759bf41..dba82e9d33666 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2360,6 +2360,9 @@ internal enum ErrorCode ERR_ImplicitlyTypedParamsParameter = 9272, ERR_VariableDeclarationNamedField = 9273, + // PROTOTYPE compact error codes + ERR_ExtensionDisallowsName = 9500, + // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index f6e520514814b..ebabecd3dbf21 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2479,6 +2479,7 @@ or ErrorCode.WRN_UnscopedRefAttributeOldRules or ErrorCode.WRN_InterceptsLocationAttributeUnsupportedSignature or ErrorCode.ERR_ImplicitlyTypedParamsParameter or ErrorCode.ERR_VariableDeclarationNamedField + or ErrorCode.ERR_ExtensionDisallowsName => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 38c4399efd622..30724c5576c1c 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -296,6 +296,8 @@ internal enum MessageID IDS_FeatureFirstClassSpan = MessageBase + 12849, IDS_FeatureUnboundGenericTypesInNameof = MessageBase + 12850, IDS_FeatureSimpleLambdaParameterModifiers = MessageBase + 12851, + + IDS_FeatureExtensions = MessageBase + 12852, } // Message IDs may refer to strings that need to be localized. @@ -480,6 +482,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureFirstClassSpan: case MessageID.IDS_FeatureUnboundGenericTypesInNameof: case MessageID.IDS_FeatureSimpleLambdaParameterModifiers: + case MessageID.IDS_FeatureExtensions: return LanguageVersion.Preview; // C# 13.0 features. diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 6968dc30e0fb5..3c53475dbf132 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -160,7 +160,7 @@ parameter_list ; parameter - : attribute_list* modifier* type? (identifier_token | '__arglist') equals_value_clause? + : attribute_list* modifier* type? (identifier_token | '__arglist')? equals_value_clause? ; constructor_initializer @@ -323,6 +323,7 @@ enum_member_declaration type_declaration : class_declaration + | extension_declaration | interface_declaration | record_declaration | struct_declaration @@ -332,6 +333,10 @@ class_declaration : attribute_list* modifier* 'class' identifier_token type_parameter_list? parameter_list? base_list? type_parameter_constraint_clause* '{'? member_declaration* '}'? ';'? ; +extension_declaration + : attribute_list* modifier* 'extension' type_parameter_list? parameter_list? type_parameter_constraint_clause* '{'? member_declaration* '}'? ';'? + ; + interface_declaration : attribute_list* modifier* 'interface' identifier_token type_parameter_list? parameter_list? base_list? type_parameter_constraint_clause* '{'? member_declaration* '}'? ';'? ; diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs index 78d8aedb8b8f2..f268ad36627da 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs @@ -16509,7 +16509,7 @@ internal BaseTypeDeclarationSyntax(SyntaxKind kind) } /// Gets the identifier. - public abstract SyntaxToken Identifier { get; } + public abstract SyntaxToken? Identifier { get; } /// Gets the base type list. public abstract BaseListSyntax? BaseList { get; } @@ -16524,7 +16524,7 @@ internal BaseTypeDeclarationSyntax(SyntaxKind kind) public abstract SyntaxToken? SemicolonToken { get; } } -/// Base class for type declaration syntax (class, struct, interface, record). +/// Base class for type declaration syntax (class, struct, interface, record, extension). internal abstract partial class TypeDeclarationSyntax : BaseTypeDeclarationSyntax { internal TypeDeclarationSyntax(SyntaxKind kind, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) @@ -16537,7 +16537,7 @@ internal TypeDeclarationSyntax(SyntaxKind kind) { } - /// Gets the type keyword token ("class", "struct", "interface", "record"). + /// Gets the type keyword token ("class", "struct", "interface", "record", "extension"). public abstract SyntaxToken Keyword { get; } public abstract TypeParameterListSyntax? TypeParameterList { get; } @@ -18109,6 +18109,236 @@ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) => new EnumMemberDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.identifier, this.equalsValue, GetDiagnostics(), annotations); } +/// Extension container syntax. +internal sealed partial class ExtensionDeclarationSyntax : TypeDeclarationSyntax +{ + internal readonly GreenNode? attributeLists; + internal readonly GreenNode? modifiers; + internal readonly SyntaxToken keyword; + internal readonly TypeParameterListSyntax? typeParameterList; + internal readonly ParameterListSyntax? parameterList; + internal readonly GreenNode? constraintClauses; + internal readonly SyntaxToken? openBraceToken; + internal readonly GreenNode? members; + internal readonly SyntaxToken? closeBraceToken; + internal readonly SyntaxToken? semicolonToken; + + internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 10; + if (attributeLists != null) + { + this.AdjustFlagsAndWidth(attributeLists); + this.attributeLists = attributeLists; + } + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(keyword); + this.keyword = keyword; + if (typeParameterList != null) + { + this.AdjustFlagsAndWidth(typeParameterList); + this.typeParameterList = typeParameterList; + } + if (parameterList != null) + { + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + } + if (constraintClauses != null) + { + this.AdjustFlagsAndWidth(constraintClauses); + this.constraintClauses = constraintClauses; + } + if (openBraceToken != null) + { + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + } + if (members != null) + { + this.AdjustFlagsAndWidth(members); + this.members = members; + } + if (closeBraceToken != null) + { + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 10; + if (attributeLists != null) + { + this.AdjustFlagsAndWidth(attributeLists); + this.attributeLists = attributeLists; + } + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(keyword); + this.keyword = keyword; + if (typeParameterList != null) + { + this.AdjustFlagsAndWidth(typeParameterList); + this.typeParameterList = typeParameterList; + } + if (parameterList != null) + { + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + } + if (constraintClauses != null) + { + this.AdjustFlagsAndWidth(constraintClauses); + this.constraintClauses = constraintClauses; + } + if (openBraceToken != null) + { + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + } + if (members != null) + { + this.AdjustFlagsAndWidth(members); + this.members = members; + } + if (closeBraceToken != null) + { + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + internal ExtensionDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, GreenNode? constraintClauses, SyntaxToken? openBraceToken, GreenNode? members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken) + : base(kind) + { + this.SlotCount = 10; + if (attributeLists != null) + { + this.AdjustFlagsAndWidth(attributeLists); + this.attributeLists = attributeLists; + } + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(keyword); + this.keyword = keyword; + if (typeParameterList != null) + { + this.AdjustFlagsAndWidth(typeParameterList); + this.typeParameterList = typeParameterList; + } + if (parameterList != null) + { + this.AdjustFlagsAndWidth(parameterList); + this.parameterList = parameterList; + } + if (constraintClauses != null) + { + this.AdjustFlagsAndWidth(constraintClauses); + this.constraintClauses = constraintClauses; + } + if (openBraceToken != null) + { + this.AdjustFlagsAndWidth(openBraceToken); + this.openBraceToken = openBraceToken; + } + if (members != null) + { + this.AdjustFlagsAndWidth(members); + this.members = members; + } + if (closeBraceToken != null) + { + this.AdjustFlagsAndWidth(closeBraceToken); + this.closeBraceToken = closeBraceToken; + } + if (semicolonToken != null) + { + this.AdjustFlagsAndWidth(semicolonToken); + this.semicolonToken = semicolonToken; + } + } + + public override CoreSyntax.SyntaxList AttributeLists => new CoreSyntax.SyntaxList(this.attributeLists); + public override CoreSyntax.SyntaxList Modifiers => new CoreSyntax.SyntaxList(this.modifiers); + public override SyntaxToken Keyword => this.keyword; + public override TypeParameterListSyntax? TypeParameterList => this.typeParameterList; + public override ParameterListSyntax? ParameterList => this.parameterList; + public override CoreSyntax.SyntaxList ConstraintClauses => new CoreSyntax.SyntaxList(this.constraintClauses); + public override SyntaxToken? OpenBraceToken => this.openBraceToken; + public override CoreSyntax.SyntaxList Members => new CoreSyntax.SyntaxList(this.members); + public override SyntaxToken? CloseBraceToken => this.closeBraceToken; + public override SyntaxToken? SemicolonToken => this.semicolonToken; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.attributeLists, + 1 => this.modifiers, + 2 => this.keyword, + 3 => this.typeParameterList, + 4 => this.parameterList, + 5 => this.constraintClauses, + 6 => this.openBraceToken, + 7 => this.members, + 8 => this.closeBraceToken, + 9 => this.semicolonToken, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.ExtensionDeclarationSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this); + + public ExtensionDeclarationSyntax Update(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax typeParameterList, ParameterListSyntax parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken) + { + if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || keyword != this.Keyword || typeParameterList != this.TypeParameterList || parameterList != this.ParameterList || constraintClauses != this.ConstraintClauses || openBraceToken != this.OpenBraceToken || members != this.Members || closeBraceToken != this.CloseBraceToken || semicolonToken != this.SemicolonToken) + { + var newNode = SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, keyword, typeParameterList, parameterList, constraintClauses, openBraceToken, members, closeBraceToken, semicolonToken); + 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 ExtensionDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.keyword, this.typeParameterList, this.parameterList, this.constraintClauses, this.openBraceToken, this.members, this.closeBraceToken, this.semicolonToken, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new ExtensionDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.keyword, this.typeParameterList, this.parameterList, this.constraintClauses, this.openBraceToken, this.members, this.closeBraceToken, this.semicolonToken, GetDiagnostics(), annotations); +} + /// Base list syntax. internal sealed partial class BaseListSyntax : CSharpSyntaxNode { @@ -21618,10 +21848,10 @@ internal sealed partial class ParameterSyntax : BaseParameterSyntax internal readonly GreenNode? attributeLists; internal readonly GreenNode? modifiers; internal readonly TypeSyntax? type; - internal readonly SyntaxToken identifier; + internal readonly SyntaxToken? identifier; internal readonly EqualsValueClauseSyntax? @default; - internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) : base(kind, diagnostics, annotations) { this.SlotCount = 5; @@ -21640,8 +21870,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? this.AdjustFlagsAndWidth(type); this.type = type; } - this.AdjustFlagsAndWidth(identifier); - this.identifier = identifier; + if (identifier != null) + { + this.AdjustFlagsAndWidth(identifier); + this.identifier = identifier; + } if (@default != null) { this.AdjustFlagsAndWidth(@default); @@ -21649,7 +21882,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? } } - internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default, SyntaxFactoryContext context) + internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default, SyntaxFactoryContext context) : base(kind) { this.SetFactoryContext(context); @@ -21669,8 +21902,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? this.AdjustFlagsAndWidth(type); this.type = type; } - this.AdjustFlagsAndWidth(identifier); - this.identifier = identifier; + if (identifier != null) + { + this.AdjustFlagsAndWidth(identifier); + this.identifier = identifier; + } if (@default != null) { this.AdjustFlagsAndWidth(@default); @@ -21678,7 +21914,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? } } - internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default) + internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default) : base(kind) { this.SlotCount = 5; @@ -21697,8 +21933,11 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? this.AdjustFlagsAndWidth(type); this.type = type; } - this.AdjustFlagsAndWidth(identifier); - this.identifier = identifier; + if (identifier != null) + { + this.AdjustFlagsAndWidth(identifier); + this.identifier = identifier; + } if (@default != null) { this.AdjustFlagsAndWidth(@default); @@ -21712,7 +21951,7 @@ internal ParameterSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? public override CoreSyntax.SyntaxList Modifiers => new CoreSyntax.SyntaxList(this.modifiers); public override TypeSyntax? Type => this.type; /// Gets the identifier. - public SyntaxToken Identifier => this.identifier; + public SyntaxToken? Identifier => this.identifier; public EqualsValueClauseSyntax? Default => this.@default; internal override GreenNode? GetSlot(int index) @@ -26654,6 +26893,7 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitEnumDeclaration(EnumDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitDelegateDeclaration(DelegateDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); public virtual TResult VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); public virtual TResult VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); public virtual TResult VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); @@ -26902,6 +27142,7 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitEnumDeclaration(EnumDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitDelegateDeclaration(DelegateDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + public virtual void VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); public virtual void VisitSimpleBaseType(SimpleBaseTypeSyntax node) => this.DefaultVisit(node); public virtual void VisitPrimaryConstructorBaseType(PrimaryConstructorBaseTypeSyntax node) => this.DefaultVisit(node); @@ -27490,6 +27731,9 @@ public override CSharpSyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyn public override CSharpSyntaxNode VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.Identifier), (EqualsValueClauseSyntax)Visit(node.EqualsValue)); + public override CSharpSyntaxNode VisitExtensionDeclaration(ExtensionDeclarationSyntax node) + => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.Keyword), (TypeParameterListSyntax)Visit(node.TypeParameterList), (ParameterListSyntax)Visit(node.ParameterList), VisitList(node.ConstraintClauses), (SyntaxToken)Visit(node.OpenBraceToken), VisitList(node.Members), (SyntaxToken)Visit(node.CloseBraceToken), (SyntaxToken)Visit(node.SemicolonToken)); + public override CSharpSyntaxNode VisitBaseList(BaseListSyntax node) => node.Update((SyntaxToken)Visit(node.ColonToken), VisitList(node.Types)); @@ -31416,6 +31660,43 @@ public EnumMemberDeclarationSyntax EnumMemberDeclaration(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken? openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken) + { +#if DEBUG + if (keyword == null) throw new ArgumentNullException(nameof(keyword)); + if (keyword.Kind != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword)); + if (openBraceToken != null) + { + switch (openBraceToken.Kind) + { + case SyntaxKind.OpenBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(openBraceToken)); + } + } + if (closeBraceToken != null) + { + switch (closeBraceToken.Kind) + { + case SyntaxKind.CloseBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(closeBraceToken)); + } + } + if (semicolonToken != null) + { + switch (semicolonToken.Kind) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + } +#endif + + return new ExtensionDeclarationSyntax(SyntaxKind.ExtensionDeclaration, attributeLists.Node, modifiers.Node, keyword, typeParameterList, parameterList, constraintClauses.Node, openBraceToken, members.Node, closeBraceToken, semicolonToken, this.context); + } + public BaseListSyntax BaseList(SyntaxToken colonToken, CoreSyntax.SeparatedSyntaxList types) { #if DEBUG @@ -32059,15 +32340,18 @@ public BracketedParameterListSyntax BracketedParameterList(SyntaxToken openBrack return result; } - public ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default) + public ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default) { #if DEBUG - if (identifier == null) throw new ArgumentNullException(nameof(identifier)); - switch (identifier.Kind) + if (identifier != null) { - case SyntaxKind.IdentifierToken: - case SyntaxKind.ArgListKeyword: break; - default: throw new ArgumentException(nameof(identifier)); + switch (identifier.Kind) + { + case SyntaxKind.IdentifierToken: + case SyntaxKind.ArgListKeyword: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(identifier)); + } } #endif @@ -36684,6 +36968,43 @@ public static EnumMemberDeclarationSyntax EnumMemberDeclaration(CoreSyntax.Synta return new EnumMemberDeclarationSyntax(SyntaxKind.EnumMemberDeclaration, attributeLists.Node, modifiers.Node, identifier, equalsValue); } + public static ExtensionDeclarationSyntax ExtensionDeclaration(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, CoreSyntax.SyntaxList constraintClauses, SyntaxToken? openBraceToken, CoreSyntax.SyntaxList members, SyntaxToken? closeBraceToken, SyntaxToken? semicolonToken) + { +#if DEBUG + if (keyword == null) throw new ArgumentNullException(nameof(keyword)); + if (keyword.Kind != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword)); + if (openBraceToken != null) + { + switch (openBraceToken.Kind) + { + case SyntaxKind.OpenBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(openBraceToken)); + } + } + if (closeBraceToken != null) + { + switch (closeBraceToken.Kind) + { + case SyntaxKind.CloseBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(closeBraceToken)); + } + } + if (semicolonToken != null) + { + switch (semicolonToken.Kind) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + } +#endif + + return new ExtensionDeclarationSyntax(SyntaxKind.ExtensionDeclaration, attributeLists.Node, modifiers.Node, keyword, typeParameterList, parameterList, constraintClauses.Node, openBraceToken, members.Node, closeBraceToken, semicolonToken); + } + public static BaseListSyntax BaseList(SyntaxToken colonToken, CoreSyntax.SeparatedSyntaxList types) { #if DEBUG @@ -37327,15 +37648,18 @@ public static BracketedParameterListSyntax BracketedParameterList(SyntaxToken op return result; } - public static ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken identifier, EqualsValueClauseSyntax? @default) + public static ParameterSyntax Parameter(CoreSyntax.SyntaxList attributeLists, CoreSyntax.SyntaxList modifiers, TypeSyntax? type, SyntaxToken? identifier, EqualsValueClauseSyntax? @default) { #if DEBUG - if (identifier == null) throw new ArgumentNullException(nameof(identifier)); - switch (identifier.Kind) + if (identifier != null) { - case SyntaxKind.IdentifierToken: - case SyntaxKind.ArgListKeyword: break; - default: throw new ArgumentException(nameof(identifier)); + switch (identifier.Kind) + { + case SyntaxKind.IdentifierToken: + case SyntaxKind.ArgListKeyword: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(identifier)); + } } #endif diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs index 0b31bde257994..66df0106254e3 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs @@ -525,6 +525,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a EnumMemberDeclarationSyntax node. public virtual TResult? VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a ExtensionDeclarationSyntax node. + public virtual TResult? VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a BaseListSyntax node. public virtual TResult? VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); @@ -1260,6 +1263,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a EnumMemberDeclarationSyntax node. public virtual void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a ExtensionDeclarationSyntax node. + public virtual void VisitExtensionDeclaration(ExtensionDeclarationSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a BaseListSyntax node. public virtual void VisitBaseList(BaseListSyntax node) => this.DefaultVisit(node); @@ -1995,6 +2001,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor public override SyntaxNode? VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.Identifier), (EqualsValueClauseSyntax?)Visit(node.EqualsValue)); + public override SyntaxNode? VisitExtensionDeclaration(ExtensionDeclarationSyntax node) + => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.Keyword), (TypeParameterListSyntax?)Visit(node.TypeParameterList), (ParameterListSyntax?)Visit(node.ParameterList), VisitList(node.ConstraintClauses), VisitToken(node.OpenBraceToken), VisitList(node.Members), VisitToken(node.CloseBraceToken), VisitToken(node.SemicolonToken)); + public override SyntaxNode? VisitBaseList(BaseListSyntax node) => node.Update(VisitToken(node.ColonToken), VisitList(node.Types)); @@ -3196,14 +3205,6 @@ public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.ParameterSyntax)parameter.Green, (Syntax.InternalSyntax.SyntaxToken)arrowToken.Node!, block == null ? null : (Syntax.InternalSyntax.BlockSyntax)block.Green, expressionBody == null ? null : (Syntax.InternalSyntax.ExpressionSyntax)expressionBody.Green).CreateRed(); } - /// Creates a new SimpleLambdaExpressionSyntax instance. - public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList attributeLists, SyntaxTokenList modifiers, ParameterSyntax parameter, BlockSyntax? block, ExpressionSyntax? expressionBody) - => SyntaxFactory.SimpleLambdaExpression(attributeLists, modifiers, parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), block, expressionBody); - - /// Creates a new SimpleLambdaExpressionSyntax instance. - public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(ParameterSyntax parameter) - => SyntaxFactory.SimpleLambdaExpression(default, default(SyntaxTokenList), parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), default, default); - /// Creates a new RefExpressionSyntax instance. public static RefExpressionSyntax RefExpression(SyntaxToken refKeyword, ExpressionSyntax expression) { @@ -5146,6 +5147,39 @@ public static EnumMemberDeclarationSyntax EnumMemberDeclaration(SyntaxToken iden public static EnumMemberDeclarationSyntax EnumMemberDeclaration(string identifier) => SyntaxFactory.EnumMemberDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Identifier(identifier), default); + /// Creates a new ExtensionDeclarationSyntax instance. + public static ExtensionDeclarationSyntax ExtensionDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxToken openBraceToken, SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken) + { + if (keyword.Kind() != SyntaxKind.ExtensionKeyword) throw new ArgumentException(nameof(keyword)); + switch (openBraceToken.Kind()) + { + case SyntaxKind.OpenBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(openBraceToken)); + } + switch (closeBraceToken.Kind()) + { + case SyntaxKind.CloseBraceToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(closeBraceToken)); + } + switch (semicolonToken.Kind()) + { + case SyntaxKind.SemicolonToken: + case SyntaxKind.None: break; + default: throw new ArgumentException(nameof(semicolonToken)); + } + return (ExtensionDeclarationSyntax)Syntax.InternalSyntax.SyntaxFactory.ExtensionDeclaration(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken)keyword.Node!, typeParameterList == null ? null : (Syntax.InternalSyntax.TypeParameterListSyntax)typeParameterList.Green, parameterList == null ? null : (Syntax.InternalSyntax.ParameterListSyntax)parameterList.Green, constraintClauses.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken?)openBraceToken.Node, members.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken?)closeBraceToken.Node, (Syntax.InternalSyntax.SyntaxToken?)semicolonToken.Node).CreateRed(); + } + + /// Creates a new ExtensionDeclarationSyntax instance. + public static ExtensionDeclarationSyntax ExtensionDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxList members) + => SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), typeParameterList, parameterList, constraintClauses, default, members, default, default); + + /// Creates a new ExtensionDeclarationSyntax instance. + public static ExtensionDeclarationSyntax ExtensionDeclaration() + => SyntaxFactory.ExtensionDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), default, default, default, default, default, default, default); + /// Creates a new BaseListSyntax instance. public static BaseListSyntax BaseList(SyntaxToken colonToken, SeparatedSyntaxList types) { @@ -5718,16 +5752,13 @@ public static ParameterSyntax Parameter(SyntaxList attribut switch (identifier.Kind()) { case SyntaxKind.IdentifierToken: - case SyntaxKind.ArgListKeyword: break; + case SyntaxKind.ArgListKeyword: + case SyntaxKind.None: break; default: throw new ArgumentException(nameof(identifier)); } - return (ParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.Parameter(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), type == null ? null : (Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.SyntaxToken)identifier.Node!, @default == null ? null : (Syntax.InternalSyntax.EqualsValueClauseSyntax)@default.Green).CreateRed(); + return (ParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.Parameter(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), type == null ? null : (Syntax.InternalSyntax.TypeSyntax)type.Green, (Syntax.InternalSyntax.SyntaxToken?)identifier.Node, @default == null ? null : (Syntax.InternalSyntax.EqualsValueClauseSyntax)@default.Green).CreateRed(); } - /// Creates a new ParameterSyntax instance. - public static ParameterSyntax Parameter(SyntaxToken identifier) - => SyntaxFactory.Parameter(default, default(SyntaxTokenList), default, identifier, default); - /// Creates a new FunctionPointerParameterSyntax instance. public static FunctionPointerParameterSyntax FunctionPointerParameter(SyntaxList attributeLists, SyntaxTokenList modifiers, TypeSyntax type) { diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs index 0c97b7c25c0a7..aa66360fb08d8 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs @@ -10261,7 +10261,7 @@ internal BaseTypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, Syntax public new BaseTypeDeclarationSyntax AddModifiers(params SyntaxToken[] items) => (BaseTypeDeclarationSyntax)AddModifiersCore(items); } -/// Base class for type declaration syntax (class, struct, interface, record). +/// Base class for type declaration syntax (class, struct, interface, record, extension). public abstract partial class TypeDeclarationSyntax : BaseTypeDeclarationSyntax { internal TypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) @@ -10269,7 +10269,7 @@ internal TypeDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode { } - /// Gets the type keyword token ("class", "struct", "interface", "record"). + /// Gets the type keyword token ("class", "struct", "interface", "record", "extension"). public abstract SyntaxToken Keyword { get; } public TypeDeclarationSyntax WithKeyword(SyntaxToken keyword) => WithKeywordCore(keyword); internal abstract TypeDeclarationSyntax WithKeywordCore(SyntaxToken keyword); @@ -11312,6 +11312,154 @@ public EnumMemberDeclarationSyntax Update(SyntaxList attrib public new EnumMemberDeclarationSyntax AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items)); } +/// Extension container syntax. +/// +/// This node is associated with the following syntax kinds: +/// +/// +/// +/// +public sealed partial class ExtensionDeclarationSyntax : TypeDeclarationSyntax +{ + private SyntaxNode? attributeLists; + private TypeParameterListSyntax? typeParameterList; + private ParameterListSyntax? parameterList; + private SyntaxNode? constraintClauses; + private SyntaxNode? members; + + internal ExtensionDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + public override SyntaxList AttributeLists => new SyntaxList(GetRed(ref this.attributeLists, 0)); + + public override SyntaxTokenList Modifiers + { + get + { + var slot = this.Green.GetSlot(1); + return slot != null ? new SyntaxTokenList(this, slot, GetChildPosition(1), GetChildIndex(1)) : default; + } + } + + public override SyntaxToken Keyword => new SyntaxToken(this, ((InternalSyntax.ExtensionDeclarationSyntax)this.Green).keyword, GetChildPosition(2), GetChildIndex(2)); + + public override TypeParameterListSyntax? TypeParameterList => GetRed(ref this.typeParameterList, 3); + + public override ParameterListSyntax? ParameterList => GetRed(ref this.parameterList, 4); + + public override SyntaxList ConstraintClauses => new SyntaxList(GetRed(ref this.constraintClauses, 5)); + + public override SyntaxToken OpenBraceToken + { + get + { + var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).openBraceToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(6), GetChildIndex(6)) : default; + } + } + + public override SyntaxList Members => new SyntaxList(GetRed(ref this.members, 7)); + + public override SyntaxToken CloseBraceToken + { + get + { + var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).closeBraceToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(8), GetChildIndex(8)) : default; + } + } + + public override SyntaxToken SemicolonToken + { + get + { + var slot = ((Syntax.InternalSyntax.ExtensionDeclarationSyntax)this.Green).semicolonToken; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(9), GetChildIndex(9)) : default; + } + } + + internal override SyntaxNode? GetNodeSlot(int index) + => index switch + { + 0 => GetRedAtZero(ref this.attributeLists)!, + 3 => GetRed(ref this.typeParameterList, 3), + 4 => GetRed(ref this.parameterList, 4), + 5 => GetRed(ref this.constraintClauses, 5)!, + 7 => GetRed(ref this.members, 7)!, + _ => null, + }; + + internal override SyntaxNode? GetCachedSlot(int index) + => index switch + { + 0 => this.attributeLists, + 3 => this.typeParameterList, + 4 => this.parameterList, + 5 => this.constraintClauses, + 7 => this.members, + _ => null, + }; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitExtensionDeclaration(this); + public override TResult? Accept(CSharpSyntaxVisitor visitor) where TResult : default => visitor.VisitExtensionDeclaration(this); + + public ExtensionDeclarationSyntax Update(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken keyword, TypeParameterListSyntax? typeParameterList, ParameterListSyntax? parameterList, SyntaxList constraintClauses, SyntaxToken openBraceToken, SyntaxList members, SyntaxToken closeBraceToken, SyntaxToken semicolonToken) + { + if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || keyword != this.Keyword || typeParameterList != this.TypeParameterList || parameterList != this.ParameterList || constraintClauses != this.ConstraintClauses || openBraceToken != this.OpenBraceToken || members != this.Members || closeBraceToken != this.CloseBraceToken || semicolonToken != this.SemicolonToken) + { + var newNode = SyntaxFactory.ExtensionDeclaration(attributeLists, modifiers, keyword, typeParameterList, parameterList, constraintClauses, openBraceToken, members, closeBraceToken, semicolonToken); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + internal override MemberDeclarationSyntax WithAttributeListsCore(SyntaxList attributeLists) => WithAttributeLists(attributeLists); + public new ExtensionDeclarationSyntax WithAttributeLists(SyntaxList attributeLists) => Update(attributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override MemberDeclarationSyntax WithModifiersCore(SyntaxTokenList modifiers) => WithModifiers(modifiers); + public new ExtensionDeclarationSyntax WithModifiers(SyntaxTokenList modifiers) => Update(this.AttributeLists, modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithKeywordCore(SyntaxToken keyword) => WithKeyword(keyword); + public new ExtensionDeclarationSyntax WithKeyword(SyntaxToken keyword) => Update(this.AttributeLists, this.Modifiers, keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithTypeParameterListCore(TypeParameterListSyntax? typeParameterList) => WithTypeParameterList(typeParameterList); + public new ExtensionDeclarationSyntax WithTypeParameterList(TypeParameterListSyntax? typeParameterList) => Update(this.AttributeLists, this.Modifiers, this.Keyword, typeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithParameterListCore(ParameterListSyntax? parameterList) => WithParameterList(parameterList); + public new ExtensionDeclarationSyntax WithParameterList(ParameterListSyntax? parameterList) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, parameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithConstraintClausesCore(SyntaxList constraintClauses) => WithConstraintClauses(constraintClauses); + public new ExtensionDeclarationSyntax WithConstraintClauses(SyntaxList constraintClauses) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, constraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override BaseTypeDeclarationSyntax WithOpenBraceTokenCore(SyntaxToken openBraceToken) => WithOpenBraceToken(openBraceToken); + public new ExtensionDeclarationSyntax WithOpenBraceToken(SyntaxToken openBraceToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, openBraceToken, this.Members, this.CloseBraceToken, this.SemicolonToken); + internal override TypeDeclarationSyntax WithMembersCore(SyntaxList members) => WithMembers(members); + public new ExtensionDeclarationSyntax WithMembers(SyntaxList members) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, members, this.CloseBraceToken, this.SemicolonToken); + internal override BaseTypeDeclarationSyntax WithCloseBraceTokenCore(SyntaxToken closeBraceToken) => WithCloseBraceToken(closeBraceToken); + public new ExtensionDeclarationSyntax WithCloseBraceToken(SyntaxToken closeBraceToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, closeBraceToken, this.SemicolonToken); + internal override BaseTypeDeclarationSyntax WithSemicolonTokenCore(SyntaxToken semicolonToken) => WithSemicolonToken(semicolonToken); + public new ExtensionDeclarationSyntax WithSemicolonToken(SyntaxToken semicolonToken) => Update(this.AttributeLists, this.Modifiers, this.Keyword, this.TypeParameterList, this.ParameterList, this.ConstraintClauses, this.OpenBraceToken, this.Members, this.CloseBraceToken, semicolonToken); + + internal override MemberDeclarationSyntax AddAttributeListsCore(params AttributeListSyntax[] items) => AddAttributeLists(items); + public new ExtensionDeclarationSyntax AddAttributeLists(params AttributeListSyntax[] items) => WithAttributeLists(this.AttributeLists.AddRange(items)); + internal override MemberDeclarationSyntax AddModifiersCore(params SyntaxToken[] items) => AddModifiers(items); + public new ExtensionDeclarationSyntax AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items)); + internal override TypeDeclarationSyntax AddTypeParameterListParametersCore(params TypeParameterSyntax[] items) => AddTypeParameterListParameters(items); + public new ExtensionDeclarationSyntax AddTypeParameterListParameters(params TypeParameterSyntax[] items) + { + var typeParameterList = this.TypeParameterList ?? SyntaxFactory.TypeParameterList(); + return WithTypeParameterList(typeParameterList.WithParameters(typeParameterList.Parameters.AddRange(items))); + } + internal override TypeDeclarationSyntax AddParameterListParametersCore(params ParameterSyntax[] items) => AddParameterListParameters(items); + public new ExtensionDeclarationSyntax AddParameterListParameters(params ParameterSyntax[] items) + { + var parameterList = this.ParameterList ?? SyntaxFactory.ParameterList(); + return WithParameterList(parameterList.WithParameters(parameterList.Parameters.AddRange(items))); + } + internal override TypeDeclarationSyntax AddConstraintClausesCore(params TypeParameterConstraintClauseSyntax[] items) => AddConstraintClauses(items); + public new ExtensionDeclarationSyntax AddConstraintClauses(params TypeParameterConstraintClauseSyntax[] items) => WithConstraintClauses(this.ConstraintClauses.AddRange(items)); + internal override TypeDeclarationSyntax AddMembersCore(params MemberDeclarationSyntax[] items) => AddMembers(items); + public new ExtensionDeclarationSyntax AddMembers(params MemberDeclarationSyntax[] items) => WithMembers(this.Members.AddRange(items)); +} + /// Base list syntax. /// /// This node is associated with the following syntax kinds: @@ -13636,7 +13784,14 @@ public override SyntaxTokenList Modifiers public override TypeSyntax? Type => GetRed(ref this.type, 2); /// Gets the identifier. - public SyntaxToken Identifier => new SyntaxToken(this, ((InternalSyntax.ParameterSyntax)this.Green).identifier, GetChildPosition(3), GetChildIndex(3)); + public SyntaxToken Identifier + { + get + { + var slot = ((Syntax.InternalSyntax.ParameterSyntax)this.Green).identifier; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(3), GetChildIndex(3)) : default; + } + } public EqualsValueClauseSyntax? Default => GetRed(ref this.@default, 4); diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 12f19f4de2626..e1277d96a3152 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -84,7 +84,7 @@ internal enum TerminatorState IsEndOfFunctionPointerParameterList = 1 << 23, IsEndOfFunctionPointerParameterListErrored = 1 << 24, IsEndOfFunctionPointerCallingConvention = 1 << 25, - IsEndOfRecordOrClassOrStructOrInterfaceSignature = 1 << 26, + IsEndOfTypeSignature = 1 << 26, IsExpressionOrPatternInCaseLabelOfSwitchStatement = 1 << 27, IsPatternInSwitchExpressionArm = 1 << 28, } @@ -128,7 +128,7 @@ private bool IsTerminator() case TerminatorState.IsEndOfFunctionPointerParameterList when this.IsEndOfFunctionPointerParameterList(errored: false): case TerminatorState.IsEndOfFunctionPointerParameterListErrored when this.IsEndOfFunctionPointerParameterList(errored: true): case TerminatorState.IsEndOfFunctionPointerCallingConvention when this.IsEndOfFunctionPointerCallingConvention(): - case TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature when this.IsEndOfRecordOrClassOrStructOrInterfaceSignature(): + case TerminatorState.IsEndOfTypeSignature when this.IsEndOfTypeSignature(): return true; } } @@ -1692,13 +1692,13 @@ private MemberDeclarationSyntax ParseTypeDeclaration(SyntaxList attributes, SyntaxListBuilder modifiers) + private TypeDeclarationSyntax ParseMainTypeDeclaration(SyntaxList attributes, SyntaxListBuilder modifiers) { Debug.Assert(this.CurrentToken.Kind is SyntaxKind.ClassKeyword or SyntaxKind.StructKeyword or SyntaxKind.InterfaceKeyword || - this.CurrentToken.ContextualKind == SyntaxKind.RecordKeyword); + this.CurrentToken.ContextualKind is SyntaxKind.RecordKeyword or SyntaxKind.ExtensionKeyword); // "top-level" expressions and statements should never occur inside an asynchronous context Debug.Assert(!IsInAsync); @@ -1728,19 +1728,34 @@ private TypeDeclarationSyntax ParseClassOrStructOrInterfaceDeclaration(SyntaxLis keyword = ConvertToKeyword(this.EatToken()); } + bool isExtension = keyword.Kind == SyntaxKind.ExtensionKeyword; var outerSaveTerm = _termState; - _termState |= TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature; + _termState |= TerminatorState.IsEndOfTypeSignature; var saveTerm = _termState; _termState |= TerminatorState.IsPossibleAggregateClauseStartOrStop; - var name = this.ParseIdentifierToken(); + SyntaxToken? name; + if (isExtension) + { + name = null; + if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken) + { + keyword = AddTrailingSkippedSyntax(keyword, this.AddError(this.EatToken(), ErrorCode.ERR_ExtensionDisallowsName)); + } + } + else + { + name = this.ParseIdentifierToken(); + } + var typeParameters = this.ParseTypeParameterList(); - var paramList = CurrentToken.Kind == SyntaxKind.OpenParenToken - ? ParseParenthesizedParameterList() : null; + // For extension declarations, there must be a parameter list + var paramList = CurrentToken.Kind == SyntaxKind.OpenParenToken || isExtension + ? ParseParenthesizedParameterList(forExtension: isExtension) : null; - var baseList = this.ParseBaseList(); + var baseList = isExtension ? null : this.ParseBaseList(); _termState = saveTerm; // Parse class body @@ -1882,7 +1897,7 @@ bool tryScanRecordStart([NotNullWhen(true)] out SyntaxToken? keyword, out Syntax } static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxFactory, SyntaxList attributes, SyntaxListBuilder modifiers, SyntaxToken keyword, SyntaxToken? recordModifier, - SyntaxToken name, TypeParameterListSyntax typeParameters, ParameterListSyntax? paramList, BaseListSyntax baseList, SyntaxListBuilder constraints, + SyntaxToken? name, TypeParameterListSyntax typeParameters, ParameterListSyntax? paramList, BaseListSyntax? baseList, SyntaxListBuilder constraints, SyntaxToken? openBrace, SyntaxListBuilder members, SyntaxToken? closeBrace, SyntaxToken semicolon) { var modifiersList = (SyntaxList)modifiers.ToList(); @@ -1891,6 +1906,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF switch (keyword.Kind) { case SyntaxKind.ClassKeyword: + Debug.Assert(name is not null); return syntaxFactory.ClassDeclaration( attributes, modifiersList, @@ -1906,6 +1922,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF semicolon); case SyntaxKind.StructKeyword: + Debug.Assert(name is not null); return syntaxFactory.StructDeclaration( attributes, modifiersList, @@ -1921,6 +1938,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF semicolon); case SyntaxKind.InterfaceKeyword: + Debug.Assert(name is not null); return syntaxFactory.InterfaceDeclaration( attributes, modifiersList, @@ -1939,6 +1957,7 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF // record struct ... // record ... // record class ... + Debug.Assert(name is not null); SyntaxKind declarationKind = recordModifier?.Kind == SyntaxKind.StructKeyword ? SyntaxKind.RecordStructDeclaration : SyntaxKind.RecordDeclaration; return syntaxFactory.RecordDeclaration( declarationKind, @@ -1956,6 +1975,21 @@ static TypeDeclarationSyntax constructTypeDeclaration(ContextAwareSyntax syntaxF closeBrace, semicolon); + case SyntaxKind.ExtensionKeyword: + Debug.Assert(name is null); + Debug.Assert(baseList is null); + return syntaxFactory.ExtensionDeclaration( + attributes, + modifiers.ToList(), + keyword, + typeParameters, + paramList, + constraints, + openBrace, + members, + closeBrace, + semicolon); + default: throw ExceptionUtilities.UnexpectedValue(keyword.Kind); } @@ -2053,8 +2087,8 @@ private bool IsPossibleAggregateClauseStartOrStop() private BaseListSyntax ParseBaseList() { - // We are only called from ParseClassOrStructOrInterfaceDeclaration which unilaterally sets this. - Debug.Assert((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0); + // We are only called from ParseMainTypeDeclaration which unilaterally sets this. + Debug.Assert((_termState & TerminatorState.IsEndOfTypeSignature) != 0); var colon = this.TryEatToken(SyntaxKind.ColonToken); if (colon == null) @@ -2163,7 +2197,7 @@ private TypeParameterConstraintClauseSyntax ParseTypeParameterConstraintClause() bool haveComma; if (this.CurrentToken.Kind == SyntaxKind.OpenBraceToken - || ((_termState & TerminatorState.IsEndOfRecordOrClassOrStructOrInterfaceSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken) + || ((_termState & TerminatorState.IsEndOfTypeSignature) != 0 && this.CurrentToken.Kind == SyntaxKind.SemicolonToken) || this.CurrentToken.Kind == SyntaxKind.EqualsGreaterThanToken || this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword) { @@ -2389,6 +2423,12 @@ private bool IsTypeDeclarationStart() // older code that is not using C# 9 we conditionally parse based on langversion return IsFeatureEnabled(MessageID.IDS_FeatureRecords); } + + if (IsExtensionContainerStart()) + { + return true; + } + return false; default: @@ -3064,6 +3104,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind bool isPossibleTypeDeclaration; this.ParseModifiers(modifiers, forAccessors: false, forTopLevelStatements: false, out isPossibleTypeDeclaration); + if (IsExtensionContainerStart()) + { + return this.ParseMainTypeDeclaration(attributes, modifiers); + } + // Check for constructor form if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && this.PeekToken(1).Kind == SyntaxKind.OpenParenToken) { @@ -3193,6 +3238,11 @@ private MemberDeclarationSyntax ParseMemberDeclarationCore(SyntaxKind parentKind } } + private bool IsExtensionContainerStart() + { + return this.CurrentToken.ContextualKind == SyntaxKind.ExtensionKeyword && IsFeatureEnabled(MessageID.IDS_FeatureExtensions); + } + // if the modifiers do not contain async or replace and the type is the identifier "async" or "replace", then // add that identifier to the modifiers and assign a new type from the identifierOrThisOpt and the // type parameter list @@ -3307,7 +3357,7 @@ private ConstructorDeclarationSyntax ParseConstructorDeclaration( _termState |= TerminatorState.IsEndOfMethodSignature; try { - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); var initializer = this.CurrentToken.Kind == SyntaxKind.ColonToken ? this.ParseConstructorInitializer() : null; @@ -3447,7 +3497,7 @@ private bool IsEndOfTypeParameterList() private bool IsEndOfMethodSignature() => this.CurrentToken.Kind is SyntaxKind.SemicolonToken or SyntaxKind.OpenBraceToken; - private bool IsEndOfRecordOrClassOrStructOrInterfaceSignature() + private bool IsEndOfTypeSignature() { return this.CurrentToken.Kind is SyntaxKind.SemicolonToken or SyntaxKind.OpenBraceToken; } @@ -3473,7 +3523,7 @@ private MethodDeclarationSyntax ParseMethodDeclaration( var saveTerm = _termState; _termState |= TerminatorState.IsEndOfMethodSignature; - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); var constraints = default(SyntaxListBuilder); if (this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword) @@ -3685,7 +3735,7 @@ private ConversionOperatorDeclarationSyntax TryParseConversionOperatorDeclaratio type = ParseIdentifierName(); } - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); this.ParseBlockAndExpressionBodiesWithSemicolon(out var blockBody, out var expressionBody, out var semicolon); @@ -3889,7 +3939,7 @@ private MemberDeclarationSyntax ParseOperatorDeclaration( } } - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); switch (paramList.Parameters.Count) { @@ -4502,14 +4552,14 @@ private static SyntaxKind GetAccessorKind(SyntaxToken accessorName) }; } - internal ParameterListSyntax ParseParenthesizedParameterList() + internal ParameterListSyntax ParseParenthesizedParameterList(bool forExtension) { - if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameterList(this.CurrentNode as CSharp.Syntax.ParameterListSyntax)) + if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameterList(this.CurrentNode as CSharp.Syntax.ParameterListSyntax, allowOptionalIdentifier: forExtension)) { return (ParameterListSyntax)this.EatNode(); } - var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken); + var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, forExtension); return _syntaxFactory.ParameterList(open, parameters, close); } @@ -4520,11 +4570,11 @@ internal BracketedParameterListSyntax ParseBracketedParameterList() return (BracketedParameterListSyntax)this.EatNode(); } - var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken); + var parameters = this.ParseParameterList(out var open, out var close, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, forExtension: false); return _syntaxFactory.BracketedParameterList(open, parameters, close); } - private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list) + private static bool CanReuseParameterList(Syntax.ParameterListSyntax list, bool allowOptionalIdentifier) { if (list == null) { @@ -4543,7 +4593,7 @@ private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list foreach (var parameter in list.Parameters) { - if (!CanReuseParameter(parameter)) + if (!CanReuseParameter(parameter, allowOptionalIdentifier)) { return false; } @@ -4552,7 +4602,7 @@ private static bool CanReuseParameterList(CSharp.Syntax.ParameterListSyntax list return true; } - private static bool CanReuseBracketedParameterList(CSharp.Syntax.BracketedParameterListSyntax list) + private static bool CanReuseBracketedParameterList(Syntax.BracketedParameterListSyntax list) { if (list == null) { @@ -4571,7 +4621,7 @@ private static bool CanReuseBracketedParameterList(CSharp.Syntax.BracketedParame foreach (var parameter in list.Parameters) { - if (!CanReuseParameter(parameter)) + if (!CanReuseParameter(parameter, allowOptionalIdentifier: false)) { return false; } @@ -4584,22 +4634,28 @@ private SeparatedSyntaxList ParseParameterList( out SyntaxToken open, out SyntaxToken close, SyntaxKind openKind, - SyntaxKind closeKind) + SyntaxKind closeKind, + bool forExtension) { open = this.EatToken(openKind); var saveTerm = _termState; _termState |= TerminatorState.IsEndOfParameterList; + Func parseElement = forExtension + ? static @this => @this.ParseParameter(allowOptionalIdentifier: true) + : static @this => @this.ParseParameter(allowOptionalIdentifier: false); + var parameters = ParseCommaSeparatedSyntaxList( ref open, closeKind, static @this => @this.IsPossibleParameter(), - static @this => @this.ParseParameter(), + parseElement, skipBadParameterListTokens, allowTrailingSeparator: false, - requireOneElement: false, + requireOneElement: forExtension, // For extension declarations, we require at least one receiver parameter allowSemicolonAsSeparator: false); + // PROTOTYPE consider suppressing parsing diagnostics on extension parameters beyond the first one _termState = saveTerm; close = this.EatToken(closeKind); @@ -4639,7 +4695,7 @@ private bool IsPossibleParameter() } } - private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter) + private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter, bool allowOptionalIdentifier) { if (parameter == null) { @@ -4670,14 +4726,22 @@ private static bool CanReuseParameter(CSharp.Syntax.ParameterSyntax parameter) } } + // We can only reuse parameters without identifiers (found in extension declarations) in context that allow optional identifiers. + // The reverse is fine though. Normal parameters (from non extensions) can be re-used into an extension declaration + // as all normal parameters are legal extension parameters. + if (!allowOptionalIdentifier && parameter.Identifier.Kind() == SyntaxKind.None) + { + return false; + } + return true; } #nullable enable - private ParameterSyntax ParseParameter() + private ParameterSyntax ParseParameter(bool allowOptionalIdentifier) { - if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as CSharp.Syntax.ParameterSyntax)) + if (this.IsIncrementalAndFactoryContextMatches && CanReuseParameter(this.CurrentNode as Syntax.ParameterSyntax, allowOptionalIdentifier)) { return (ParameterSyntax)this.EatNode(); } @@ -4696,19 +4760,22 @@ private ParameterSyntax ParseParameter() } var type = this.ParseType(mode: ParseTypeMode.Parameter); - SyntaxToken identifier; + SyntaxToken? identifier; if (this.CurrentToken.Kind == SyntaxKind.IdentifierToken && IsCurrentTokenWhereOfConstraintClause()) { - identifier = this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected); + identifier = allowOptionalIdentifier ? null : this.AddError(CreateMissingIdentifierToken(), ErrorCode.ERR_IdentifierExpected); } else { - identifier = this.ParseIdentifierToken(); + // The receiver parameter on an extension declaration may have a name or not + identifier = allowOptionalIdentifier && this.CurrentToken.Kind != SyntaxKind.IdentifierToken + ? null + : this.ParseIdentifierToken(); } // When the user type "int goo[]", give them a useful error - if (this.CurrentToken.Kind is SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind is SyntaxKind.CloseBracketToken) + if (identifier is not null && this.CurrentToken.Kind is SyntaxKind.OpenBracketToken && this.PeekToken(1).Kind is SyntaxKind.CloseBracketToken) { identifier = AddTrailingSkippedSyntax(identifier, SyntaxList.List( this.AddError(this.EatToken(), ErrorCode.ERR_BadArraySyntax), @@ -5442,7 +5509,7 @@ private bool IsLocalFunctionAfterIdentifier() using var _ = this.GetDisposableResetPoint(resetOnDispose: true); var typeParameterListOpt = this.ParseTypeParameterList(); - var paramList = ParseParenthesizedParameterList(); + var paramList = ParseParenthesizedParameterList(forExtension: false); if (!paramList.IsMissing && (this.CurrentToken.Kind is SyntaxKind.OpenBraceToken or SyntaxKind.EqualsGreaterThanToken || @@ -5502,7 +5569,7 @@ private DelegateDeclarationSyntax ParseDelegateDeclaration(SyntaxList); if (this.CurrentToken.ContextualKind == SyntaxKind.WhereKeyword) @@ -8429,7 +8496,7 @@ private bool IsPossibleMethodDeclarationFollowingNullableType() var saveTerm = _termState; _termState |= TerminatorState.IsEndOfMethodSignature; - var paramList = this.ParseParenthesizedParameterList(); + var paramList = this.ParseParenthesizedParameterList(forExtension: false); _termState = saveTerm; var separatedParameters = paramList.Parameters.GetWithSeparators(); @@ -10540,7 +10607,7 @@ private LocalFunctionStatementSyntax TryParseLocalFunctionStatementBody( TypeParameterListSyntax typeParameterListOpt = this.ParseTypeParameterList(); // "await f()" still makes sense, so don't force accept a local function if there's a type parameter list. - ParameterListSyntax paramList = this.ParseParenthesizedParameterList(); + ParameterListSyntax paramList = this.ParseParenthesizedParameterList(forExtension: false); // "await x()" is ambiguous (see note at start of this method), but we assume "await x(await y)" is meant to be a function if it's in a non-async context. if (!forceLocalFunc) { @@ -13186,7 +13253,7 @@ AnonymousMethodExpressionSyntax parseAnonymousMethodExpressionWorker() ParameterListSyntax parameterList = null; if (this.CurrentToken.Kind == SyntaxKind.OpenParenToken) { - parameterList = this.ParseParenthesizedParameterList(); + parameterList = this.ParseParenthesizedParameterList(forExtension: false); } // In mismatched braces cases (missing a }) it is possible for delegate declarations to be @@ -13261,7 +13328,7 @@ private bool IsAnonymousFunctionAsyncModifier() return true; case var kind: return IsPredefinedType(kind); - }; + } } /// diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 0ebff1a371642..5f122b7e67c97 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,5 +1,25 @@ Microsoft.CodeAnalysis.CSharp.Conversion.IsSpan.get -> bool Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp13 = 1300 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddConstraintClauses(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddMembers(params Microsoft.CodeAnalysis.CSharp.Syntax.MemberDeclarationSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddTypeParameterListParameters(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Update(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithAttributeLists(Microsoft.CodeAnalysis.SyntaxList attributeLists) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithCloseBraceToken(Microsoft.CodeAnalysis.SyntaxToken closeBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithConstraintClauses(Microsoft.CodeAnalysis.SyntaxList constraintClauses) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithKeyword(Microsoft.CodeAnalysis.SyntaxToken keyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithMembers(Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithOpenBraceToken(Microsoft.CodeAnalysis.SyntaxToken openBraceToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithSemicolonToken(Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.WithTypeParameterList(Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionDeclaration = 9079 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ExtensionKeyword = 8451 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.InterceptableLocation abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Data.get -> string! abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetDisplayLocation() -> string! @@ -7,8 +27,28 @@ abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Version.get -> int Microsoft.CodeAnalysis.CSharp.SyntaxKind.RazorContentToken = 8523 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(object? obj) -> bool override abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.GetHashCode() -> int +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AttributeLists.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.BaseList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BaseListSyntax? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.CloseBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.ConstraintClauses.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Identifier.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Keyword.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Members.get -> Microsoft.CodeAnalysis.SyntaxList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.OpenBraceToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.ParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.SemicolonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +override Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.TypeParameterList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptableLocation(this Microsoft.CodeAnalysis.SemanticModel? semanticModel, Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax! node, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.CSharp.InterceptableLocation? static Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetInterceptsLocationAttributeSyntax(this Microsoft.CodeAnalysis.CSharp.InterceptableLocation! location) -> string! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration() -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxList members) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken keyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterListSyntax? typeParameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax? parameterList, Microsoft.CodeAnalysis.SyntaxList constraintClauses, Microsoft.CodeAnalysis.SyntaxToken openBraceToken, Microsoft.CodeAnalysis.SyntaxList members, Microsoft.CodeAnalysis.SyntaxToken closeBraceToken, Microsoft.CodeAnalysis.SyntaxToken semicolonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> TResult? [RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser [RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Dispose() -> void [RSEXPERIMENTAL003]Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.ParseLeadingTrivia() -> Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser.Result diff --git a/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs new file mode 100644 index 0000000000000..b6b919098d81b --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/ExtensionDeclarationSyntax.cs @@ -0,0 +1,22 @@ +// 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. + +namespace Microsoft.CodeAnalysis.CSharp.Syntax +{ + public partial class ExtensionDeclarationSyntax + { + public override SyntaxToken Identifier => default; + + internal override BaseTypeDeclarationSyntax WithIdentifierCore(SyntaxToken identifier) + => throw new System.NotSupportedException(); + + public override BaseListSyntax? BaseList => null; + + internal override BaseTypeDeclarationSyntax AddBaseListTypesCore(params BaseTypeSyntax[] items) + => throw new System.NotSupportedException(); + + internal override BaseTypeDeclarationSyntax WithBaseListCore(BaseListSyntax? baseList) + => throw new System.NotSupportedException(); + } +} diff --git a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs index b41530c1f7a5d..6750b331260e9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/InternalSyntax/TypeDeclarationSyntax.cs @@ -4,6 +4,7 @@ #nullable disable +using Roslyn.Utilities; using CoreSyntax = Microsoft.CodeAnalysis.Syntax.InternalSyntax; namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax @@ -153,4 +154,47 @@ public override TypeDeclarationSyntax UpdateCore( semicolonToken); } } + + internal partial class ExtensionDeclarationSyntax + { + public override TypeDeclarationSyntax UpdateCore( + CoreSyntax.SyntaxList attributeLists, + CoreSyntax.SyntaxList modifiers, + SyntaxToken keyword, + SyntaxToken identifier, + TypeParameterListSyntax typeParameterList, + ParameterListSyntax parameterList, + BaseListSyntax baseList, + CoreSyntax.SyntaxList constraintClauses, + SyntaxToken openBraceToken, + CoreSyntax.SyntaxList members, + SyntaxToken closeBraceToken, + SyntaxToken semicolonToken) + { + if (identifier is not null) + { + throw ExceptionUtilities.Unreachable(); + } + + if (baseList is not null) + { + throw ExceptionUtilities.Unreachable(); + } + + return this.Update( + attributeLists, + modifiers, + keyword, + typeParameterList, + parameterList, + constraintClauses, + openBraceToken, + members, + closeBraceToken, + semicolonToken); + } + + public override SyntaxToken Identifier => null; + public override BaseListSyntax BaseList => null; + } } diff --git a/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs new file mode 100644 index 0000000000000..44e699e832c3f --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/ParameterDeclarationSyntax.cs @@ -0,0 +1,16 @@ +// 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. + +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp +{ + public partial class SyntaxFactory + { + /// Creates a new ParameterSyntax instance. + public static ParameterSyntax Parameter(SyntaxToken identifier) + => SyntaxFactory.Parameter(default, default(SyntaxTokenList), null, identifier, null); + } +} + diff --git a/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs index 7e070e3fe7c8b..dbd917f946cc9 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SimpleLambdaExpressionSyntax.cs @@ -39,6 +39,14 @@ namespace Microsoft.CodeAnalysis.CSharp { public partial class SyntaxFactory { + /// Creates a new SimpleLambdaExpressionSyntax instance. + public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxList attributeLists, SyntaxTokenList modifiers, ParameterSyntax parameter, BlockSyntax? block, ExpressionSyntax? expressionBody) + => SyntaxFactory.SimpleLambdaExpression(attributeLists, modifiers, parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), block, expressionBody); + + /// Creates a new SimpleLambdaExpressionSyntax instance. + public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(ParameterSyntax parameter) + => SyntaxFactory.SimpleLambdaExpression(default, default(SyntaxTokenList), parameter, SyntaxFactory.Token(SyntaxKind.EqualsGreaterThanToken), null, null); + public static SimpleLambdaExpressionSyntax SimpleLambdaExpression(SyntaxToken asyncKeyword, ParameterSyntax parameter, SyntaxToken arrowToken, BlockSyntax? block, ExpressionSyntax? expressionBody) => SimpleLambdaExpression(attributeLists: default, TokenList(asyncKeyword), parameter, arrowToken, block, expressionBody); diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 8e05ae9fee8b7..2d86da2a20261 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -1440,7 +1440,7 @@ - + @@ -3352,7 +3352,7 @@ Base class for type declaration syntax. - + Gets the identifier. @@ -3384,11 +3384,11 @@ - Base class for type declaration syntax (class, struct, interface, record). + Base class for type declaration syntax (class, struct, interface, record, extension). - Gets the type keyword token ("class", "struct", "interface", "record"). + Gets the type keyword token ("class", "struct", "interface", "record", "extension"). @@ -3617,6 +3617,30 @@ + + + Extension container syntax. + + + + + + + + + + + + + + + + + + + + + Base list syntax. @@ -4307,7 +4331,7 @@ - + Parameter syntax. @@ -4323,7 +4347,8 @@ - + + Gets the identifier. diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index 5c7b02cdd3254..a1cbe33a1b30f 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1817,7 +1817,7 @@ public static ParameterListSyntax ParseParameterList(string text, int offset = 0 using (var lexer = MakeLexer(text, offset, (CSharpParseOptions?)options)) using (var parser = MakeParser(lexer)) { - var node = parser.ParseParenthesizedParameterList(); + var node = parser.ParseParenthesizedParameterList(forExtension: false); if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); return (ParameterListSyntax)node.CreateRed(); } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index d697c4c2202be..d110fee28917e 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -421,6 +421,8 @@ public enum SyntaxKind : ushort FileKeyword = 8449, /// Represents . AllowsKeyword = 8450, + /// Represents . + ExtensionKeyword = 8451, // when adding a contextual keyword following functions must be adapted: // @@ -925,5 +927,7 @@ public enum SyntaxKind : ushort CollectionExpression = 9076, ExpressionElement = 9077, SpreadElement = 9078, + + ExtensionDeclaration = 9079, } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index 17382780cb90e..46cf10aa83278 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1166,7 +1166,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text) public static IEnumerable GetContextualKeywordKinds() { - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.AllowsKeyword; i++) + for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.ExtensionKeyword; i++) { // 8441 corresponds to a deleted kind (DataKeyword) that was previously shipped. if (i != 8441) @@ -1228,6 +1228,7 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.ScopedKeyword: case SyntaxKind.FileKeyword: case SyntaxKind.AllowsKeyword: + case SyntaxKind.ExtensionKeyword: return true; default: return false; @@ -1355,6 +1356,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.FileKeyword; case "allows": return SyntaxKind.AllowsKeyword; + case "extension": + return SyntaxKind.ExtensionKeyword; default: return SyntaxKind.None; } @@ -1802,6 +1805,8 @@ public static string GetText(SyntaxKind kind) return "file"; case SyntaxKind.AllowsKeyword: return "allows"; + case SyntaxKind.ExtensionKeyword: + return "extension"; default: return string.Empty; } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index f9beb8f61f97b..d771b28ccc4ec 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -757,6 +757,11 @@ Strom výrazů nesmí obsahovat výraz with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer {0}: Externí událost nemůže mít inicializátor. @@ -2422,6 +2427,11 @@ vzory rozšířených vlastností + + extensions + extensions + + field keyword klíčové slovo pole @@ -8907,8 +8917,8 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter - Invalid token '{0}' in class, record, struct, or interface member declaration - Neplatný token {0} v deklaraci člena rozhraní, třídy, záznamu nebo struktury + Invalid token '{0}' in a member declaration + Neplatný token {0} v deklaraci člena rozhraní, třídy, záznamu nebo struktury diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f67d28a8bb90d..2fc7e06de4d54 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -757,6 +757,11 @@ Eine Ausdrucksbaumstruktur darf keinen with-Ausdruck enthalten. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer "{0}": Externes Ereignis darf keinen Initialisierer aufweisen. @@ -2422,6 +2427,11 @@ Muster für erweiterte Eigenschaften + + extensions + extensions + + field keyword Feld Schlüsselwort @@ -8907,8 +8917,8 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus - Invalid token '{0}' in class, record, struct, or interface member declaration - Ungültiges Token "{0}" in Klassen-, Datensatz-, Struktur- oder Schnittstellenmemberdeklaration + Invalid token '{0}' in a member declaration + Ungültiges Token "{0}" in Klassen-, Datensatz-, Struktur- oder Schnittstellenmemberdeklaration diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 97ad7e39a3a67..523b525596346 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -757,6 +757,11 @@ Un árbol de expresión no puede contener una expresión with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer "{0}": un evento externo no puede tener un inicializador @@ -2422,6 +2427,11 @@ patrones de propiedad extendidos + + extensions + extensions + + field keyword palabra clave field @@ -8907,8 +8917,8 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar - Invalid token '{0}' in class, record, struct, or interface member declaration - El token "{0}" no es válido en una clase, un registro, una estructura o una declaración de miembro de interfaz + Invalid token '{0}' in a member declaration + El token "{0}" no es válido en una clase, un registro, una estructura o una declaración de miembro de interfaz diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 6c4bc747be0fc..7383e0cf667c8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -757,6 +757,11 @@ Une arborescence de l'expression ne peut pas contenir d'expression with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}' : un événement extern ne peut pas avoir d'initialiseur @@ -2422,6 +2427,11 @@ modèles de propriétés étendues + + extensions + extensions + + field keyword mot-clé du champ @@ -8907,8 +8917,8 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e - Invalid token '{0}' in class, record, struct, or interface member declaration - Jeton '{0}' non valide dans la déclaration de membre de classe, d'enregistrement, de struct ou d'interface + Invalid token '{0}' in a member declaration + Jeton '{0}' non valide dans la déclaration de membre de classe, d'enregistrement, de struct ou d'interface diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 8ac91c37499e7..abed7030e83f3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -757,6 +757,11 @@ Un albero delle espressioni non può contenere un'espressione with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}': l'evento extern non può avere inizializzatori @@ -2422,6 +2427,11 @@ criteri di proprietà estesa + + extensions + extensions + + field keyword parola chiave campo @@ -8907,8 +8917,8 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi - Invalid token '{0}' in class, record, struct, or interface member declaration - Il token '{0}' nella dichiarazione del membro di classe, record, struct o interfaccia non è valido + Invalid token '{0}' in a member declaration + Il token '{0}' nella dichiarazione del membro di classe, record, struct o interfaccia non è valido diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 1435728a114fc..7f18696497376 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -757,6 +757,11 @@ 式ツリーは、with 式を含むことはできません + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}': extern イベントは初期化子を持つことができません @@ -2422,6 +2427,11 @@ 拡張プロパティ パターン + + extensions + extensions + + field keyword field キーワード @@ -8907,8 +8917,8 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 - Invalid token '{0}' in class, record, struct, or interface member declaration - クラス、レコード、構造体、またはインターフェイス メンバーの宣言でトークン '{0}' が無効です + Invalid token '{0}' in a member declaration + クラス、レコード、構造体、またはインターフェイス メンバーの宣言でトークン '{0}' が無効です diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index d4c4a339c7929..e34d54bccda34 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -757,6 +757,11 @@ 식 트리에는 with 식이 포함될 수 없습니다. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}': extern 이벤트에는 이니셜라이저를 사용할 수 없습니다. @@ -2422,6 +2427,11 @@ 확장 속성 패턴 + + extensions + extensions + + field keyword 필드 키워드 @@ -8907,8 +8917,8 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA - Invalid token '{0}' in class, record, struct, or interface member declaration - 클래스, 레코드, 구조체 또는 인터페이스 멤버 선언에 잘못된 토큰 '{0}'이(가) 있습니다. + Invalid token '{0}' in a member declaration + 클래스, 레코드, 구조체 또는 인터페이스 멤버 선언에 잘못된 토큰 '{0}'이(가) 있습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 242fa39cf7703..0189c6cfdbb7a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -757,6 +757,11 @@ Drzewo wyrażeń nie może zawierać wyrażenia with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer „{0}”: zdarzenie extern nie może mieć inicjatora @@ -2422,6 +2427,11 @@ wzorce właściwości rozszerzonych + + extensions + extensions + + field keyword słowo kluczowe pola @@ -8907,8 +8917,8 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n - Invalid token '{0}' in class, record, struct, or interface member declaration - Nieprawidłowy token „{0}” w deklaracji składowej klasy, rekordu, struktury lub interfejsu + Invalid token '{0}' in a member declaration + Nieprawidłowy token „{0}” w deklaracji składowej klasy, rekordu, struktury lub interfejsu diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index aecc0953a73cf..0939296d30e53 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -757,6 +757,11 @@ Uma árvore de expressão não pode conter uma expressão with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}': o evento externo não pode ter inicializador @@ -2422,6 +2427,11 @@ padrões de propriedade estendida + + extensions + extensions + + field keyword campo palavra-chave @@ -8907,8 +8917,8 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar - Invalid token '{0}' in class, record, struct, or interface member declaration - Token inválido '{0}' na declaração de membro de classe, de registro, de struct ou de interface + Invalid token '{0}' in a member declaration + Token inválido '{0}' na declaração de membro de classe, de registro, de struct ou de interface diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index f01a4b78a48da..702b2f26094ea 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -757,6 +757,11 @@ Дерево выражения не может содержать выражение with. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer "{0}": внешнее событие не может иметь инициализатор @@ -2422,6 +2427,11 @@ шаблоны расширенных свойств + + extensions + extensions + + field keyword ключевое слово поля @@ -8908,8 +8918,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Invalid token '{0}' in class, record, struct, or interface member declaration - Недопустимый токен "{0}" в объявлении класса, записи, структуры или элемента интерфейса + Invalid token '{0}' in a member declaration + Недопустимый токен "{0}" в объявлении класса, записи, структуры или элемента интерфейса diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 96e2fa7558ec1..bb9d1866d880e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -757,6 +757,11 @@ İfade ağacı, with ifadesi içeremez. + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}': dış etkinliğin başlatıcısı olamaz @@ -2422,6 +2427,11 @@ genişletilmiş özellik desenleri + + extensions + extensions + + field keyword alan anahtar sözcüğü @@ -8907,8 +8917,8 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm - Invalid token '{0}' in class, record, struct, or interface member declaration - Sınıf, kayıt, yapı veya arabirim üye bildiriminde '{0}' belirteci geçersiz + Invalid token '{0}' in a member declaration + Sınıf, kayıt, yapı veya arabirim üye bildiriminde '{0}' belirteci geçersiz diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 2ff45997e4afb..7e487541e5f36 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -757,6 +757,11 @@ 表达式树不能包含 with 表达式。 + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer “{0}”: 外部事件不能有初始值设定项 @@ -2422,6 +2427,11 @@ 扩展的属性模式 + + extensions + extensions + + field keyword 字段关键字 @@ -8907,8 +8917,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Invalid token '{0}' in class, record, struct, or interface member declaration - 类、记录、结构或接口成员声明中的标记“{0}”无效 + Invalid token '{0}' in a member declaration + 类、记录、结构或接口成员声明中的标记“{0}”无效 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index ec8fad7250765..de89a093f15b7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -757,6 +757,11 @@ 運算式樹狀架構不得包含 with 運算式。 + + Extension declarations may not have a name. + Extension declarations may not have a name. + + '{0}': extern event cannot have initializer '{0}': 外部事件不可有初始設定式 @@ -2422,6 +2427,11 @@ 擴充屬性模式 + + extensions + extensions + + field keyword 欄位關鍵字 @@ -8907,8 +8917,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Invalid token '{0}' in class, record, struct, or interface member declaration - 類別、記錄、結構或介面成員宣告中的語彙基元 '{0}' 無效 + Invalid token '{0}' in a member declaration + 類別、記錄、結構或介面成員宣告中的語彙基元 '{0}' 無效 diff --git a/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs index 971a72c210829..b2901f9adeb50 100644 --- a/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs +++ b/src/Compilers/CSharp/Test/Emit3/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs @@ -36,6 +36,8 @@ public void DiagnosticAnalyzerAllInOne() missingSyntaxKinds.Add(SyntaxKind.CollectionExpression); missingSyntaxKinds.Add(SyntaxKind.ExpressionElement); missingSyntaxKinds.Add(SyntaxKind.SpreadElement); + // PROTOTYPE Add to all-in-one + missingSyntaxKinds.Add(SyntaxKind.ExtensionDeclaration); var analyzer = new CSharpTrackingDiagnosticAnalyzer(); var options = new AnalyzerOptions(new[] { new TestAdditionalText() }.ToImmutableArray()); 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 88f2342f45eec..604aa3566ef2d 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 @@ -520,6 +520,9 @@ private static Syntax.InternalSyntax.DelegateDeclarationSyntax GenerateDelegateD private static Syntax.InternalSyntax.EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration() => InternalSyntaxFactory.EnumMemberDeclaration(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), InternalSyntaxFactory.Identifier("Identifier"), null); + private static Syntax.InternalSyntax.ExtensionDeclarationSyntax GenerateExtensionDeclaration() + => InternalSyntaxFactory.ExtensionDeclaration(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.ExtensionKeyword), null, null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, null); + private static Syntax.InternalSyntax.BaseListSyntax GenerateBaseList() => InternalSyntaxFactory.BaseList(InternalSyntaxFactory.Token(SyntaxKind.ColonToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList()); @@ -602,7 +605,7 @@ private static Syntax.InternalSyntax.BracketedParameterListSyntax GenerateBracke => InternalSyntaxFactory.BracketedParameterList(InternalSyntaxFactory.Token(SyntaxKind.OpenBracketToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.CloseBracketToken)); private static Syntax.InternalSyntax.ParameterSyntax GenerateParameter() - => InternalSyntaxFactory.Parameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, InternalSyntaxFactory.Identifier("Identifier"), null); + => InternalSyntaxFactory.Parameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), null, null, null); private static Syntax.InternalSyntax.FunctionPointerParameterSyntax GenerateFunctionPointerParameter() => InternalSyntaxFactory.FunctionPointerParameter(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), GenerateIdentifierName()); @@ -2891,6 +2894,25 @@ public void TestEnumMemberDeclarationFactoryAndProperties() AttachAndCheckDiagnostics(node); } + [Fact] + public void TestExtensionDeclarationFactoryAndProperties() + { + var node = GenerateExtensionDeclaration(); + + Assert.Equal(default, node.AttributeLists); + Assert.Equal(default, node.Modifiers); + Assert.Equal(SyntaxKind.ExtensionKeyword, node.Keyword.Kind); + Assert.Null(node.TypeParameterList); + Assert.Null(node.ParameterList); + Assert.Equal(default, node.ConstraintClauses); + Assert.Null(node.OpenBraceToken); + Assert.Equal(default, node.Members); + Assert.Null(node.CloseBraceToken); + Assert.Null(node.SemicolonToken); + + AttachAndCheckDiagnostics(node); + } + [Fact] public void TestBaseListFactoryAndProperties() { @@ -3268,7 +3290,7 @@ public void TestParameterFactoryAndProperties() Assert.Equal(default, node.AttributeLists); Assert.Equal(default, node.Modifiers); Assert.Null(node.Type); - Assert.Equal(SyntaxKind.IdentifierToken, node.Identifier.Kind); + Assert.Null(node.Identifier); Assert.Null(node.Default); AttachAndCheckDiagnostics(node); @@ -8297,6 +8319,32 @@ public void TestEnumMemberDeclarationIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestExtensionDeclarationTokenDeleteRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + 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 TestExtensionDeclarationIdentityRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestBaseListTokenDeleteRewriter() { @@ -10736,6 +10784,9 @@ private static DelegateDeclarationSyntax GenerateDelegateDeclaration() private static EnumMemberDeclarationSyntax GenerateEnumMemberDeclaration() => SyntaxFactory.EnumMemberDeclaration(new SyntaxList(), new SyntaxTokenList(), SyntaxFactory.Identifier("Identifier"), default(EqualsValueClauseSyntax)); + private static ExtensionDeclarationSyntax GenerateExtensionDeclaration() + => SyntaxFactory.ExtensionDeclaration(new SyntaxList(), new SyntaxTokenList(), SyntaxFactory.Token(SyntaxKind.ExtensionKeyword), default(TypeParameterListSyntax), default(ParameterListSyntax), new SyntaxList(), default(SyntaxToken), new SyntaxList(), default(SyntaxToken), default(SyntaxToken)); + private static BaseListSyntax GenerateBaseList() => SyntaxFactory.BaseList(SyntaxFactory.Token(SyntaxKind.ColonToken), new SeparatedSyntaxList()); @@ -10818,7 +10869,7 @@ private static BracketedParameterListSyntax GenerateBracketedParameterList() => SyntaxFactory.BracketedParameterList(SyntaxFactory.Token(SyntaxKind.OpenBracketToken), new SeparatedSyntaxList(), SyntaxFactory.Token(SyntaxKind.CloseBracketToken)); private static ParameterSyntax GenerateParameter() - => SyntaxFactory.Parameter(new SyntaxList(), new SyntaxTokenList(), default(TypeSyntax), SyntaxFactory.Identifier("Identifier"), default(EqualsValueClauseSyntax)); + => SyntaxFactory.Parameter(new SyntaxList(), new SyntaxTokenList(), default(TypeSyntax), default(SyntaxToken), default(EqualsValueClauseSyntax)); private static FunctionPointerParameterSyntax GenerateFunctionPointerParameter() => SyntaxFactory.FunctionPointerParameter(new SyntaxList(), new SyntaxTokenList(), GenerateIdentifierName()); @@ -13107,6 +13158,25 @@ public void TestEnumMemberDeclarationFactoryAndProperties() Assert.Equal(node, newNode); } + [Fact] + public void TestExtensionDeclarationFactoryAndProperties() + { + var node = GenerateExtensionDeclaration(); + + Assert.Equal(default, node.AttributeLists); + Assert.Equal(default, node.Modifiers); + Assert.Equal(SyntaxKind.ExtensionKeyword, node.Keyword.Kind()); + Assert.Null(node.TypeParameterList); + Assert.Null(node.ParameterList); + Assert.Equal(default, node.ConstraintClauses); + Assert.Equal(SyntaxKind.None, node.OpenBraceToken.Kind()); + Assert.Equal(default, node.Members); + Assert.Equal(SyntaxKind.None, node.CloseBraceToken.Kind()); + Assert.Equal(SyntaxKind.None, node.SemicolonToken.Kind()); + var newNode = node.WithAttributeLists(node.AttributeLists).WithModifiers(node.Modifiers).WithKeyword(node.Keyword).WithTypeParameterList(node.TypeParameterList).WithParameterList(node.ParameterList).WithConstraintClauses(node.ConstraintClauses).WithOpenBraceToken(node.OpenBraceToken).WithMembers(node.Members).WithCloseBraceToken(node.CloseBraceToken).WithSemicolonToken(node.SemicolonToken); + Assert.Equal(node, newNode); + } + [Fact] public void TestBaseListFactoryAndProperties() { @@ -13484,7 +13554,7 @@ public void TestParameterFactoryAndProperties() Assert.Equal(default, node.AttributeLists); Assert.Equal(default, node.Modifiers); Assert.Null(node.Type); - Assert.Equal(SyntaxKind.IdentifierToken, node.Identifier.Kind()); + Assert.Equal(SyntaxKind.None, node.Identifier.Kind()); Assert.Null(node.Default); var newNode = node.WithAttributeLists(node.AttributeLists).WithModifiers(node.Modifiers).WithType(node.Type).WithIdentifier(node.Identifier).WithDefault(node.Default); Assert.Equal(node, newNode); @@ -18513,6 +18583,32 @@ public void TestEnumMemberDeclarationIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestExtensionDeclarationTokenDeleteRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + 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 TestExtensionDeclarationIdentityRewriter() + { + var oldNode = GenerateExtensionDeclaration(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestBaseListTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs index 9b02ce60e8227..b133bb0333a74 100644 --- a/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/IncrementalParsing/IncrementalParsingTests.cs @@ -9,6 +9,8 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Roslyn.Test.Utilities; using Xunit; @@ -104,27 +106,35 @@ public void TestChangeClassNameToNotMatchConstructor() TestDiffsInOrder(diffs, SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, - SyntaxKind.IdentifierToken, - SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, - SyntaxKind.VoidKeyword); + SyntaxKind.IdentifierToken); } - private static void TestDiffsInOrder(ImmutableArray diffs, params SyntaxKind[] kinds) + private static void TestDiffsInOrder(ImmutableArray diffs, params SyntaxKind[] expectedKinds) { - Assert.InRange(diffs.Length, 0, kinds.Length); + if (diffs.Length != expectedKinds.Length) + { + Assert.Fail(getMessage()); + } - int diffI = 0; - foreach (var kind in kinds) + for (int i = 0; i < diffs.Length; i++) { - if (diffI < diffs.Length && diffs[diffI].IsKind(kind)) + if (!diffs[i].IsKind(expectedKinds[i])) { - diffI++; + Assert.Fail(getMessage()); } } - // all diffs must be consumed. - Assert.Equal(diffI, diffs.Length); + string getMessage() + { + var builder = PooledStringBuilder.GetInstance(); + builder.Builder.AppendLine("Actual:"); + foreach (var diff in diffs) + { + builder.Builder.AppendLine($"SyntaxKind.{diff.Kind()},"); + } + + return builder.ToStringAndFree(); + } } [Fact] @@ -140,8 +150,7 @@ public void TestChangeClassNameToMatchConstructor() TestDiffsInOrder(diffs, SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, - SyntaxKind.IdentifierToken, - SyntaxKind.ConstructorDeclaration); + SyntaxKind.IdentifierToken); } [Fact] @@ -226,7 +235,6 @@ public void TestChangeMethodName() SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.IdentifierToken); } @@ -294,11 +302,8 @@ class C { void N() { } } SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, SyntaxKind.ClassKeyword, - SyntaxKind.IdentifierToken, SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.IdentifierToken, - SyntaxKind.ParameterList, SyntaxKind.Block, SyntaxKind.EndOfFileToken); } @@ -377,7 +382,6 @@ class C { void c() { } } SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, // class declaration on edge before change SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.Block, SyntaxKind.ClassDeclaration, // class declaration on edge after change SyntaxKind.ClassKeyword, // edge of change and directives different @@ -421,7 +425,6 @@ class C { void c() { } } SyntaxKind.CompilationUnit, SyntaxKind.ClassDeclaration, // class declaration on edge before change SyntaxKind.MethodDeclaration, - SyntaxKind.PredefinedType, SyntaxKind.Block, SyntaxKind.ClassDeclaration, // class declaration on edge after change SyntaxKind.ClassKeyword, // edge of change and directives different @@ -442,11 +445,9 @@ public void TestGlobalStatementToStatementChange() SyntaxKind.GlobalStatement, SyntaxKind.Block, SyntaxKind.OpenBraceToken, - SyntaxKind.EmptyStatement, SyntaxKind.LocalDeclarationStatement, SyntaxKind.VariableDeclaration, SyntaxKind.PointerType, - SyntaxKind.IdentifierName, SyntaxKind.VariableDeclarator, SyntaxKind.SemicolonToken, // missing SyntaxKind.CloseBraceToken); // missing @@ -464,12 +465,10 @@ public void TestStatementToGlobalStatementChange() TestDiffsInOrder(diffs, SyntaxKind.CompilationUnit, SyntaxKind.GlobalStatement, - SyntaxKind.EmptyStatement, SyntaxKind.GlobalStatement, SyntaxKind.ExpressionStatement, SyntaxKind.MultiplyExpression, SyntaxKind.IdentifierName, - SyntaxKind.IdentifierName, SyntaxKind.SemicolonToken); } @@ -846,6 +845,437 @@ public void M2() WalkTreeAndVerify(withCloseBraceDeletedTree.GetCompilationUnitRoot(), fullTree.GetCompilationUnitRoot()); } + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromExtensionToClass() + { + var text = @" +class C +{ + extension(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("extension", "class D"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassKeyword, + SyntaxKind.IdentifierToken); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromExtensionToClass_NoParameterIdentifier() + { + var text = @" +class C +{ + extension(object) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("extension", "class D"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify( + // (4,19): error CS1001: Identifier expected + // class D(object) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19)); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassKeyword, + SyntaxKind.IdentifierToken, + SyntaxKind.ParameterList, + SyntaxKind.Parameter, + SyntaxKind.IdentifierToken); + + UsingTree(newTree, + // (4,19): error CS1001: Identifier expected + // class D(object) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromExtensionToClass_WithName() + { + var text = @" +class C +{ + extension E(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("extension", "class"); + oldTree.GetDiagnostics().Verify( + // (4,15): error CS9500: Extension declarations may not have a name. + // extension E(object x) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "E").WithLocation(4, 15)); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassDeclaration, + SyntaxKind.ClassKeyword, + SyntaxKind.IdentifierToken); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "E"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromClassToExtension() + { + var text = @" +class C +{ + class D(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("class D", "extension"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromClassToExtension_NoParameterIdentifier() + { + var text = @" +class C +{ + class D(object) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("class D", "extension"); + oldTree.GetDiagnostics().Verify( + // (4,19): error CS1001: Identifier expected + // class D(object) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(4, 19)); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword, + SyntaxKind.ParameterList, + SyntaxKind.Parameter); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateFromClassToExtension_WithName() + { + var text = @" +class C +{ + struct D(object x) { } +} +"; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("struct", "extension"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify( + // (4,15): error CS9500: Extension declarations may not have a name. + // extension D(object x) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "D").WithLocation(4, 15)); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword); + + UsingTree(newTree, + // (4,15): error CS9500: Extension declarations may not have a name. + // extension D(object x) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "D").WithLocation(4, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.Extensions)] + public void UpdateExtension_ChangeParameterList() + { + var text = """ +class C +{ + extension(object, Type z1) { } +} +"""; + var oldTree = this.Parse(text, LanguageVersionFacts.CSharpNext); + var newTree = oldTree.WithReplaceFirst("z1", "z2"); + oldTree.GetDiagnostics().Verify(); + newTree.GetDiagnostics().Verify(); + + var diffs = SyntaxDifferences.GetRebuiltNodes(oldTree, newTree); + TestDiffsInOrder(diffs, + SyntaxKind.CompilationUnit, + SyntaxKind.ClassDeclaration, + SyntaxKind.ExtensionDeclaration, + SyntaxKind.ExtensionKeyword, + SyntaxKind.ParameterList, + SyntaxKind.Parameter, + SyntaxKind.IdentifierToken); + + UsingTree(newTree); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "z2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + #region "Regression" #if false diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs new file mode 100644 index 0000000000000..b17bde0719be2 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ExtensionsParsingTests.cs @@ -0,0 +1,4802 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#nullable disable + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +[CompilerTrait(CompilerFeature.Extensions)] +public class ExtensionsParsingTests : ParsingTests +{ + public ExtensionsParsingTests(ITestOutputHelper output) : base(output) { } + + [Fact] + public void LangVer13() + { + // PROTOTYPE consider giving a LangVer error to trigger UpgradeProject + UsingTree(""" +class C +{ + extension(object o) where T : struct { } +} +""", + TestOptions.Regular13, + // (3,17): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 17), + // (3,26): error CS8124: Tuple must contain at least two elements. + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 26), + // (3,34): error CS1002: ; expected + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "T").WithLocation(3, 34), + // (3,36): error CS1519: Invalid token ':' in class, record, struct, or interface member declaration + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 36), + // (3,36): error CS1519: Invalid token ':' in class, record, struct, or interface member declaration + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 36), + // (3,45): error CS1001: Identifier expected + // extension(object o) where T : struct { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 45)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + } + } + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + M(SyntaxKind.CommaToken); + M(SyntaxKind.TupleElement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "where"); + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void LangVer14(bool useCSharp14) + { + UsingTree(""" +class C +{ + extension(object o) where T : struct { } +} +""", + useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MultipleConstraints() + { + UsingTree(""" +class C +{ + extension(object o) where T1 : struct where T2 : class { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.ClassConstraint); + { + N(SyntaxKind.ClassKeyword); + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MultipleConstraints_Incomplete() + { + UsingTree(""" +class C +{ + extension(object o) where T1 where T2 : class { } +} +""", + TestOptions.RegularPreview, + // (3,42): error CS1003: Syntax error, ':' expected + // extension(object o) where T1 where T2 : class { } + Diagnostic(ErrorCode.ERR_SyntaxError, "where").WithArguments(":").WithLocation(3, 42), + // (3,42): error CS1031: Type expected + // extension(object o) where T1 where T2 : class { } + Diagnostic(ErrorCode.ERR_TypeExpected, "where").WithLocation(3, 42)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T1"); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T2"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.ClassConstraint); + { + N(SyntaxKind.ClassKeyword); + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithName() + { + UsingTree(""" +class C +{ + extension Name(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,15): error CS9500: Extension declarations may not have a name. + // extension Name(Type) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithName_02() + { + UsingTree(""" +class C +{ + extension Name(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,15): error CS9500: Extension declarations may not have a name. + // extension Name(Type) { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithDefaultParameterValue() + { + var src = """ +class C +{ + extension(Type x = null) { } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithDefaultParameterValue_02() + { + var src = """ +class C +{ + extension(Type = null) { } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithDefaultParameterValue_03() + { + var src = """ +class C +{ + extension(Type =) { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,21): error CS1525: Invalid expression term ')' + // extension(Type =) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(3, 21)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithBaseList() + { + var src = """ +class C +{ + extension Name(Type) : Type2() { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,15): error CS9500: Extension declarations may not have a name. + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_ExtensionDisallowsName, "Name").WithLocation(3, 15), + // (3,26): error CS1514: { expected + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_LbraceExpected, ":").WithLocation(3, 26), + // (3,26): error CS1513: } expected + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_RbraceExpected, ":").WithLocation(3, 26), + // (3,26): error CS1519: Invalid token ':' in a member declaration + // extension Name(Type) : Type2() { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ":").WithArguments(":").WithLocation(3, 26)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + M(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "Type2"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory, CombinatorialData] + public void TypeNamedExtension(bool useCSharp14) + { + UsingTree(""" +class extension +{ + extension(Type constructorParameter) { } +} +""", + TestOptions.Regular13); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "constructorParameter"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + + // PROTOTYPE report error for declaring type named "extension" + // Note: break from C# 13 + UsingTree(""" +class extension +{ + extension(Type constructorParameter) { } +} +""", + useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "constructorParameter"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + + UsingTree(""" +class extension +{ + @extension(Type constructorParameter) { } +} +""", + useCSharp14 ? TestOptions.RegularNext : TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "@extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "constructorParameter"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_NoName() + { + UsingTree(""" +class C +{ + extension(Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_NoName_02() + { + UsingTree(""" +class C +{ + extension(object) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple() + { + var src = """ +class C +{ + extension(Type x1, Type x2) { } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_02() + { + var src = """ +class C +{ + extension(Type, Type) { } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_03() + { + var src = """ +class C +{ + extension(object object) { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,22): error CS1003: Syntax error, ',' expected + // extension(object object) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "object").WithArguments(",").WithLocation(3, 22)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_04() + { + var src = """ +class C +{ + extension(Type, object object) { } +} +"""; + + UsingTree(src, TestOptions.RegularPreview, + // (3,28): error CS1003: Syntax error, ',' expected + // extension(Type, object object) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "object").WithArguments(",").WithLocation(3, 28)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_05() + { + var src = """ +class C +{ + extension(Type, object =) { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,29): error CS1525: Invalid expression term ')' + // extension(Type, object =) { } + Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(3, 29)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_06() + { + var src = """ +class C +{ + extension(Type, object { } +} +"""; + UsingTree(src, TestOptions.RegularPreview, + // (3,28): error CS1026: ) expected + // extension(Type, object { } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(3, 28)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_Multiple_07() + { + var src = """ +class C +{ + extension(Type, params object[]) { } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ParamsKeyword); + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ReceiverParameter_MissingClosingParen() + { + var src = """ +class C +{ + extension(object { } +} +"""; + + UsingTree(src, TestOptions.RegularPreview, + // (3,22): error CS1026: ) expected + // extension(object { } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(3, 22)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.ObjectKeyword); + } + } + M(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void NoClosingBrace() + { + UsingTree(""" +class C +{ + extension(Type) { void M() { } +} +""", + TestOptions.RegularPreview, + // (4,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TopLevel() + { + var src = """ +extension(Type) { } +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void InNestedType() + { + var src = """ +class C +{ + class Nested + { + extension(Type) { } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Nested"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void InExtension() + { + var src = """ +class C +{ + extension(Type1) + { + extension(Type2) { } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type1"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type2"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithAttributes() + { + // PROTOTYPE should be a semantic error + UsingTree(""" +class C +{ + [MyAttribute] + extension(Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyAttribute"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Partial() + { + UsingTree(""" +class C +{ + partial extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,27): error CS1001: Identifier expected + // partial extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 27)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Scoped() + { + UsingTree(""" +class C +{ + scoped extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,26): error CS1001: Identifier expected + // scoped extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 26)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "scoped"); + } + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Async() + { + UsingTree(""" +class C +{ + async extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,25): error CS1001: Identifier expected + // async extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(3, 25)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + N(SyntaxKind.IdentifierToken, "extension"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + M(SyntaxKind.IdentifierToken); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Const() + { + UsingTree(""" +class C +{ + const extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,20): error CS1001: Identifier expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 20), + // (3,20): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_BadVarDecl, "(Type").WithLocation(3, 20), + // (3,20): error CS1003: Syntax error, '[' expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 20), + // (3,25): error CS1003: Syntax error, ']' expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 25), + // (3,27): error CS1003: Syntax error, ',' expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 27), + // (3,29): error CS1002: ; expected + // const extension(Type) { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(3, 29), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.ConstKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + N(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.BracketedArgumentList); + { + M(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CloseBracketToken); + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Fixed() + { + UsingTree(""" +class C +{ + fixed extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,20): error CS1001: Identifier expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "(").WithLocation(3, 20), + // (3,20): error CS1528: Expected ; or = (cannot specify constructor arguments in declaration) + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_BadVarDecl, "(Type").WithLocation(3, 20), + // (3,20): error CS1003: Syntax error, '[' expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("[").WithLocation(3, 20), + // (3,25): error CS1003: Syntax error, ']' expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments("]").WithLocation(3, 25), + // (3,27): error CS1003: Syntax error, ',' expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(",").WithLocation(3, 27), + // (3,29): error CS1002: ; expected + // fixed extension(Type) { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "}").WithLocation(3, 29), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FixedKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + N(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.BracketedArgumentList); + { + M(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CloseBracketToken); + } + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifiers_Ref() + { + UsingTree(""" +class C +{ + ref extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,18): error CS1519: Invalid token '(' in a member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 18), + // (3,23): error CS8124: Tuple must contain at least two elements. + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 23), + // (3,25): error CS1519: Invalid token '{' in a member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 25), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CommaToken); + M(SyntaxKind.TupleElement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData("abstract", SyntaxKind.AbstractKeyword)] + [InlineData("sealed", SyntaxKind.SealedKeyword)] + [InlineData("static", SyntaxKind.StaticKeyword)] + [InlineData("new", SyntaxKind.NewKeyword)] + [InlineData("public", SyntaxKind.PublicKeyword)] + [InlineData("protected", SyntaxKind.ProtectedKeyword)] + [InlineData("private", SyntaxKind.PrivateKeyword)] + [InlineData("readonly", SyntaxKind.ReadOnlyKeyword)] + [InlineData("volatile", SyntaxKind.VolatileKeyword)] + [InlineData("extern", SyntaxKind.ExternKeyword)] + [InlineData("unsafe", SyntaxKind.UnsafeKeyword)] + [InlineData("virtual", SyntaxKind.VirtualKeyword)] + [InlineData("override", SyntaxKind.OverrideKeyword)] + [InlineData("required", SyntaxKind.RequiredKeyword)] + [InlineData("file", SyntaxKind.FileKeyword)] + public void WithModifiers_Misc(string modifier, SyntaxKind expected) + { + var src = $$""" +class C +{ + {{modifier}} extension(Type) { } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(expected); + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation + public void Member_Const() + { + var src = """ +class C +{ + extension(Type) + { + const int i = 0; + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.ConstKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "i"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_FixedField() + { + var src = """ +class C +{ + extension(Type) + { + fixed int field[10]; + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FixedKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + N(SyntaxKind.BracketedArgumentList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Argument); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "10"); + } + } + N(SyntaxKind.CloseBracketToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_EventField() + { + var src = """ +class C +{ + extension(Type) + { + event EventHandler eventField; + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "EventHandler"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "eventField"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Event() + { + var src = """ +class C +{ + extension(Type) + { + event EventHandler Event { add; remove; } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "EventHandler"); + } + N(SyntaxKind.IdentifierToken, "Event"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.AddAccessorDeclaration); + { + N(SyntaxKind.AddKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.RemoveAccessorDeclaration); + { + N(SyntaxKind.RemoveKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_MethodAndProperty() + { + UsingTree(""" +class C +{ + extension(Type) + { + void M() { } + int Property { get; set; } + } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "Property"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Nested() + { + var src = """ +class C +{ + extension(Type) + { + class Nested { } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Nested"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation + public void Member_Constructor() + { + var src = """ +class C +{ + extension(Type) + { + Constructor() { } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation + public void Member_StaticConstructor() + { + var src = """ +class C +{ + extension(Type) + { + static Constructor() { } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.IdentifierToken, "Constructor"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [ConditionalFact(typeof(NoIOperationValidation))] // PROTOTYPE enable IOperation + public void Member_Finalizer() + { + var src = """ +class C +{ + extension(Type) + { + ~Finalizer() { } + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.DestructorDeclaration); + { + N(SyntaxKind.TildeToken); + N(SyntaxKind.IdentifierToken, "Finalizer"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Field() + { + var src = """ +class C +{ + extension(Type) + { + int field; + } +} +"""; + // PROTOTYPE should be a semantic error + var comp = CreateCompilation(src); + comp.VerifyDiagnostics(); + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "field"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Indexer() + { + var src = """ +class C +{ + extension(Type) + { + int this[int i] { get => 0; set { } } + } +} +"""; + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IndexerDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.BracketedParameterList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "i"); + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_Operator() + { + var src = """ +class C +{ + extension(Type) + { + public static Type operator +(Type a, Type b) => a; + } +} +"""; + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PlusToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "a"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "b"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Member_ConversionOperator() + { + var src = """ +class C +{ + extension(Type) + { + static implicit operator int(Type t) => 0; + } +} +"""; + + UsingTree(src, TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConversionOperatorDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "0"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithRef() + { + UsingTree(""" +class C +{ + ref extension(Type) { } +} +""", + TestOptions.RegularPreview, + // (3,18): error CS1519: Invalid token '(' in class, record, struct, or interface member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "(").WithArguments("(").WithLocation(3, 18), + // (3,23): error CS8124: Tuple must contain at least two elements. + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_TupleTooFewElements, ")").WithLocation(3, 23), + // (3,25): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration + // ref extension(Type) { } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 25), + // (4,1): error CS1022: Type or namespace definition, or end-of-file expected + // } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(4, 1)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RefType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "extension"); + } + } + } + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + M(SyntaxKind.CommaToken); + M(SyntaxKind.TupleElement); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithAttributeOnParameter() + { + UsingTree(""" +class C +{ + extension([MyAttribute] Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyAttribute"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifierOnParameter() + { + UsingTree(""" +class C +{ + extension(ref Type) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifierOnParameter_Scoped() + { + UsingTree(""" +class C +{ + extension(scoped Type x) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ScopedKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithModifierOnParameter_ScopedRef() + { + UsingTree(""" +class C +{ + extension(scoped ref Type x) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.ScopedKeyword); + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData("partial")] + [InlineData("await")] + [InlineData("on")] + [InlineData("by")] + public void MiscIdentifier(string identifier) + { + UsingTree($$""" +class C +{ + extension(Type {{identifier}}) { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, identifier); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_SemiColon() + { + UsingTree(""" +class C +{ + extension(Type) { ; + class D { } +} +""", + TestOptions.RegularPreview, + // (3,23): error CS1519: Invalid token ';' in a member declaration + // extension(Type) { ; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23), + // (5,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(5, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_SemiColon_02() + { + UsingTree(""" +class C +{ + extension(Type) { ; +} +""", + TestOptions.RegularPreview, + // (3,23): error CS1519: Invalid token ';' in a member declaration + // extension(Type) { ; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 23), + // (4,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_SemiColon_03() + { + UsingTree(""" +class C +{ + extension' expected + // extension").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, '(' expected + // extension(Type) where T : struct; + class D { } +} +""", + TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace() + { + UsingTree(""" +class C +{ + extension(Type) { { +} +""", + TestOptions.RegularPreview, + // (3,23): error CS1519: Invalid token '{' in a member declaration + // extension(Type) { { + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(3, 23), + // (4,2): error CS1513: } expected + // } + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + M(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_02() + { + UsingTree(""" +class C +{ + extension(Type) where { } +} +""", + TestOptions.RegularPreview, + // (3,30): error CS1001: Identifier expected + // extension(Type) where { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(3, 30), + // (3,30): error CS1003: Syntax error, ':' expected + // extension(Type) where { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(3, 30), + // (3,30): error CS1031: Type expected + // extension(Type) where { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 30)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_03() + { + UsingTree(""" +class C +{ + extension(Type) where T { } + class D { } +} +""", + TestOptions.RegularPreview, + // (3,32): error CS1003: Syntax error, ':' expected + // extension(Type) where T { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments(":").WithLocation(3, 32), + // (3,32): error CS1031: Type expected + // extension(Type) where T { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 32)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + M(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_04() + { + UsingTree(""" +class C +{ + extension(Type) where T : { } +} +""", + TestOptions.RegularPreview, + // (3,34): error CS1031: Type expected + // extension(Type) where T : { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 34)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_05() + { + UsingTree(""" +class C +{ + extension(Type) where T : struct, { } +} +""", + TestOptions.RegularPreview, + // (3,42): error CS1031: Type expected + // extension(Type) where T : struct, { } + Diagnostic(ErrorCode.ERR_TypeExpected, "{").WithLocation(3, 42)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ExtensionDeclaration); + { + N(SyntaxKind.ExtensionKeyword); + N(SyntaxKind.TypeParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.TypeParameter); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.TypeParameterConstraintClause); + { + N(SyntaxKind.WhereKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "T"); + } + N(SyntaxKind.ColonToken); + N(SyntaxKind.StructConstraint); + { + N(SyntaxKind.StructKeyword); + } + N(SyntaxKind.CommaToken); + M(SyntaxKind.TypeConstraint); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void WithTerminator_OpenBrace_06() + { + UsingTree(""" +class C +{ + extension' expected + // extension").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, '(' expected + // extension