Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions src/libraries/Common/tests/System/FunctionPointerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,32 @@ public static unsafe void GenericFunctionPointer()
Assert.True(fcnPtr2.ContainsGenericParameters);
}

[Fact]
public static unsafe void FunctionPointerVisibility()
{
Type t = typeof(FunctionPointerHolder).Project();

// A function pointer with public return type should be visible
Type fnPtrPublicReturn = t.GetField(nameof(FunctionPointerHolder.Field_Int), Bindings)!.FieldType;
Assert.True(fnPtrPublicReturn.IsFunctionPointer);
Assert.True(fnPtrPublicReturn.IsVisible);

// A function pointer with public parameter types should be visible
Type fnPtrPublicParams = t.GetField(nameof(FunctionPointerHolder.Field_PublicParam), Bindings)!.FieldType;
Assert.True(fnPtrPublicParams.IsFunctionPointer);
Assert.True(fnPtrPublicParams.IsVisible);

// A function pointer with private return type should not be visible
Type fnPtrPrivateReturn = t.GetField("Field_PrivateReturn", Bindings)!.FieldType;
Assert.True(fnPtrPrivateReturn.IsFunctionPointer);
Assert.False(fnPtrPrivateReturn.IsVisible);

// A function pointer with private parameter type should not be visible
Type fnPtrPrivateParam = t.GetField("Field_PrivateParam", Bindings)!.FieldType;
Assert.True(fnPtrPrivateParam.IsFunctionPointer);
Assert.False(fnPtrPrivateParam.IsVisible);
}

[Theory]
[InlineData(nameof(FunctionPointerHolder.MethodReturnValue1),
"MethodReturnValue1()",
Expand Down Expand Up @@ -270,7 +296,9 @@ private static void VerifyFieldOrProperty(Type fnPtrType)

private unsafe class FunctionPointerHolder
{
#pragma warning disable 0649
// CS0649: Field is never assigned to (fields are used via reflection)
// CS0169: Field is never used (private fields are accessed via reflection)
#pragma warning disable 0649, 0169
public delegate*<void> ToString_1;
public delegate*unmanaged<void> ToString_2;
public delegate*<int> ToString_3;
Expand All @@ -283,7 +311,12 @@ private unsafe class FunctionPointerHolder

public delegate* managed<int> Field_Int;
public delegate* managed<MyClass> Field_MyClass;
#pragma warning restore 0649

// Fields for visibility tests
public delegate* managed<int, void> Field_PublicParam;
private delegate* managed<PrivateClass> Field_PrivateReturn;
private delegate* managed<PrivateClass, void> Field_PrivateParam;
#pragma warning restore 0649, 0169

public delegate* managed<int> Prop_Int { get; }
public delegate* managed<MyClass> Prop_MyClass { get; }
Expand All @@ -299,6 +332,7 @@ private unsafe class FunctionPointerHolder

public class MyClass { }
public struct MyStruct { }
private class PrivateClass { }
}
}
}
28 changes: 28 additions & 0 deletions src/libraries/System.Private.CoreLib/src/System/Type.Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ public virtual bool ContainsGenericParameters
if (IsGenericParameter)
return true;

if (IsFunctionPointer)
{
if (GetFunctionPointerReturnType().ContainsGenericParameters)
return true;

foreach (Type parameterType in GetFunctionPointerParameterTypes())
{
if (parameterType.ContainsGenericParameters)
return true;
}

return false;
}

if (!IsGenericType)
return false;

Expand Down Expand Up @@ -88,6 +102,20 @@ public bool IsVisible
if (HasElementType)
return GetElementType()!.IsVisible;

if (IsFunctionPointer)
{
if (!GetFunctionPointerReturnType().IsVisible)
return false;

foreach (Type parameterType in GetFunctionPointerParameterTypes())
{
if (!parameterType.IsVisible)
return false;
}

return true;
}

Type type = this;
while (type.IsNested)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1509,6 +1509,51 @@ public enum NestedEnum
C
}
}

/// <summary>
/// A mock function pointer type used to test the abstract ContainsGenericParameters implementation.
/// </summary>
private sealed class MockFunctionPointerType : MockType
{
private readonly Type _returnType;
private readonly Type[] _parameterTypes;

public MockFunctionPointerType(Type returnType, Type[] parameterTypes)
{
_returnType = returnType;
_parameterTypes = parameterTypes ?? Type.EmptyTypes;
}

protected override bool HasElementTypeImpl() => false;
public override bool IsGenericParameter => false;
public override bool IsFunctionPointer => true;
public override Type GetFunctionPointerReturnType() => _returnType;
public override Type[] GetFunctionPointerParameterTypes() => _parameterTypes;
}

[Fact]
public static void FunctionPointerContainsGenericParameters_MockType()
{
// Function pointer with non-generic return type and no parameters should not contain generic parameters
var fnPtrNonGeneric = new MockFunctionPointerType(typeof(string), Type.EmptyTypes);
Assert.True(fnPtrNonGeneric.IsFunctionPointer);
Assert.False(fnPtrNonGeneric.ContainsGenericParameters);

// Function pointer with generic return type should contain generic parameters
var fnPtrGenericReturn = new MockFunctionPointerType(typeof(List<>), Type.EmptyTypes);
Assert.True(fnPtrGenericReturn.IsFunctionPointer);
Assert.True(fnPtrGenericReturn.ContainsGenericParameters);

// Function pointer with non-generic return type but generic parameter type should contain generic parameters
var fnPtrGenericParam = new MockFunctionPointerType(typeof(string), new Type[] { typeof(List<>) });
Assert.True(fnPtrGenericParam.IsFunctionPointer);
Assert.True(fnPtrGenericParam.ContainsGenericParameters);

// Function pointer with non-generic return type and non-generic parameter type should not contain generic parameters
var fnPtrAllNonGeneric = new MockFunctionPointerType(typeof(string), new Type[] { typeof(int) });
Assert.True(fnPtrAllNonGeneric.IsFunctionPointer);
Assert.False(fnPtrAllNonGeneric.ContainsGenericParameters);
}
}

public class NonGenericClass { }
Expand Down
Loading