Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotating System.Text.Json library for aot form factor #68464

Merged
merged 10 commits into from
May 5, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ namespace System.Diagnostics.CodeAnalysis
/// This allows tools to understand which methods are unsafe to call when compiling ahead of time.
/// </remarks>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
public sealed class RequiresDynamicCodeAttribute : Attribute
#if SYSTEM_PRIVATE_CORELIB
public
#else
internal
#endif
sealed class RequiresDynamicCodeAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="RequiresDynamicCodeAttribute"/> class
Expand Down
190 changes: 115 additions & 75 deletions src/libraries/System.Text.Json/ref/System.Text.Json.cs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/ref/System.Text.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\StringSyntaxAttribute.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresDynamicCodeAttribute.cs" />
</ItemGroup>

<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Text.Json/src/System.Text.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ System.Text.Json.Nodes.JsonValue</PackageDescription>
</ItemGroup>
<ItemGroup Condition="!$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\StringSyntaxAttribute.cs" />
<Compile Include="$(CoreLibSharedDir)System\Diagnostics\CodeAnalysis\RequiresDynamicCodeAttribute.cs" />
</ItemGroup>
<!-- Application tfms (.NETCoreApp, .NETFramework) need to use the same or higher version of .NETStandard's dependencies. -->
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ internal JsonArray (JsonElement element, JsonNodeOptions? options = null) : base
/// The object to be added to the end of the <see cref="JsonArray"/>.
/// </param>
[RequiresUnreferencedCode(JsonValue.CreateUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonValue.CreateUnreferencedCodeMessage)]
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
public void Add<T>(T? value)
{
if (value == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { }
/// <param name="options">Options to control the behavior.</param>
/// <returns>The new instance of the <see cref="JsonValue"/> class that contains the specified value.</returns>
[RequiresUnreferencedCode(CreateUnreferencedCodeMessage + " Use the overload that takes a JsonTypeInfo, or make sure all of the required types are preserved.")]
[RequiresDynamicCode(CreateUnreferencedCodeMessage + " Use the overload that takes a JsonTypeInfo, or make sure all of the required types are preserved.")]
public static JsonValue? Create<T>(T? value, JsonNodeOptions? options = null)
{
if (value == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ namespace System.Text.Json.Nodes
internal sealed partial class JsonValueNotTrimmable<TValue> : JsonValue<TValue>
{
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
public JsonValueNotTrimmable(TValue value, JsonNodeOptions? options = null) : base(value, options) { }

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked with RequiresUnreferencedCode.")]
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The ctor is marked RequiresDynamicCode.")]
public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null)
{
if (writer is null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
Expand All @@ -15,12 +15,15 @@ namespace System.Text.Json.Serialization
internal sealed class IAsyncEnumerableConverterFactory : JsonConverterFactory
{
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
public IAsyncEnumerableConverterFactory() { }

public override bool CanConvert(Type typeToConvert) => GetAsyncEnumerableInterface(typeToConvert) is not null;

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The ctor is marked RequiresDynamicCode.")]
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Type? asyncEnumerableInterface = GetAsyncEnumerableInterface(typeToConvert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal sealed class IEnumerableConverterFactory : JsonConverterFactory
private static readonly IListConverter<IList> s_converterForIList = new IListConverter<IList>();

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
public IEnumerableConverterFactory() { }

public override bool CanConvert(Type typeToConvert)
Expand All @@ -30,6 +31,8 @@ public override bool CanConvert(Type typeToConvert)

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The ctor is marked RequiresDynamicCode.")]
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Type converterType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal static class IEnumerableConverterFactoryHelpers
internal const string ImmutableConvertersUnreferencedCodeMessage = "System.Collections.Immutable converters use Reflection to find and create Immutable Collection types, which requires unreferenced code.";

[RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(ImmutableConvertersUnreferencedCodeMessage)]
public static MethodInfo GetImmutableEnumerableCreateRangeMethod(this Type type, Type elementType)
{
Type? constructingType = GetImmutableEnumerableConstructingType(type);
Expand All @@ -41,6 +42,7 @@ public static MethodInfo GetImmutableEnumerableCreateRangeMethod(this Type type,
}

[RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(ImmutableConvertersUnreferencedCodeMessage)]
public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type, Type keyType, Type valueType)
{
Type? constructingType = GetImmutableDictionaryConstructingType(type);
Expand All @@ -64,6 +66,7 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type,
}

[RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(ImmutableConvertersUnreferencedCodeMessage)]
private static Type? GetImmutableEnumerableConstructingType(Type type)
{
Debug.Assert(type.IsImmutableEnumerableType());
Expand All @@ -76,6 +79,7 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type,
}

[RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(ImmutableConvertersUnreferencedCodeMessage)]
private static Type? GetImmutableDictionaryConstructingType(Type type)
{
Debug.Assert(type.IsImmutableDictionaryType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ internal sealed class ImmutableDictionaryOfTKeyTValueConverterWithReflection<TCo
where TKey : notnull
{
[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
public ImmutableDictionaryOfTKeyTValueConverterWithReflection()
{
}

[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
internal override void ConfigureJsonTypeInfoUsingReflection(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
jsonTypeInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateImmutableDictionaryCreateRangeDelegate<TCollection, TKey, TValue>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ internal sealed class ImmutableEnumerableOfTConverterWithReflection<TCollection,
where TCollection : IEnumerable<TElement>
{
[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
public ImmutableEnumerableOfTConverterWithReflection()
{
}

[RequiresUnreferencedCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
[RequiresDynamicCode(IEnumerableConverterFactoryHelpers.ImmutableConvertersUnreferencedCodeMessage)]
internal override void ConfigureJsonTypeInfoUsingReflection(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
jsonTypeInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateImmutableEnumerableCreateRangeDelegate<TCollection, TElement>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ internal sealed class StackOrQueueConverterWithReflection<TCollection>
where TCollection : IEnumerable
{
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
public StackOrQueueConverterWithReflection() { }

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
internal override void ConfigureJsonTypeInfoUsingReflection(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
jsonTypeInfo.AddMethodDelegate = options.MemberAccessorStrategy.CreateAddMethodDelegate<TCollection>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
Expand All @@ -14,6 +14,7 @@ internal sealed class FSharpListConverter<TList, TElement> : IEnumerableDefaultC
private readonly Func<IEnumerable<TElement>, TList> _listConstructor;

[RequiresUnreferencedCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
[RequiresDynamicCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
public FSharpListConverter()
{
_listConstructor = FSharpCoreReflectionProxy.Instance.CreateFSharpListConstructor<TList, TElement>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
Expand All @@ -15,6 +15,7 @@ internal sealed class FSharpMapConverter<TMap, TKey, TValue> : DictionaryDefault
private readonly Func<IEnumerable<Tuple<TKey, TValue>>, TMap> _mapConstructor;

[RequiresUnreferencedCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
[RequiresDynamicCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
public FSharpMapConverter()
{
_mapConstructor = FSharpCoreReflectionProxy.Instance.CreateFSharpMapConstructor<TMap, TKey, TValue>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
Expand All @@ -23,6 +23,7 @@ internal sealed class FSharpOptionConverter<TOption, TElement> : JsonConverter<T
private readonly ConverterStrategy _converterStrategy;

[RequiresUnreferencedCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
[RequiresDynamicCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
public FSharpOptionConverter(JsonConverter<TElement> elementConverter)
{
_elementConverter = elementConverter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
Expand All @@ -14,6 +14,7 @@ internal sealed class FSharpSetConverter<TSet, TElement> : IEnumerableDefaultCon
private readonly Func<IEnumerable<TElement>, TSet> _setConstructor;

[RequiresUnreferencedCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
[RequiresDynamicCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
public FSharpSetConverter()
{
_setConstructor = FSharpCoreReflectionProxy.Instance.CreateFSharpSetConstructor<TSet, TElement>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
Expand All @@ -11,18 +11,23 @@ namespace System.Text.Json.Serialization.Converters
internal sealed class FSharpTypeConverterFactory : JsonConverterFactory
{
[RequiresUnreferencedCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
[RequiresDynamicCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
public FSharpTypeConverterFactory() { }

private ObjectConverterFactory? _recordConverterFactory;

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked with RequiresUnreferencedCode.")]
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The ctor is marked RequiresDynamicCode.")]
public override bool CanConvert(Type typeToConvert) =>
FSharpCoreReflectionProxy.IsFSharpType(typeToConvert) &&
FSharpCoreReflectionProxy.Instance.DetectFSharpKind(typeToConvert) is not FSharpKind.Unrecognized;

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "The ctor is marked with RequiresUnreferencedCode.")]
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The ctor is marked RequiresDynamicCode.")]
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(CanConvert(typeToConvert));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
Expand All @@ -23,6 +23,7 @@ internal sealed class FSharpValueOptionConverter<TValueOption, TElement> : JsonC
private readonly ConverterStrategy _converterStrategy;

[RequiresUnreferencedCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
[RequiresDynamicCode(FSharpCoreReflectionProxy.FSharpCoreUnreferencedCodeMessage)]
public FSharpValueOptionConverter(JsonConverter<TElement> elementConverter)
{
_elementConverter = elementConverter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal sealed class ObjectConverterFactory : JsonConverterFactory
private readonly bool _useDefaultConstructorInUnannotatedStructs;

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
public ObjectConverterFactory(bool useDefaultConstructorInUnannotatedStructs = true)
{
_useDefaultConstructorInUnannotatedStructs = useDefaultConstructorInUnannotatedStructs;
Expand All @@ -36,6 +37,8 @@ public override bool CanConvert(Type typeToConvert)
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern",
Justification = "The ctor is marked RequiresUnreferencedCode.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode",
Justification = "The ctor is marked RequiresDynamicCode.")]
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
if (typeToConvert.IsKeyValuePair())
Expand Down Expand Up @@ -99,6 +102,7 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer
return converter;
}

[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
private static JsonConverter CreateKeyValuePairConverter(Type type)
{
Debug.Assert(type.IsKeyValuePair());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ internal sealed class LargeObjectWithParameterizedConstructorConverterWithReflec
: LargeObjectWithParameterizedConstructorConverter<T> where T : notnull
{
[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
public LargeObjectWithParameterizedConstructorConverterWithReflection()
{
}

[RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)]
[RequiresDynamicCode(JsonSerializer.SerializationRequiresDynamicCodeMessage)]
internal override void ConfigureJsonTypeInfoUsingReflection(JsonTypeInfo jsonTypeInfo, JsonSerializerOptions options)
{
jsonTypeInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateParameterizedConstructor<T>(ConstructorInfo!);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ internal static JsonConverter Create(Type enumType, EnumConverterOptions convert
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:MakeGenericType",
Justification = "'EnumConverter<T> where T : struct' implies 'T : new()', so the trimmer is warning calling MakeGenericType here because enumType's constructors are not annotated. " +
"But EnumConverter doesn't call new T(), so this is safe.")]
[UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", Justification = "The factory constructors are only invoked in the context of reflection serialization code paths " +
LakshanF marked this conversation as resolved.
Show resolved Hide resolved
"and are marked with 'RequiresDynamicCode'")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
private static Type GetEnumConverterType(Type enumType) => typeof(EnumConverter<>).MakeGenericType(enumType);
}
Expand Down
Loading