Skip to content

Commit a95e718

Browse files
Remove NullabilityInfoContext.IsSupported feature switch (#103970)
* Remove NullabilityInfoContext.IsSupported feature switch * Remove trimming tests
1 parent fd534b2 commit a95e718

File tree

12 files changed

+10
-252
lines changed

12 files changed

+10
-252
lines changed

docs/workflow/trimming/feature-switches.md

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ configurations but their defaults might vary as any SDK can set the defaults dif
2929
| _EnableConsumingManagedCodeFromNativeHosting | System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting | Getting a managed function from native hosting is disabled when set to false and related functionality can be trimmed. |
3030
| VerifyDependencyInjectionOpenGenericServiceTrimmability | Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability | When set to true, DependencyInjection will verify trimming annotations applied to open generic services are correct |
3131
| DisableDependencyInjectionDynamicEngine | Microsoft.Extensions.DependencyInjection.DisableDynamicEngine | When set to true, DependencyInjection will avoid using System.Reflection.Emit when realizing services |
32-
| NullabilityInfoContextSupport | System.Reflection.NullabilityInfoContext.IsSupported | Nullable attributes can be trimmed when set to false |
3332
| DynamicCodeSupport | System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported | Changes RuntimeFeature.IsDynamicCodeSupported to false to allow testing AOT-safe fallback code without publishing for Native AOT. |
3433
| _AggressiveAttributeTrimming | System.AggressiveAttributeTrimming | When set to true, aggressively trims attributes to allow for the most size savings possible, even if it could result in runtime behavior changes |
3534
| JsonSerializerIsReflectionEnabledByDefault | System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault | When set to false, disables using reflection as the default contract resolver in System.Text.Json |

src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml

-31
Original file line numberDiff line numberDiff line change
@@ -57,37 +57,6 @@
5757
</type>
5858
</assembly>
5959

60-
<!--
61-
The following attributes are necessary when NullabilityInfoContext is supported.
62-
Note these attributes are allowed to be in any assembly.
63-
-->
64-
<assembly fullname="*" feature="System.Reflection.NullabilityInfoContext.IsSupported" featurevalue="false">
65-
<type fullname="System.Diagnostics.CodeAnalysis.AllowNullAttribute">
66-
<attribute internal="RemoveAttributeInstances" />
67-
</type>
68-
<type fullname="System.Diagnostics.CodeAnalysis.DisallowNullAttribute">
69-
<attribute internal="RemoveAttributeInstances" />
70-
</type>
71-
<type fullname="System.Diagnostics.CodeAnalysis.MaybeNullAttribute">
72-
<attribute internal="RemoveAttributeInstances" />
73-
</type>
74-
<type fullname="System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute">
75-
<attribute internal="RemoveAttributeInstances" />
76-
</type>
77-
<type fullname="System.Diagnostics.CodeAnalysis.NotNullAttribute">
78-
<attribute internal="RemoveAttributeInstances" />
79-
</type>
80-
<type fullname="System.Runtime.CompilerServices.NullableAttribute">
81-
<attribute internal="RemoveAttributeInstances" />
82-
</type>
83-
<type fullname="System.Runtime.CompilerServices.NullableContextAttribute">
84-
<attribute internal="RemoveAttributeInstances" />
85-
</type>
86-
<type fullname="System.Runtime.CompilerServices.NullablePublicOnlyAttribute">
87-
<attribute internal="RemoveAttributeInstances" />
88-
</type>
89-
</assembly>
90-
9160
<!-- The following attributes are only necessary when COM is supported -->
9261
<assembly fullname="System.Private.CoreLib" feature="System.Runtime.InteropServices.BuiltInComInterop.IsSupported" featurevalue="false">
9362
<type fullname="System.Runtime.InteropServices.ClassInterfaceAttribute">

src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml

-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@
3636
<type fullname="System.Reflection.Metadata.MetadataUpdater" feature="System.Reflection.Metadata.MetadataUpdater.IsSupported" featurevalue="false">
3737
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
3838
</type>
39-
<type fullname="System.Reflection.NullabilityInfoContext" feature="System.Reflection.NullabilityInfoContext.IsSupported" featurevalue="false">
40-
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
41-
</type>
4239
<type fullname="Internal.Runtime.InteropServices.ComponentActivator" feature="System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting" featurevalue="false">
4340
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
4441
</type>

src/libraries/System.Private.CoreLib/src/Resources/Strings.resx

-3
Original file line numberDiff line numberDiff line change
@@ -4058,9 +4058,6 @@
40584058
<data name="TimeZoneNotFound_ValidTimeZoneFileMissing" xml:space="preserve">
40594059
<value>Unable to properly load any time zone data files.</value>
40604060
</data>
4061-
<data name="NullabilityInfoContext_NotSupported" xml:space="preserve">
4062-
<value>NullabilityInfoContext is not supported in the current application because 'System.Reflection.NullabilityInfoContext.IsSupported' is set to false. Set the MSBuild Property 'NullabilityInfoContextSupport' to true in order to enable it.</value>
4063-
</data>
40644061
<data name="ThreadState_AlreadyStarted" xml:space="preserve">
40654062
<value>Thread is running or terminated; it cannot restart.</value>
40664063
</data>

src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs

-23
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ sealed class NullabilityInfoContext
2222
private readonly Dictionary<Module, NotAnnotatedStatus> _publicOnlyModules = new();
2323
private readonly Dictionary<MemberInfo, NullabilityState> _context = new();
2424

25-
internal static bool IsSupported { get; } =
26-
AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true;
27-
2825
[Flags]
2926
private enum NotAnnotatedStatus
3027
{
@@ -75,9 +72,6 @@ public NullabilityInfo Create(ParameterInfo parameterInfo)
7572
#else
7673
NetstandardHelpers.ThrowIfNull(parameterInfo, nameof(parameterInfo));
7774
#endif
78-
79-
EnsureIsSupported();
80-
8175
IList<CustomAttributeData> attributes = parameterInfo.GetCustomAttributesData();
8276
NullableAttributeStateParser parser = parameterInfo.Member is MethodBase method && IsPrivateOrInternalMethodAndAnnotationDisabled(method)
8377
? NullableAttributeStateParser.Unknown
@@ -204,9 +198,6 @@ public NullabilityInfo Create(PropertyInfo propertyInfo)
204198
#else
205199
NetstandardHelpers.ThrowIfNull(propertyInfo, nameof(propertyInfo));
206200
#endif
207-
208-
EnsureIsSupported();
209-
210201
MethodInfo? getter = propertyInfo.GetGetMethod(true);
211202
MethodInfo? setter = propertyInfo.GetSetMethod(true);
212203
bool annotationsDisabled = (getter == null || IsPrivateOrInternalMethodAndAnnotationDisabled(getter))
@@ -263,9 +254,6 @@ public NullabilityInfo Create(EventInfo eventInfo)
263254
#else
264255
NetstandardHelpers.ThrowIfNull(eventInfo, nameof(eventInfo));
265256
#endif
266-
267-
EnsureIsSupported();
268-
269257
return GetNullabilityInfo(eventInfo, eventInfo.EventHandlerType!, CreateParser(eventInfo.GetCustomAttributesData()));
270258
}
271259

@@ -284,24 +272,13 @@ public NullabilityInfo Create(FieldInfo fieldInfo)
284272
#else
285273
NetstandardHelpers.ThrowIfNull(fieldInfo, nameof(fieldInfo));
286274
#endif
287-
288-
EnsureIsSupported();
289-
290275
IList<CustomAttributeData> attributes = fieldInfo.GetCustomAttributesData();
291276
NullableAttributeStateParser parser = IsPrivateOrInternalFieldAndAnnotationDisabled(fieldInfo) ? NullableAttributeStateParser.Unknown : CreateParser(attributes);
292277
NullabilityInfo nullability = GetNullabilityInfo(fieldInfo, fieldInfo.FieldType, parser);
293278
CheckNullabilityAttributes(nullability, attributes);
294279
return nullability;
295280
}
296281

