Skip to content

Commit

Permalink
Remove NullabilityInfoContext.IsSupported feature switch (#103970)
Browse files Browse the repository at this point in the history
* Remove NullabilityInfoContext.IsSupported feature switch

* Remove trimming tests
  • Loading branch information
eiriktsarpalis committed Jun 26, 2024
1 parent fd534b2 commit a95e718
Show file tree
Hide file tree
Showing 12 changed files with 10 additions and 252 deletions.
1 change: 0 additions & 1 deletion docs/workflow/trimming/feature-switches.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ configurations but their defaults might vary as any SDK can set the defaults dif
| _EnableConsumingManagedCodeFromNativeHosting | System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting | Getting a managed function from native hosting is disabled when set to false and related functionality can be trimmed. |
| VerifyDependencyInjectionOpenGenericServiceTrimmability | Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability | When set to true, DependencyInjection will verify trimming annotations applied to open generic services are correct |
| DisableDependencyInjectionDynamicEngine | Microsoft.Extensions.DependencyInjection.DisableDynamicEngine | When set to true, DependencyInjection will avoid using System.Reflection.Emit when realizing services |
| NullabilityInfoContextSupport | System.Reflection.NullabilityInfoContext.IsSupported | Nullable attributes can be trimmed when set to false |
| DynamicCodeSupport | System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported | Changes RuntimeFeature.IsDynamicCodeSupported to false to allow testing AOT-safe fallback code without publishing for Native AOT. |
| _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 |
| JsonSerializerIsReflectionEnabledByDefault | System.Text.Json.JsonSerializer.IsReflectionEnabledByDefault | When set to false, disables using reflection as the default contract resolver in System.Text.Json |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,6 @@
</type>
</assembly>

<!--
The following attributes are necessary when NullabilityInfoContext is supported.
Note these attributes are allowed to be in any assembly.
-->
<assembly fullname="*" feature="System.Reflection.NullabilityInfoContext.IsSupported" featurevalue="false">
<type fullname="System.Diagnostics.CodeAnalysis.AllowNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.DisallowNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.MaybeNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Diagnostics.CodeAnalysis.NotNullAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NullableAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NullableContextAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
<type fullname="System.Runtime.CompilerServices.NullablePublicOnlyAttribute">
<attribute internal="RemoveAttributeInstances" />
</type>
</assembly>

<!-- The following attributes are only necessary when COM is supported -->
<assembly fullname="System.Private.CoreLib" feature="System.Runtime.InteropServices.BuiltInComInterop.IsSupported" featurevalue="false">
<type fullname="System.Runtime.InteropServices.ClassInterfaceAttribute">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@
<type fullname="System.Reflection.Metadata.MetadataUpdater" feature="System.Reflection.Metadata.MetadataUpdater.IsSupported" featurevalue="false">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
<type fullname="System.Reflection.NullabilityInfoContext" feature="System.Reflection.NullabilityInfoContext.IsSupported" featurevalue="false">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
<type fullname="Internal.Runtime.InteropServices.ComponentActivator" feature="System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting" featurevalue="false">
<method signature="System.Boolean get_IsSupported()" body="stub" value="false" />
</type>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4058,9 +4058,6 @@
<data name="TimeZoneNotFound_ValidTimeZoneFileMissing" xml:space="preserve">
<value>Unable to properly load any time zone data files.</value>
</data>
<data name="NullabilityInfoContext_NotSupported" xml:space="preserve">
<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>
</data>
<data name="ThreadState_AlreadyStarted" xml:space="preserve">
<value>Thread is running or terminated; it cannot restart.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ sealed class NullabilityInfoContext
private readonly Dictionary<Module, NotAnnotatedStatus> _publicOnlyModules = new();
private readonly Dictionary<MemberInfo, NullabilityState> _context = new();

internal static bool IsSupported { get; } =
AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true;

[Flags]
private enum NotAnnotatedStatus
{
Expand Down Expand Up @@ -75,9 +72,6 @@ public NullabilityInfo Create(ParameterInfo parameterInfo)
#else
NetstandardHelpers.ThrowIfNull(parameterInfo, nameof(parameterInfo));
#endif

EnsureIsSupported();

IList<CustomAttributeData> attributes = parameterInfo.GetCustomAttributesData();
NullableAttributeStateParser parser = parameterInfo.Member is MethodBase method && IsPrivateOrInternalMethodAndAnnotationDisabled(method)
? NullableAttributeStateParser.Unknown
Expand Down Expand Up @@ -204,9 +198,6 @@ public NullabilityInfo Create(PropertyInfo propertyInfo)
#else
NetstandardHelpers.ThrowIfNull(propertyInfo, nameof(propertyInfo));
#endif

EnsureIsSupported();

MethodInfo? getter = propertyInfo.GetGetMethod(true);
MethodInfo? setter = propertyInfo.GetSetMethod(true);
bool annotationsDisabled = (getter == null || IsPrivateOrInternalMethodAndAnnotationDisabled(getter))
Expand Down Expand Up @@ -263,9 +254,6 @@ public NullabilityInfo Create(EventInfo eventInfo)
#else
NetstandardHelpers.ThrowIfNull(eventInfo, nameof(eventInfo));
#endif

EnsureIsSupported();

return GetNullabilityInfo(eventInfo, eventInfo.EventHandlerType!, CreateParser(eventInfo.GetCustomAttributesData()));
}

Expand All @@ -284,24 +272,13 @@ public NullabilityInfo Create(FieldInfo fieldInfo)
#else
NetstandardHelpers.ThrowIfNull(fieldInfo, nameof(fieldInfo));
#endif

EnsureIsSupported();

IList<CustomAttributeData> attributes = fieldInfo.GetCustomAttributesData();
NullableAttributeStateParser parser = IsPrivateOrInternalFieldAndAnnotationDisabled(fieldInfo) ? NullableAttributeStateParser.Unknown : CreateParser(attributes);
NullabilityInfo nullability = GetNullabilityInfo(fieldInfo, fieldInfo.FieldType, parser);
CheckNullabilityAttributes(nullability, attributes);
return nullability;
}

