diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index ed6e1a9cc2af0..2e6e1e10bc39b 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -6180,6 +6180,15 @@ internal static string ERR_InvalidFormatForGuidForOption { } } + /// + /// Looks up a localized string similar to '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'.. + /// + internal static string ERR_InvalidFunctionPointerCallingConvention { + get { + return ResourceManager.GetString("ERR_InvalidFunctionPointerCallingConvention", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid type specified as an argument for TypeForwardedTo attribute. /// @@ -11374,6 +11383,15 @@ internal static string IDS_FeatureFixedBuffer { } } + /// + /// Looks up a localized string similar to function pointers. + /// + internal static string IDS_FeatureFunctionPointers { + get { + return ResourceManager.GetString("IDS_FeatureFunctionPointers", resourceCulture); + } + } + /// /// Looks up a localized string similar to generics. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index b06d12164a68f..ac3749a5e954e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5945,6 +5945,12 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Command-line syntax error: '{0}' is not a valid value for the '{1}' option. The value must be of the form '{2}'. + + function pointers + + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + Internal error in the C# compiler. diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index e5d2405fbf9ac..77ebe952bb9f7 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1736,6 +1736,12 @@ internal enum ErrorCode ERR_InternalError = 8751, + #region diagnostics introduced in preview + + ERR_InvalidFunctionPointerCallingConvention = 8752, + + #endregion + // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) } } diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 402907c2c08a7..f60f831e5567b 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -185,6 +185,7 @@ internal enum MessageID IDS_FeatureSwitchExpression = MessageBase + 12763, IDS_FeatureAsyncUsing = MessageBase + 12764, IDS_FeatureLambdaDiscardParameters = MessageBase + 12765, + IDS_FeatureFunctionPointers = MessageBase + 12766, } // Message IDs may refer to strings that need to be localized. @@ -293,6 +294,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) { // Preview features. case MessageID.IDS_FeatureLambdaDiscardParameters: // semantic check + case MessageID.IDS_FeatureFunctionPointers: return LanguageVersion.Preview; // C# 8.0 features. diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index d5c72f4d4b4ea..3b1a021eaced2 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -318,6 +318,7 @@ namespace_declaration type : array_type + | function_pointer_type | name | nullable_type | omitted_type_argument @@ -335,6 +336,14 @@ array_rank_specifier : '[' (expression (',' expression)*)? ']' ; +function_pointer_type + : 'delegate' '*' syntax_token? '<' modified_type (',' modified_type)* '>' + ; + +modified_type + : modifier* type + ; + nullable_type : type '?' ; diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs index 8b16e6b6abf15..dff4b836e2512 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Internal.Generated.cs @@ -1048,6 +1048,302 @@ static PointerTypeSyntax() } } + internal sealed partial class FunctionPointerTypeSyntax : TypeSyntax + { + internal readonly SyntaxToken delegateKeyword; + internal readonly SyntaxToken asteriskToken; + internal readonly SyntaxToken? callingConvention; + internal readonly SyntaxToken lessThanToken; + internal readonly GreenNode? arguments; + internal readonly SyntaxToken greaterThanToken; + + internal FunctionPointerTypeSyntax(SyntaxKind kind, SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken? callingConvention, SyntaxToken lessThanToken, GreenNode? arguments, SyntaxToken greaterThanToken, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 6; + this.AdjustFlagsAndWidth(delegateKeyword); + this.delegateKeyword = delegateKeyword; + this.AdjustFlagsAndWidth(asteriskToken); + this.asteriskToken = asteriskToken; + if (callingConvention != null) + { + this.AdjustFlagsAndWidth(callingConvention); + this.callingConvention = callingConvention; + } + this.AdjustFlagsAndWidth(lessThanToken); + this.lessThanToken = lessThanToken; + if (arguments != null) + { + this.AdjustFlagsAndWidth(arguments); + this.arguments = arguments; + } + this.AdjustFlagsAndWidth(greaterThanToken); + this.greaterThanToken = greaterThanToken; + } + + internal FunctionPointerTypeSyntax(SyntaxKind kind, SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken? callingConvention, SyntaxToken lessThanToken, GreenNode? arguments, SyntaxToken greaterThanToken, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 6; + this.AdjustFlagsAndWidth(delegateKeyword); + this.delegateKeyword = delegateKeyword; + this.AdjustFlagsAndWidth(asteriskToken); + this.asteriskToken = asteriskToken; + if (callingConvention != null) + { + this.AdjustFlagsAndWidth(callingConvention); + this.callingConvention = callingConvention; + } + this.AdjustFlagsAndWidth(lessThanToken); + this.lessThanToken = lessThanToken; + if (arguments != null) + { + this.AdjustFlagsAndWidth(arguments); + this.arguments = arguments; + } + this.AdjustFlagsAndWidth(greaterThanToken); + this.greaterThanToken = greaterThanToken; + } + + internal FunctionPointerTypeSyntax(SyntaxKind kind, SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken? callingConvention, SyntaxToken lessThanToken, GreenNode? arguments, SyntaxToken greaterThanToken) + : base(kind) + { + this.SlotCount = 6; + this.AdjustFlagsAndWidth(delegateKeyword); + this.delegateKeyword = delegateKeyword; + this.AdjustFlagsAndWidth(asteriskToken); + this.asteriskToken = asteriskToken; + if (callingConvention != null) + { + this.AdjustFlagsAndWidth(callingConvention); + this.callingConvention = callingConvention; + } + this.AdjustFlagsAndWidth(lessThanToken); + this.lessThanToken = lessThanToken; + if (arguments != null) + { + this.AdjustFlagsAndWidth(arguments); + this.arguments = arguments; + } + this.AdjustFlagsAndWidth(greaterThanToken); + this.greaterThanToken = greaterThanToken; + } + + /// SyntaxToken representing the delegate keyword. + public SyntaxToken DelegateKeyword => this.delegateKeyword; + /// SyntaxToken representing the asterisk. + public SyntaxToken AsteriskToken => this.asteriskToken; + /// SyntaxToken representing the optional calling convention. + public SyntaxToken? CallingConvention => this.callingConvention; + /// SyntaxToken representing the less than token. + public SyntaxToken LessThanToken => this.lessThanToken; + /// SeparatedSyntaxList of ModifiedTypes representing the list of parameters and return type. + public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList Arguments => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.arguments)); + /// SyntaxToken representing the greater than token. + public SyntaxToken GreaterThanToken => this.greaterThanToken; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.delegateKeyword, + 1 => this.asteriskToken, + 2 => this.callingConvention, + 3 => this.lessThanToken, + 4 => this.arguments, + 5 => this.greaterThanToken, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.FunctionPointerTypeSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFunctionPointerType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFunctionPointerType(this); + + public FunctionPointerTypeSyntax Update(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken callingConvention, SyntaxToken lessThanToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList arguments, SyntaxToken greaterThanToken) + { + if (delegateKeyword != this.DelegateKeyword || asteriskToken != this.AsteriskToken || callingConvention != this.CallingConvention || lessThanToken != this.LessThanToken || arguments != this.Arguments || greaterThanToken != this.GreaterThanToken) + { + var newNode = SyntaxFactory.FunctionPointerType(delegateKeyword, asteriskToken, callingConvention, lessThanToken, arguments, greaterThanToken); + 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 FunctionPointerTypeSyntax(this.Kind, this.delegateKeyword, this.asteriskToken, this.callingConvention, this.lessThanToken, this.arguments, this.greaterThanToken, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) + => new FunctionPointerTypeSyntax(this.Kind, this.delegateKeyword, this.asteriskToken, this.callingConvention, this.lessThanToken, this.arguments, this.greaterThanToken, GetDiagnostics(), annotations); + + internal FunctionPointerTypeSyntax(ObjectReader reader) + : base(reader) + { + this.SlotCount = 6; + var delegateKeyword = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(delegateKeyword); + this.delegateKeyword = delegateKeyword; + var asteriskToken = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(asteriskToken); + this.asteriskToken = asteriskToken; + var callingConvention = (SyntaxToken?)reader.ReadValue(); + if (callingConvention != null) + { + AdjustFlagsAndWidth(callingConvention); + this.callingConvention = callingConvention; + } + var lessThanToken = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(lessThanToken); + this.lessThanToken = lessThanToken; + var arguments = (GreenNode?)reader.ReadValue(); + if (arguments != null) + { + AdjustFlagsAndWidth(arguments); + this.arguments = arguments; + } + var greaterThanToken = (SyntaxToken)reader.ReadValue(); + AdjustFlagsAndWidth(greaterThanToken); + this.greaterThanToken = greaterThanToken; + } + + internal override void WriteTo(ObjectWriter writer) + { + base.WriteTo(writer); + writer.WriteValue(this.delegateKeyword); + writer.WriteValue(this.asteriskToken); + writer.WriteValue(this.callingConvention); + writer.WriteValue(this.lessThanToken); + writer.WriteValue(this.arguments); + writer.WriteValue(this.greaterThanToken); + } + + static FunctionPointerTypeSyntax() + { + ObjectBinder.RegisterTypeReader(typeof(FunctionPointerTypeSyntax), r => new FunctionPointerTypeSyntax(r)); + } + } + + internal sealed partial class ModifiedType : CSharpSyntaxNode + { + internal readonly GreenNode? modifiers; + internal readonly TypeSyntax type; + + internal ModifiedType(SyntaxKind kind, GreenNode? modifiers, TypeSyntax type, DiagnosticInfo[] diagnostics, SyntaxAnnotation[] annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 2; + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(type); + this.type = type; + } + + internal ModifiedType(SyntaxKind kind, GreenNode? modifiers, TypeSyntax type, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 2; + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(type); + this.type = type; + } + + internal ModifiedType(SyntaxKind kind, GreenNode? modifiers, TypeSyntax type) + : base(kind) + { + this.SlotCount = 2; + if (modifiers != null) + { + this.AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + this.AdjustFlagsAndWidth(type); + this.type = type; + } + + /// SyntaxList of the optional modifier keywords. + public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Modifiers => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.modifiers); + /// TypeSyntax representing the modified type. + public TypeSyntax Type => this.type; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.modifiers, + 1 => this.type, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.ModifiedType(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitModifiedType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitModifiedType(this); + + public ModifiedType Update(Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, TypeSyntax type) + { + if (modifiers != this.Modifiers || type != this.Type) + { + var newNode = SyntaxFactory.ModifiedType(modifiers, type); + 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 ModifiedType(this.Kind, this.modifiers, this.type, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[] annotations) + => new ModifiedType(this.Kind, this.modifiers, this.type, GetDiagnostics(), annotations); + + internal ModifiedType(ObjectReader reader) + : base(reader) + { + this.SlotCount = 2; + var modifiers = (GreenNode?)reader.ReadValue(); + if (modifiers != null) + { + AdjustFlagsAndWidth(modifiers); + this.modifiers = modifiers; + } + var type = (TypeSyntax)reader.ReadValue(); + AdjustFlagsAndWidth(type); + this.type = type; + } + + internal override void WriteTo(ObjectWriter writer) + { + base.WriteTo(writer); + writer.WriteValue(this.modifiers); + writer.WriteValue(this.type); + } + + static ModifiedType() + { + ObjectBinder.RegisterTypeReader(typeof(ModifiedType), r => new ModifiedType(r)); + } + } + /// Class which represents the syntax node for a nullable type. internal sealed partial class NullableTypeSyntax : TypeSyntax { @@ -30234,6 +30530,8 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitArrayType(ArrayTypeSyntax node) => this.DefaultVisit(node); public virtual TResult VisitArrayRankSpecifier(ArrayRankSpecifierSyntax node) => this.DefaultVisit(node); public virtual TResult VisitPointerType(PointerTypeSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitFunctionPointerType(FunctionPointerTypeSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitModifiedType(ModifiedType node) => this.DefaultVisit(node); public virtual TResult VisitNullableType(NullableTypeSyntax node) => this.DefaultVisit(node); public virtual TResult VisitTupleType(TupleTypeSyntax node) => this.DefaultVisit(node); public virtual TResult VisitTupleElement(TupleElementSyntax node) => this.DefaultVisit(node); @@ -30453,6 +30751,8 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitArrayType(ArrayTypeSyntax node) => this.DefaultVisit(node); public virtual void VisitArrayRankSpecifier(ArrayRankSpecifierSyntax node) => this.DefaultVisit(node); public virtual void VisitPointerType(PointerTypeSyntax node) => this.DefaultVisit(node); + public virtual void VisitFunctionPointerType(FunctionPointerTypeSyntax node) => this.DefaultVisit(node); + public virtual void VisitModifiedType(ModifiedType node) => this.DefaultVisit(node); public virtual void VisitNullableType(NullableTypeSyntax node) => this.DefaultVisit(node); public virtual void VisitTupleType(TupleTypeSyntax node) => this.DefaultVisit(node); public virtual void VisitTupleElement(TupleElementSyntax node) => this.DefaultVisit(node); @@ -30690,6 +30990,12 @@ public override CSharpSyntaxNode VisitArrayRankSpecifier(ArrayRankSpecifierSynta public override CSharpSyntaxNode VisitPointerType(PointerTypeSyntax node) => node.Update((TypeSyntax)Visit(node.ElementType), (SyntaxToken)Visit(node.AsteriskToken)); + public override CSharpSyntaxNode VisitFunctionPointerType(FunctionPointerTypeSyntax node) + => node.Update((SyntaxToken)Visit(node.DelegateKeyword), (SyntaxToken)Visit(node.AsteriskToken), (SyntaxToken)Visit(node.CallingConvention), (SyntaxToken)Visit(node.LessThanToken), VisitList(node.Arguments), (SyntaxToken)Visit(node.GreaterThanToken)); + + public override CSharpSyntaxNode VisitModifiedType(ModifiedType node) + => node.Update(VisitList(node.Modifiers), (TypeSyntax)Visit(node.Type)); + public override CSharpSyntaxNode VisitNullableType(NullableTypeSyntax node) => node.Update((TypeSyntax)Visit(node.ElementType), (SyntaxToken)Visit(node.QuestionToken)); @@ -31529,6 +31835,41 @@ public PointerTypeSyntax PointerType(TypeSyntax elementType, SyntaxToken asteris return result; } + public FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken? callingConvention, SyntaxToken lessThanToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList arguments, SyntaxToken greaterThanToken) + { + #if DEBUG + if (delegateKeyword == null) throw new ArgumentNullException(nameof(delegateKeyword)); + if (delegateKeyword.Kind != SyntaxKind.DelegateKeyword) throw new ArgumentException(nameof(delegateKeyword)); + if (asteriskToken == null) throw new ArgumentNullException(nameof(asteriskToken)); + if (asteriskToken.Kind != SyntaxKind.AsteriskToken) throw new ArgumentException(nameof(asteriskToken)); + if (lessThanToken == null) throw new ArgumentNullException(nameof(lessThanToken)); + if (lessThanToken.Kind != SyntaxKind.LessThanToken) throw new ArgumentException(nameof(lessThanToken)); + if (greaterThanToken == null) throw new ArgumentNullException(nameof(greaterThanToken)); + if (greaterThanToken.Kind != SyntaxKind.GreaterThanToken) throw new ArgumentException(nameof(greaterThanToken)); + #endif + + return new FunctionPointerTypeSyntax(SyntaxKind.FunctionPointerType, delegateKeyword, asteriskToken, callingConvention, lessThanToken, arguments.Node, greaterThanToken, this.context); + } + + public ModifiedType ModifiedType(Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, TypeSyntax type) + { + #if DEBUG + if (type == null) throw new ArgumentNullException(nameof(type)); + #endif + + int hash; + var cached = CSharpSyntaxNodeCache.TryGetNode((int)SyntaxKind.ModifiedType, modifiers.Node, type, this.context, out hash); + if (cached != null) return (ModifiedType)cached; + + var result = new ModifiedType(SyntaxKind.ModifiedType, modifiers.Node, type, this.context); + if (hash >= 0) + { + SyntaxNodeCache.AddNode(result, hash); + } + + return result; + } + public NullableTypeSyntax NullableType(TypeSyntax elementType, SyntaxToken questionToken) { #if DEBUG @@ -36093,6 +36434,41 @@ public static PointerTypeSyntax PointerType(TypeSyntax elementType, SyntaxToken return result; } + public static FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken? callingConvention, SyntaxToken lessThanToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList arguments, SyntaxToken greaterThanToken) + { + #if DEBUG + if (delegateKeyword == null) throw new ArgumentNullException(nameof(delegateKeyword)); + if (delegateKeyword.Kind != SyntaxKind.DelegateKeyword) throw new ArgumentException(nameof(delegateKeyword)); + if (asteriskToken == null) throw new ArgumentNullException(nameof(asteriskToken)); + if (asteriskToken.Kind != SyntaxKind.AsteriskToken) throw new ArgumentException(nameof(asteriskToken)); + if (lessThanToken == null) throw new ArgumentNullException(nameof(lessThanToken)); + if (lessThanToken.Kind != SyntaxKind.LessThanToken) throw new ArgumentException(nameof(lessThanToken)); + if (greaterThanToken == null) throw new ArgumentNullException(nameof(greaterThanToken)); + if (greaterThanToken.Kind != SyntaxKind.GreaterThanToken) throw new ArgumentException(nameof(greaterThanToken)); + #endif + + return new FunctionPointerTypeSyntax(SyntaxKind.FunctionPointerType, delegateKeyword, asteriskToken, callingConvention, lessThanToken, arguments.Node, greaterThanToken); + } + + public static ModifiedType ModifiedType(Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, TypeSyntax type) + { + #if DEBUG + if (type == null) throw new ArgumentNullException(nameof(type)); + #endif + + int hash; + var cached = SyntaxNodeCache.TryGetNode((int)SyntaxKind.ModifiedType, modifiers.Node, type, out hash); + if (cached != null) return (ModifiedType)cached; + + var result = new ModifiedType(SyntaxKind.ModifiedType, modifiers.Node, type); + if (hash >= 0) + { + SyntaxNodeCache.AddNode(result, hash); + } + + return result; + } + public static NullableTypeSyntax NullableType(TypeSyntax elementType, SyntaxToken questionToken) { #if DEBUG @@ -40453,6 +40829,8 @@ internal static IEnumerable GetNodeTypes() typeof(ArrayTypeSyntax), typeof(ArrayRankSpecifierSyntax), typeof(PointerTypeSyntax), + typeof(FunctionPointerTypeSyntax), + typeof(ModifiedType), typeof(NullableTypeSyntax), typeof(TupleTypeSyntax), typeof(TupleElementSyntax), diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs index 558faab8b24ae..cf99075f34b22 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Main.Generated.cs @@ -40,6 +40,12 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a PointerTypeSyntax node. public virtual TResult VisitPointerType(PointerTypeSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a FunctionPointerTypeSyntax node. + public virtual TResult VisitFunctionPointerType(FunctionPointerTypeSyntax node) => this.DefaultVisit(node); + + /// Called when the visitor visits a ModifiedType node. + public virtual TResult VisitModifiedType(ModifiedType node) => this.DefaultVisit(node); + /// Called when the visitor visits a NullableTypeSyntax node. public virtual TResult VisitNullableType(NullableTypeSyntax node) => this.DefaultVisit(node); @@ -688,6 +694,12 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a PointerTypeSyntax node. public virtual void VisitPointerType(PointerTypeSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a FunctionPointerTypeSyntax node. + public virtual void VisitFunctionPointerType(FunctionPointerTypeSyntax node) => this.DefaultVisit(node); + + /// Called when the visitor visits a ModifiedType node. + public virtual void VisitModifiedType(ModifiedType node) => this.DefaultVisit(node); + /// Called when the visitor visits a NullableTypeSyntax node. public virtual void VisitNullableType(NullableTypeSyntax node) => this.DefaultVisit(node); @@ -1336,6 +1348,12 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor public override SyntaxNode? VisitPointerType(PointerTypeSyntax node) => node.Update((TypeSyntax?)Visit(node.ElementType) ?? throw new ArgumentNullException("elementType"), VisitToken(node.AsteriskToken)); + public override SyntaxNode? VisitFunctionPointerType(FunctionPointerTypeSyntax node) + => node.Update(VisitToken(node.DelegateKeyword), VisitToken(node.AsteriskToken), VisitToken(node.CallingConvention), VisitToken(node.LessThanToken), VisitList(node.Arguments), VisitToken(node.GreaterThanToken)); + + public override SyntaxNode? VisitModifiedType(ModifiedType node) + => node.Update(VisitList(node.Modifiers), (TypeSyntax?)Visit(node.Type) ?? throw new ArgumentNullException("type")); + public override SyntaxNode? VisitNullableType(NullableTypeSyntax node) => node.Update((TypeSyntax?)Visit(node.ElementType) ?? throw new ArgumentNullException("elementType"), VisitToken(node.QuestionToken)); @@ -2088,6 +2106,35 @@ public static PointerTypeSyntax PointerType(TypeSyntax elementType, SyntaxToken public static PointerTypeSyntax PointerType(TypeSyntax elementType) => SyntaxFactory.PointerType(elementType, SyntaxFactory.Token(SyntaxKind.AsteriskToken)); + /// Creates a new FunctionPointerTypeSyntax instance. + public static FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken callingConvention, SyntaxToken lessThanToken, SeparatedSyntaxList arguments, SyntaxToken greaterThanToken) + { + if (delegateKeyword.Kind() != SyntaxKind.DelegateKeyword) throw new ArgumentException(nameof(delegateKeyword)); + if (asteriskToken.Kind() != SyntaxKind.AsteriskToken) throw new ArgumentException(nameof(asteriskToken)); + if (lessThanToken.Kind() != SyntaxKind.LessThanToken) throw new ArgumentException(nameof(lessThanToken)); + if (greaterThanToken.Kind() != SyntaxKind.GreaterThanToken) throw new ArgumentException(nameof(greaterThanToken)); + return (FunctionPointerTypeSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerType((Syntax.InternalSyntax.SyntaxToken)delegateKeyword.Node!, (Syntax.InternalSyntax.SyntaxToken)asteriskToken.Node!, (Syntax.InternalSyntax.SyntaxToken?)callingConvention.Node, (Syntax.InternalSyntax.SyntaxToken)lessThanToken.Node!, arguments.Node.ToGreenSeparatedList(), (Syntax.InternalSyntax.SyntaxToken)greaterThanToken.Node!).CreateRed(); + } + + /// Creates a new FunctionPointerTypeSyntax instance. + public static FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken callingConvention, SeparatedSyntaxList arguments) + => SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), callingConvention, SyntaxFactory.Token(SyntaxKind.LessThanToken), arguments, SyntaxFactory.Token(SyntaxKind.GreaterThanToken)); + + /// Creates a new FunctionPointerTypeSyntax instance. + public static FunctionPointerTypeSyntax FunctionPointerType(SeparatedSyntaxList arguments = default) + => SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), default, SyntaxFactory.Token(SyntaxKind.LessThanToken), arguments, SyntaxFactory.Token(SyntaxKind.GreaterThanToken)); + + /// Creates a new ModifiedType instance. + public static ModifiedType ModifiedType(SyntaxTokenList modifiers, TypeSyntax type) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + return (ModifiedType)Syntax.InternalSyntax.SyntaxFactory.ModifiedType(modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.TypeSyntax)type.Green).CreateRed(); + } + + /// Creates a new ModifiedType instance. + public static ModifiedType ModifiedType(TypeSyntax type) + => SyntaxFactory.ModifiedType(default(SyntaxTokenList), type); + /// Creates a new NullableTypeSyntax instance. public static NullableTypeSyntax NullableType(TypeSyntax elementType, SyntaxToken questionToken) { diff --git a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs index 1784ddc5423be..2aa55bf71401e 100644 --- a/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/Syntax.xml.Syntax.Generated.cs @@ -455,6 +455,123 @@ public PointerTypeSyntax Update(TypeSyntax elementType, SyntaxToken asteriskToke public PointerTypeSyntax WithAsteriskToken(SyntaxToken asteriskToken) => Update(this.ElementType, asteriskToken); } + public sealed partial class FunctionPointerTypeSyntax : TypeSyntax + { + private SyntaxNode? arguments; + + internal FunctionPointerTypeSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + /// SyntaxToken representing the delegate keyword. + public SyntaxToken DelegateKeyword => new SyntaxToken(this, ((Syntax.InternalSyntax.FunctionPointerTypeSyntax)this.Green).delegateKeyword, Position, 0); + + /// SyntaxToken representing the asterisk. + public SyntaxToken AsteriskToken => new SyntaxToken(this, ((Syntax.InternalSyntax.FunctionPointerTypeSyntax)this.Green).asteriskToken, GetChildPosition(1), GetChildIndex(1)); + + /// SyntaxToken representing the optional calling convention. + public SyntaxToken CallingConvention + { + get + { + var slot = ((Syntax.InternalSyntax.FunctionPointerTypeSyntax)this.Green).callingConvention; + return slot != null ? new SyntaxToken(this, slot, GetChildPosition(2), GetChildIndex(2)) : default; + } + } + + /// SyntaxToken representing the less than token. + public SyntaxToken LessThanToken => new SyntaxToken(this, ((Syntax.InternalSyntax.FunctionPointerTypeSyntax)this.Green).lessThanToken, GetChildPosition(3), GetChildIndex(3)); + + /// SeparatedSyntaxList of ModifiedTypes representing the list of parameters and return type. + public SeparatedSyntaxList Arguments + { + get + { + var red = GetRed(ref this.arguments, 4); + return red != null ? new SeparatedSyntaxList(red, GetChildIndex(4)) : default; + } + } + + /// SyntaxToken representing the greater than token. + public SyntaxToken GreaterThanToken => new SyntaxToken(this, ((Syntax.InternalSyntax.FunctionPointerTypeSyntax)this.Green).greaterThanToken, GetChildPosition(5), GetChildIndex(5)); + + internal override SyntaxNode? GetNodeSlot(int index) => index == 4 ? GetRed(ref this.arguments, 4)! : null; + + internal override SyntaxNode? GetCachedSlot(int index) => index == 4 ? this.arguments : null; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFunctionPointerType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFunctionPointerType(this); + + public FunctionPointerTypeSyntax Update(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken callingConvention, SyntaxToken lessThanToken, SeparatedSyntaxList arguments, SyntaxToken greaterThanToken) + { + if (delegateKeyword != this.DelegateKeyword || asteriskToken != this.AsteriskToken || callingConvention != this.CallingConvention || lessThanToken != this.LessThanToken || arguments != this.Arguments || greaterThanToken != this.GreaterThanToken) + { + var newNode = SyntaxFactory.FunctionPointerType(delegateKeyword, asteriskToken, callingConvention, lessThanToken, arguments, greaterThanToken); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + public FunctionPointerTypeSyntax WithDelegateKeyword(SyntaxToken delegateKeyword) => Update(delegateKeyword, this.AsteriskToken, this.CallingConvention, this.LessThanToken, this.Arguments, this.GreaterThanToken); + public FunctionPointerTypeSyntax WithAsteriskToken(SyntaxToken asteriskToken) => Update(this.DelegateKeyword, asteriskToken, this.CallingConvention, this.LessThanToken, this.Arguments, this.GreaterThanToken); + public FunctionPointerTypeSyntax WithCallingConvention(SyntaxToken callingConvention) => Update(this.DelegateKeyword, this.AsteriskToken, callingConvention, this.LessThanToken, this.Arguments, this.GreaterThanToken); + public FunctionPointerTypeSyntax WithLessThanToken(SyntaxToken lessThanToken) => Update(this.DelegateKeyword, this.AsteriskToken, this.CallingConvention, lessThanToken, this.Arguments, this.GreaterThanToken); + public FunctionPointerTypeSyntax WithArguments(SeparatedSyntaxList arguments) => Update(this.DelegateKeyword, this.AsteriskToken, this.CallingConvention, this.LessThanToken, arguments, this.GreaterThanToken); + public FunctionPointerTypeSyntax WithGreaterThanToken(SyntaxToken greaterThanToken) => Update(this.DelegateKeyword, this.AsteriskToken, this.CallingConvention, this.LessThanToken, this.Arguments, greaterThanToken); + + public FunctionPointerTypeSyntax AddArguments(params ModifiedType[] items) => WithArguments(this.Arguments.AddRange(items)); + } + + public sealed partial class ModifiedType : CSharpSyntaxNode + { + private TypeSyntax? type; + + internal ModifiedType(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + /// SyntaxList of the optional modifier keywords. + public SyntaxTokenList Modifiers + { + get + { + var slot = this.Green.GetSlot(0); + return slot != null ? new SyntaxTokenList(this, slot, Position, 0) : default; + } + } + + /// TypeSyntax representing the modified type. + public TypeSyntax Type => GetRed(ref this.type, 1)!; + + internal override SyntaxNode? GetNodeSlot(int index) => index == 1 ? GetRed(ref this.type, 1)! : null; + + internal override SyntaxNode? GetCachedSlot(int index) => index == 1 ? this.type : null; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitModifiedType(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitModifiedType(this); + + public ModifiedType Update(SyntaxTokenList modifiers, TypeSyntax type) + { + if (modifiers != this.Modifiers || type != this.Type) + { + var newNode = SyntaxFactory.ModifiedType(modifiers, type); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + public ModifiedType WithModifiers(SyntaxTokenList modifiers) => Update(modifiers, this.Type); + public ModifiedType WithType(TypeSyntax type) => Update(this.Modifiers, type); + + public ModifiedType AddModifiers(params SyntaxToken[] items) => WithModifiers(this.Modifiers.AddRange(items)); + } + /// Class which represents the syntax node for a nullable type. public sealed partial class NullableTypeSyntax : TypeSyntax { diff --git a/src/Compilers/CSharp/Portable/GlobalSuppressions.cs b/src/Compilers/CSharp/Portable/GlobalSuppressions.cs index 0e52e4c28a740..7dc92280f15ce 100644 --- a/src/Compilers/CSharp/Portable/GlobalSuppressions.cs +++ b/src/Compilers/CSharp/Portable/GlobalSuppressions.cs @@ -32,4 +32,4 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Text.Encoding,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Threading.CancellationToken)~Microsoft.CodeAnalysis.SyntaxTree")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(Microsoft.CodeAnalysis.Text.SourceText,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Collections.Immutable.ImmutableDictionary{System.String,Microsoft.CodeAnalysis.ReportDiagnostic},System.Threading.CancellationToken)~Microsoft.CodeAnalysis.SyntaxTree")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.DeconstructionPatternClause(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.SubpatternSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.DeconstructionPatternClauseSyntax")] - +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType})~Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax")] diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index a723f71b6ace7..a401d1e39067a 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -77,9 +77,11 @@ internal enum TerminatorState IsEndOfTypeParameterList = 1 << 20, IsEndOfMethodSignature = 1 << 21, IsEndOfNameInExplicitInterface = 1 << 22, + IsEndOfFunctionPointerParameterList = 1 << 23, + IsEndOfFunctionPointerParameterListErrored = 1 << 24, } - private const int LastTerminatorState = (int)TerminatorState.IsEndOfNameInExplicitInterface; + private const int LastTerminatorState = (int)TerminatorState.IsEndOfFunctionPointerParameterListErrored; private bool IsTerminator() { @@ -115,6 +117,8 @@ private bool IsTerminator() case TerminatorState.IsEndOfTypeParameterList when this.IsEndOfTypeParameterList(): case TerminatorState.IsEndOfMethodSignature when this.IsEndOfMethodSignature(): case TerminatorState.IsEndOfNameInExplicitInterface when this.IsEndOfNameInExplicitInterface(): + case TerminatorState.IsEndOfFunctionPointerParameterList when this.IsEndOfFunctionPointerParameterList(errored: false): + case TerminatorState.IsEndOfFunctionPointerParameterListErrored when this.IsEndOfFunctionPointerParameterList(errored: true): return true; } } @@ -1857,7 +1861,7 @@ private bool IsTypeDeclarationStart() switch (this.CurrentToken.Kind) { case SyntaxKind.ClassKeyword: - case SyntaxKind.DelegateKeyword: + case SyntaxKind.DelegateKeyword when !IsFunctionPointerStart(): case SyntaxKind.EnumKeyword: case SyntaxKind.InterfaceKeyword: case SyntaxKind.StructKeyword: @@ -2533,6 +2537,8 @@ private bool IsEndOfNameInExplicitInterface() return this.CurrentToken.Kind == SyntaxKind.DotToken || this.CurrentToken.Kind == SyntaxKind.ColonColonToken; } + private bool IsEndOfFunctionPointerParameterList(bool errored) => this.CurrentToken.Kind == (errored ? SyntaxKind.CloseParenToken : SyntaxKind.GreaterThanToken); + private MethodDeclarationSyntax ParseMethodDeclaration( SyntaxList attributes, SyntaxListBuilder modifiers, @@ -3547,6 +3553,7 @@ private bool IsPossibleParameter() case SyntaxKind.OpenBracketToken: // attribute case SyntaxKind.ArgListKeyword: case SyntaxKind.OpenParenToken: // tuple + case SyntaxKind.DelegateKeyword when IsFunctionPointerStart(): // Function pointer type return true; case SyntaxKind.IdentifierToken: @@ -3646,7 +3653,7 @@ private ParameterSyntax ParseParameter() } } - private static bool IsParameterModifier(SyntaxKind kind) + private static bool IsParameterModifier(SyntaxKind kind, bool isFunctionPointerParameter = false) { switch (kind) { @@ -3655,15 +3662,16 @@ private static bool IsParameterModifier(SyntaxKind kind) case SyntaxKind.OutKeyword: case SyntaxKind.InKeyword: case SyntaxKind.ParamsKeyword: + case SyntaxKind.ReadOnlyKeyword when isFunctionPointerParameter: return true; } return false; } - private void ParseParameterModifiers(SyntaxListBuilder modifiers) + private void ParseParameterModifiers(SyntaxListBuilder modifiers, bool isFunctionPointerParameter = false) { - while (IsParameterModifier(this.CurrentToken.Kind)) + while (IsParameterModifier(this.CurrentToken.Kind, isFunctionPointerParameter)) { var modifier = this.EatToken(); @@ -5605,7 +5613,9 @@ private enum ScanTypeFlags /// /// Definitely a type name: either a predefined type (int, string, etc.) or an array - /// type (ending with a [] brackets), or a pointer type (ending with *s). + /// type (ending with a [] brackets), or a pointer type (ending with *s), or a function + /// pointer type (ending with > in valid cases, or a *, ), or calling convention + /// identifier, in invalid cases). /// MustBeType, @@ -5751,6 +5761,10 @@ private ScanTypeFlags ScanType(ParseTypeMode mode, out SyntaxToken lastTokenOfTy return ScanTypeFlags.NotType; } } + else if (IsFunctionPointerStart()) + { + return ScanFunctionPointerType(out lastTokenOfType); + } else { // Can't be a type! @@ -5874,6 +5888,83 @@ private ScanTypeFlags ScanTupleType(out SyntaxToken lastTokenOfType) return ScanTypeFlags.NotType; } +#nullable enable + private ScanTypeFlags ScanFunctionPointerType(out SyntaxToken lastTokenOfType) + { + Debug.Assert(IsFunctionPointerStart()); + _ = EatToken(SyntaxKind.DelegateKeyword); + lastTokenOfType = EatToken(SyntaxKind.AsteriskToken); + + if (IsPossibleCallingConvention(lastTokenOfType)) + { + lastTokenOfType = EatToken(); + } + + if (!IsPossibleFunctionPointerParameterListStart(CurrentToken)) + { + // Even though this function pointer type is incomplete, we know that it + // must be the start of a type, as there is no other possible interpretation + // of delegate*. By always treating it as a type, we ensure that any disambiguation + // done in later parsing treats this as a type, which will produce better + // errors at later stages. + return ScanTypeFlags.MustBeType; + } + + var validStartingToken = EatToken().Kind == SyntaxKind.LessThanToken; + + var saveTerm = _termState; + _termState |= validStartingToken ? TerminatorState.IsEndOfFunctionPointerParameterList : TerminatorState.IsEndOfFunctionPointerParameterListErrored; + + try + { + do + { + var ignoredModifiers = _pool.Allocate(); + try + { + ParseParameterModifiers(ignoredModifiers, isFunctionPointerParameter: true); + } + finally + { + _pool.Free(ignoredModifiers); + } + + _ = ScanType(out _); + + if (skipBadFunctionPointerParameterTokens() == PostSkipAction.Abort) + { + break; + } + + _ = EatToken(SyntaxKind.CommaToken); + } + while (true); + } + finally + { + _termState = saveTerm; + } + + if (!validStartingToken && CurrentToken.Kind == SyntaxKind.CloseParenToken) + { + lastTokenOfType = EatTokenAsKind(SyntaxKind.GreaterThanToken); + } + else + { + lastTokenOfType = EatToken(SyntaxKind.GreaterThanToken); + } + + return ScanTypeFlags.MustBeType; + + PostSkipAction skipBadFunctionPointerParameterTokens() + { + return SkipBadTokensWithExpectedKind(isNotExpectedFunction: p => p.CurrentToken.Kind != SyntaxKind.CommaToken, + abortFunction: p => p.IsTerminator(), + expected: SyntaxKind.CommaToken, trailingTrivia: out _); + } + } +#nullable restore + private static bool IsPredefinedType(SyntaxKind keyword) { return SyntaxFacts.IsPredefinedType(keyword); @@ -5905,7 +5996,7 @@ private enum ParseTypeMode AfterTupleComma, AsExpression, NewExpression, - FirstElementOfPossibleTupleLiteral + FirstElementOfPossibleTupleLiteral, } private TypeSyntax ParseType(ParseTypeMode mode = ParseTypeMode.Normal) @@ -6266,6 +6357,10 @@ private TypeSyntax ParseUnderlyingType(bool parentIsParameter, NameOptions optio { return this.ParseTupleType(); } + else if (IsFunctionPointerStart()) + { + return ParseFunctionPointerTypeSyntax(); + } else { var name = this.CreateMissingIdentifierName(); @@ -6273,6 +6368,164 @@ private TypeSyntax ParseUnderlyingType(bool parentIsParameter, NameOptions optio } } +#nullable enable + private FunctionPointerTypeSyntax ParseFunctionPointerTypeSyntax() + { + Debug.Assert(IsFunctionPointerStart()); + var @delegate = EatToken(SyntaxKind.DelegateKeyword); + var asterisk = EatToken(SyntaxKind.AsteriskToken); + // Invalid calling conventions will be reported at type binding time + var callingConvention = IsPossibleCallingConvention(asterisk) ? EatToken() : null; + + if (!IsPossibleFunctionPointerParameterListStart(CurrentToken)) + { + var lessThanTokenError = WithAdditionalDiagnostics(SyntaxFactory.MissingToken(SyntaxKind.LessThanToken), GetExpectedTokenError(SyntaxKind.LessThanToken, SyntaxKind.None)); + var missingTypes = _pool.AllocateSeparated(); + var missingTypeName = CreateMissingIdentifierName(); + var missingType = SyntaxFactory.ModifiedType(default, missingTypeName); + missingTypes.Add(missingType); + // Handle the simple case of delegate*>. We don't try to deal with any variation of delegate*invalid>, as + // we don't know for sure that the expression isn't a relational with something else. + var greaterThanTokenError = TryEatToken(SyntaxKind.GreaterThanToken) ?? SyntaxFactory.MissingToken(SyntaxKind.GreaterThanToken); + + var funcPtr = SyntaxFactory.FunctionPointerType(@delegate, asterisk, callingConvention, lessThanTokenError, missingTypes, greaterThanTokenError); + _pool.Free(missingTypes); + return funcPtr; + } + + var lessThanToken = EatTokenAsKind(SyntaxKind.LessThanToken); + var saveTerm = _termState; + _termState |= (lessThanToken.IsMissing ? TerminatorState.IsEndOfFunctionPointerParameterListErrored : TerminatorState.IsEndOfFunctionPointerParameterList); + var types = _pool.AllocateSeparated(); + + try + { + while (true) + { + var modifiers = _pool.Allocate(); + try + { + ParseParameterModifiers(modifiers, isFunctionPointerParameter: true); + + var parameterType = ParseTypeOrVoid(); + types.Add(SyntaxFactory.ModifiedType(modifiers, parameterType)); + + if (skipBadFunctionPointerParameterListTokens() == PostSkipAction.Abort) + { + break; + } + + Debug.Assert(CurrentToken.Kind == SyntaxKind.CommaToken); + types.AddSeparator(EatToken(SyntaxKind.CommaToken)); + } + finally + { + _pool.Free(modifiers); + } + } + + SyntaxToken greaterThanToken; + if (lessThanToken.IsMissing && CurrentToken.Kind == SyntaxKind.CloseParenToken) + { + greaterThanToken = EatTokenAsKind(SyntaxKind.GreaterThanToken); + } + else + { + greaterThanToken = EatToken(SyntaxKind.GreaterThanToken); + } + + var funcPointer = SyntaxFactory.FunctionPointerType(@delegate, asterisk, callingConvention, lessThanToken, types, greaterThanToken); + funcPointer = CheckFeatureAvailability(funcPointer, MessageID.IDS_FeatureFunctionPointers); + return funcPointer; + } + finally + { + _termState = saveTerm; + _pool.Free(types); + } + + PostSkipAction skipBadFunctionPointerParameterListTokens() + { + CSharpSyntaxNode? tmp = null; + Debug.Assert(types.Count > 0); + return SkipBadSeparatedListTokensWithExpectedKind(ref tmp, + types, + isNotExpectedFunction: p => p.CurrentToken.Kind != SyntaxKind.CommaToken, + abortFunction: p => p.IsTerminator(), + expected: SyntaxKind.CommaToken); + } + } + + private bool IsFunctionPointerStart() + => CurrentToken.Kind == SyntaxKind.DelegateKeyword && PeekToken(1).Kind == SyntaxKind.AsteriskToken; + + private bool IsPossibleCallingConvention(SyntaxToken asteriskToken) + { + if (IsPossibleFunctionPointerParameterListStart(CurrentToken)) + { + return false; + } + + // If the next token is a known function pointer calling convention, treat it as a + // calling convention no matter what. If it wasn't intended to be a calling convention + // we'd have an error anyway, and it's more likely the user intended for it to be a + // function pointer convention than not. + // PROTOTYPE(func-ptr): refactor this out into a helper method to share with binding + switch (CurrentToken.Text) + { + case "cdecl": + case "managed": + case "unmanaged": + case "thiscall": + case "stdcall": + return true; + } + + // For nicer error recovery, we only treat predefined types and identifiers as if they could be the + // calling convention. For any other keyword, they're almost certainly part of some other + // construct, and would produce better errors if parsed separately. The user could have this: + // + // delegate* /* Declaration in progress */ while (true) {} + // + // The parse tree will look much better if the while(true) is considered a separate structure, + // even though it does look like it could be the start of an invalid function pointer definition. + if (CurrentToken.Kind != SyntaxKind.IdentifierToken && !IsPredefinedType(CurrentToken.Kind)) + { + return false; + } + + // If the asterisk was at the end of the previous line and it's not a valid calling convention, + // chances are anything on a new line should not be considered part of the function pointer. + // For example: + // + // delegate* + // int myValue = 1; + // + // would be better interpreted if the int myValue = 1 is considered separately + if (asteriskToken.TrailingTrivia.Any((int)SyntaxKind.EndOfLineTrivia)) + { + return false; + } + + // We attempt to make error recovery a little nicer here by only treating a single + // identifier token as a calling convention if the token afterwards is actually a + // possible start to the function pointer parameter list. The intuition is that, for + // some partial trees like this: + // + // (delegate*MyProperty.MyMethod(); + // + // The user is actually in the middle of adding a cast, and if we interpreted MyProperty + // as a calling convention, we'd get a much worse set of errors than if we treated the + // function pointer as having no calling convention. + return IsPossibleFunctionPointerParameterListStart(PeekToken(1)); + } + + private static bool IsPossibleFunctionPointerParameterListStart(SyntaxToken token) + // We consider both ( and < to be possible starts, in order to make error recovery more graceful + // in the scenario where a user accidentally surrounds their function pointer type list with parens. + => token.Kind == SyntaxKind.LessThanToken || token.Kind == SyntaxKind.OpenParenToken; +#nullable restore + private TypeSyntax ParsePointerTypeMods(TypeSyntax type) { // Check for pointer types @@ -10936,6 +11189,9 @@ private bool IsPossibleLambdaParameter() case SyntaxKind.IdentifierToken: return this.IsTrueIdentifier(); + case SyntaxKind.DelegateKeyword: + return this.IsFunctionPointerStart(); + default: return IsPredefinedType(this.CurrentToken.Kind); } @@ -10994,6 +11250,11 @@ private bool ShouldParseLambdaParameterType(bool hasModifier) return true; } + if (this.IsFunctionPointerStart()) + { + return true; + } + if (this.IsTrueIdentifier(this.CurrentToken)) { // Don't parse out a type if we see: diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs index 86446aaa8b46e..74ae1616c934d 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser_Patterns.cs @@ -61,7 +61,7 @@ private CSharpSyntaxNode ParseTypeOrPatternForIsOperatorCore() } // If it starts with 'nameof(', skip the 'if' and parse as a constant pattern. - if (LooksLikeTypeOfPattern(tk)) + if (LooksLikeTypeOfPattern()) { var resetPoint = this.GetResetPoint(); try @@ -126,12 +126,32 @@ private CSharpSyntaxNode ParseTypeOrPatternForIsOperatorCore() /// /// Given tk, the type of the current token, does this look like the type of a pattern? /// - private bool LooksLikeTypeOfPattern(SyntaxKind tk) + private bool LooksLikeTypeOfPattern() { - return SyntaxFacts.IsPredefinedType(tk) || - (tk == SyntaxKind.IdentifierToken && this.CurrentToken.ContextualKind != SyntaxKind.UnderscoreToken && - (this.CurrentToken.ContextualKind != SyntaxKind.NameOfKeyword || this.PeekToken(1).Kind != SyntaxKind.OpenParenToken)) || - LooksLikeTupleArrayType(); + var tk = CurrentToken.Kind; + if (SyntaxFacts.IsPredefinedType(tk)) + { + return true; + } + + if (tk == SyntaxKind.IdentifierToken && this.CurrentToken.ContextualKind != SyntaxKind.UnderscoreToken && + (this.CurrentToken.ContextualKind != SyntaxKind.NameOfKeyword || this.PeekToken(1).Kind != SyntaxKind.OpenParenToken)) + { + return true; + } + + if (LooksLikeTupleArrayType()) + { + return true; + } + + // We'll parse the function pointer, but issue an error in semantic analysis + if (IsFunctionPointerStart()) + { + return true; + } + + return false; } // @@ -347,7 +367,7 @@ private CSharpSyntaxNode ParseExpressionOrPattern(bool whenIsKeyword, bool forSw try { TypeSyntax type = null; - if (LooksLikeTypeOfPattern(tk)) + if (LooksLikeTypeOfPattern()) { type = this.ParseType(ParseTypeMode.DefinitePattern); if (type.IsMissing || !CanTokenFollowTypeInPattern()) diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 2e7319a75691c..2ed84d29bb858 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -11,9 +11,31 @@ Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.WithBlock Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.AddArguments(params Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.Arguments.get -> Microsoft.CodeAnalysis.SeparatedSyntaxList +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.AsteriskToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.CallingConvention.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.DelegateKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.GreaterThanToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.LessThanToken.get -> Microsoft.CodeAnalysis.SyntaxToken +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.SyntaxToken asteriskToken, Microsoft.CodeAnalysis.SyntaxToken callingConvention, Microsoft.CodeAnalysis.SyntaxToken lessThanToken, Microsoft.CodeAnalysis.SeparatedSyntaxList arguments, Microsoft.CodeAnalysis.SyntaxToken greaterThanToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithArguments(Microsoft.CodeAnalysis.SeparatedSyntaxList arguments) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithAsteriskToken(Microsoft.CodeAnalysis.SyntaxToken asteriskToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithCallingConvention(Microsoft.CodeAnalysis.SyntaxToken callingConvention) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithDelegateKeyword(Microsoft.CodeAnalysis.SyntaxToken delegateKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithGreaterThanToken(Microsoft.CodeAnalysis.SyntaxToken greaterThanToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.WithLessThanToken(Microsoft.CodeAnalysis.SyntaxToken lessThanToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithBlock(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.LambdaExpressionSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.AddModifiers(params Microsoft.CodeAnalysis.SyntaxToken[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.Modifiers.get -> Microsoft.CodeAnalysis.SyntaxTokenList +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.Type.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.Update(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.WithModifiers(Microsoft.CodeAnalysis.SyntaxTokenList modifiers) -> Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType +Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.AddBlockStatements(params Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax[] items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.WithBlock(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax @@ -22,18 +44,35 @@ Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.AddBlockStatem Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithBlock(Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.WithExpressionBody(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax +Microsoft.CodeAnalysis.CSharp.SyntaxKind.ModifiedType = 9057 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.FunctionPointerType = 9056 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax abstract Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousFunctionExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitModifiedType(Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType node) -> Microsoft.CodeAnalysis.SyntaxNode +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> Microsoft.CodeAnalysis.SyntaxNode override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax +override Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult +override Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> void +override Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor visitor) -> TResult override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.Block.get -> Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax override Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.AnonymousMethodExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.AnonymousMethodExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SeparatedSyntaxList arguments = default(Microsoft.CodeAnalysis.SeparatedSyntaxList)) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SyntaxToken callingConvention, Microsoft.CodeAnalysis.SeparatedSyntaxList arguments) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SyntaxToken delegateKeyword, Microsoft.CodeAnalysis.SyntaxToken asteriskToken, Microsoft.CodeAnalysis.SyntaxToken callingConvention, Microsoft.CodeAnalysis.SyntaxToken lessThanToken, Microsoft.CodeAnalysis.SeparatedSyntaxList arguments, Microsoft.CodeAnalysis.SyntaxToken greaterThanToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ModifiedType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ModifiedType(Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax parameterList, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedLambdaExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SimpleLambdaExpression(Microsoft.CodeAnalysis.SyntaxToken asyncKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax parameter, Microsoft.CodeAnalysis.SyntaxToken arrowToken, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax block, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expressionBody) -> Microsoft.CodeAnalysis.CSharp.Syntax.SimpleLambdaExpressionSyntax +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitModifiedType(Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitModifiedType(Microsoft.CodeAnalysis.CSharp.Syntax.ModifiedType node) -> TResult +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> TResult diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index d4589ef67bb79..d94ca4ad852bd 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -223,6 +223,56 @@ Creates a PointerTypeSyntax node. + + + + + + SyntaxToken representing the delegate keyword. + + + + + + SyntaxToken representing the asterisk. + + + + + SyntaxToken representing the optional calling convention. + + + + + + SyntaxToken representing the less than token. + + + + + SeparatedSyntaxList of ModifiedTypes representing the list of parameters and return type. + + + + + + SyntaxToken representing the greater than token. + + + + + + + + SyntaxList of the optional modifier keywords. + + + + + TypeSyntax representing the modified type. + + + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 89b43c01cd782..2c3db69c5487f 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -594,5 +594,7 @@ public enum SyntaxKind : ushort ImplicitStackAllocArrayCreationExpression = 9053, SuppressNullableWarningExpression = 9054, NullableDirectiveTrivia = 9055, + FunctionPointerType = 9056, + ModifiedType = 9057, } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 301de31075750..91f4d4ecf8ef0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Neplatný název algoritmu hash: {0} @@ -829,6 +834,11 @@ rozšiřitelný příkaz fixed + + function pointers + function pointers + + index operator operátor indexu diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index efe063d472119..742c246c68b96 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Ungültiger Name für Hashalgorithmus: "{0}" @@ -829,6 +834,11 @@ Erweiterbare fixed-Anweisung + + function pointers + function pointers + + index operator Indexoperator diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index f7c6745971011..8dd22f1316629 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Nombre de algoritmo hash no válido: "{0}" @@ -830,6 +835,11 @@ declaración fija extensible + + function pointers + function pointers + + index operator operador de índice diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 3f0c495358965..3c8828f7bb123 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Nom d'algorithme de hachage non valide : '{0}' @@ -829,6 +834,11 @@ instruction fixed extensible + + function pointers + function pointers + + index operator opérateur d'index diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 9ac10140a2bf6..0c74c36970fd1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Il nome dell'algoritmo hash non è valido: '{0}' @@ -829,6 +834,11 @@ istruzione fixed estendibile + + function pointers + function pointers + + index operator operatore di indice diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 46a89bde0bd71..697302e111657 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' 無効なハッシュ アルゴリズム名: '{0}' @@ -829,6 +834,11 @@ 拡張可能な fixed ステートメント + + function pointers + function pointers + + index operator インデックス演算子 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index fbad2a17b5450..d69c91f7dc631 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' 잘못된 해시 알고리즘 이름: '{0}' @@ -829,6 +834,11 @@ 확장 가능한 fixed 문 + + function pointers + function pointers + + index operator 인덱스 연산자 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 39ffad0032bc7..c7b3647890b63 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Nieprawidłowa nazwa algorytmu wyznaczania wartości skrótu: „{0}” @@ -829,6 +834,11 @@ rozszerzalna instrukcja fixed + + function pointers + function pointers + + index operator operator indeksowania diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 5c0f011ef540b..a70a00bfacba0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Nome de algoritmo de hash inválido: '{0}' @@ -829,6 +834,11 @@ instrução fixa extensível + + function pointers + function pointers + + index operator operador de índice diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 4c525e8eb3307..e09846ab0d1b3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Недопустимое имя хэш-алгоритма: "{0}" @@ -829,6 +834,11 @@ расширяемый оператор fixed + + function pointers + function pointers + + index operator оператор index diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 2b88c024f68fe..1164d8d948ab7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' Geçersiz karma algoritması adı: '{0}' @@ -829,6 +834,11 @@ genişletilebilir fixed deyimi + + function pointers + function pointers + + index operator dizin işleci diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 7503df260c04e..a989dd4dbb78a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' 无效的哈希算法名称:“{0}” @@ -829,6 +834,11 @@ 可扩展 fixed 语句 + + function pointers + function pointers + + index operator 索引运算符 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 31be7fab29761..724e994f1fb11 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -237,6 +237,11 @@ Internal error in the C# compiler. + + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + '{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'unmanaged', 'thiscall', and 'stdcall'. + + Invalid hash algorithm name: '{0}' 雜湊演算法名稱無效: '{0}' @@ -829,6 +834,11 @@ 可延伸 fixed 陳述式 + + function pointers + function pointers + + index operator 索引運算子 diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs index 3bbbf1a9ddddd..fccf62a5fb3df 100644 --- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs +++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs @@ -25,7 +25,12 @@ public void DiagnosticAnalyzerAllInOne() symbolKindsWithNoCodeBlocks.Add(SymbolKind.Property); // Add nodes that are not yet in AllInOneCSharpCode to this list. - var missingSyntaxKinds = new HashSet(); + var missingSyntaxKinds = new HashSet() + { + // PROTOYPE(func-ptr): Remove + SyntaxKind.FunctionPointerType, + SyntaxKind.ModifiedType + }; var analyzer = new CSharpTrackingDiagnosticAnalyzer(); CreateCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { analyzer }); diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index 2c8dc55f4d287..0e4ef8f9abe3a 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 @@ -37,6 +37,12 @@ private static Syntax.InternalSyntax.ArrayRankSpecifierSyntax GenerateArrayRankS private static Syntax.InternalSyntax.PointerTypeSyntax GeneratePointerType() => InternalSyntaxFactory.PointerType(GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.AsteriskToken)); + private static Syntax.InternalSyntax.FunctionPointerTypeSyntax GenerateFunctionPointerType() + => InternalSyntaxFactory.FunctionPointerType(InternalSyntaxFactory.Token(SyntaxKind.DelegateKeyword), InternalSyntaxFactory.Token(SyntaxKind.AsteriskToken), null, InternalSyntaxFactory.Token(SyntaxKind.LessThanToken), new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList(), InternalSyntaxFactory.Token(SyntaxKind.GreaterThanToken)); + + private static Syntax.InternalSyntax.ModifiedType GenerateModifiedType() + => InternalSyntaxFactory.ModifiedType(new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(), GenerateIdentifierName()); + private static Syntax.InternalSyntax.NullableTypeSyntax GenerateNullableType() => InternalSyntaxFactory.NullableType(GenerateIdentifierName(), InternalSyntaxFactory.Token(SyntaxKind.QuestionToken)); @@ -758,6 +764,32 @@ public void TestPointerTypeFactoryAndProperties() AttachAndCheckDiagnostics(node); } + [Fact] + public void TestFunctionPointerTypeFactoryAndProperties() + { + var node = GenerateFunctionPointerType(); + + Assert.Equal(SyntaxKind.DelegateKeyword, node.DelegateKeyword.Kind); + Assert.Equal(SyntaxKind.AsteriskToken, node.AsteriskToken.Kind); + Assert.Null(node.CallingConvention); + Assert.Equal(SyntaxKind.LessThanToken, node.LessThanToken.Kind); + Assert.Equal(default, node.Arguments); + Assert.Equal(SyntaxKind.GreaterThanToken, node.GreaterThanToken.Kind); + + AttachAndCheckDiagnostics(node); + } + + [Fact] + public void TestModifiedTypeFactoryAndProperties() + { + var node = GenerateModifiedType(); + + Assert.Equal(default, node.Modifiers); + Assert.NotNull(node.Type); + + AttachAndCheckDiagnostics(node); + } + [Fact] public void TestNullableTypeFactoryAndProperties() { @@ -3631,6 +3663,58 @@ public void TestPointerTypeIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestFunctionPointerTypeTokenDeleteRewriter() + { + var oldNode = GenerateFunctionPointerType(); + 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 TestFunctionPointerTypeIdentityRewriter() + { + var oldNode = GenerateFunctionPointerType(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + + [Fact] + public void TestModifiedTypeTokenDeleteRewriter() + { + var oldNode = GenerateModifiedType(); + 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 TestModifiedTypeIdentityRewriter() + { + var oldNode = GenerateModifiedType(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestNullableTypeTokenDeleteRewriter() { @@ -9019,6 +9103,12 @@ private static ArrayRankSpecifierSyntax GenerateArrayRankSpecifier() private static PointerTypeSyntax GeneratePointerType() => SyntaxFactory.PointerType(GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.AsteriskToken)); + private static FunctionPointerTypeSyntax GenerateFunctionPointerType() + => SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), default(SyntaxToken), SyntaxFactory.Token(SyntaxKind.LessThanToken), new SeparatedSyntaxList(), SyntaxFactory.Token(SyntaxKind.GreaterThanToken)); + + private static ModifiedType GenerateModifiedType() + => SyntaxFactory.ModifiedType(new SyntaxTokenList(), GenerateIdentifierName()); + private static NullableTypeSyntax GenerateNullableType() => SyntaxFactory.NullableType(GenerateIdentifierName(), SyntaxFactory.Token(SyntaxKind.QuestionToken)); @@ -9740,6 +9830,32 @@ public void TestPointerTypeFactoryAndProperties() Assert.Equal(node, newNode); } + [Fact] + public void TestFunctionPointerTypeFactoryAndProperties() + { + var node = GenerateFunctionPointerType(); + + Assert.Equal(SyntaxKind.DelegateKeyword, node.DelegateKeyword.Kind()); + Assert.Equal(SyntaxKind.AsteriskToken, node.AsteriskToken.Kind()); + Assert.Equal(SyntaxKind.None, node.CallingConvention.Kind()); + Assert.Equal(SyntaxKind.LessThanToken, node.LessThanToken.Kind()); + Assert.Equal(default, node.Arguments); + Assert.Equal(SyntaxKind.GreaterThanToken, node.GreaterThanToken.Kind()); + var newNode = node.WithDelegateKeyword(node.DelegateKeyword).WithAsteriskToken(node.AsteriskToken).WithCallingConvention(node.CallingConvention).WithLessThanToken(node.LessThanToken).WithArguments(node.Arguments).WithGreaterThanToken(node.GreaterThanToken); + Assert.Equal(node, newNode); + } + + [Fact] + public void TestModifiedTypeFactoryAndProperties() + { + var node = GenerateModifiedType(); + + Assert.Equal(default, node.Modifiers); + Assert.NotNull(node.Type); + var newNode = node.WithModifiers(node.Modifiers).WithType(node.Type); + Assert.Equal(node, newNode); + } + [Fact] public void TestNullableTypeFactoryAndProperties() { @@ -12613,6 +12729,58 @@ public void TestPointerTypeIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestFunctionPointerTypeTokenDeleteRewriter() + { + var oldNode = GenerateFunctionPointerType(); + 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 TestFunctionPointerTypeIdentityRewriter() + { + var oldNode = GenerateFunctionPointerType(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + + [Fact] + public void TestModifiedTypeTokenDeleteRewriter() + { + var oldNode = GenerateModifiedType(); + 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 TestModifiedTypeIdentityRewriter() + { + var oldNode = GenerateModifiedType(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestNullableTypeTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs new file mode 100644 index 0000000000000..e873f68589052 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs @@ -0,0 +1,2951 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing +{ + public class FunctionPointerTests : ParsingTests + { + public FunctionPointerTests(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void SimpleFunctionPointerTest() + { + UsingStatement("delegate* ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory] + [InlineData("cdecl")] + [InlineData("managed")] + [InlineData("stdcall")] + [InlineData("thiscall")] + [InlineData("unmanaged")] + [InlineData("invalidcallingconvetion")] // This is a semantic error, not a syntax error + [InlineData("void")] // This is a semantic error, not a syntax error + public void CallingConventions(string conventionString) + { + UsingStatement($"delegate* {conventionString} ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(conventionString == "void" ? SyntaxKind.VoidKeyword : SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + [Fact] + public void LangVersion8() + { + UsingStatement("delegate* cdecl ptr;", options: TestOptions.Regular8, + // (1,1): error CS8652: The feature 'function pointers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // delegate* cdecl ptr; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate* cdecl").WithArguments("function pointers").WithLocation(1, 1)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void VoidsAsType() + { + // Void isn't allowed in anything but the return type, but that's a semantic error, not a syntax error + UsingStatement("delegate* ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void NestedFunctionPointers() + { + UsingStatement("delegate*, delegate* managed> ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PointerType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.AsteriskToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PointerType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.AsteriskToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PointerType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.AsteriskToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void PointerToAFunctionPointer() + { + UsingStatement("delegate** ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PointerType); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.AsteriskToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void RefModifiers() + { + UsingStatement("delegate* ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Goo"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.InKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Bar"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.OutKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Baz"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.ReadOnlyKeyword); + N(SyntaxKind.PointerType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.AsteriskToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void Unterminated_01() + { + UsingStatement("delegate*< ;", options: TestOptions.RegularPreview, + // (1,12): error CS1031: Type expected + // delegate*< ; + Diagnostic(ErrorCode.ERR_TypeExpected, ";").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, '>' expected + // delegate*< ; + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">", ";").WithLocation(1, 12), + // (1,12): error CS1001: Identifier expected + // delegate*< ; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 12)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void Unterminated_02() + { + UsingStatement("delegate*' expected + // delegate*", ";").WithLocation(1, 15), + // (1,15): error CS1001: Identifier expected + // delegate*' expected + // delegate*", ";").WithLocation(1, 19), + // (1,19): error CS1001: Identifier expected + // delegate*' expected + // delegate*", ";").WithLocation(1, 20), + // (1,20): error CS1001: Identifier expected + // delegate* ptr;", options: TestOptions.RegularPreview, + // (1,11): error CS1003: Syntax error, '<' expected + // delegate* Dotted.Name ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "Dotted").WithArguments("<", "").WithLocation(1, 11), + // (1,17): error CS1003: Syntax error, ',' expected + // delegate* Dotted.Name ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, ".").WithArguments(",", ".").WithLocation(1, 17)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "Dotted"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void Unterminated_10() + { + UsingStatement("delegate*( ;", options: TestOptions.RegularPreview, + // (1,10): error CS1003: Syntax error, '<' expected + // delegate*( ; + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<", "(").WithLocation(1, 10), + // (1,12): error CS1031: Type expected + // delegate*( ; + Diagnostic(ErrorCode.ERR_TypeExpected, ";").WithLocation(1, 12), + // (1,12): error CS1003: Syntax error, '>' expected + // delegate*( ; + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">", ";").WithLocation(1, 12), + // (1,12): error CS1001: Identifier expected + // delegate*( ; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 12)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void Unterminated_11() + { + UsingStatement("delegate* @cdecl>", options: TestOptions.RegularPreview, + // (1,11): error CS1003: Syntax error, '<' expected + // delegate* @cdecl> + Diagnostic(ErrorCode.ERR_SyntaxError, "@cdecl").WithArguments("<", "").WithLocation(1, 11), + // (1,17): error CS1003: Syntax error, ',' expected + // delegate* @cdecl> + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",", ">").WithLocation(1, 17), + // (1,18): error CS1002: ; expected + // delegate* @cdecl> + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 18)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "@cdecl"); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void NoParamOrReturnTypes() + { + UsingStatement("delegate*<> ptr;", options: TestOptions.RegularPreview, + // (1,11): error CS1031: Type expected + // delegate*<> ptr; + Diagnostic(ErrorCode.ERR_TypeExpected, ">").WithLocation(1, 11)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void UsingParensInsteadOfAngles() + { + UsingStatement("delegate*(int, void)", options: TestOptions.RegularPreview, + // (1,10): error CS1003: Syntax error, '<' expected + // delegate*(int, void) + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<", "(").WithLocation(1, 10), + // (1,20): error CS1003: Syntax error, '>' expected + // delegate*(int, void) + Diagnostic(ErrorCode.ERR_SyntaxError, ")").WithArguments(">", ")").WithLocation(1, 20), + // (1,21): error CS1001: Identifier expected + // delegate*(int, void) + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 21), + // (1,21): error CS1002: ; expected + // delegate*(int, void) + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 21)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void MethodTypes() + { + UsingTree(@" +class C +{ + public delegate* M(delegate* param1, delegate* cdecl param2) {} +}", + options: TestOptions.RegularPreview); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "param1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "D"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "param2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void HardCast() + { + UsingExpression("(delegate* thiscall)ptr", options: TestOptions.RegularPreview); + N(SyntaxKind.CastExpression); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + EOF(); + } + + [Fact] + public void AsCast() + { + UsingExpression("ptr as delegate* stdcall", options: TestOptions.RegularPreview); + N(SyntaxKind.AsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + N(SyntaxKind.AsKeyword); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + EOF(); + } + + [Fact] + public void TupleType() + { + UsingExpression("((delegate* i1, delegate* managed i2))ptr", options: TestOptions.RegularPreview); + N(SyntaxKind.CastExpression); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleType); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "i1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.TupleElement); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "D"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "i2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + EOF(); + } + + [Fact] + public void GenericArguments() + { + UsingExpression("new M, delegate*>()", options: TestOptions.RegularPreview); + N(SyntaxKind.ObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.GenericName); + { + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.TypeArgumentList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "D"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + EOF(); + } + + [Fact] + public void TypeOf() + { + UsingExpression("typeof(delegate* cdecl)", options: TestOptions.RegularPreview); + N(SyntaxKind.TypeOfExpression); + { + N(SyntaxKind.TypeOfKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.ReadOnlyKeyword); + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "D"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.CloseParenToken); + } + EOF(); + } + + [Fact] + public void ArrayType() + { + UsingStatement("delegate*[] ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.ArrayType); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.ArrayRankSpecifier); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.OmittedArraySizeExpression); + { + N(SyntaxKind.OmittedArraySizeExpressionToken); + } + N(SyntaxKind.CloseBracketToken); + } + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void DelegateTypes() + { + UsingNode(@" +class C +{ + delegate delegate* cdecl M(delegate* p); +}", + options: TestOptions.RegularPreview); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.DelegateDeclaration); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "D"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "p"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LambdaParameterType() + { + UsingExpression("(delegate* p1) => {}", options: TestOptions.RegularPreview); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "p1"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void LocalVariableAndFunction() + { + UsingNode(@" +public void M() +{ + delegate* l1; + delegate* L2() { } + delegate* l3; +}", options: TestOptions.RegularPreview); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PublicKeyword); + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "l1"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "L2"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "l3"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void IsExpression() + { + UsingExpression("o is delegate*", options: TestOptions.RegularPreview); + N(SyntaxKind.IsExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + EOF(); + } + + [Fact] + public void IsNamedExpression() + { + UsingExpression("o is delegate* ptr", options: TestOptions.RegularPreview); + N(SyntaxKind.IsPatternExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.IsKeyword); + N(SyntaxKind.DeclarationPattern); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + } + EOF(); + } + + [Fact] + public void SwitchStatementCase() + { + UsingStatement(@" +switch (o) +{ + case delegate* { } _: + case delegate* (var x, var y): + break; +}", options: TestOptions.RegularPreview); + + N(SyntaxKind.SwitchStatement); + { + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchSection); + { + N(SyntaxKind.CasePatternSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.RecursivePattern); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.PropertyPatternClause); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.DiscardDesignation); + { + N(SyntaxKind.UnderscoreToken); + } + } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.CasePatternSwitchLabel); + { + N(SyntaxKind.CaseKeyword); + N(SyntaxKind.RecursivePattern); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.PositionalPatternClause); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Subpattern); + { + N(SyntaxKind.VarPattern); + { + N(SyntaxKind.VarKeyword); + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Subpattern); + { + N(SyntaxKind.VarPattern); + { + N(SyntaxKind.VarKeyword); + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "y"); + } + } + } + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.ColonToken); + } + N(SyntaxKind.BreakStatement); + { + N(SyntaxKind.BreakKeyword); + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void SwitchExpressions() + { + UsingExpression(@" +o switch +{ + delegate* _ => 1, + delegate* (var a, 2) ptr => 2, +}", options: TestOptions.RegularPreview); + + N(SyntaxKind.SwitchExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "o"); + } + N(SyntaxKind.SwitchKeyword); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SwitchExpressionArm); + { + N(SyntaxKind.DeclarationPattern); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.DiscardDesignation); + { + N(SyntaxKind.UnderscoreToken); + } + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.SwitchExpressionArm); + { + N(SyntaxKind.RecursivePattern); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.PositionalPatternClause); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Subpattern); + { + N(SyntaxKind.VarPattern); + { + N(SyntaxKind.VarKeyword); + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "a"); + } + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Subpattern); + { + N(SyntaxKind.ConstantPattern); + { + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SingleVariableDesignation); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "2"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.CloseBraceToken); + } + EOF(); + } + + [Fact] + public void UsingStatementType() + { + UsingStatement("using (delegate* ptr = MyMethod()) {}", options: TestOptions.RegularPreview); + N(SyntaxKind.UsingStatement); + { + N(SyntaxKind.UsingKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyMethod"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + } + } + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void UsingDeclarationType() + { + UsingStatement("using delegate* ptr = MyMethod();", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.UsingKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyMethod"); + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void FixedStatement() + { + UsingStatement("fixed (delegate* ptr = &MyMethod) {}", options: TestOptions.RegularPreview); + N(SyntaxKind.FixedStatement); + { + N(SyntaxKind.FixedKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.AddressOfExpression); + { + N(SyntaxKind.AmpersandToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "MyMethod"); + } + } + } + } + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void ForEachVariable() + { + UsingStatement("foreach (delegate* ptr in ptrs) {}", options: TestOptions.RegularPreview); + N(SyntaxKind.ForEachStatement); + { + N(SyntaxKind.ForEachKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.IdentifierToken, "ptr"); + N(SyntaxKind.InKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "ptrs"); + } + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void ForVariable() + { + UsingStatement("for (delegate* ptr = null;;) {}", options: TestOptions.RegularPreview); + N(SyntaxKind.ForStatement); + { + N(SyntaxKind.ForKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + } + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.CloseParenToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact] + public void SizeOf() + { + UsingExpression("sizeof(delegate*)", options: TestOptions.RegularPreview); + N(SyntaxKind.SizeOfExpression); + { + N(SyntaxKind.SizeOfKeyword); + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.CloseParenToken); + } + EOF(); + } + + [Fact] + public void SpecifiedParameterNamesAndDefaults() + { + UsingStatement("delegate* ptr;", options: TestOptions.RegularPreview, + // (1,15): error CS1003: Syntax error, ',' expected + // delegate* ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "param1").WithArguments(",", "").WithLocation(1, 15), + // (1,30): error CS1003: Syntax error, ',' expected + // delegate* ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "param2").WithArguments(",", "").WithLocation(1, 30)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void MissingListStart_01() + { + UsingStatement("delegate*void> ptr;", options: TestOptions.RegularPreview, + // (1,10): error CS1003: Syntax error, '<' expected + // delegate*void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments("<", "").WithLocation(1, 10), + // (1,10): error CS1001: Identifier expected + // delegate*void> ptr; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "void").WithLocation(1, 10), + // (1,10): error CS1003: Syntax error, ',' expected + // delegate*void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",", "void").WithLocation(1, 10)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void MissingListStart_02() + { + UsingStatement("delegate* cdecl void> ptr;", options: TestOptions.RegularPreview, + // (1,17): error CS1003: Syntax error, '<' expected + // delegate* cdecl void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments("<", "").WithLocation(1, 17), + // (1,17): error CS1001: Identifier expected + // delegate* cdecl void> ptr; + Diagnostic(ErrorCode.ERR_IdentifierExpected, "void").WithLocation(1, 17), + // (1,17): error CS1003: Syntax error, ',' expected + // delegate* cdecl void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "void").WithArguments(",", "void").WithLocation(1, 17)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken, "cdecl"); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void MissingListStart_03() + { + UsingStatement("delegate*> ptr;", options: TestOptions.RegularPreview, + // (1,10): error CS1003: Syntax error, '<' expected + // delegate*> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments("<", "").WithLocation(1, 10)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void ManyInvalidModifiers() + { + UsingStatement("delegate* ptr;", options: TestOptions.RegularPreview); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.ParamsKeyword); + N(SyntaxKind.ReadOnlyKeyword); + N(SyntaxKind.RefKeyword); + N(SyntaxKind.RefKeyword); + N(SyntaxKind.ThisKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void AsyncInParameterList_InAsyncFunction() + { + UsingNode(@" +async void M() +{ + delegate* ptr; +}", options: TestOptions.RegularPreview); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.AsyncKeyword); + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void AsyncInParameterList_InNonAsyncFunction() + { + UsingNode(@" +void M() +{ + delegate* ptr; +}", options: TestOptions.RegularPreview); + N(SyntaxKind.CompilationUnit); + { + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void AwaitInParameterList_InAsyncFunction() + { + UsingNode(@" +async void M() +{ + delegate* ptr; +}", options: TestOptions.RegularPreview, + // (4,15): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // delegate* ptr; + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(4, 15), + // (4,22): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression + // delegate* ptr; + Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(4, 22)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.AsyncKeyword); + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void AwaitInParameterList_InNonAsyncFunction() + { + UsingNode(@" +void M() +{ + delegate* ptr; +}", options: TestOptions.RegularPreview); + N(SyntaxKind.CompilationUnit); + { + 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.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "await"); + } + } + N(SyntaxKind.GreaterThanToken); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void IncompleteAtEndOfFile() + { + UsingStatement("delegate*", options: TestOptions.RegularPreview, + // (1,10): error CS1003: Syntax error, '<' expected + // delegate* + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(1, 10), + // (1,10): error CS1001: Identifier expected + // delegate* + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 10), + // (1,10): error CS1002: ; expected + // delegate* + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 10)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void IncompleteAtEndOfFileWithIdentifier() + { + UsingStatement("delegate* cdecl", options: TestOptions.RegularPreview, + // (1,11): error CS1003: Syntax error, '<' expected + // delegate* cdecl + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(1, 16), + // (1,16): error CS1001: Identifier expected + // delegate* cdecl + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 16), + // (1,16): error CS1002: ; expected + // delegate* cdecl + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 16)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken, "cdecl"); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact] + public void MixedParensAndAngles_01() + { + UsingStatement("delegate* cdecl' expected + // delegate* cdecl", ";").WithLocation(1, 26), + // (1,26): error CS1001: Identifier expected + // delegate* cdecl ptr;", options: TestOptions.RegularPreview, + // (1,16): error CS1003: Syntax error, '<' expected + // delegate* cdecl(void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, "(").WithArguments("<", "(").WithLocation(1, 16), + // (1,21): error CS1003: Syntax error, ',' expected + // delegate* cdecl(void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, ">").WithArguments(",", ">").WithLocation(1, 21), + // (1,26): error CS1003: Syntax error, '>' expected + // delegate* cdecl(void> ptr; + Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments(">", ";").WithLocation(1, 26), + // (1,26): error CS1001: Identifier expected + // delegate* cdecl(void> ptr; + Diagnostic(ErrorCode.ERR_IdentifierExpected, ";").WithLocation(1, 26)); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken, "cdecl"); + M(SyntaxKind.LessThanToken); + N(SyntaxKind.ModifiedType); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [InlineData("cdecl")] + [InlineData("unmanaged")] + [InlineData("managed")] + [InlineData("stdcall")] + [InlineData("thiscall")] + [Theory] + public void ValidCallingConventionNextLine(string convention) + { + UsingNode($@" +void C() +{{ + delegate* + {convention} +}}", options: TestOptions.RegularPreview, + // (5,10): error CS1003: Syntax error, '<' expected + // {convention} + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(5, convention.Length + 5), + // (5,10): error CS1001: Identifier expected + // {convention} + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(5, convention.Length + 5), + // (5,10): error CS1002: ; expected + // {convention} + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(5, convention.Length + 5)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.IdentifierToken, convention); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void InvalidCallingConventionNextLine() + { + UsingNode(@" +void C() +{ + delegate* + int ptr = 1; +}", options: TestOptions.RegularPreview, + // (4,14): error CS1003: Syntax error, '<' expected + // delegate* + Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments("<", "").WithLocation(4, 14), + // (4,14): error CS1001: Identifier expected + // delegate* + Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(4, 14), + // (4,14): error CS1002: ; expected + // delegate* + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(4, 14)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + M(SyntaxKind.LessThanToken); + M(SyntaxKind.ModifiedType); + { + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.GreaterThanToken); + } + M(SyntaxKind.VariableDeclarator); + { + M(SyntaxKind.IdentifierToken); + } + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "ptr"); + N(SyntaxKind.EqualsValueClause); + { + N(SyntaxKind.EqualsToken); + N(SyntaxKind.NumericLiteralExpression); + { + N(SyntaxKind.NumericLiteralToken, "1"); + } + } + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs index fdcfd02fedbb7..dae0eaf144317 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/DiagnosticAnalyzerDriver/DiagnosticAnalyzerDriverTests.cs @@ -30,7 +30,12 @@ public async Task DiagnosticAnalyzerDriverAllInOne() symbolKindsWithNoCodeBlocks.Add(SymbolKind.Property); symbolKindsWithNoCodeBlocks.Add(SymbolKind.NamedType); - var missingSyntaxNodes = new HashSet(); + var missingSyntaxNodes = new HashSet() + { + // PROTOYPE(func-ptr): Remove + SyntaxKind.FunctionPointerType, + SyntaxKind.ModifiedType, + }; var analyzer = new CSharpTrackingDiagnosticAnalyzer(); using var workspace = TestWorkspace.CreateCSharp(source, TestOptions.Regular);