Skip to content

Commit cefd1f7

Browse files
committed
Fix RuntimeHelpers.IsReferenceOrContainsReferences polyfill
1 parent 0ab8bd1 commit cefd1f7

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

CommunityToolkit.HighPerformance/Helpers/Internals/RuntimeHelpers.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,13 @@ private static bool IsReferenceOrContainsReferences(Type type)
191191
return false;
192192
}
193193

194+
// Explicitly check for pointer types first
195+
if (type.IsPointer)
196+
{
197+
return false;
198+
}
199+
200+
// Check for value types (this has to be after checking for pointers)
194201
if (!type.IsValueType)
195202
{
196203
return true;

CommunityToolkit.HighPerformance/Properties/AssemblyInfo.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,9 @@
88
// This doesn't affect the correctness of methods in this assembly, as none of them
99
// are relying on the JIT ensuring that all local memory is zeroed out to work. Doing
1010
// this can provide some minor performance benefits, depending on the workload.
11-
[module: SkipLocalsInit]
11+
[module: SkipLocalsInit]
12+
13+
// We need to test the RuntimeHelpers polyfills on applicable runtimes
14+
#if !NETSTANDARD2_1_OR_GREATER
15+
[assembly: InternalsVisibleTo("CommunityToolkit.HighPerformance.UnitTests")]
16+
#endif
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if !NETCOREAPP3_1_OR_GREATER
6+
7+
using System;
8+
using CommunityToolkit.HighPerformance.Helpers.Internals;
9+
using Microsoft.VisualStudio.TestTools.UnitTesting;
10+
11+
#pragma warning disable CS0649
12+
13+
namespace CommunityToolkit.HighPerformance.UnitTests.Helpers.Internals;
14+
15+
[TestClass]
16+
public class Test_RuntimeHelpers
17+
{
18+
[TestMethod]
19+
public void Test_RuntimeHelpers_ManagedTypes()
20+
{
21+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<object>());
22+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<string>());
23+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<int[]>());
24+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<Memory<int>>());
25+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<ManagedStruct1>());
26+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<ManagedStruct2>());
27+
Assert.IsTrue(RuntimeHelpers.IsReferenceOrContainsReferences<ManagedStruct3>());
28+
}
29+
30+
[TestMethod]
31+
public void Test_RuntimeHelpers_UnmanagedTypes()
32+
{
33+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<byte>());
34+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<int>());
35+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<IntPtr>());
36+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<Guid>());
37+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<byte>());
38+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<UnmanagedStruct1>());
39+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<UnmanagedStruct2>());
40+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<GenericStruct<UnmanagedStruct1>>());
41+
Assert.IsFalse(RuntimeHelpers.IsReferenceOrContainsReferences<GenericStruct<UnmanagedStruct2>>());
42+
}
43+
44+
private unsafe struct ManagedStruct1
45+
{
46+
public int A;
47+
public Memory<int> B;
48+
}
49+
50+
private struct ManagedStruct2
51+
{
52+
public int A;
53+
public ManagedStruct1 B;
54+
}
55+
56+
private struct ManagedStruct3
57+
{
58+
public GenericStruct<Memory<int>> A;
59+
}
60+
61+
private unsafe struct UnmanagedStruct1
62+
{
63+
public int A;
64+
public double B;
65+
public Guid C;
66+
public IntPtr D;
67+
public int* E;
68+
public void** F;
69+
public GenericStruct<int> G;
70+
public GenericStruct<Guid> H;
71+
}
72+
73+
private struct UnmanagedStruct2
74+
{
75+
public int A;
76+
public UnmanagedStruct1 B;
77+
public UnmanagedStruct1? C;
78+
public Guid? D;
79+
}
80+
81+
private struct GenericStruct<T>
82+
where T : struct
83+
{
84+
public T A;
85+
public T? B;
86+
}
87+
}
88+
89+
#endif

0 commit comments

Comments
 (0)