PR Feedback:

* Scope public API for calling convention types to just be for function pointer signatures.
* Scope public API for calling convention to reflect metadata always.
* Some code cleanup.
上级 f3028634
......@@ -3304,7 +3304,7 @@ protected override IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol
throw new ArgumentException(string.Format(CSharpResources.CallingConventionTypesRequireUnmanaged, nameof(callingConventionTypes), nameof(callingConvention)));
}
if (!callingConvention.IsValid() || callingConvention == SignatureCallingConvention.VarArgs)
if (!callingConvention.IsValid())
{
throw new ArgumentOutOfRangeException(nameof(callingConvention));
}
......@@ -3314,11 +3314,11 @@ protected override IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol
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) => getCustomModifierForType(type, i))
? callingConventionTypes.SelectAsArray((type, i, @this) => getCustomModifierForType(type, @this, i), this)
: ImmutableArray<CustomModifier>.Empty;
return FunctionPointerTypeSymbol.CreateFromParts(
callingConvention.FromSignatureConvention(),
internalCallingConvention,
conventionModifiers,
returnTypeWithAnnotations,
returnRefKind: returnRefKind,
......@@ -3326,10 +3326,15 @@ protected override IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol
parameterRefKinds: parameterRefKinds,
compilation: this).GetPublicSymbol();
static CustomModifier getCustomModifierForType(INamedTypeSymbol type, int index)
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))
if (!FunctionPointerTypeSymbol.IsCallingConventionModifier(internalType) || @this.Assembly.CorLibrary != internalType.ContainingAssembly.CorLibrary)
{
throw new ArgumentException(string.Format(CSharpResources.CallingConventionTypeIsInvalid, type.ToDisplayString()));
}
......
......@@ -240,8 +240,9 @@ static void checkUnmanagedSupport(CSharpCompilation compilation, Location errorL
/// <summary>
/// Creates a function pointer method symbol from individual parts. This method should only be used when diagnostics are not needed.
/// This should only be used from testing code.
/// </summary>
internal static FunctionPointerMethodSymbol CreateFromParts(
internal static FunctionPointerMethodSymbol CreateFromPartsForTest(
CallingConvention callingConvention,
TypeWithAnnotations returnType,
ImmutableArray<CustomModifier> refCustomModifiers,
......@@ -282,13 +283,7 @@ static void checkUnmanagedSupport(CSharpCompilation compilation, Location errorL
modifiersBuilder.AddRange(callingConventionModifiers);
}
if (GetCustomModifierForRefKind(returnRefKind, compilation) is CustomModifier modifier)
{
modifiersBuilder.Add(modifier);
}
ImmutableArray<CustomModifier> refCustomModifiers;
if (returnRefKind == RefKind.None)
{
refCustomModifiers = ImmutableArray<CustomModifier>.Empty;
......@@ -296,14 +291,18 @@ static void checkUnmanagedSupport(CSharpCompilation compilation, Location errorL
}
else
{
if (GetCustomModifierForRefKind(returnRefKind, compilation) is CustomModifier modifier)
{
modifiersBuilder.Add(modifier);
}
refCustomModifiers = modifiersBuilder.ToImmutableAndFree();
}
return CreateFromParts(
return new FunctionPointerMethodSymbol(
callingConvention,
returnRefKind,
returnTypeWithAnnotations,
refCustomModifiers,
returnRefKind,
parameterTypes,
parameterRefCustomModifiers: default,
parameterRefKinds,
......
......@@ -29,7 +29,7 @@ public static FunctionPointerTypeSymbol CreateFromSource(FunctionPointerTypeSynt
/// 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 CreateFromParts(
public static FunctionPointerTypeSymbol CreateFromPartsForTests(
CallingConvention callingConvention,
TypeWithAnnotations returnType,
ImmutableArray<CustomModifier> refCustomModifiers,
......@@ -38,7 +38,7 @@ public static FunctionPointerTypeSymbol CreateFromSource(FunctionPointerTypeSynt
ImmutableArray<ImmutableArray<CustomModifier>> parameterRefCustomModifiers,
ImmutableArray<RefKind> parameterRefKinds,
CSharpCompilation compilation)
=> new FunctionPointerTypeSymbol(FunctionPointerMethodSymbol.CreateFromParts(callingConvention, returnType, refCustomModifiers, returnRefKind, parameterTypes, parameterRefCustomModifiers, parameterRefKinds, 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.
......
......@@ -7715,20 +7715,20 @@ void M()
var @string = comp1.GetSpecialType(SpecialType.System_String);
var testMod = CSharpCustomModifier.CreateOptional(comp1.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvTest`1"));
var funcPtr = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtr = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string), refCustomModifiers: default,
returnRefKind: RefKind.None, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
parameterRefCustomModifiers: default, compilation: comp1);
var funcPtrRef = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtrRef = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string), refCustomModifiers: default,
parameterRefCustomModifiers: default, returnRefKind: RefKind.Ref, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
compilation: comp1);
var funcPtrWithTestOnReturn = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtrWithTestOnReturn = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string, customModifiers: ImmutableArray.Create(testMod)), refCustomModifiers: default,
parameterRefCustomModifiers: default, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
compilation: comp1);
var funcPtrWithTestOnRef = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtrWithTestOnRef = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string), refCustomModifiers: ImmutableArray.Create(testMod),
parameterRefCustomModifiers: default, returnRefKind: RefKind.Ref, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
compilation: comp1);
......@@ -7802,20 +7802,20 @@ static void M()
var @string = comp2.GetSpecialType(SpecialType.System_String);
var testMod = CSharpCustomModifier.CreateOptional(comp2.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvTest"));
var funcPtr = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtr = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string), refCustomModifiers: default,
returnRefKind: RefKind.None, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
parameterRefCustomModifiers: default, compilation: comp2);
var funcPtrRef = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtrRef = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string), refCustomModifiers: default,
returnRefKind: RefKind.Ref, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
parameterRefCustomModifiers: default, compilation: comp2);
var funcPtrWithTestOnReturn = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtrWithTestOnReturn = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string, customModifiers: ImmutableArray.Create(testMod)), refCustomModifiers: default,
returnRefKind: RefKind.None, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
parameterRefCustomModifiers: default, compilation: comp2);
var funcPtrWithTestOnRef = FunctionPointerTypeSymbol.CreateFromParts(
var funcPtrWithTestOnRef = FunctionPointerTypeSymbol.CreateFromPartsForTests(
CallingConvention.Unmanaged, TypeWithAnnotations.Create(@string), refCustomModifiers: ImmutableArray.Create(testMod),
returnRefKind: RefKind.Ref, parameterTypes: ImmutableArray<TypeWithAnnotations>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty,
parameterRefCustomModifiers: default, compilation: comp2);
......
......@@ -1535,9 +1535,9 @@ public void PublicApi_CreateInvalidInputs()
Assert.Throws<ArgumentNullException>("parameterTypes", () => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: default, parameterRefKinds: ImmutableArray<RefKind>.Empty));
Assert.Throws<ArgumentNullException>("parameterTypes[0]", () => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray.Create((ITypeSymbol?)null)!, parameterRefKinds: ImmutableArray.Create(RefKind.None)));
Assert.Throws<ArgumentNullException>("parameterRefKinds", () => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: default));
Assert.Throws<ArgumentNullException>("callingConventionTypes[0]", () => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: SignatureCallingConvention.Unmanaged, ImmutableArray.Create((INamedTypeSymbol)null!)));
Assert.Throws<ArgumentException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray.Create(RefKind.None)));
Assert.Throws<ArgumentException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.Out, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty));
Assert.Throws<ArgumentOutOfRangeException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: SignatureCallingConvention.VarArgs));
Assert.Throws<ArgumentOutOfRangeException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: (SignatureCallingConvention)10));
Assert.Throws<ArgumentException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: SignatureCallingConvention.Default, callingConventionTypes: ImmutableArray.Create(cdeclType)!));
Assert.Throws<ArgumentException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: SignatureCallingConvention.StdCall, callingConventionTypes: ImmutableArray.Create(cdeclType)!));
......@@ -1547,6 +1547,17 @@ public void PublicApi_CreateInvalidInputs()
Assert.Throws<ArgumentException>(() => comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: SignatureCallingConvention.Unmanaged, callingConventionTypes: ImmutableArray.Create(@string)!));
}
[Fact]
public void PublicApi_VarargsHasUseSiteDiagnostic()
{
var comp = (Compilation)CreateCompilation("");
var @string = comp.GetSpecialType(SpecialType.System_String);
var ptr = comp.CreateFunctionPointerTypeSymbol(returnType: @string, returnRefKind: RefKind.None, parameterTypes: ImmutableArray<ITypeSymbol>.Empty, parameterRefKinds: ImmutableArray<RefKind>.Empty, callingConvention: SignatureCallingConvention.VarArgs);
Assert.Equal(SignatureCallingConvention.VarArgs, ptr.Signature.CallingConvention);
AssertEx.Equal("error CS8806: The calling convention of 'delegate* unmanaged[]<string>' is not supported by the language.", ptr.EnsureCSharpSymbolOrNull(nameof(ptr)).GetUseSiteDiagnostic().ToString());
}
[Fact]
public void PublicApi_CreateTypeSymbolNoRefKinds()
{
......@@ -1927,6 +1938,43 @@ void M()
Assert.Equal("delegate*<ref System.Void> ptr5", model.GetDeclaredSymbol(decls[4]).ToTestDisplayString());
}
[Fact]
public void PublicApi_NonApplicationCorLibrary()
{
var otherCorLib = CreateEmptyCompilation(@"
namespace System
{
public class Object { }
public abstract class ValueType { }
public struct Void { }
public class String { }
namespace Runtime.CompilerServices
{
internal class CallConvTest {}
public static class RuntimeFeature
{
public const string UnmanagedSignatureCallingConvention = nameof(UnmanagedSignatureCallingConvention);
}
}
}
", options: TestOptions.UnsafeReleaseDll, parseOptions: TestOptions.RegularPreview);
var mainComp = CreateCompilation("", references: new[] { otherCorLib.ToMetadataReference() });
var returnType = mainComp.GetSpecialType(SpecialType.System_String).GetPublicSymbol();
var testConvention = otherCorLib.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvTest");
Assert.NotNull(testConvention);
Assert.True((object)testConvention!.ContainingAssembly.CorLibrary != mainComp.Assembly.CorLibrary);
Assert.True(FunctionPointerTypeSymbol.IsCallingConventionModifier(testConvention));
Assert.Throws<ArgumentException>(() => mainComp.CreateFunctionPointerTypeSymbol(
returnType!,
returnRefKind: RefKind.None,
parameterTypes: ImmutableArray<ITypeSymbol>.Empty,
parameterRefKinds: ImmutableArray<RefKind>.Empty,
callingConvention: SignatureCallingConvention.Unmanaged,
callingConventionTypes: ImmutableArray.Create(testConvention.GetPublicSymbol()!)));
}
[Fact]
public void Equality_UnmanagedExtensionModifiers()
{
......@@ -1996,7 +2044,7 @@ static void verifyEquality((FunctionPointerTypeSymbol NoRef, FunctionPointerType
}
(FunctionPointerTypeSymbol NoRef, FunctionPointerTypeSymbol ByRef) createTypeSymbol(ImmutableArray<CustomModifier> customModifiers, CallingConvention callingConvention = CallingConvention.Unmanaged)
=> (FunctionPointerTypeSymbol.CreateFromParts(
=> (FunctionPointerTypeSymbol.CreateFromPartsForTests(
callingConvention,
TypeWithAnnotations.Create(returnType, customModifiers: customModifiers),
refCustomModifiers: default,
......@@ -2005,7 +2053,7 @@ static void verifyEquality((FunctionPointerTypeSymbol NoRef, FunctionPointerType
parameterRefCustomModifiers: default,
parameterRefKinds: ImmutableArray<RefKind>.Empty,
compilation: comp),
FunctionPointerTypeSymbol.CreateFromParts(
FunctionPointerTypeSymbol.CreateFromPartsForTests(
callingConvention,
TypeWithAnnotations.Create(returnType),
customModifiers,
......@@ -2063,7 +2111,7 @@ static void verifyEquality((FunctionPointerTypeSymbol NoRef, FunctionPointerType
}
(FunctionPointerTypeSymbol NoRef, FunctionPointerTypeSymbol ByRef) createTypeSymbol(ImmutableArray<CustomModifier> customModifiers, CallingConvention callingConvention = CallingConvention.Unmanaged)
=> (FunctionPointerTypeSymbol.CreateFromParts(
=> (FunctionPointerTypeSymbol.CreateFromPartsForTests(
callingConvention,
TypeWithAnnotations.Create(returnType, customModifiers: customModifiers),
refCustomModifiers: default,
......@@ -2072,7 +2120,7 @@ static void verifyEquality((FunctionPointerTypeSymbol NoRef, FunctionPointerType
parameterRefCustomModifiers: default,
parameterRefKinds: ImmutableArray<RefKind>.Empty,
compilation: comp),
FunctionPointerTypeSymbol.CreateFromParts(
FunctionPointerTypeSymbol.CreateFromPartsForTests(
callingConvention,
TypeWithAnnotations.Create(returnType),
customModifiers,
......@@ -2122,7 +2170,7 @@ static void verifyEquality((FunctionPointerTypeSymbol NoRef, FunctionPointerType
}
(FunctionPointerTypeSymbol NoRef, FunctionPointerTypeSymbol ByRef) createTypeSymbol(ImmutableArray<CustomModifier> typeCustomModifiers, ImmutableArray<CustomModifier> refCustomModifiers, CallingConvention callingConvention = CallingConvention.Unmanaged)
=> (FunctionPointerTypeSymbol.CreateFromParts(
=> (FunctionPointerTypeSymbol.CreateFromPartsForTests(
callingConvention,
TypeWithAnnotations.Create(returnType, customModifiers: typeCustomModifiers),
refCustomModifiers: default,
......@@ -2131,7 +2179,7 @@ static void verifyEquality((FunctionPointerTypeSymbol NoRef, FunctionPointerType
parameterRefCustomModifiers: default,
parameterRefKinds: ImmutableArray<RefKind>.Empty,
compilation: comp),
FunctionPointerTypeSymbol.CreateFromParts(
FunctionPointerTypeSymbol.CreateFromPartsForTests(
callingConvention,
TypeWithAnnotations.Create(returnType, customModifiers: typeCustomModifiers),
refCustomModifiers,
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
......@@ -2324,5 +2325,82 @@ public interface IInnerInterface
var compilation = CreateCompilation(text);
compilation.VerifyDiagnostics();
}
[Fact]
public void CallingConventionOnMethods_FromSource()
{
var sourceComp = CreateCompilation(@"
class C
{
void M1() { }
void M2(params object[] p) { }
void M3(__arglist) { }
}");
sourceComp.VerifyDiagnostics();
var c = sourceComp.GetTypeByMetadataName("C").GetPublicSymbol();
var m1 = (IMethodSymbol)c.GetMember("M1");
Assert.NotNull(m1);
Assert.Equal(SignatureCallingConvention.Default, m1.CallingConvention);
Assert.Empty(m1.CallingConventionTypes);
var m2 = (IMethodSymbol)c.GetMember("M2");
Assert.NotNull(m2);
Assert.Equal(SignatureCallingConvention.Default, m2.CallingConvention);
Assert.Empty(m2.CallingConventionTypes);
var m3 = (IMethodSymbol)c.GetMember("M3");
Assert.NotNull(m3);
Assert.Equal(SignatureCallingConvention.VarArgs, m3.CallingConvention);
Assert.Empty(m3.CallingConventionTypes);
}
[Fact]
public void CallingConventionOnMethods_FromMetadata()
{
var metadataComp = CreateCompilationWithIL("", ilSource: @"
.class public auto ansi beforefieldinit C extends [mscorlib]System.Object
{
.method public hidebysig instance void M1 () cil managed
{
ret
}
.method public hidebysig instance void M2 (object[] p) cil managed
{
.param [1] .custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = ( 01 00 00 00 )
ret
}
.method public hidebysig instance vararg void M3 () cil managed
{
ret
}
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
}");
metadataComp.VerifyDiagnostics();
var c = metadataComp.GetTypeByMetadataName("C").GetPublicSymbol();
var m1 = (IMethodSymbol)c.GetMember("M1");
Assert.NotNull(m1);
Assert.Equal(SignatureCallingConvention.Default, m1.CallingConvention);
Assert.Empty(m1.CallingConventionTypes);
var m2 = (IMethodSymbol)c.GetMember("M2");
Assert.NotNull(m2);
Assert.Equal(SignatureCallingConvention.Default, m2.CallingConvention);
Assert.Empty(m2.CallingConventionTypes);
var m3 = (IMethodSymbol)c.GetMember("M3");
Assert.NotNull(m3);
Assert.Equal(SignatureCallingConvention.VarArgs, m3.CallingConvention);
Assert.Empty(m3.CallingConventionTypes);
}
}
}
......@@ -216,15 +216,14 @@ public interface IMethodSymbol : ISymbol
ImmutableArray<AttributeData> GetReturnTypeAttributes();
/// <summary>
/// The calling convention enum of the method method symbol. If this value is <see cref="SignatureCallingConvention.Unmanaged"/>,
/// then <see cref="CallingConventionTypes"/> may have additional calling convention types that are considered part of the
/// calling convention of the method.
/// The calling convention enum of the method method symbol.
/// </summary>
SignatureCallingConvention CallingConvention { get; }
/// <summary>
/// Modifier types that are considered part of the calling convention of this method. If <see cref="CallingConvention"/> is not
/// <see cref="SignatureCallingConvention.Unmanaged"/>, then this will be an empty array.
/// Modifier types that are considered part of the calling convention of this method, if the <see cref="MethodKind"/> is <see cref="MethodKind.FunctionPointerSignature"/>
/// and the <see cref="CallingConvention"/> is <see cref="SignatureCallingConvention.Unmanaged"/>. If this is not a function pointer signature or the calling convention is
/// not unmanaged, this is an empty array. Order and duplication of these modifiers reflect source/metadata order and duplication, whichever this symbol came from.
/// </summary>
ImmutableArray<INamedTypeSymbol> CallingConventionTypes { get; }
......
......@@ -8841,186 +8841,27 @@ private unsafe void M2(delegate* unmanaged<int, float> y)
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task TestWithFunctionPointerUnmanagedCdeclConvention()
{
await TestInRegularAndScriptAsync(
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Cdecl]<int, float> y;
[|M2(y)|];
}
}",
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Cdecl]<int, float> y;
[|M2(y)|];
}
private unsafe void M2(delegate* unmanaged[Cdecl]<int, float> y)
{
throw new NotImplementedException();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task TestWithFunctionPointerUnmanagedStdcallConvention()
{
await TestInRegularAndScriptAsync(
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Stdcall]<int, float> y;
[|M2(y)|];
}
}",
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Stdcall]<int, float> y;
[|M2(y)|];
}
private unsafe void M2(delegate* unmanaged[Stdcall]<int, float> y)
{
throw new NotImplementedException();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task TestWithFunctionPointerUnmanagedThiscallConvention()
[Theory, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
[InlineData("Cdecl")]
[InlineData("Fastcall")]
[InlineData("Thiscall")]
[InlineData("Stdcall")]
[InlineData("Thiscall, Stdcall")]
[InlineData("Bad")] // Bad conventions should still be generatable
public async Task TestWithFunctionPointerUnmanagedSpecificConvention(string convention)
{
await TestInRegularAndScriptAsync(
@"
$@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Thiscall]<int, float> y;
[|M2(y)|];
}
}",
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Thiscall]<int, float> y;
[|M2(y)|];
}
private unsafe void M2(delegate* unmanaged[Thiscall]<int, float> y)
{
throw new NotImplementedException();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task TestWithFunctionPointerUnmanagedFastcallConvention()
{
await TestInRegularAndScriptAsync(
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Fastcall]<int, float> y;
[|M2(y)|];
}
}",
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Fastcall]<int, float> y;
[|M2(y)|];
}
private unsafe void M2(delegate* unmanaged[Fastcall]<int, float> y)
{
throw new NotImplementedException();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task TestWithFunctionPointerUnmanagedBadConvention()
{
await TestInRegularAndScriptAsync(
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Bad]<int, float> y;
[|M2(y)|];
}
}",
@"
using System;
class Class
{
unsafe void M()
{
delegate* unmanaged[Bad]<int, float> y;
[|M2(y)|];
}
private unsafe void M2(delegate* unmanaged[Bad]<int, float> y)
{
throw new NotImplementedException();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateMethod)]
public async Task TestWithFunctionPointerUnmanagedThiscallStdcallConvention()
{
await TestInRegularAndScriptAsync(
@"
using System;
class Class
{
{{
unsafe void M()
{
delegate* unmanaged[Thiscall, Stdcall]<int, float> y;
{{
delegate* unmanaged[{convention}]<int, float> y;
[|M2(y)|];
}
}",
}}
}}",
@"
using System;
......@@ -9028,11 +8869,11 @@ class Class
{
unsafe void M()
{
delegate* unmanaged[Thiscall, Stdcall]<int, float> y;
delegate* unmanaged[{convention}]<int, float> y;
[|M2(y)|];
}
private unsafe void M2(delegate* unmanaged[Thiscall, Stdcall]<int, float> y)
private unsafe void M2(delegate* unmanaged[{convention}]<int, float> y)
{
throw new NotImplementedException();
}
......
......@@ -6,6 +6,7 @@
using System.Linq;
using System.Threading;
#if !CODE_STYLE
using System.Collections.Generic;
using Microsoft.CodeAnalysis.CSharp.CodeGeneration;
#endif
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -131,36 +132,30 @@ public static bool TryCreateNativeIntegerType(INamedTypeSymbol symbol, out TypeS
public override TypeSyntax VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol)
{
FunctionPointerCallingConventionSyntax? callingConventionSyntax = null;
if (symbol.Signature.CallingConvention != System.Reflection.Metadata.SignatureCallingConvention.Default)
// For varargs there is no C# syntax. You get a use-site diagnostic if you attempt to use it, and just
// making a default-convention symbol is likely good enough. This is only observable through metadata
// that always be uncompilable in C# anyway.
if (symbol.Signature.CallingConvention != System.Reflection.Metadata.SignatureCallingConvention.Default
&& symbol.Signature.CallingConvention != System.Reflection.Metadata.SignatureCallingConvention.VarArgs)
{
SeparatedSyntaxList<FunctionPointerUnmanagedCallingConventionSyntax> conventionsList = default;
switch (symbol.Signature.CallingConvention)
IEnumerable<FunctionPointerUnmanagedCallingConventionSyntax>? conventionsList = symbol.Signature.CallingConvention switch
{
case System.Reflection.Metadata.SignatureCallingConvention.CDecl:
conventionsList = SyntaxFactory.SeparatedList(new[] { GetConventionForString("Cdecl") });
break;
case System.Reflection.Metadata.SignatureCallingConvention.StdCall:
conventionsList = SyntaxFactory.SeparatedList(new[] { GetConventionForString("Stdcall") });
break;
case System.Reflection.Metadata.SignatureCallingConvention.ThisCall:
conventionsList = SyntaxFactory.SeparatedList(new[] { GetConventionForString("Thiscall") });
break;
case System.Reflection.Metadata.SignatureCallingConvention.FastCall:
conventionsList = SyntaxFactory.SeparatedList(new[] { GetConventionForString("Fastcall") });
break;
default:
System.Reflection.Metadata.SignatureCallingConvention.CDecl => new[] { GetConventionForString("Cdecl") },
System.Reflection.Metadata.SignatureCallingConvention.StdCall => new[] { GetConventionForString("Stdcall") },
System.Reflection.Metadata.SignatureCallingConvention.ThisCall => new[] { GetConventionForString("Thiscall") },
System.Reflection.Metadata.SignatureCallingConvention.FastCall => new[] { GetConventionForString("Fastcall") },
System.Reflection.Metadata.SignatureCallingConvention.Unmanaged =>
// All types that come from CallingConventionTypes start with "CallConv". We don't want the prefix for the actual
// syntax, so strip it off
const int CallConvLength = 8;
conventionsList = SyntaxFactory.SeparatedList(symbol.Signature.CallingConventionTypes.SelectAsArray(type => GetConventionForString(type.Name[CallConvLength..])));
break;
}
symbol.Signature.CallingConventionTypes.Select(type => GetConventionForString(type.Name["CallConv".Length..])),
_ => throw ExceptionUtilities.UnexpectedValue(symbol.Signature.CallingConvention),
};
callingConventionSyntax = SyntaxFactory.FunctionPointerCallingConvention(
SyntaxFactory.Token(SyntaxKind.UnmanagedKeyword),
conventionsList.Count > 0
? SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(conventionsList)
conventionsList is object
? SyntaxFactory.FunctionPointerUnmanagedCallingConventionList(SyntaxFactory.SeparatedList(conventionsList))
: null);
static FunctionPointerUnmanagedCallingConventionSyntax GetConventionForString(string identifier)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册