private static void EnsureIsSupported()
{
if (!IsSupported)
{
throw new InvalidOperationException(SR.NullabilityInfoContext_NotSupported);
}
}

private bool IsPrivateOrInternalFieldAndAnnotationDisabled(FieldInfo fieldInfo)
{
if ((fieldInfo.IsPrivate || fieldInfo.IsFamilyAndAssembly || fieldInfo.IsAssembly) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,43 +284,6 @@ public void GenericDictionaryPropertyTest(string propertyName, NullabilityState
Assert.Null(nullability.ElementType);
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void VerifyIsSupportedThrows()
{
RemoteInvokeOptions options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("System.Reflection.NullabilityInfoContext.IsSupported", "false");

using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() =>
{
FieldInfo field = testType.GetField("FieldNullable", flags);
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(field));
EventInfo @event = testType.GetEvent("EventNullable");
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(@event));
PropertyInfo property = testType.GetProperty("PropertyNullable", flags);
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(property));
MethodInfo method = testType.GetMethod("MethodNullNonNullNonNon", flags);
Assert.Throws<InvalidOperationException>(() => nullabilityContext.Create(method.ReturnParameter));
}, options);
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void VerifyIsSupportedWorks()
{
RemoteInvokeOptions options = new RemoteInvokeOptions();
options.RuntimeConfigurationOptions.Add("System.Reflection.NullabilityInfoContext.IsSupported", "true");

using RemoteInvokeHandle remoteHandle = RemoteExecutor.Invoke(() =>
{
FieldInfo field = testType.GetField("FieldNullable", flags);
NullabilityInfo nullability = nullabilityContext.Create(field);
Assert.Equal(NullabilityState.Nullable, nullability.ReadState);
Assert.Equal(NullabilityState.Nullable, nullability.WriteState);
}, options);
}

