未验证 提交 4d24556d 编写于 作者: M msftbot[bot] 提交者: GitHub

Merge pull request #46730 from 333fred/features/function-pointers

Merge features/function-pointers into master
......@@ -233,6 +233,7 @@ private BoundExpression BindObjectCreationExpression(BoundUnconvertedObjectCreat
Error(diagnostics, ErrorCode.ERR_TypelessNewIllegalTargetType, syntax, type);
goto case TypeKind.Error;
case TypeKind.Pointer:
case TypeKind.FunctionPointer:
Error(diagnostics, ErrorCode.ERR_UnsafeTypeInObjectCreation, syntax, type);
goto case TypeKind.Error;
case TypeKind.Error:
......
......@@ -214,7 +214,7 @@ private BoundExpression ToBadExpression(BoundExpression expr, LookupResultKind r
}
}
internal TypeSymbol CreateErrorType(string name = "")
internal NamedTypeSymbol CreateErrorType(string name = "")
{
return new ExtendedErrorTypeSymbol(this.Compilation, name, arity: 0, errorInfo: null, unreported: false);
}
......
......@@ -2989,6 +2989,12 @@ internal bool HasImplicitPointerConversion(TypeSymbol? source, TypeSymbol? desti
return false;
}
if (sourceSig.CallingConvention == Cci.CallingConvention.Unmanaged &&
!sourceSig.GetCallingConventionModifiers().SetEquals(destinationSig.GetCallingConventionModifiers()))
{
return false;
}
for (int i = 0; i < sourceSig.ParameterCount; i++)
{
var sourceParam = sourceSig.Parameters[i];
......
......@@ -6126,7 +6126,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>&amp;method group</value>
</data>
<data name="ERR_InvalidFunctionPointerCallingConvention" xml:space="preserve">
<value>'{0}' is not a valid calling convention for a function pointer. Valid conventions are 'cdecl', 'managed', 'thiscall', and 'stdcall'.</value>
<value>'{0}' is not a valid calling convention specifier for a function pointer.</value>
</data>
<data name="ERR_TypeNotFound" xml:space="preserve">
<value>Type '{0}' is not defined.</value>
</data>
<data name="ERR_TypeMustBePublic" xml:space="preserve">
<value>Type '{0}' must be public to be used as a calling convention.</value>
</data>
<data name="ERR_InternalError" xml:space="preserve">
<value>Internal error in the C# compiler.</value>
......@@ -6317,18 +6323,30 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_UnsupportedCallingConvention" xml:space="preserve">
<value>The calling convention of '{0}' is not supported by the language.</value>
</data>
<data name="ERR_RuntimeDoesNotSupportUnmanagedDefaultCallConv" xml:space="preserve">
<value>The target runtime doesn't support extensible or runtime-environment default calling conventions.</value>
</data>
<data name="NotSameNumberParameterTypesAndRefKinds" xml:space="preserve">
<value>Given {0} parameter types and {1} parameter ref kinds. These arrays must have the same length.</value>
</data>
<data name="OutIsNotValidForReturn" xml:space="preserve">
<value>'RefKind.Out' is not a valid ref kind for a return type.</value>
</data>
<data name="CallingConventionTypesRequireUnmanaged" xml:space="preserve">
<value>Passing '{0}' is not valid unless '{1}' is 'SignatureCallingConvention.Unmanaged'.</value>
</data>
<data name="CallingConventionTypeIsInvalid" xml:space="preserve">
<value>Cannot use '{0}' as a calling convention modifier.</value>
</data>
<data name="ERR_CannotConvertAddressOfToDelegate" xml:space="preserve">
<value>Cannot convert &amp;method group '{0}' to delegate type '{0}'.</value>
</data>
<data name="ERR_AddressOfToNonFunctionPointer" xml:space="preserve">
<value>Cannot convert &amp;method group '{0}' to non-function pointer type '{1}'.</value>
</data>
<data name="ERR_CannotSpecifyManagedWithUnmanagedSpecifiers" xml:space="preserve">
<value>'managed' calling convention cannot be combined with unmanaged calling convention specifiers.</value>
</data>
<data name="ERR_FeatureNotAvailableInVersion9" xml:space="preserve">
<value>Feature '{0}' is not available in C# 9.0. Please use language version {1} or greater.</value>
</data>
......
......@@ -3260,7 +3260,9 @@ protected override IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol
ITypeSymbol returnType,
RefKind returnRefKind,
ImmutableArray<ITypeSymbol> parameterTypes,
ImmutableArray<RefKind> parameterRefKinds)
ImmutableArray<RefKind> parameterRefKinds,
SignatureCallingConvention callingConvention,
ImmutableArray<INamedTypeSymbol> callingConventionTypes)
{
if (returnType is null)
{
......@@ -3297,11 +3299,48 @@ protected override IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol
throw new ArgumentException(CSharpResources.OutIsNotValidForReturn);
}
if (callingConvention != SignatureCallingConvention.Unmanaged && !callingConventionTypes.IsDefaultOrEmpty)
{
throw new ArgumentException(string.Format(CSharpResources.CallingConventionTypesRequireUnmanaged, nameof(callingConventionTypes), nameof(callingConvention)));
}
if (!callingConvention.IsValid())
{
throw new ArgumentOutOfRangeException(nameof(callingConvention));
}
var returnTypeWithAnnotations = TypeWithAnnotations.Create(returnType.EnsureCSharpSymbolOrNull(nameof(returnType)), returnType.NullableAnnotation.ToInternalAnnotation());
var parameterTypesWithAnnotations = parameterTypes.SelectAsArray(
type => TypeWithAnnotations.Create(type.EnsureCSharpSymbolOrNull(nameof(parameterTypes)), type.NullableAnnotation.ToInternalAnnotation()));
var internalCallingConvention = callingConvention.FromSignatureConvention();
var conventionModifiers = internalCallingConvention == CallingConvention.Unmanaged && !callingConventionTypes.IsDefaultOrEmpty
? callingConventionTypes.SelectAsArray((type, i, @this) => getCustomModifierForType(type, @this, i), this)
: ImmutableArray<CustomModifier>.Empty;
return FunctionPointerTypeSymbol.CreateFromParts(returnTypeWithAnnotations, returnRefKind, parameterTypesWithAnnotations, parameterRefKinds, this).GetPublicSymbol();
return FunctionPointerTypeSymbol.CreateFromParts(
internalCallingConvention,
conventionModifiers,
returnTypeWithAnnotations,
returnRefKind: returnRefKind,
parameterTypes: parameterTypesWithAnnotations,
parameterRefKinds: parameterRefKinds,
compilation: this).GetPublicSymbol();
static CustomModifier getCustomModifierForType(INamedTypeSymbol type, CSharpCompilation @this, int index)
{
if (type is null)
{
throw new ArgumentNullException($"{nameof(callingConventionTypes)}[{index}]");
}
var internalType = type.EnsureCSharpSymbolOrNull($"{nameof(callingConventionTypes)}[{index}]");
if (!FunctionPointerTypeSymbol.IsCallingConventionModifier(internalType) || @this.Assembly.CorLibrary != internalType.ContainingAssembly)
{
throw new ArgumentException(string.Format(CSharpResources.CallingConventionTypeIsInvalid, type.ToDisplayString()));
}
return CSharpCustomModifier.CreateOptional(internalType);
}
}
protected override INamedTypeSymbol CommonCreateNativeIntegerTypeSymbol(bool signed)
......
......@@ -1885,7 +1885,13 @@ internal enum ErrorCode
WRN_UseDefViolationOut = 8886,
WRN_UseDefViolation = 8887,
ERR_CannotSpecifyManagedWithUnmanagedSpecifiers = 8888,
ERR_RuntimeDoesNotSupportUnmanagedDefaultCallConv = 8889,
ERR_TypeNotFound = 8890,
ERR_TypeMustBePublic = 8891,
#endregion diagnostics introduced for C# 9.0
// Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd)
}
}
......@@ -353,7 +353,28 @@ array_rank_specifier
;
function_pointer_type
: 'delegate' '*' syntax_token? '<' parameter (',' parameter)* '>'
: 'delegate' '*' function_pointer_calling_convention? function_pointer_parameter_list
;
function_pointer_calling_convention
: 'managed' function_pointer_unmanaged_calling_convention_list?
| 'unmanaged' function_pointer_unmanaged_calling_convention_list?
;
function_pointer_unmanaged_calling_convention_list
: '[' function_pointer_unmanaged_calling_convention (',' function_pointer_unmanaged_calling_convention)* ']'
;
function_pointer_unmanaged_calling_convention
: identifier_token
;
function_pointer_parameter_list
: '<' function_pointer_parameter (',' function_pointer_parameter)* '>'
;
function_pointer_parameter
: attribute_list* modifier* type
;
nullable_type
......@@ -1268,6 +1289,11 @@ base_parameter_list
| parameter_list
;
base_parameter
: function_pointer_parameter
| parameter
;
character_literal_token
: /* see lexical specification */
;
......
......@@ -55,6 +55,22 @@ public partial class CSharpSyntaxVisitor<TResult>
[return: MaybeNull]
public virtual TResult VisitFunctionPointerType(FunctionPointerTypeSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerParameterListSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitFunctionPointerParameterList(FunctionPointerParameterListSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerCallingConventionSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitFunctionPointerCallingConvention(FunctionPointerCallingConventionSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerUnmanagedCallingConventionListSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitFunctionPointerUnmanagedCallingConventionList(FunctionPointerUnmanagedCallingConventionListSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerUnmanagedCallingConventionSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitFunctionPointerUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a NullableTypeSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitNullableType(NullableTypeSyntax node) => this.DefaultVisit(node);
......@@ -747,6 +763,10 @@ public partial class CSharpSyntaxVisitor<TResult>
[return: MaybeNull]
public virtual TResult VisitParameter(ParameterSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerParameterSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitFunctionPointerParameter(FunctionPointerParameterSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a IncompleteMemberSyntax node.</summary>
[return: MaybeNull]
public virtual TResult VisitIncompleteMember(IncompleteMemberSyntax node) => this.DefaultVisit(node);
......@@ -952,6 +972,18 @@ public partial class CSharpSyntaxVisitor
/// <summary>Called when the visitor visits a FunctionPointerTypeSyntax node.</summary>
public virtual void VisitFunctionPointerType(FunctionPointerTypeSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerParameterListSyntax node.</summary>
public virtual void VisitFunctionPointerParameterList(FunctionPointerParameterListSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerCallingConventionSyntax node.</summary>
public virtual void VisitFunctionPointerCallingConvention(FunctionPointerCallingConventionSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerUnmanagedCallingConventionListSyntax node.</summary>
public virtual void VisitFunctionPointerUnmanagedCallingConventionList(FunctionPointerUnmanagedCallingConventionListSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerUnmanagedCallingConventionSyntax node.</summary>
public virtual void VisitFunctionPointerUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a NullableTypeSyntax node.</summary>
public virtual void VisitNullableType(NullableTypeSyntax node) => this.DefaultVisit(node);
......@@ -1471,6 +1503,9 @@ public partial class CSharpSyntaxVisitor
/// <summary>Called when the visitor visits a ParameterSyntax node.</summary>
public virtual void VisitParameter(ParameterSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a FunctionPointerParameterSyntax node.</summary>
public virtual void VisitFunctionPointerParameter(FunctionPointerParameterSyntax node) => this.DefaultVisit(node);
/// <summary>Called when the visitor visits a IncompleteMemberSyntax node.</summary>
public virtual void VisitIncompleteMember(IncompleteMemberSyntax node) => this.DefaultVisit(node);
......@@ -1631,7 +1666,19 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor<SyntaxNode?>
=> 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.Parameters), VisitToken(node.GreaterThanToken));
=> node.Update(VisitToken(node.DelegateKeyword), VisitToken(node.AsteriskToken), (FunctionPointerCallingConventionSyntax?)Visit(node.CallingConvention), (FunctionPointerParameterListSyntax?)Visit(node.ParameterList) ?? throw new ArgumentNullException("parameterList"));
public override SyntaxNode? VisitFunctionPointerParameterList(FunctionPointerParameterListSyntax node)
=> node.Update(VisitToken(node.LessThanToken), VisitList(node.Parameters), VisitToken(node.GreaterThanToken));
public override SyntaxNode? VisitFunctionPointerCallingConvention(FunctionPointerCallingConventionSyntax node)
=> node.Update(VisitToken(node.ManagedOrUnmanagedKeyword), (FunctionPointerUnmanagedCallingConventionListSyntax?)Visit(node.UnmanagedCallingConventionList));
public override SyntaxNode? VisitFunctionPointerUnmanagedCallingConventionList(FunctionPointerUnmanagedCallingConventionListSyntax node)
=> node.Update(VisitToken(node.OpenBracketToken), VisitList(node.CallingConventions), VisitToken(node.CloseBracketToken));
public override SyntaxNode? VisitFunctionPointerUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax node)
=> node.Update(VisitToken(node.Name));
public override SyntaxNode? VisitNullableType(NullableTypeSyntax node)
=> node.Update((TypeSyntax?)Visit(node.ElementType) ?? throw new ArgumentNullException("elementType"), VisitToken(node.QuestionToken));
......@@ -2152,6 +2199,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor<SyntaxNode?>
public override SyntaxNode? VisitParameter(ParameterSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (TypeSyntax?)Visit(node.Type), VisitToken(node.Identifier), (EqualsValueClauseSyntax?)Visit(node.Default));
public override SyntaxNode? VisitFunctionPointerParameter(FunctionPointerParameterSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (TypeSyntax?)Visit(node.Type) ?? throw new ArgumentNullException("type"));
public override SyntaxNode? VisitIncompleteMember(IncompleteMemberSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (TypeSyntax?)Visit(node.Type));
......@@ -2416,22 +2466,68 @@ public static PointerTypeSyntax PointerType(TypeSyntax elementType)
=> SyntaxFactory.PointerType(elementType, SyntaxFactory.Token(SyntaxKind.AsteriskToken));
/// <summary>Creates a new FunctionPointerTypeSyntax instance.</summary>
public static FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, SyntaxToken callingConvention, SyntaxToken lessThanToken, SeparatedSyntaxList<ParameterSyntax> parameters, SyntaxToken greaterThanToken)
public static FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken delegateKeyword, SyntaxToken asteriskToken, FunctionPointerCallingConventionSyntax? callingConvention, FunctionPointerParameterListSyntax parameterList)
{
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!, parameters.Node.ToGreenSeparatedList<Syntax.InternalSyntax.ParameterSyntax>(), (Syntax.InternalSyntax.SyntaxToken)greaterThanToken.Node!).CreateRed();
if (parameterList == null) throw new ArgumentNullException(nameof(parameterList));
return (FunctionPointerTypeSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerType((Syntax.InternalSyntax.SyntaxToken)delegateKeyword.Node!, (Syntax.InternalSyntax.SyntaxToken)asteriskToken.Node!, callingConvention == null ? null : (Syntax.InternalSyntax.FunctionPointerCallingConventionSyntax)callingConvention.Green, (Syntax.InternalSyntax.FunctionPointerParameterListSyntax)parameterList.Green).CreateRed();
}
/// <summary>Creates a new FunctionPointerTypeSyntax instance.</summary>
public static FunctionPointerTypeSyntax FunctionPointerType(SyntaxToken callingConvention, SeparatedSyntaxList<ParameterSyntax> parameters)
=> SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), callingConvention, SyntaxFactory.Token(SyntaxKind.LessThanToken), parameters, SyntaxFactory.Token(SyntaxKind.GreaterThanToken));
public static FunctionPointerTypeSyntax FunctionPointerType(FunctionPointerCallingConventionSyntax? callingConvention, FunctionPointerParameterListSyntax parameterList)
=> SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), callingConvention, parameterList);
/// <summary>Creates a new FunctionPointerTypeSyntax instance.</summary>
public static FunctionPointerTypeSyntax FunctionPointerType(SeparatedSyntaxList<ParameterSyntax> parameters = default)
=> SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), default, SyntaxFactory.Token(SyntaxKind.LessThanToken), parameters, SyntaxFactory.Token(SyntaxKind.GreaterThanToken));
public static FunctionPointerTypeSyntax FunctionPointerType()
=> SyntaxFactory.FunctionPointerType(SyntaxFactory.Token(SyntaxKind.DelegateKeyword), SyntaxFactory.Token(SyntaxKind.AsteriskToken), default, SyntaxFactory.FunctionPointerParameterList());
/// <summary>Creates a new FunctionPointerParameterListSyntax instance.</summary>
public static FunctionPointerParameterListSyntax FunctionPointerParameterList(SyntaxToken lessThanToken, SeparatedSyntaxList<FunctionPointerParameterSyntax> parameters, SyntaxToken greaterThanToken)
{
if (lessThanToken.Kind() != SyntaxKind.LessThanToken) throw new ArgumentException(nameof(lessThanToken));
if (greaterThanToken.Kind() != SyntaxKind.GreaterThanToken) throw new ArgumentException(nameof(greaterThanToken));
return (FunctionPointerParameterListSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerParameterList((Syntax.InternalSyntax.SyntaxToken)lessThanToken.Node!, parameters.Node.ToGreenSeparatedList<Syntax.InternalSyntax.FunctionPointerParameterSyntax>(), (Syntax.InternalSyntax.SyntaxToken)greaterThanToken.Node!).CreateRed();
}
/// <summary>Creates a new FunctionPointerParameterListSyntax instance.</summary>
public static FunctionPointerParameterListSyntax FunctionPointerParameterList(SeparatedSyntaxList<FunctionPointerParameterSyntax> parameters = default)
=> SyntaxFactory.FunctionPointerParameterList(SyntaxFactory.Token(SyntaxKind.LessThanToken), parameters, SyntaxFactory.Token(SyntaxKind.GreaterThanToken));
/// <summary>Creates a new FunctionPointerCallingConventionSyntax instance.</summary>
public static FunctionPointerCallingConventionSyntax FunctionPointerCallingConvention(SyntaxToken managedOrUnmanagedKeyword, FunctionPointerUnmanagedCallingConventionListSyntax? unmanagedCallingConventionList)
{
switch (managedOrUnmanagedKeyword.Kind())
{
case SyntaxKind.ManagedKeyword:
case SyntaxKind.UnmanagedKeyword: break;
default: throw new ArgumentException(nameof(managedOrUnmanagedKeyword));
}
return (FunctionPointerCallingConventionSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerCallingConvention((Syntax.InternalSyntax.SyntaxToken)managedOrUnmanagedKeyword.Node!, unmanagedCallingConventionList == null ? null : (Syntax.InternalSyntax.FunctionPointerUnmanagedCallingConventionListSyntax)unmanagedCallingConventionList.Green).CreateRed();
}
/// <summary>Creates a new FunctionPointerCallingConventionSyntax instance.</summary>
public static FunctionPointerCallingConventionSyntax FunctionPointerCallingConvention(SyntaxToken managedOrUnmanagedKeyword)
=> SyntaxFactory.FunctionPointerCallingConvention(managedOrUnmanagedKeyword, default);
/// <summary>Creates a new FunctionPointerUnmanagedCallingConventionListSyntax instance.</summary>
public static FunctionPointerUnmanagedCallingConventionListSyntax FunctionPointerUnmanagedCallingConventionList(SyntaxToken openBracketToken, SeparatedSyntaxList<FunctionPointerUnmanagedCallingConventionSyntax> callingConventions, SyntaxToken closeBracketToken)
{
if (openBracketToken.Kind() != SyntaxKind.OpenBracketToken) throw new ArgumentException(nameof(openBracketToken));
if (closeBracketToken.Kind() != SyntaxKind.CloseBracketToken) throw new ArgumentException(nameof(closeBracketToken));
return (FunctionPointerUnmanagedCallingConventionListSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerUnmanagedCallingConventionList((Syntax.InternalSyntax.SyntaxToken)openBracketToken.Node!, callingConventions.Node.ToGreenSeparatedList<Syntax.InternalSyntax.FunctionPointerUnmanagedCallingConventionSyntax>(), (Syntax.InternalSyntax.SyntaxToken)closeBracketToken.Node!).CreateRed();
}
/// <summary>Creates a new FunctionPointerUnmanagedCallingConventionListSyntax instance.</summary>
public static FunctionPointerUnmanagedCallingConventionListSyntax FunctionPointerUnmanagedCallingConventionList(SeparatedSyntaxList<FunctionPointerUnmanagedCallingConventionSyntax> callingConventions = default)
=> SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(SyntaxFactory.Token(SyntaxKind.OpenBracketToken), callingConventions, SyntaxFactory.Token(SyntaxKind.CloseBracketToken));
/// <summary>Creates a new FunctionPointerUnmanagedCallingConventionSyntax instance.</summary>
public static FunctionPointerUnmanagedCallingConventionSyntax FunctionPointerUnmanagedCallingConvention(SyntaxToken name)
{
if (name.Kind() != SyntaxKind.IdentifierToken) throw new ArgumentException(nameof(name));
return (FunctionPointerUnmanagedCallingConventionSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerUnmanagedCallingConvention((Syntax.InternalSyntax.SyntaxToken)name.Node!).CreateRed();
}
/// <summary>Creates a new NullableTypeSyntax instance.</summary>
public static NullableTypeSyntax NullableType(TypeSyntax elementType, SyntaxToken questionToken)
......@@ -5580,6 +5676,17 @@ public static ParameterSyntax Parameter(SyntaxList<AttributeListSyntax> attribut
public static ParameterSyntax Parameter(SyntaxToken identifier)
=> SyntaxFactory.Parameter(default, default(SyntaxTokenList), default, identifier, default);
/// <summary>Creates a new FunctionPointerParameterSyntax instance.</summary>
public static FunctionPointerParameterSyntax FunctionPointerParameter(SyntaxList<AttributeListSyntax> attributeLists, SyntaxTokenList modifiers, TypeSyntax type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return (FunctionPointerParameterSyntax)Syntax.InternalSyntax.SyntaxFactory.FunctionPointerParameter(attributeLists.Node.ToGreenList<Syntax.InternalSyntax.AttributeListSyntax>(), modifiers.Node.ToGreenList<Syntax.InternalSyntax.SyntaxToken>(), (Syntax.InternalSyntax.TypeSyntax)type.Green).CreateRed();
}
/// <summary>Creates a new FunctionPointerParameterSyntax instance.</summary>
public static FunctionPointerParameterSyntax FunctionPointerParameter(TypeSyntax type)
=> SyntaxFactory.FunctionPointerParameter(default, default(SyntaxTokenList), type);
/// <summary>Creates a new IncompleteMemberSyntax instance.</summary>
public static IncompleteMemberSyntax IncompleteMember(SyntaxList<AttributeListSyntax> attributeLists, SyntaxTokenList modifiers, TypeSyntax? type)
{
......
......@@ -34,7 +34,7 @@
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(System.String,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,System.Text.Encoding,System.Threading.CancellationToken)~Microsoft.CodeAnalysis.SyntaxTree")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(Microsoft.CodeAnalysis.Text.SourceText,Microsoft.CodeAnalysis.CSharp.CSharpParseOptions,System.String,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 = "<Pending>", 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 = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerType(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.ParameterSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetDeclaredSymbol(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.CompilationUnitSyntax,System.Threading.CancellationToken)~Microsoft.CodeAnalysis.IMethodSymbol")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetSymbolInfo(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax,System.Threading.CancellationToken)~Microsoft.CodeAnalysis.SymbolInfo")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.CSharpExtensions.GetMemberGroup(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.PrimaryConstructorBaseTypeSyntax,System.Threading.CancellationToken)~System.Collections.Immutable.ImmutableArray{Microsoft.CodeAnalysis.ISymbol}")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerUnmanagedCallingConventionSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerUnmanagedCallingConventionListSyntax")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0027:Public API with optional parameter(s) should have the most parameters amongst its public overloads.", Justification = "<Pending>", Scope = "member", Target = "~M:Microsoft.CodeAnalysis.CSharp.SyntaxFactory.FunctionPointerParameterList(Microsoft.CodeAnalysis.SeparatedSyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerParameterSyntax})~Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerParameterListSyntax")]
......@@ -84,7 +84,8 @@ internal enum TerminatorState
IsEndOfNameInExplicitInterface = 1 << 22,
IsEndOfFunctionPointerParameterList = 1 << 23,
IsEndOfFunctionPointerParameterListErrored = 1 << 24,
IsEndOfRecordSignature = 1 << 25,
IsEndOfFunctionPointerCallingConvention = 1 << 25,
IsEndOfRecordSignature = 1 << 26,
}
private const int LastTerminatorState = (int)TerminatorState.IsEndOfRecordSignature;
......@@ -125,6 +126,7 @@ private bool IsTerminator()
case TerminatorState.IsEndOfNameInExplicitInterface when this.IsEndOfNameInExplicitInterface():
case TerminatorState.IsEndOfFunctionPointerParameterList when this.IsEndOfFunctionPointerParameterList(errored: false):
case TerminatorState.IsEndOfFunctionPointerParameterListErrored when this.IsEndOfFunctionPointerParameterList(errored: true):
case TerminatorState.IsEndOfFunctionPointerCallingConvention when this.IsEndOfFunctionPointerCallingConvention():
case TerminatorState.IsEndOfRecordSignature when this.IsEndOfRecordSignature():
return true;
}
......@@ -3052,6 +3054,8 @@ private bool IsEndOfNameInExplicitInterface()
private bool IsEndOfFunctionPointerParameterList(bool errored) => this.CurrentToken.Kind == (errored ? SyntaxKind.CloseParenToken : SyntaxKind.GreaterThanToken);
private bool IsEndOfFunctionPointerCallingConvention() => this.CurrentToken.Kind == SyntaxKind.CloseBracketToken;
private MethodDeclarationSyntax ParseMethodDeclaration(
SyntaxList<AttributeListSyntax> attributes,
SyntaxListBuilder modifiers,
......@@ -6415,9 +6419,54 @@ private ScanTypeFlags ScanFunctionPointerType(out SyntaxToken lastTokenOfType)
_ = EatToken(SyntaxKind.DelegateKeyword);
lastTokenOfType = EatToken(SyntaxKind.AsteriskToken);
if (IsPossibleCallingConvention(lastTokenOfType))
TerminatorState saveTerm;
if (CurrentToken.Kind == SyntaxKind.IdentifierToken)
{
lastTokenOfType = EatToken();
var peek1 = PeekToken(1);
switch (CurrentToken)
{
case { ContextualKind: SyntaxKind.ManagedKeyword }:
case { ContextualKind: SyntaxKind.UnmanagedKeyword }:
case var _ when IsPossibleFunctionPointerParameterListStart(peek1):
case var _ when peek1.Kind == SyntaxKind.OpenBracketToken:
lastTokenOfType = EatToken();
break;
default:
// Whatever is next, it's probably not part of the type. We know that delegate* must be
// a function pointer start, however, so say the asterisk is the last element and bail
return ScanTypeFlags.MustBeType;
}
if (CurrentToken.Kind == SyntaxKind.OpenBracketToken)
{
lastTokenOfType = EatToken(SyntaxKind.OpenBracketToken);
saveTerm = _termState;
_termState |= TerminatorState.IsEndOfFunctionPointerCallingConvention;
try
{
while (true)
{
lastTokenOfType = TryEatToken(SyntaxKind.IdentifierToken) ?? lastTokenOfType;
if (skipBadFunctionPointerTokens() == PostSkipAction.Abort)
{
break;
}
Debug.Assert(CurrentToken.Kind == SyntaxKind.CommaToken);
lastTokenOfType = EatToken();
}
lastTokenOfType = TryEatToken(SyntaxKind.CloseBracketToken) ?? lastTokenOfType;
}
finally
{
_termState = saveTerm;
}
}
}
if (!IsPossibleFunctionPointerParameterListStart(CurrentToken))
......@@ -6432,26 +6481,20 @@ private ScanTypeFlags ScanFunctionPointerType(out SyntaxToken lastTokenOfType)
var validStartingToken = EatToken().Kind == SyntaxKind.LessThanToken;
var saveTerm = _termState;
saveTerm = _termState;
_termState |= validStartingToken ? TerminatorState.IsEndOfFunctionPointerParameterList : TerminatorState.IsEndOfFunctionPointerParameterListErrored;
var ignoredModifiers = _pool.Allocate<SyntaxToken>();
try
{
do
{
var ignoredModifiers = _pool.Allocate<SyntaxToken>();
try
{
ParseParameterModifiers(ignoredModifiers, isFunctionPointerParameter: true);
}
finally
{
_pool.Free(ignoredModifiers);
}
ParseParameterModifiers(ignoredModifiers, isFunctionPointerParameter: true);
ignoredModifiers.Clear();
_ = ScanType(out _);
if (skipBadFunctionPointerParameterTokens() == PostSkipAction.Abort)
if (skipBadFunctionPointerTokens() == PostSkipAction.Abort)
{
break;
}
......@@ -6463,6 +6506,7 @@ private ScanTypeFlags ScanFunctionPointerType(out SyntaxToken lastTokenOfType)
finally
{
_termState = saveTerm;
_pool.Free(ignoredModifiers);
}
if (!validStartingToken && CurrentToken.Kind == SyntaxKind.CloseParenToken)
......@@ -6476,7 +6520,7 @@ private ScanTypeFlags ScanFunctionPointerType(out SyntaxToken lastTokenOfType)
return ScanTypeFlags.MustBeType;
PostSkipAction skipBadFunctionPointerParameterTokens()
PostSkipAction skipBadFunctionPointerTokens()
{
return SkipBadTokensWithExpectedKind(isNotExpectedFunction: p => p.CurrentToken.Kind != SyntaxKind.CommaToken,
abortFunction: p => p.IsTerminator(),
......@@ -6899,21 +6943,21 @@ 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;
FunctionPointerCallingConventionSyntax? callingConvention = parseCallingConvention();
if (!IsPossibleFunctionPointerParameterListStart(CurrentToken))
{
var lessThanTokenError = WithAdditionalDiagnostics(SyntaxFactory.MissingToken(SyntaxKind.LessThanToken), GetExpectedTokenError(SyntaxKind.LessThanToken, SyntaxKind.None));
var missingTypes = _pool.AllocateSeparated<ParameterSyntax>();
var missingTypes = _pool.AllocateSeparated<FunctionPointerParameterSyntax>();
var missingTypeName = CreateMissingIdentifierName();
var missingType = SyntaxFactory.Parameter(attributeLists: default, modifiers: default, missingTypeName, identifier: CreateMissingIdentifierToken(), @default: null);
var missingType = SyntaxFactory.FunctionPointerParameter(attributeLists: default, modifiers: 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);
var paramList = SyntaxFactory.FunctionPointerParameterList(lessThanTokenError, missingTypes, greaterThanTokenError);
var funcPtr = SyntaxFactory.FunctionPointerType(@delegate, asterisk, callingConvention, paramList);
_pool.Free(missingTypes);
return funcPtr;
}
......@@ -6921,7 +6965,7 @@ private FunctionPointerTypeSyntax ParseFunctionPointerTypeSyntax()
var lessThanToken = EatTokenAsKind(SyntaxKind.LessThanToken);
var saveTerm = _termState;
_termState |= (lessThanToken.IsMissing ? TerminatorState.IsEndOfFunctionPointerParameterListErrored : TerminatorState.IsEndOfFunctionPointerParameterList);
var types = _pool.AllocateSeparated<ParameterSyntax>();
var types = _pool.AllocateSeparated<FunctionPointerParameterSyntax>();
try
{
......@@ -6933,9 +6977,9 @@ private FunctionPointerTypeSyntax ParseFunctionPointerTypeSyntax()
ParseParameterModifiers(modifiers, isFunctionPointerParameter: true);
var parameterType = ParseTypeOrVoid();
types.Add(SyntaxFactory.Parameter(attributeLists: default, modifiers, parameterType, identifier: CreateMissingIdentifierToken(), @default: null));
types.Add(SyntaxFactory.FunctionPointerParameter(attributeLists: default, modifiers, parameterType));
if (skipBadFunctionPointerParameterListTokens() == PostSkipAction.Abort)
if (skipBadFunctionPointerTokens(types) == PostSkipAction.Abort)
{
break;
}
......@@ -6959,7 +7003,7 @@ private FunctionPointerTypeSyntax ParseFunctionPointerTypeSyntax()
greaterThanToken = EatToken(SyntaxKind.GreaterThanToken);
}
var funcPointer = SyntaxFactory.FunctionPointerType(@delegate, asterisk, callingConvention, lessThanToken, types, greaterThanToken);
var funcPointer = SyntaxFactory.FunctionPointerType(@delegate, asterisk, callingConvention, SyntaxFactory.FunctionPointerParameterList(lessThanToken, types, greaterThanToken));
funcPointer = CheckFeatureAvailability(funcPointer, MessageID.IDS_FeatureFunctionPointers);
return funcPointer;
}
......@@ -6969,76 +7013,96 @@ private FunctionPointerTypeSyntax ParseFunctionPointerTypeSyntax()
_pool.Free(types);
}
PostSkipAction skipBadFunctionPointerParameterListTokens()
PostSkipAction skipBadFunctionPointerTokens<T>(SeparatedSyntaxListBuilder<T> list) where T : CSharpSyntaxNode
{
CSharpSyntaxNode? tmp = null;
Debug.Assert(types.Count > 0);
Debug.Assert(list.Count > 0);
return SkipBadSeparatedListTokensWithExpectedKind(ref tmp,
types,
list,
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))
FunctionPointerCallingConventionSyntax? parseCallingConvention()
{
return false;
}
if (CurrentToken.Kind == SyntaxKind.IdentifierToken)
{
SyntaxToken managedSpecifier;
SyntaxToken peek1 = PeekToken(1);
switch (CurrentToken)
{
case { ContextualKind: SyntaxKind.ManagedKeyword }:
case { ContextualKind: SyntaxKind.UnmanagedKeyword }:
managedSpecifier = EatContextualToken(CurrentToken.ContextualKind);
break;
// 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.
if (FunctionPointerTypeSymbol.GetCallingConvention(CurrentToken.Text).IsValid)
{
return true;
}
case var _ when IsPossibleFunctionPointerParameterListStart(peek1):
// If there's a possible parameter list next, treat this as a bad identifier that should have been managed or unmanaged
managedSpecifier = EatTokenAsKind(SyntaxKind.ManagedKeyword);
break;
// 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;
}
case var _ when peek1.Kind == SyntaxKind.OpenBracketToken:
// If there's an open brace next, treat this as a bad identifier that should have been unmanaged
managedSpecifier = EatTokenAsKind(SyntaxKind.UnmanagedKeyword);
break;
// 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;
}
default:
// Whatever is next, it's probably not a calling convention or a function pointer type.
// Bail out
return null;
}
// 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));
FunctionPointerUnmanagedCallingConventionListSyntax? unmanagedCallingConventions = null;
if (CurrentToken.Kind == SyntaxKind.OpenBracketToken)
{
var openBracket = EatToken(SyntaxKind.OpenBracketToken);
var callingConventionModifiers = _pool.AllocateSeparated<FunctionPointerUnmanagedCallingConventionSyntax>();
var saveTerm = _termState;
_termState |= TerminatorState.IsEndOfFunctionPointerCallingConvention;
try
{
while (true)
{
callingConventionModifiers.Add(SyntaxFactory.FunctionPointerUnmanagedCallingConvention(EatToken(SyntaxKind.IdentifierToken)));
if (skipBadFunctionPointerTokens(callingConventionModifiers) == PostSkipAction.Abort)
{
break;
}
Debug.Assert(CurrentToken.Kind == SyntaxKind.CommaToken);
callingConventionModifiers.AddSeparator(EatToken(SyntaxKind.CommaToken));
}
var closeBracket = EatToken(SyntaxKind.CloseBracketToken);
unmanagedCallingConventions = SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(openBracket, callingConventionModifiers, closeBracket);
}
finally
{
_termState = saveTerm;
_pool.Free(callingConventionModifiers);
}
}
if (managedSpecifier.Kind == SyntaxKind.ManagedKeyword && unmanagedCallingConventions != null)
{
// 'managed' calling convention cannot be combined with unmanaged calling convention specifiers.
unmanagedCallingConventions = AddError(unmanagedCallingConventions, ErrorCode.ERR_CannotSpecifyManagedWithUnmanagedSpecifiers);
}
return SyntaxFactory.FunctionPointerCallingConvention(managedSpecifier, unmanagedCallingConventions);
}
return null;
}
}
private bool IsFunctionPointerStart()
=> CurrentToken.Kind == SyntaxKind.DelegateKeyword && PeekToken(1).Kind == SyntaxKind.AsteriskToken;
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.
......
......@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
......@@ -273,36 +274,7 @@ public override void VisitMethod(IMethodSymbol symbol)
}
else if (symbol.MethodKind == MethodKind.FunctionPointerSignature)
{
AddKeyword(SyntaxKind.DelegateKeyword);
AddPunctuation(SyntaxKind.AsteriskToken);
// Expose calling convention here when there is a public API: https://github.com/dotnet/roslyn/issues/39865
AddPunctuation(SyntaxKind.LessThanToken);
foreach (var param in symbol.Parameters)
{
param.Accept(this.NotFirstVisitor);
AddPunctuation(SyntaxKind.CommaToken);
AddSpace();
}
if (symbol.ReturnsByRef)
{
AddRefIfRequired();
}
else if (symbol.ReturnsByRefReadonly)
{
AddRefReadonlyIfRequired();
}
AddCustomModifiersIfRequired(symbol.RefCustomModifiers);
symbol.ReturnType.Accept(this.NotFirstVisitor);
AddCustomModifiersIfRequired(symbol.ReturnTypeCustomModifiers, leadingSpace: true, trailingSpace: false);
AddPunctuation(SyntaxKind.GreaterThanToken);
visitFunctionPointerSignature(symbol);
return;
}
......@@ -575,6 +547,93 @@ public override void VisitMethod(IMethodSymbol symbol)
AddParameters(symbol);
AddTypeParameterConstraints(symbol);
}
void visitFunctionPointerSignature(IMethodSymbol symbol)
{
AddKeyword(SyntaxKind.DelegateKeyword);
AddPunctuation(SyntaxKind.AsteriskToken);
if (symbol.CallingConvention != SignatureCallingConvention.Default)
{
AddSpace();
AddKeyword(SyntaxKind.UnmanagedKeyword);
var conventionTypes = symbol.CallingConventionTypes;
if (symbol.CallingConvention != SignatureCallingConvention.Unmanaged || !conventionTypes.IsEmpty)
{
AddPunctuation(SyntaxKind.OpenBracketToken);
switch (symbol.CallingConvention)
{
case SignatureCallingConvention.CDecl:
builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Cdecl"));
break;
case SignatureCallingConvention.StdCall:
builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Stdcall"));
break;
case SignatureCallingConvention.ThisCall:
builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Thiscall"));
break;
case SignatureCallingConvention.FastCall:
builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Fastcall"));
break;
case SignatureCallingConvention.Unmanaged:
Debug.Assert(!conventionTypes.IsDefaultOrEmpty);
bool isFirst = true;
foreach (var conventionType in conventionTypes)
{
if (!isFirst)
{
AddPunctuation(SyntaxKind.CommaToken);
AddSpace();
}
isFirst = false;
Debug.Assert(conventionType.Name.StartsWith("CallConv"));
const int CallConvLength = 8;
builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, conventionType, conventionType.Name[CallConvLength..]));
}
break;
}
AddPunctuation(SyntaxKind.CloseBracketToken);
}
}
else if (format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.UseExplicitManagedCallingConventionSpecifier))
{
AddSpace();
AddKeyword(SyntaxKind.ManagedKeyword);
}
AddPunctuation(SyntaxKind.LessThanToken);
foreach (var param in symbol.Parameters)
{
param.Accept(this.NotFirstVisitor);
AddPunctuation(SyntaxKind.CommaToken);
AddSpace();
}
if (symbol.ReturnsByRef)
{
AddRefIfRequired();
}
else if (symbol.ReturnsByRefReadonly)
{
AddRefReadonlyIfRequired();
}
AddCustomModifiersIfRequired(symbol.RefCustomModifiers);
symbol.ReturnType.Accept(this.NotFirstVisitor);
AddCustomModifiersIfRequired(symbol.ReturnTypeCustomModifiers, leadingSpace: true, trailingSpace: false);
AddPunctuation(SyntaxKind.GreaterThanToken);
}
}
private static SymbolDisplayPartKind GetPartKindForConstructorOrDestructor(IMethodSymbol symbol)
......
......@@ -424,9 +424,18 @@ internal virtual NamedTypeSymbol GetNativeIntegerType(NamedTypeSymbol underlying
/// </summary>
internal bool RuntimeSupportsDefaultInterfaceImplementation
{
get => !(GetSpecialTypeMember(SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__DefaultImplementationsOfInterfaces) is null);
get => GetSpecialTypeMember(SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__DefaultImplementationsOfInterfaces) is object;
}
// https://github.com/dotnet/roslyn/issues/46676: Remove when we have a runtime that supports this to test with
private bool _overrideRuntimeSupportUnmanagedSignatureCallingConvention;
internal void SetOverrideRuntimeSupportsUnmanagedSignatureCallingConvention()
=> _overrideRuntimeSupportUnmanagedSignatureCallingConvention = true;
internal bool RuntimeSupportsUnmanagedSignatureCallingConvention
=> GetSpecialTypeMember(SpecialMember.System_Runtime_CompilerServices_RuntimeFeature__UnmanagedSignatureCallingConvention) is object
|| _overrideRuntimeSupportUnmanagedSignatureCallingConvention;
/// <summary>
/// True if the target runtime support covariant returns of methods declared in classes.
/// </summary>
......
......@@ -25,16 +25,33 @@ public static FunctionPointerTypeSymbol CreateFromSource(FunctionPointerTypeSynt
basesBeingResolved,
suppressUseSiteDiagnostics));
/// <summary>
/// Creates a function pointer from individual parts. This method should only be used when diagnostics are not needed. This is
/// intended for use in test code.
/// </summary>
public static FunctionPointerTypeSymbol CreateFromPartsForTests(
CallingConvention callingConvention,
TypeWithAnnotations returnType,
ImmutableArray<CustomModifier> refCustomModifiers,
RefKind returnRefKind,
ImmutableArray<TypeWithAnnotations> parameterTypes,
ImmutableArray<ImmutableArray<CustomModifier>> parameterRefCustomModifiers,
ImmutableArray<RefKind> parameterRefKinds,
CSharpCompilation compilation)
=> new FunctionPointerTypeSymbol(FunctionPointerMethodSymbol.CreateFromPartsForTest(callingConvention, returnType, refCustomModifiers, returnRefKind, parameterTypes, parameterRefCustomModifiers, parameterRefKinds, compilation));
/// <summary>
/// Creates a function pointer from individual parts. This method should only be used when diagnostics are not needed.
/// </summary>
public static FunctionPointerTypeSymbol CreateFromParts(
CallingConvention callingConvention,
ImmutableArray<CustomModifier> callingConventionModifiers,
TypeWithAnnotations returnType,
RefKind returnRefKind,
ImmutableArray<TypeWithAnnotations> parameterTypes,
ImmutableArray<RefKind> parameterRefKinds,
CSharpCompilation compilation)
=> new FunctionPointerTypeSymbol(FunctionPointerMethodSymbol.CreateFromParts(returnType, returnRefKind, parameterTypes, parameterRefKinds, compilation));
=> new FunctionPointerTypeSymbol(FunctionPointerMethodSymbol.CreateFromParts(callingConvention, callingConventionModifiers, returnType, returnRefKind, parameterTypes, parameterRefKinds, compilation));
public static FunctionPointerTypeSymbol CreateFromMetadata(Cci.CallingConvention callingConvention, ImmutableArray<ParamInfo<TypeSymbol>> retAndParamTypes)
=> new FunctionPointerTypeSymbol(
......@@ -47,17 +64,6 @@ public static FunctionPointerTypeSymbol CreateFromMetadata(Cci.CallingConvention
ImmutableArray<ImmutableArray<CustomModifier>> paramRefCustomModifiers)
=> new FunctionPointerTypeSymbol(Signature.SubstituteParameterSymbols(substitutedReturnType, substitutedParameterTypes, refCustomModifiers, paramRefCustomModifiers));
public static (CallingConvention Convention, bool IsValid) GetCallingConvention(string convention) =>
convention switch
{
"" => (CallingConvention.Default, true),
"cdecl" => (CallingConvention.CDecl, true),
"managed" => (CallingConvention.Default, true),
"thiscall" => (CallingConvention.ThisCall, true),
"stdcall" => (CallingConvention.Standard, true),
_ => (CallingConvention.Default, false),
};
private FunctionPointerTypeSymbol(FunctionPointerMethodSymbol signature)
{
Signature = signature;
......@@ -194,5 +200,31 @@ internal static bool RefKindEquals(TypeCompareKind compareKind, RefKind refKind1
/// </summary>
internal static RefKind GetRefKindForHashCode(RefKind refKind)
=> refKind == RefKind.None ? RefKind.None : RefKind.Ref;
/// <summary>
/// Return true if the given type is valid as a calling convention modifier type.
/// </summary>
internal static bool IsCallingConventionModifier(NamedTypeSymbol modifierType)
{
return (object)modifierType.ContainingAssembly == modifierType.ContainingAssembly.CorLibrary
&& modifierType.Arity == 0
&& modifierType.Name != "CallConv"
&& modifierType.Name.StartsWith("CallConv", StringComparison.Ordinal)
#pragma warning disable IDE0055 // Formatting wants to put the braces at the beginning of the line https://github.com/dotnet/roslyn/issues/46284
&& modifierType.ContainingNamespace is
{
Name: "CompilerServices",
ContainingNamespace:
{
Name: "Runtime",
ContainingNamespace:
{
Name: "System",
ContainingNamespace: { IsGlobalNamespace: true }
}
}
};
#pragma warning restore IDE0055
}
}
}
......@@ -886,6 +886,8 @@ internal ImmutableArray<RefKind> ParameterRefKinds
get;
}
internal virtual ImmutableArray<NamedTypeSymbol> CallingConventionTypes => ImmutableArray<NamedTypeSymbol>.Empty;
/// <summary>
/// Returns the map from type parameters to type arguments.
/// If this is not a generic method instantiation, returns null.
......
......@@ -4,7 +4,9 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Threading;
using Microsoft.Cci;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols.PublicModel
......@@ -263,6 +265,10 @@ ImmutableArray<AttributeData> IMethodSymbol.GetReturnTypeAttributes()
return _underlying.GetReturnTypeAttributes().Cast<CSharpAttributeData, AttributeData>();
}
SignatureCallingConvention IMethodSymbol.CallingConvention => _underlying.CallingConvention.ToSignatureConvention();
ImmutableArray<INamedTypeSymbol> IMethodSymbol.CallingConventionTypes => _underlying.CallingConventionTypes.SelectAsArray(t => t.GetPublicSymbol());
IMethodSymbol IMethodSymbol.Construct(params ITypeSymbol[] typeArguments)
{
return _underlying.Construct(ConstructTypeArguments(typeArguments)).GetPublicSymbol();
......
......@@ -24,7 +24,7 @@ internal static class ParameterHelpers
bool allowThis,
bool addRefReadOnlyModifier)
{
return MakeParameters<ParameterSymbol, Symbol>(
return MakeParameters<ParameterSyntax, ParameterSymbol, Symbol>(
binder,
owner,
syntax.Parameters,
......@@ -59,11 +59,11 @@ internal static class ParameterHelpers
public static ImmutableArray<FunctionPointerParameterSymbol> MakeFunctionPointerParameters(
Binder binder,
FunctionPointerMethodSymbol owner,
SeparatedSyntaxList<ParameterSyntax> parametersList,
SeparatedSyntaxList<FunctionPointerParameterSyntax> parametersList,
DiagnosticBag diagnostics,
bool suppressUseSiteDiagnostics)
{
return MakeParameters(
return MakeParameters<FunctionPointerParameterSyntax, FunctionPointerParameterSymbol, FunctionPointerMethodSymbol>(
binder,
owner,
parametersList,
......@@ -75,7 +75,7 @@ internal static class ParameterHelpers
suppressUseSiteDiagnostics,
parametersList.Count - 2,
parameterCreationFunc: (Binder binder, FunctionPointerMethodSymbol owner, TypeWithAnnotations parameterType,
ParameterSyntax syntax, RefKind refKind, int ordinal,
FunctionPointerParameterSyntax syntax, RefKind refKind, int ordinal,
SyntaxToken paramsKeyword, SyntaxToken thisKeyword, bool addRefReadOnlyModifier,
DiagnosticBag diagnostics) =>
{
......@@ -104,10 +104,10 @@ internal static class ParameterHelpers
parsingFunctionPointer: true);
}
private static ImmutableArray<TParameterSymbol> MakeParameters<TParameterSymbol, TOwningSymbol>(
private static ImmutableArray<TParameterSymbol> MakeParameters<TParameterSyntax, TParameterSymbol, TOwningSymbol>(
Binder binder,
TOwningSymbol owner,
SeparatedSyntaxList<ParameterSyntax> parametersList,
SeparatedSyntaxList<TParameterSyntax> parametersList,
out SyntaxToken arglistToken,
DiagnosticBag diagnostics,
bool allowRefOrOut,
......@@ -115,8 +115,9 @@ internal static class ParameterHelpers
bool addRefReadOnlyModifier,
bool suppressUseSiteDiagnostics,
int lastIndex,
Func<Binder, TOwningSymbol, TypeWithAnnotations, ParameterSyntax, RefKind, int, SyntaxToken, SyntaxToken, bool, DiagnosticBag, TParameterSymbol> parameterCreationFunc,
Func<Binder, TOwningSymbol, TypeWithAnnotations, TParameterSyntax, RefKind, int, SyntaxToken, SyntaxToken, bool, DiagnosticBag, TParameterSymbol> parameterCreationFunc,
bool parsingFunctionPointer = false)
where TParameterSyntax : BaseParameterSyntax
where TParameterSymbol : ParameterSymbol
where TOwningSymbol : Symbol
{
......@@ -133,15 +134,6 @@ internal static class ParameterHelpers
{
if (parameterIndex > lastIndex) break;
if (mustBeLastParameter == null)
{
if (parameterSyntax.Modifiers.Any(SyntaxKind.ParamsKeyword) ||
parameterSyntax.Identifier.Kind() == SyntaxKind.ArgListKeyword)
{
mustBeLastParameter = parameterSyntax;
}
}
CheckParameterModifiers(parameterSyntax, diagnostics, parsingFunctionPointer);
var refKind = GetModifiers(parameterSyntax.Modifiers, out SyntaxToken refnessKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword);
......@@ -150,25 +142,35 @@ internal static class ParameterHelpers
diagnostics.Add(ErrorCode.ERR_ThisInBadContext, thisKeyword.GetLocation());
}
if (parameterSyntax.IsArgList)
if (parameterSyntax is ParameterSyntax concreteParam)
{
arglistToken = parameterSyntax.Identifier;
// The native compiler produces "Expected type" here, in the parser. Roslyn produces
// the somewhat more informative "arglist not valid" error.
if (paramsKeyword.Kind() != SyntaxKind.None
|| refnessKeyword.Kind() != SyntaxKind.None
|| thisKeyword.Kind() != SyntaxKind.None)
if (mustBeLastParameter == null &&
(concreteParam.Modifiers.Any(SyntaxKind.ParamsKeyword) ||
concreteParam.Identifier.Kind() == SyntaxKind.ArgListKeyword))
{
// CS1669: __arglist is not valid in this context
diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation());
mustBeLastParameter = concreteParam;
}
continue;
}
if (concreteParam.IsArgList)
{
arglistToken = concreteParam.Identifier;
// The native compiler produces "Expected type" here, in the parser. Roslyn produces
// the somewhat more informative "arglist not valid" error.
if (paramsKeyword.Kind() != SyntaxKind.None
|| refnessKeyword.Kind() != SyntaxKind.None
|| thisKeyword.Kind() != SyntaxKind.None)
{
// CS1669: __arglist is not valid in this context
diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation());
}
if (parameterSyntax.Default != null && firstDefault == -1)
{
firstDefault = parameterIndex;
continue;
}
if (concreteParam.Default != null && firstDefault == -1)
{
firstDefault = parameterIndex;
}
}
Debug.Assert(parameterSyntax.Type != null);
......@@ -277,8 +279,7 @@ internal static void EnsureNullableAttributeExists(CSharpCompilation compilation
private static Location GetParameterLocation(ParameterSymbol parameter) => parameter.GetNonNullSyntaxNode().Location;
private static void CheckParameterModifiers(
ParameterSyntax parameter, DiagnosticBag diagnostics, bool parsingFunctionPointerParams)
private static void CheckParameterModifiers(BaseParameterSyntax parameter, DiagnosticBag diagnostics, bool parsingFunctionPointerParams)
{
var seenThis = false;
var seenRef = false;
......@@ -422,7 +423,7 @@ internal static void EnsureNullableAttributeExists(CSharpCompilation compilation
private static void ReportParameterErrors(
Symbol owner,
ParameterSyntax parameterSyntax,
BaseParameterSyntax parameterSyntax,
ParameterSymbol parameter,
SyntaxToken thisKeyword,
SyntaxToken paramsKeyword,
......@@ -430,7 +431,7 @@ internal static void EnsureNullableAttributeExists(CSharpCompilation compilation
DiagnosticBag diagnostics)
{
int parameterIndex = parameter.Ordinal;
bool isDefault = parameterSyntax.Default != null;
bool isDefault = parameterSyntax is ParameterSyntax { Default: { } };
if (thisKeyword.Kind() == SyntaxKind.ThisKeyword && parameterIndex != 0)
{
......@@ -458,7 +459,7 @@ internal static void EnsureNullableAttributeExists(CSharpCompilation compilation
else if (firstDefault != -1 && parameterIndex > firstDefault && !isDefault && !parameter.IsParams)
{
// error CS1737: Optional parameters must appear after all required parameters
Location loc = parameterSyntax.Identifier.GetNextToken(includeZeroWidth: true).GetLocation(); //could be missing
Location loc = ((ParameterSyntax)(BaseParameterSyntax)parameterSyntax).Identifier.GetNextToken(includeZeroWidth: true).GetLocation(); //could be missing
diagnostics.Add(ErrorCode.ERR_DefaultValueBeforeRequiredValue, loc);
}
else if (parameter.RefKind != RefKind.None &&
......
......@@ -1573,7 +1573,7 @@ private void CheckMemberNameConflicts(DiagnosticBag diagnostics)
// following a field of the same name, or a field and a nested type of the same name.
//
if ((object?)lastSym != null)
if (lastSym is object)
{
if (symbol.Kind != SymbolKind.Method || lastSym.Kind != SymbolKind.Method)
{
......
......@@ -237,18 +237,29 @@
<summary>SyntaxToken representing the asterisk.</summary>
</PropertyComment>
</Field>
<Field Name="CallingConvention" Type="SyntaxToken" Optional="true">
<Field Name="CallingConvention" Type="FunctionPointerCallingConventionSyntax" Optional="true">
<PropertyComment>
<summary>SyntaxToken representing the optional calling convention.</summary>
<summary>Node representing the optional calling convention.</summary>
</PropertyComment>
</Field>
<Field Name="ParameterList" Type="FunctionPointerParameterListSyntax">
<PropertyComment>
<summary>List of the parameter types and return type of the function pointer.</summary>
</PropertyComment>
</Field>
</Node>
<Node Name="FunctionPointerParameterListSyntax" Base="CSharpSyntaxNode">
<TypeComment>
<summary>Function pointer parameter list syntax.</summary>
</TypeComment>
<Kind Name="FunctionPointerParameterList"/>
<Field Name="LessThanToken" Type="SyntaxToken">
<Kind Name="LessThanToken"/>
<PropertyComment>
<summary>SyntaxToken representing the less than token.</summary>
</PropertyComment>
</Field>
<Field Name="Parameters" Type="SeparatedSyntaxList&lt;ParameterSyntax&gt;" MinCount="1">
<Field Name="Parameters" Type="SeparatedSyntaxList&lt;FunctionPointerParameterSyntax&gt;" MinCount="1">
<PropertyComment>
<summary>SeparatedSyntaxList of ParameterSyntaxes representing the list of parameters and return type.</summary>
</PropertyComment>
......@@ -260,6 +271,59 @@
</PropertyComment>
</Field>
</Node>
<Node Name="FunctionPointerCallingConventionSyntax" Base="CSharpSyntaxNode">
<TypeComment>
<summary>Function pointer calling convention syntax.</summary>
</TypeComment>
<Kind Name="FunctionPointerCallingConvention"/>
<Field Name="ManagedOrUnmanagedKeyword" Type="SyntaxToken">
<Kind Name="ManagedKeyword"/>
<Kind Name="UnmanagedKeyword"/>
<PropertyComment>
<summary>SyntaxToken representing whether the calling convention is managed or unmanaged.</summary>
</PropertyComment>
</Field>
<Field Name="UnmanagedCallingConventionList" Type="FunctionPointerUnmanagedCallingConventionListSyntax" Optional="true">
<PropertyComment>
<summary>Optional list of identifiers that will contribute to an unmanaged calling convention.</summary>
</PropertyComment>
</Field>
</Node>
<Node Name="FunctionPointerUnmanagedCallingConventionListSyntax" Base="CSharpSyntaxNode">
<TypeComment>
<summary>Function pointer calling convention syntax.</summary>
</TypeComment>
<Kind Name="FunctionPointerUnmanagedCallingConventionList"/>
<Field Name="OpenBracketToken" Type="SyntaxToken">
<Kind Name="OpenBracketToken"/>
<PropertyComment>
<summary>SyntaxToken representing open bracket.</summary>
</PropertyComment>
</Field>
<Field Name="CallingConventions" Type="SeparatedSyntaxList&lt;FunctionPointerUnmanagedCallingConventionSyntax&gt;" MinCount="1">
<PropertyComment>
<summary>SeparatedSyntaxList of calling convention identifiers.</summary>
</PropertyComment>
</Field>
<Field Name="CloseBracketToken" Type="SyntaxToken">
<Kind Name="CloseBracketToken"/>
<PropertyComment>
<summary>SyntaxToken representing close bracket.</summary>
</PropertyComment>
</Field>
</Node>
<Node Name="FunctionPointerUnmanagedCallingConventionSyntax" Base="CSharpSyntaxNode">
<TypeComment>
<summary>Individual function pointer unmanaged calling convention.</summary>
</TypeComment>
<Kind Name="FunctionPointerUnmanagedCallingConvention"/>
<Field Name="Name" Type="SyntaxToken">
<Kind Name="IdentifierToken"/>
<PropertyComment>
<summary>SyntaxToken representing the calling convention identifier.</summary>
</PropertyComment>
</Field>
</Node>
<Node Name="NullableTypeSyntax" Base="TypeSyntax">
<Kind Name="NullableType"/>
<Field Name="ElementType" Type="TypeSyntax">
......@@ -4019,11 +4083,10 @@
<Kind Name="CloseBracketToken"/>
</Field>
</Node>
<Node Name="ParameterSyntax" Base="CSharpSyntaxNode">
<AbstractNode Name="BaseParameterSyntax" Base="CSharpSyntaxNode">
<TypeComment>
<summary>Parameter syntax.</summary>
<summary>Base parameter syntax.</summary>
</TypeComment>
<Kind Name="Parameter"/>
<Field Name="AttributeLists" Type="SyntaxList&lt;AttributeListSyntax&gt;">
<PropertyComment>
<summary>Gets the attribute declaration list.</summary>
......@@ -4035,6 +4098,23 @@
</PropertyComment>
</Field>
<Field Name="Type" Type="TypeSyntax" Optional="true"/>
</AbstractNode>
<Node Name="ParameterSyntax" Base="BaseParameterSyntax">
<TypeComment>
<summary>Parameter syntax.</summary>
</TypeComment>
<Kind Name="Parameter"/>
<Field Name="AttributeLists" Type="SyntaxList&lt;AttributeListSyntax&gt;" Override="true">
<PropertyComment>
<summary>Gets the attribute declaration list.</summary>
</PropertyComment>
</Field>
<Field Name="Modifiers" Type="SyntaxList&lt;SyntaxToken&gt;" Override="true">
<PropertyComment>
<summary>Gets the modifier list.</summary>
</PropertyComment>
</Field>
<Field Name="Type" Type="TypeSyntax" Optional="true" Override="true"/>
<Field Name="Identifier" Type="SyntaxToken">
<PropertyComment>
<summary>Gets the identifier.</summary>
......@@ -4044,6 +4124,23 @@
</Field>
<Field Name="Default" Type="EqualsValueClauseSyntax" Optional="true"/>
</Node>
<Node Name="FunctionPointerParameterSyntax" Base="BaseParameterSyntax">
<TypeComment>
<summary>Parameter syntax.</summary>
</TypeComment>
<Kind Name="FunctionPointerParameter"/>
<Field Name="AttributeLists" Type="SyntaxList&lt;AttributeListSyntax&gt;" Override="true">
<PropertyComment>
<summary>Gets the attribute declaration list.</summary>
</PropertyComment>
</Field>
<Field Name="Modifiers" Type="SyntaxList&lt;SyntaxToken&gt;" Override="true">
<PropertyComment>
<summary>Gets the modifier list.</summary>
</PropertyComment>
</Field>
<Field Name="Type" Type="TypeSyntax" Optional="false" Override="true"/>
</Node>
<Node Name="IncompleteMemberSyntax" Base="MemberDeclarationSyntax">
<Kind Name="IncompleteMember"/>n
<Field Name="AttributeLists" Type="SyntaxList&lt;AttributeListSyntax&gt;" Override="true"/>
......
......@@ -440,9 +440,9 @@ internal static void VisitRankSpecifiers<TArg>(this TypeSyntax type, Action<Arra
break;
case SyntaxKind.FunctionPointerType:
var functionPointerTypeSyntax = (FunctionPointerTypeSyntax)type;
for (int i = functionPointerTypeSyntax.Parameters.Count - 1; i >= 0; i--)
for (int i = functionPointerTypeSyntax.ParameterList.Parameters.Count - 1; i >= 0; i--)
{
TypeSyntax? paramType = functionPointerTypeSyntax.Parameters[i].Type;
TypeSyntax? paramType = functionPointerTypeSyntax.ParameterList.Parameters[i].Type;
Debug.Assert(paramType is object);
stack.Push(paramType);
}
......
......@@ -154,7 +154,8 @@ public static bool IsInTypeOnlyContext(ExpressionSyntax node)
return ((RefTypeSyntax)parent).Type == node;
case Parameter:
return ((ParameterSyntax)parent).Type == node;
case FunctionPointerParameter:
return ((BaseParameterSyntax)parent).Type == node;
case TypeConstraint:
return ((TypeConstraintSyntax)parent).Type == node;
......
......@@ -205,11 +205,14 @@ public enum SyntaxKind : ushort
WithKeyword = 8442,
InitKeyword = 8443,
RecordKeyword = 8444,
ManagedKeyword = 8445,
UnmanagedKeyword = 8446,
/// when adding a contextual keyword following functions must be adapted:
/// <see cref="SyntaxFacts.GetContextualKeywordKinds"/>
/// <see cref="SyntaxFacts.IsContextualKeyword(SyntaxKind)"/>
/// <see cref="SyntaxFacts.GetContextualKeywordKind(string)"/>
/// <see cref="SyntaxFacts.GetText(SyntaxKind)"/>
// keywords with an enum value less than ElifKeyword are considered i.a. contextual keywords
// additional preprocessor keywords
......@@ -615,8 +618,11 @@ public enum SyntaxKind : ushort
ImplicitStackAllocArrayCreationExpression = 9053,
SuppressNullableWarningExpression = 9054,
NullableDirectiveTrivia = 9055,
FunctionPointerType = 9056,
DefaultConstraint = 9057,
FunctionPointerParameter = 9057,
FunctionPointerParameterList = 9058,
FunctionPointerCallingConvention = 9059,
InitAccessorDeclaration = 9060,
......@@ -624,6 +630,11 @@ public enum SyntaxKind : ushort
WithInitializerExpression = 9062,
RecordDeclaration = 9063,
DefaultConstraint = 9064,
PrimaryConstructorBaseType = 9065,
FunctionPointerUnmanagedCallingConventionList = 9066,
FunctionPointerUnmanagedCallingConvention = 9067,
}
}
......@@ -1073,7 +1073,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)
public static IEnumerable<SyntaxKind> GetContextualKeywordKinds()
{
for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.InitKeyword; i++)
for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.UnmanagedKeyword; i++)
{
yield return (SyntaxKind)i;
}
......@@ -1125,6 +1125,8 @@ public static bool IsContextualKeyword(SyntaxKind kind)
case SyntaxKind.WithKeyword:
case SyntaxKind.InitKeyword:
case SyntaxKind.RecordKeyword:
case SyntaxKind.ManagedKeyword:
case SyntaxKind.UnmanagedKeyword:
return true;
default:
return false;
......@@ -1242,6 +1244,10 @@ public static SyntaxKind GetContextualKeywordKind(string text)
return SyntaxKind.InitKeyword;
case "record":
return SyntaxKind.RecordKeyword;
case "managed":
return SyntaxKind.ManagedKeyword;
case "unmanaged":
return SyntaxKind.UnmanagedKeyword;
default:
return SyntaxKind.None;
}
......@@ -1675,6 +1681,10 @@ public static string GetText(SyntaxKind kind)
return "init";
case SyntaxKind.RecordKeyword:
return "record";
case SyntaxKind.ManagedKeyword:
return "managed";
case SyntaxKind.UnmanagedKeyword:
return "unmanaged";
default:
return string.Empty;
}
......
......@@ -31,7 +31,6 @@ public void DiagnosticAnalyzerAllInOne()
// https://github.com/dotnet/roslyn/issues/44682 Add to all in one
missingSyntaxKinds.Add(SyntaxKind.WithExpression);
missingSyntaxKinds.Add(SyntaxKind.RecordDeclaration);
missingSyntaxKinds.Add(SyntaxKind.FunctionPointerType);
var analyzer = new CSharpTrackingDiagnosticAnalyzer();
var options = new AnalyzerOptions(new[] { new TestAdditionalText() }.ToImmutableArray<AdditionalText>());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册