297-
private static void EnsureIsSupported()
298-
{
299-
if (!IsSupported)
300-
{
301-
throw new InvalidOperationException(SR.NullabilityInfoContext_NotSupported);
302-
}
303-
}
304-
305282
private bool IsPrivateOrInternalFieldAndAnnotationDisabled(FieldInfo fieldInfo)
306283
{
307284
if ((fieldInfo.IsPrivate || fieldInfo.IsFamilyAndAssembly || fieldInfo.IsAssembly) &&

src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Reflection/NullabilityInfoContextTests.cs

-37
Original file line numberDiff line numberDiff line change
@@ -284,43 +284,6 @@ public void GenericDictionaryPropertyTest(string propertyName, NullabilityState
284284
Assert.Null(nullability.ElementType);
285285
}
286286

287-
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
288-
public void VerifyIsSupportedThrows()
289-
{
290-
RemoteInvokeOptions options = new RemoteInvokeOptions();
291-
options.RuntimeConfigurationOptions.Add("System.Reflection.NullabilityInfoContext.IsSupported", "false");
292-
293-
using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() =>
294-
{
295-
FieldInfo field = testType.GetField("FieldNullable", flags);
296-
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(field));
297-
298-
EventInfo @event = testType.GetEvent("EventNullable");
299-
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(@event));
300-
301-
PropertyInfo property = testType.GetProperty("PropertyNullable", flags);
302-
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(property));
303-
304-
MethodInfo method = testType.GetMethod("MethodNullNonNullNonNon", flags);
305-
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(method.ReturnParameter));
306-
}, options);
307-
}
308-
309-
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
310-
public void VerifyIsSupportedWorks()
311-
{
312-
RemoteInvokeOptions options = new RemoteInvokeOptions();
313-
options.RuntimeConfigurationOptions.Add("System.Reflection.NullabilityInfoContext.IsSupported", "true");
314-
315-
using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() =>
316-
{
317-
FieldInfo field = testType.GetField("FieldNullable", flags);
318-
NullabilityInfo nullability = nullabilityContext.Create(field);
319-
Assert.Equal(NullabilityState.Nullable, nullability.ReadState);
320-
Assert.Equal(NullabilityState.Nullable, nullability.WriteState);
321-
}, options);
322-
}
323-
324287
public static IEnumerable<object[]> GenericPropertyReferenceTypeTestData()
325288
{
326289
yield return new object[] { "PropertyNullable", NullabilityState.Nullable, NullabilityState.Nullable, typeof(TypeWithNotNullContext) };

src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/NullabilityInfoContextSupportFalse.cs

-36
This file was deleted.

src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/NullabilityInfoContextSupportTrue.cs

-34
This file was deleted.

src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/System.Runtime.TrimmingTests.proj

-6
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,6 @@
5656
<!-- Reflection.Emit doesn't work with native AOT -->
5757
<NativeAotIncompatible>true</NativeAotIncompatible>
5858
</TestConsoleAppSourceFiles>
59-
<TestConsoleAppSourceFiles Include="NullabilityInfoContextSupportFalse.cs">
60-
<DisabledProperties>NullabilityInfoContextSupport</DisabledProperties>
61-
</TestConsoleAppSourceFiles>
62-
<TestConsoleAppSourceFiles Include="NullabilityInfoContextSupportTrue.cs">
63-
<EnabledProperties>NullabilityInfoContextSupport</EnabledProperties>
64-
</TestConsoleAppSourceFiles>
6559
</ItemGroup>
6660
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
6761
<TestConsoleAppSourceFiles Include="UseWindowsThreadPoolFalse.cs">

src/libraries/System.Text.Json/src/Resources/Strings.resx

-3
Original file line numberDiff line numberDiff line change
@@ -749,9 +749,6 @@
749749
<data name="ConstructorParameterDisallowNull" xml:space="preserve">
750750
<value>The constructor parameter '{0}' on type '{1}' doesn't allow null values. Consider updating its nullability annotation.</value>
751751
</data>
752-
<data name="NullabilityInfoContext_NotSupported" xml:space="preserve">
753-
<value>NullabilityInfoContext is not supported in the current application because 'System.Reflection.NullabilityInfoContext.IsSupported' is set to false. Set the MSBuild Property 'NullabilityInfoContextSupport' to true in order to enable it.</value>
754-
</data>
755752
<data name="JsonSchemaExporter_ReferenceHandlerPreserve_NotSupported" xml:space="preserve">
756753
<value>JSON schema generation is not supported for contracts using ReferenceHandler.Preserve.</value>
757754
</data>

src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/DefaultJsonTypeInfoResolver.Helpers.cs

+10-21
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ namespace System.Text.Json.Serialization.Metadata
1313
{
1414
public partial class DefaultJsonTypeInfoResolver
1515
{
16-
private static readonly bool s_isNullabilityInfoContextSupported =
17-
AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true;
18-
1916
internal static MemberAccessor MemberAccessor
2017
{
2118
[RequiresUnreferencedCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
@@ -74,10 +71,7 @@ private static JsonTypeInfo CreateTypeInfoCore(Type type, JsonConverter converte
7471

7572
if (typeInfo is { Kind: JsonTypeInfoKind.Object, IsNullable: false })
7673
{
77-
// If the System.Reflection.NullabilityInfoContext.IsSupported feature switch has been disabled,
78-
// we want to avoid resolving nullability information for properties and parameters unless the
79-
// user has explicitly opted into nullability enforcement in which case an exception will be surfaced.
80-
NullabilityInfoContext? nullabilityCtx = s_isNullabilityInfoContextSupported || options.RespectNullableAnnotations ? new() : null;
74+
NullabilityInfoContext nullabilityCtx = new();
8175

8276
if (converter.ConstructorIsParameterized)
8377
{
@@ -99,7 +93,7 @@ private static JsonTypeInfo CreateTypeInfoCore(Type type, JsonConverter converte
9993

10094
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
10195
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
102-
private static void PopulateProperties(JsonTypeInfo typeInfo, NullabilityInfoContext? nullabilityCtx)
96+
private static void PopulateProperties(JsonTypeInfo typeInfo, NullabilityInfoContext nullabilityCtx)
10397
{
10498
Debug.Assert(!typeInfo.IsReadOnly);
10599
Debug.Assert(typeInfo.Kind is JsonTypeInfoKind.Object);
@@ -146,7 +140,7 @@ private static void PopulateProperties(JsonTypeInfo typeInfo, NullabilityInfoCon
146140
private static void AddMembersDeclaredBySuperType(
147141
JsonTypeInfo typeInfo,
148142
Type currentType,
149-
NullabilityInfoContext? nullabilityCtx,
143+
NullabilityInfoContext nullabilityCtx,
150144
bool constructorHasSetsRequiredMembersAttribute,
151145
ref JsonTypeInfo.PropertyHierarchyResolutionState state)
152146
{
@@ -207,7 +201,7 @@ private static void AddMember(
207201
JsonTypeInfo typeInfo,
208202
Type typeToConvert,
209203
MemberInfo memberInfo,
210-
NullabilityInfoContext? nullabilityCtx,
204+
NullabilityInfoContext nullabilityCtx,
211205
bool shouldCheckForRequiredKeyword,
212206
bool hasJsonIncludeAttribute,
213207
ref JsonTypeInfo.PropertyHierarchyResolutionState state)
@@ -229,7 +223,7 @@ private static void AddMember(
229223
JsonTypeInfo typeInfo,
230224
Type typeToConvert,
231225
MemberInfo memberInfo,
232-
NullabilityInfoContext? nullabilityCtx,
226+
NullabilityInfoContext nullabilityCtx,
233227
JsonSerializerOptions options,
234228
bool shouldCheckForRequiredKeyword,
235229
bool hasJsonIncludeAttribute)
@@ -289,7 +283,7 @@ private static bool PropertyIsOverriddenAndIgnored(PropertyInfo propertyInfo, Di
289283

290284
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
291285
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
292-
private static void PopulateParameterInfoValues(JsonTypeInfo typeInfo, NullabilityInfoContext? nullabilityCtx)
286+
private static void PopulateParameterInfoValues(JsonTypeInfo typeInfo, NullabilityInfoContext nullabilityCtx)
293287
{
294288
Debug.Assert(typeInfo.Converter.ConstructorInfo != null);
295289
ParameterInfo[] parameters = typeInfo.Converter.ConstructorInfo.GetParameters();
@@ -330,7 +324,7 @@ private static void PopulatePropertyInfo(
330324
MemberInfo memberInfo,
331325
JsonConverter? customConverter,
332326
JsonIgnoreCondition? ignoreCondition,
333-
NullabilityInfoContext? nullabilityCtx,
327+
NullabilityInfoContext nullabilityCtx,
334328
bool shouldCheckForRequiredKeyword,
335329
bool hasJsonIncludeAttribute)
336330
{
@@ -473,9 +467,9 @@ internal static void DeterminePropertyAccessors<T>(JsonPropertyInfo<T> jsonPrope
473467

474468
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
475469
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
476-
private static void DeterminePropertyNullability(JsonPropertyInfo propertyInfo, MemberInfo memberInfo, NullabilityInfoContext? nullabilityCtx)
470+
private static void DeterminePropertyNullability(JsonPropertyInfo propertyInfo, MemberInfo memberInfo, NullabilityInfoContext nullabilityCtx)
477471
{
478-
if (!propertyInfo.PropertyTypeCanBeNull || nullabilityCtx is null)
472+
if (!propertyInfo.PropertyTypeCanBeNull)
479473
{
480474
return;
481475
}
@@ -497,17 +491,12 @@ private static void DeterminePropertyNullability(JsonPropertyInfo propertyInfo,
497491

498492
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
499493
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
500-
private static NullabilityState DetermineParameterNullability(ParameterInfo parameterInfo, NullabilityInfoContext? nullabilityCtx)
494+
private static NullabilityState DetermineParameterNullability(ParameterInfo parameterInfo, NullabilityInfoContext nullabilityCtx)
501495
{
502496
if (!parameterInfo.ParameterType.IsNullableType())
503497
{
504498
return NullabilityState.NotNull;
505499
}
506-
507-
if (nullabilityCtx is null)
508-
{
509-
return NullabilityState.Unknown;
510-
}
511500
#if NET8_0
512501
// Workaround for https://github.com/dotnet/runtime/issues/92487
513502
// The fix has been incorporated into .NET 9 (and the polyfilled implementations in netfx).

0 commit comments

Comments
 (0)