public static IEnumerable<object[]> GenericPropertyReferenceTypeTestData()
{
yield return new object[] { "PropertyNullable", NullabilityState.Nullable, NullabilityState.Nullable, typeof(TypeWithNotNullContext) };
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@
<!-- Reflection.Emit doesn't work with native AOT -->
<NativeAotIncompatible>true</NativeAotIncompatible>
</TestConsoleAppSourceFiles>
<TestConsoleAppSourceFiles Include="NullabilityInfoContextSupportFalse.cs">
<DisabledProperties>NullabilityInfoContextSupport</DisabledProperties>
</TestConsoleAppSourceFiles>
<TestConsoleAppSourceFiles Include="NullabilityInfoContextSupportTrue.cs">
<EnabledProperties>NullabilityInfoContextSupport</EnabledProperties>
</TestConsoleAppSourceFiles>
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
<TestConsoleAppSourceFiles Include="UseWindowsThreadPoolFalse.cs">
Expand Down
3 changes: 0 additions & 3 deletions src/libraries/System.Text.Json/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -749,9 +749,6 @@
<data name="ConstructorParameterDisallowNull" xml:space="preserve">
<value>The constructor parameter '{0}' on type '{1}' doesn't allow null values. Consider updating its nullability annotation.</value>
</data>
<data name="NullabilityInfoContext_NotSupported" xml:space="preserve">
<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>
</data>
<data name="JsonSchemaExporter_ReferenceHandlerPreserve_NotSupported" xml:space="preserve">
<value>JSON schema generation is not supported for contracts using ReferenceHandler.Preserve.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ namespace System.Text.Json.Serialization.Metadata
{
public partial class DefaultJsonTypeInfoResolver
{
private static readonly bool s_isNullabilityInfoContextSupported =
AppContext.TryGetSwitch("System.Reflection.NullabilityInfoContext.IsSupported", out bool isSupported) ? isSupported : true;

internal static MemberAccessor MemberAccessor
{
[RequiresUnreferencedCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
Expand Down Expand Up @@ -74,10 +71,7 @@ private static JsonTypeInfo CreateTypeInfoCore(Type type, JsonConverter converte

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

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

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
private static void PopulateProperties(JsonTypeInfo typeInfo, NullabilityInfoContext? nullabilityCtx)
private static void PopulateProperties(JsonTypeInfo typeInfo, NullabilityInfoContext nullabilityCtx)
{
Debug.Assert(!typeInfo.IsReadOnly);
Debug.Assert(typeInfo.Kind is JsonTypeInfoKind.Object);
Expand Down Expand Up @@ -146,7 +140,7 @@ private static void PopulateProperties(JsonTypeInfo typeInfo, NullabilityInfoCon
private static void AddMembersDeclaredBySuperType(
JsonTypeInfo typeInfo,
Type currentType,
NullabilityInfoContext? nullabilityCtx,
NullabilityInfoContext nullabilityCtx,
bool constructorHasSetsRequiredMembersAttribute,
ref JsonTypeInfo.PropertyHierarchyResolutionState state)
{
Expand Down Expand Up @@ -207,7 +201,7 @@ private static void AddMember(
JsonTypeInfo typeInfo,
Type typeToConvert,
MemberInfo memberInfo,
NullabilityInfoContext? nullabilityCtx,
NullabilityInfoContext nullabilityCtx,
bool shouldCheckForRequiredKeyword,
bool hasJsonIncludeAttribute,
ref JsonTypeInfo.PropertyHierarchyResolutionState state)
Expand All @@ -229,7 +223,7 @@ private static void AddMember(
JsonTypeInfo typeInfo,
Type typeToConvert,
MemberInfo memberInfo,
NullabilityInfoContext? nullabilityCtx,
NullabilityInfoContext nullabilityCtx,
JsonSerializerOptions options,
bool shouldCheckForRequiredKeyword,
bool hasJsonIncludeAttribute)
Expand Down Expand Up @@ -289,7 +283,7 @@ private static bool PropertyIsOverriddenAndIgnored(PropertyInfo propertyInfo, Di

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
private static void PopulateParameterInfoValues(JsonTypeInfo typeInfo, NullabilityInfoContext? nullabilityCtx)
private static void PopulateParameterInfoValues(JsonTypeInfo typeInfo, NullabilityInfoContext nullabilityCtx)
{
Debug.Assert(typeInfo.Converter.ConstructorInfo != null);
ParameterInfo[] parameters = typeInfo.Converter.ConstructorInfo.GetParameters();
Expand Down Expand Up @@ -330,7 +324,7 @@ private static void PopulatePropertyInfo(
MemberInfo memberInfo,
JsonConverter? customConverter,
JsonIgnoreCondition? ignoreCondition,
NullabilityInfoContext? nullabilityCtx,
NullabilityInfoContext nullabilityCtx,
bool shouldCheckForRequiredKeyword,
bool hasJsonIncludeAttribute)
{
Expand Down Expand Up @@ -473,9 +467,9 @@ internal static void DeterminePropertyAccessors<T>(JsonPropertyInfo<T> jsonPrope

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
private static void DeterminePropertyNullability(JsonPropertyInfo propertyInfo, MemberInfo memberInfo, NullabilityInfoContext? nullabilityCtx)
private static void DeterminePropertyNullability(JsonPropertyInfo propertyInfo, MemberInfo memberInfo, NullabilityInfoContext nullabilityCtx)
{
if (!propertyInfo.PropertyTypeCanBeNull || nullabilityCtx is null)
if (!propertyInfo.PropertyTypeCanBeNull)
{
return;
}
Expand All @@ -497,17 +491,12 @@ private static void DeterminePropertyNullability(JsonPropertyInfo propertyInfo,

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
private static NullabilityState DetermineParameterNullability(ParameterInfo parameterInfo, NullabilityInfoContext? nullabilityCtx)
private static NullabilityState DetermineParameterNullability(ParameterInfo parameterInfo, NullabilityInfoContext nullabilityCtx)
{
if (!parameterInfo.ParameterType.IsNullableType())
{
return NullabilityState.NotNull;
}

if (nullabilityCtx is null)
{
return NullabilityState.Unknown;
}
#if NET8_0
// Workaround for https://github.com/dotnet/runtime/issues/92487
// The fix has been incorporated into .NET 9 (and the polyfilled implementations in netfx).
Expand Down
Loading

0 comments on commit a95e718

Please sign in to comment.