From 992e0495562d6aa4411914f166a7269ec46f5771 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 1 Jun 2021 19:10:09 -0500 Subject: [PATCH] Fully annotate JsonNode for trimmability (#53184) Follow up to https://github.com/dotnet/runtime/pull/52934. - Using JsonNode in dynamic statements is not trim compatible. Add a LibraryBuild warning since there isn't a direct API to put the warning on. - Mark JsonValueNotTrimmable's ctor as unsafe - Fix up a few warning messages - minor doc fixup Contributes to #45623 --- .../System.Text.Json/ref/System.Text.Json.cs | 4 +- .../ILLink.Suppressions.LibraryBuild.xml | 12 ++++ .../src/System/Text/Json/Nodes/JsonArray.cs | 2 +- .../Text/Json/Nodes/JsonNode.Dynamic.cs | 13 +++- .../Text/Json/Nodes/JsonObject.Dynamic.cs | 16 +++-- .../Json/Nodes/JsonValue.CreateOverloads.cs | 70 +++++++++---------- .../src/System/Text/Json/Nodes/JsonValue.cs | 8 ++- .../Text/Json/Nodes/JsonValueNotTrimmable.cs | 3 +- .../src/System/Text/Json/Nodes/MetaDynamic.cs | 7 +- 9 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.LibraryBuild.xml diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 73c434927e1afd..ed8880c117feae 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -518,7 +518,7 @@ public JsonArray(params System.Text.Json.Nodes.JsonNode?[] items) { } public int Count { get { throw null; } } bool System.Collections.Generic.ICollection.IsReadOnly { get { throw null; } } public void Add(System.Text.Json.Nodes.JsonNode? item) { } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Creating JsonValue instances with non-primitive types is not compatible with trimming. It can result in non-primitive types being serialized, which may have their members trimmed.")] public void Add(T? value) { } public void Clear() { } public bool Contains(System.Text.Json.Nodes.JsonNode? item) { throw null; } @@ -711,7 +711,7 @@ public abstract partial class JsonValue : System.Text.Json.Nodes.JsonNode [System.CLSCompliantAttribute(false)] public static System.Text.Json.Nodes.JsonValue Create(ulong value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } public static System.Text.Json.Nodes.JsonValue? Create(T? value, System.Text.Json.Serialization.Metadata.JsonTypeInfo jsonTypeInfo, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Creating JsonValue instances with non-primitive types is not compatible with trimming. It can result in non-primitive types being serialized, which may have their members trimmed. Use the overload that takes a JsonTypeInfo, or make sure all of the required types are preserved.")] public static System.Text.Json.Nodes.JsonValue? Create(T? value, System.Text.Json.Nodes.JsonNodeOptions? options = default(System.Text.Json.Nodes.JsonNodeOptions?)) { throw null; } public abstract bool TryGetValue([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out T? value); } diff --git a/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.LibraryBuild.xml b/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.LibraryBuild.xml new file mode 100644 index 00000000000000..b12ccebb9c92cb --- /dev/null +++ b/src/libraries/System.Text.Json/src/ILLink/ILLink.Suppressions.LibraryBuild.xml @@ -0,0 +1,12 @@ + + + + + ILLink + IL2026 + member + M:System.Text.Json.Nodes.JsonNode.System#Dynamic#IDynamicMetaObjectProvider#GetMetaObject(System.Linq.Expressions.Expression) + System.Text.Json's integration with dynamic is not trim compatible. However, there isn't a direct API developers call. Instead they use the 'dynamic' keyword, which gets compiled into calls to Microsoft.CSharp. Microsoft.CSharp looks for IDynamicMetaObjectProvider implementations. Leaving this warning in the product so developers get a warning stating that using dynamic JsonValue code may be broken in trimmed apps. + + + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs index e012afc9f6a472..d2e51b64192cd6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonArray.cs @@ -98,7 +98,7 @@ internal JsonArray (JsonElement element, JsonNodeOptions? options = null) : base /// /// The object to be added to the end of the . /// - [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + [RequiresUnreferencedCode(JsonValue.CreateUnreferencedCodeMessage)] public void Add(T? value) { if (value == null) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Dynamic.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Dynamic.cs index 9ed5c2677c8239..457af37eb0f218 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Dynamic.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonNode.Dynamic.cs @@ -1,6 +1,7 @@ // 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; using System.Dynamic; using System.Linq.Expressions; using System.Reflection; @@ -10,9 +11,17 @@ namespace System.Text.Json.Nodes public partial class JsonNode : IDynamicMetaObjectProvider { internal virtual MethodInfo? TryGetMemberMethodInfo => null; - internal virtual MethodInfo? TrySetMemberMethodInfo => null; + internal virtual MethodInfo? TrySetMemberMethodInfo + { + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + get => null; + } DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => - new MetaDynamic(parameter, this); + CreateDynamicObject(parameter, this); + + [RequiresUnreferencedCode("Using JsonNode instances as dynamic types is not compatible with trimming. It can result in non-primitive types being serialized, which may have their members trimmed.")] + private static DynamicMetaObject CreateDynamicObject(Expression parameter, JsonNode node) => + new MetaDynamic(parameter, node); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs index 3bd87615e550aa..b343b70d3fa52a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.Dynamic.cs @@ -1,6 +1,7 @@ // 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; using System.Dynamic; using System.Reflection; @@ -21,6 +22,7 @@ private bool TryGetMemberCallback(GetMemberBinder binder, out object? result) return true; } + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] private bool TrySetMemberCallback(SetMemberBinder binder, object? value) { JsonNode? node = null; @@ -37,17 +39,17 @@ private bool TrySetMemberCallback(SetMemberBinder binder, object? value) return true; } - private static MethodInfo GetMethod(string name) => typeof(JsonObject).GetMethod( - name, BindingFlags.Instance | BindingFlags.NonPublic)!; + private const BindingFlags MemberInfoBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; private static MethodInfo? s_TryGetMember; internal override MethodInfo? TryGetMemberMethodInfo => - s_TryGetMember ?? - (s_TryGetMember = GetMethod(nameof(TryGetMemberCallback))); + s_TryGetMember ??= typeof(JsonObject).GetMethod(nameof(TryGetMemberCallback), MemberInfoBindingFlags); private static MethodInfo? s_TrySetMember; - internal override MethodInfo? TrySetMemberMethodInfo => - s_TrySetMember ?? - (s_TrySetMember = GetMethod(nameof(TrySetMemberCallback))); + internal override MethodInfo? TrySetMemberMethodInfo + { + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + get => s_TrySetMember ??= typeof(JsonObject).GetMethod(nameof(TrySetMemberCallback), MemberInfoBindingFlags); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs index db055815f97a01..c708101f3ccf38 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.CreateOverloads.cs @@ -10,7 +10,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(bool value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.BooleanConverter); @@ -18,7 +18,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(bool? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.BooleanConverter) : null; @@ -26,7 +26,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(byte value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.ByteConverter); @@ -34,7 +34,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(byte? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.ByteConverter) : null; @@ -42,7 +42,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(char value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.CharConverter); @@ -50,7 +50,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(char? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.CharConverter) : null; @@ -58,7 +58,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(DateTime value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DateTimeConverter); @@ -66,7 +66,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(DateTime? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DateTimeConverter) : null; @@ -74,7 +74,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(DateTimeOffset value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DateTimeOffsetConverter); @@ -82,7 +82,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(DateTimeOffset? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DateTimeOffsetConverter) : null; @@ -90,7 +90,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(decimal value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DecimalConverter); @@ -98,7 +98,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(decimal? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DecimalConverter) : null; @@ -106,7 +106,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(double value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.DoubleConverter); @@ -114,7 +114,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(double? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.DoubleConverter) : null; @@ -122,7 +122,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(Guid value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.GuidConverter); @@ -130,7 +130,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(Guid? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.GuidConverter) : null; @@ -138,7 +138,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(short value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.Int16Converter); @@ -146,7 +146,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(short? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.Int16Converter) : null; @@ -154,7 +154,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(int value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.Int32Converter); @@ -162,7 +162,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(int? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.Int32Converter) : null; @@ -170,7 +170,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(long value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.Int64Converter); @@ -178,7 +178,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(long? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.Int64Converter) : null; @@ -186,7 +186,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -195,7 +195,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -204,7 +204,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue Create(float value, JsonNodeOptions? options = null) => new JsonValueTrimmable(value, JsonMetadataServices.SingleConverter); @@ -212,7 +212,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(float? value, JsonNodeOptions? options = null) => value.HasValue ? new JsonValueTrimmable(value.Value, JsonMetadataServices.SingleConverter) : null; @@ -220,7 +220,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(string? value, JsonNodeOptions? options = null) => value != null ? new JsonValueTrimmable(value, JsonMetadataServices.StringConverter) : null; @@ -228,7 +228,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -237,7 +237,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -246,7 +246,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -255,7 +255,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -264,7 +264,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -273,7 +273,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. [CLSCompliantAttribute(false)] @@ -282,7 +282,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(JsonElement value, JsonNodeOptions? options = null) @@ -300,7 +300,7 @@ public partial class JsonValue /// /// Initializes a new instance of the class that contains the specified value. /// - /// The value to add. + /// The underlying value of the new instance. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(JsonElement? value, JsonNodeOptions? options = null) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs index fb5967e02dde17..1d0eb05631c47b 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValue.cs @@ -13,6 +13,8 @@ namespace System.Text.Json.Nodes /// public abstract partial class JsonValue : JsonNode { + internal const string CreateUnreferencedCodeMessage = "Creating JsonValue instances with non-primitive types is not compatible with trimming. It can result in non-primitive types being serialized, which may have their members trimmed."; + private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } /// @@ -25,7 +27,7 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } /// The value to create. /// Options to control the behavior. /// The new instance of the class that contains the specified value. - [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] + [RequiresUnreferencedCode(CreateUnreferencedCodeMessage + " Use the overload that takes a JsonTypeInfo, or make sure all of the required types are preserved.")] public static JsonValue? Create(T? value, JsonNodeOptions? options = null) { if (value == null) @@ -41,6 +43,8 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } } VerifyJsonElementIsNotArrayOrObject(ref element); + + return new JsonValueTrimmable(element, JsonMetadataServices.JsonElementConverter, options); } return new JsonValueNotTrimmable(value, options); @@ -54,7 +58,7 @@ private protected JsonValue(JsonNodeOptions? options = null) : base(options) { } /// /// The type of value to create. /// The value to create. - /// The that is later used to serialize the value. + /// The that will be used to serialize the value. /// Options to control the behavior. /// The new instance of the class that contains the specified value. public static JsonValue? Create(T? value, JsonTypeInfo jsonTypeInfo, JsonNodeOptions? options = null) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs index 41a7c3d5b35775..df596feb79a9d0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueNotTrimmable.cs @@ -10,10 +10,11 @@ namespace System.Text.Json.Nodes /// internal sealed partial class JsonValueNotTrimmable : JsonValue { + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] public JsonValueNotTrimmable(TValue value, JsonNodeOptions? options = null) : base(value, options) { } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "The methods used to create this JsonValue are marked RequiresUnreferencedCode.")] + Justification = "The ctor is marked with RequiresUnreferencedCode.")] public override void WriteTo(Utf8JsonWriter writer, JsonSerializerOptions? options = null) { if (writer == null) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/MetaDynamic.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/MetaDynamic.cs index 81175877cb0bc6..8806fe3035284c 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/MetaDynamic.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/MetaDynamic.cs @@ -3,10 +3,11 @@ using System.Collections.ObjectModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Dynamic; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; -using System.Dynamic; namespace System.Text.Json.Nodes { @@ -19,6 +20,8 @@ internal sealed class MetaDynamic : DynamicMetaObject private static readonly ConstantExpression Int1Expression = Expression.Constant((object)1); private JsonNode Dynamic { get; } + + [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] internal MetaDynamic(Expression expression, JsonNode dynamicObject) : base(expression, BindingRestrictions.Empty, dynamicObject) { @@ -41,6 +44,8 @@ public override DynamicMetaObject BindGetMember(GetMemberBinder binder) ); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The ctor is marked with RequiresUnreferencedCode.")] public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) { MethodInfo? methodInfo = Dynamic.TrySetMemberMethodInfo;