Resolve ILLink warnings in System.ComponentModel.Annotations (#49901)
authorEric Erhardt <eric.erhardt@microsoft.com>
Wed, 24 Mar 2021 13:33:38 +0000 (08:33 -0500)
committerGitHub <noreply@github.com>
Wed, 24 Mar 2021 13:33:38 +0000 (09:33 -0400)
* Resolve ILLink warnings in System.ComponentModel.Annotations

Contributes to #45623

* PR feedback

13 files changed:
src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
src/libraries/System.ComponentModel.Annotations/src/ILLink/ILLink.Suppressions.xml [deleted file]
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/CompareAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/CustomValidationAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/DisplayAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/DisplayFormatAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/LocalizableString.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/MaxLengthAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/MinLengthAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/ValidationAttribute.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/ValidationAttributeStore.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/ValidationContext.cs
src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/Validator.cs

index d898cdd..2bc7c17 100644 (file)
@@ -30,6 +30,7 @@ namespace System.ComponentModel.DataAnnotations
     [System.AttributeUsageAttribute(System.AttributeTargets.Property, AllowMultiple=false)]
     public partial class CompareAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
     {
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The property referenced by 'otherProperty' may be trimmed. Ensure it is preserved.")]
         public CompareAttribute(string otherProperty) { }
         public string OtherProperty { get { throw null; } }
         public string? OtherPropertyDisplayName { get { throw null; } }
@@ -51,8 +52,9 @@ namespace System.ComponentModel.DataAnnotations
     [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Field | System.AttributeTargets.Method | System.AttributeTargets.Parameter | System.AttributeTargets.Property, AllowMultiple=true)]
     public sealed partial class CustomValidationAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
     {
-        public CustomValidationAttribute(System.Type validatorType, string method) { }
+        public CustomValidationAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)] System.Type validatorType, string method) { }
         public string Method { get { throw null; } }
+        [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods)]
         public System.Type ValidatorType { get { throw null; } }
         public override string FormatErrorMessage(string name) { throw null; }
         protected override System.ComponentModel.DataAnnotations.ValidationResult? IsValid(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { throw null; }
@@ -99,6 +101,7 @@ namespace System.ComponentModel.DataAnnotations
         public string? Name { get { throw null; } set { } }
         public int Order { get { throw null; } set { } }
         public string? Prompt { get { throw null; } set { } }
+        [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
         public System.Type? ResourceType { get { throw null; } set { } }
         public string? ShortName { get { throw null; } set { } }
         public bool? GetAutoGenerateField() { throw null; }
@@ -129,6 +132,7 @@ namespace System.ComponentModel.DataAnnotations
         public string? DataFormatString { get { throw null; } set { } }
         public bool HtmlEncode { get { throw null; } set { } }
         public string? NullDisplayText { get { throw null; } set { } }
+        [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
         public System.Type? NullDisplayTextResourceType { get { throw null; } set { } }
         public string? GetNullDisplayText() { throw null; }
     }
@@ -185,7 +189,9 @@ namespace System.ComponentModel.DataAnnotations
     [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.Property, AllowMultiple=false)]
     public partial class MaxLengthAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
     {
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved.")]
         public MaxLengthAttribute() { }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved.")]
         public MaxLengthAttribute(int length) { }
         public int Length { get { throw null; } }
         public override string FormatErrorMessage(string name) { throw null; }
@@ -201,6 +207,7 @@ namespace System.ComponentModel.DataAnnotations
     [System.AttributeUsageAttribute(System.AttributeTargets.Field | System.AttributeTargets.Parameter | System.AttributeTargets.Property, AllowMultiple=false)]
     public partial class MinLengthAttribute : System.ComponentModel.DataAnnotations.ValidationAttribute
     {
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved.")]
         public MinLengthAttribute(int length) { }
         public int Length { get { throw null; } }
         public override string FormatErrorMessage(string name) { throw null; }
@@ -289,6 +296,7 @@ namespace System.ComponentModel.DataAnnotations
         protected ValidationAttribute(string errorMessage) { }
         public string? ErrorMessage { get { throw null; } set { } }
         public string? ErrorMessageResourceName { get { throw null; } set { } }
+        [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicProperties | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties)]
         public System.Type? ErrorMessageResourceType { get { throw null; } set { } }
         protected string ErrorMessageString { get { throw null; } }
         public virtual bool RequiresValidationContext { get { throw null; } }
@@ -301,8 +309,11 @@ namespace System.ComponentModel.DataAnnotations
     }
     public sealed partial class ValidationContext : System.IServiceProvider
     {
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public ValidationContext(object instance) { }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public ValidationContext(object instance, System.Collections.Generic.IDictionary<object, object?>? items) { }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public ValidationContext(object instance, System.IServiceProvider? serviceProvider, System.Collections.Generic.IDictionary<object, object?>? items) { }
         public string DisplayName { get { throw null; } set { } }
         public System.Collections.Generic.IDictionary<object, object?> Items { get { throw null; } }
@@ -336,12 +347,18 @@ namespace System.ComponentModel.DataAnnotations
     }
     public static partial class Validator
     {
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public static bool TryValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection<System.ComponentModel.DataAnnotations.ValidationResult>? validationResults) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public static bool TryValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection<System.ComponentModel.DataAnnotations.ValidationResult>? validationResults, bool validateAllProperties) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of validationContext.ObjectType cannot be statically discovered.")]
         public static bool TryValidateProperty(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection<System.ComponentModel.DataAnnotations.ValidationResult>? validationResults) { throw null; }
         public static bool TryValidateValue(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.ICollection<System.ComponentModel.DataAnnotations.ValidationResult>? validationResults, System.Collections.Generic.IEnumerable<System.ComponentModel.DataAnnotations.ValidationAttribute> validationAttributes) { throw null; }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public static void ValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of instance cannot be statically discovered.")]
         public static void ValidateObject(object instance, System.ComponentModel.DataAnnotations.ValidationContext validationContext, bool validateAllProperties) { }
+        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The Type of validationContext.ObjectType cannot be statically discovered.")]
         public static void ValidateProperty(object? value, System.ComponentModel.DataAnnotations.ValidationContext validationContext) { }
         public static void ValidateValue(object value, System.ComponentModel.DataAnnotations.ValidationContext validationContext, System.Collections.Generic.IEnumerable<System.ComponentModel.DataAnnotations.ValidationAttribute> validationAttributes) { }
     }
diff --git a/src/libraries/System.ComponentModel.Annotations/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.ComponentModel.Annotations/src/ILLink/ILLink.Suppressions.xml
deleted file mode 100644 (file)
index acf0ec2..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<linker>
-  <assembly fullname="System.ComponentModel.Annotations, PublicKeyToken=b03f5f7f11d50a3a">
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2072</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.CompareAttribute.IsValid(System.Object,System.ComponentModel.DataAnnotations.ValidationContext)</property>
-    </attribute>
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2072</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.CountPropertyHelper.TryGetCount(System.Object,System.Int32@)</property>
-    </attribute>
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2072</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.CustomValidationAttribute.ValidateMethodParameter</property>
-    </attribute>
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2072</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.Validator.GetPropertyValues(System.Object,System.ComponentModel.DataAnnotations.ValidationContext)</property>
-    </attribute>
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2077</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.LocalizableString.GetLocalizableValue</property>
-    </attribute>
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2077</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.ValidationAttributeStore.TypeStoreItem.CreatePropertyStoreItems</property>
-    </attribute>
-    <attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
-      <argument>ILLink</argument>
-      <argument>IL2080</argument>
-      <property name="Scope">member</property>
-      <property name="Target">M:System.ComponentModel.DataAnnotations.ValidationAttribute.SetResourceAccessorByPropertyLookup</property>
-    </attribute>
-  </assembly>
-</linker>
index ec7caa4..cd995d2 100644 (file)
@@ -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.Globalization;
 using System.Linq;
 using System.Reflection;
@@ -10,6 +11,7 @@ namespace System.ComponentModel.DataAnnotations
     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
     public class CompareAttribute : ValidationAttribute
     {
+        [RequiresUnreferencedCode("The property referenced by 'otherProperty' may be trimmed. Ensure it is preserved.")]
         public CompareAttribute(string otherProperty) : base(SR.CompareAttribute_MustMatch)
         {
             OtherProperty = otherProperty ?? throw new ArgumentNullException(nameof(otherProperty));
@@ -25,6 +27,8 @@ namespace System.ComponentModel.DataAnnotations
             string.Format(
                 CultureInfo.CurrentCulture, ErrorMessageString, name, OtherPropertyDisplayName ?? OtherProperty);
 
+        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:UnrecognizedReflectionPattern",
+            Justification = "The ctor is marked with RequiresUnreferencedCode informing the caller to preserve the other property.")]
         protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
         {
             var otherPropertyInfo = validationContext.ObjectType.GetRuntimeProperty(OtherProperty);
index 67c7077..73684d7 100644 (file)
@@ -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.Globalization;
 using System.Linq;
 using System.Reflection;
@@ -83,7 +84,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     <see cref="Method" />.
         /// </param>
         /// <param name="method">The name of the method to invoke in <paramref name="validatorType" />.</param>
-        public CustomValidationAttribute(Type validatorType, string method)
+        public CustomValidationAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type validatorType, string method)
             : base(() => SR.CustomValidationAttribute_ValidationError)
         {
             ValidatorType = validatorType;
@@ -98,6 +99,7 @@ namespace System.ComponentModel.DataAnnotations
         /// <summary>
         ///     Gets the type that contains the validation method identified by <see cref="Method" />.
         /// </summary>
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
         public Type ValidatorType { get; }
 
         /// <summary>
@@ -250,9 +252,8 @@ namespace System.ComponentModel.DataAnnotations
             }
 
             // Named method must be public and static
-            var methodInfo = ValidatorType.GetRuntimeMethods()
-                .SingleOrDefault(m => string.Equals(m.Name, Method, StringComparison.Ordinal)
-                                    && m.IsPublic && m.IsStatic);
+            var methodInfo = ValidatorType.GetMethods(BindingFlags.Public | BindingFlags.Static)
+                .SingleOrDefault(m => string.Equals(m.Name, Method, StringComparison.Ordinal));
             if (methodInfo == null)
             {
                 return SR.Format(SR.CustomValidationAttribute_Method_Not_Found, Method, ValidatorType.Name);
index 2d8b11f..e88df44 100644 (file)
@@ -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.Globalization;
 
 namespace System.ComponentModel.DataAnnotations
@@ -25,6 +26,8 @@ namespace System.ComponentModel.DataAnnotations
         private bool? _autoGenerateField;
         private bool? _autoGenerateFilter;
         private int? _order;
+
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
         private Type? _resourceType;
 
         #endregion
@@ -167,6 +170,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     <see cref="GetName" />, <see cref="GetDescription" />, <see cref="GetPrompt" />, and <see cref="GetGroupName" />
         ///     methods to return localized values.
         /// </summary>
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
         public Type? ResourceType
         {
             get => _resourceType;
index 96a82b0..9bc7650 100644 (file)
@@ -1,6 +1,8 @@
 // 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;
+
 namespace System.ComponentModel.DataAnnotations
 {
     /// <summary>
@@ -72,6 +74,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     Using <see cref="NullDisplayTextResourceType" /> along with <see cref="NullDisplayText" />, allows the <see cref="GetNullDisplayText" />
         ///     method to return localized values.
         /// </summary>
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
         public Type? NullDisplayTextResourceType
         {
             get => _nullDisplayText.ResourceType;
index 5c8dfca..ff7adc8 100644 (file)
@@ -1,7 +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.Globalization;
+using System.Diagnostics.CodeAnalysis;
 using System.Reflection;
 
 namespace System.ComponentModel.DataAnnotations
@@ -17,6 +17,7 @@ namespace System.ComponentModel.DataAnnotations
         private readonly string _propertyName;
         private Func<string?>? _cachedResult;
         private string? _propertyValue;
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
         private Type? _resourceType;
 
         #endregion
@@ -62,6 +63,7 @@ namespace System.ComponentModel.DataAnnotations
         /// <summary>
         ///     Gets or sets the resource type to be used for localization.
         /// </summary>
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
         public Type? ResourceType
         {
             get => _resourceType;
index 903112d..483d76c 100644 (file)
@@ -3,6 +3,7 @@
 
 using System.Collections;
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.Reflection;
 
@@ -24,6 +25,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     The maximum allowable length of collection/string data.
         ///     Value must be greater than zero.
         /// </param>
+        [RequiresUnreferencedCode(CountPropertyHelper.RequiresUnreferencedCodeMessage)]
         public MaxLengthAttribute(int length)
             : base(() => DefaultErrorMessageString)
         {
@@ -34,6 +36,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     Initializes a new instance of the <see cref="MaxLengthAttribute" /> class.
         ///     The maximum allowable length supported by the database will be used.
         /// </summary>
+        [RequiresUnreferencedCode(CountPropertyHelper.RequiresUnreferencedCodeMessage)]
         public MaxLengthAttribute()
             : base(() => DefaultErrorMessageString)
         {
@@ -59,6 +62,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     <c>true</c> if the value is null or less than or equal to the specified maximum length, otherwise <c>false</c>
         /// </returns>
         /// <exception cref="InvalidOperationException">Length is zero or less than negative one.</exception>
+        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The ctors are marked with RequiresUnreferencedCode.")]
         public override bool IsValid(object? value)
         {
             // Check the lengths for legality
@@ -110,6 +114,9 @@ namespace System.ComponentModel.DataAnnotations
 
     internal static class CountPropertyHelper
     {
+        internal const string RequiresUnreferencedCodeMessage = "Uses reflection to get the 'Count' property on types that don't implement ICollection. This 'Count' property may be trimmed. Ensure it is preserved.";
+
+        [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
         public static bool TryGetCount(object value, out int count)
         {
             Debug.Assert(value != null);
index 7b0e09f..8171f65 100644 (file)
@@ -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.Globalization;
 
 namespace System.ComponentModel.DataAnnotations
@@ -19,6 +20,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     The minimum allowable length of collection/string data.
         ///     Value must be greater than or equal to zero.
         /// </param>
+        [RequiresUnreferencedCode(CountPropertyHelper.RequiresUnreferencedCodeMessage)]
         public MinLengthAttribute(int length)
             : base(SR.MinLengthAttribute_ValidationError)
         {
@@ -43,6 +45,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     <c>false</c>
         /// </returns>
         /// <exception cref="InvalidOperationException">Length is less than zero.</exception>
+        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The ctor is marked with RequiresUnreferencedCode.")]
         public override bool IsValid(object? value)
         {
             // Check the lengths for legality
index eedd0de..2202c0d 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.Reflection;
 
@@ -25,6 +26,7 @@ namespace System.ComponentModel.DataAnnotations
         private string? _errorMessage;
         private Func<string>? _errorMessageResourceAccessor;
         private string? _errorMessageResourceName;
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
         private Type? _errorMessageResourceType;
         private volatile bool _hasBaseIsValid;
         private string? _defaultErrorMessage;
@@ -175,6 +177,7 @@ namespace System.ComponentModel.DataAnnotations
         ///         Use <see cref="ErrorMessage" /> instead of this pair if error messages are not localized.
         ///     </para>
         /// </value>
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
         public Type? ErrorMessageResourceType
         {
             get => _errorMessageResourceType;
index 8210a65..b53562e 100644 (file)
@@ -32,6 +32,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="validationContext">The context that describes the type.  It cannot be null.</param>
         /// <returns>The collection of validation attributes.  It could be empty.</returns>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         internal IEnumerable<ValidationAttribute> GetTypeValidationAttributes(ValidationContext validationContext)
         {
             EnsureValidationContext(validationContext);
@@ -44,6 +45,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="validationContext">The context that describes the type.  It cannot be null.</param>
         /// <returns>The display attribute instance, if present.</returns>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         internal DisplayAttribute? GetTypeDisplayAttribute(ValidationContext validationContext)
         {
             EnsureValidationContext(validationContext);
@@ -56,6 +58,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="validationContext">The context that describes the property.  It cannot be null.</param>
         /// <returns>The collection of validation attributes.  It could be empty.</returns>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         internal IEnumerable<ValidationAttribute> GetPropertyValidationAttributes(ValidationContext validationContext)
         {
             EnsureValidationContext(validationContext);
@@ -69,6 +72,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="validationContext">The context that describes the property.  It cannot be null.</param>
         /// <returns>The display attribute instance, if present.</returns>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         internal DisplayAttribute? GetPropertyDisplayAttribute(ValidationContext validationContext)
         {
             EnsureValidationContext(validationContext);
@@ -82,6 +86,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="validationContext">The context that describes the property.  It cannot be null.</param>
         /// <returns>The type of the specified property</returns>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         internal Type GetPropertyType(ValidationContext validationContext)
         {
             EnsureValidationContext(validationContext);
@@ -97,6 +102,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="validationContext">The <see cref="ValidationContext" /> to check.</param>
         /// <returns><c>true</c> when the <paramref name="validationContext" /> represents a property, <c>false</c> otherwise.</returns>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         internal bool IsPropertyContext(ValidationContext validationContext)
         {
             EnsureValidationContext(validationContext);
@@ -110,7 +116,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="type">The type whose store item is needed.  It cannot be null</param>
         /// <returns>The type store item.  It will not be null.</returns>
-        private TypeStoreItem GetTypeStoreItem(Type type)
+        private TypeStoreItem GetTypeStoreItem([DynamicallyAccessedMembers(TypeStoreItem.DynamicallyAccessedTypes)] Type type)
         {
             Debug.Assert(type != null);
 
@@ -167,11 +173,14 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         private sealed class TypeStoreItem : StoreItem
         {
+            internal const DynamicallyAccessedMemberTypes DynamicallyAccessedTypes = DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties;
+
             private readonly object _syncRoot = new object();
+            [DynamicallyAccessedMembers(DynamicallyAccessedTypes)]
             private readonly Type _type;
             private Dictionary<string, PropertyStoreItem>? _propertyStoreItems;
 
-            internal TypeStoreItem(Type type, IEnumerable<Attribute> attributes)
+            internal TypeStoreItem([DynamicallyAccessedMembers(DynamicallyAccessedTypes)] Type type, IEnumerable<Attribute> attributes)
                 : base(attributes)
             {
                 _type = type;
index f12578a..f670db0 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
 
 namespace System.ComponentModel.DataAnnotations
 {
@@ -26,6 +27,8 @@ namespace System.ComponentModel.DataAnnotations
         // Also we use this ability in Validator.CreateValidationContext()??
         : IServiceProvider
     {
+        internal const string InstanceTypeNotStaticallyDiscovered = "The Type of instance cannot be statically discovered.";
+
         #region Member Fields
 
         private readonly Dictionary<object, object?> _items;
@@ -41,6 +44,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </summary>
         /// <param name="instance">The object instance being validated.  It cannot be <c>null</c>.</param>
         /// <exception cref="ArgumentNullException">When <paramref name="instance" /> is <c>null</c></exception>
+        [RequiresUnreferencedCode(InstanceTypeNotStaticallyDiscovered)]
         public ValidationContext(object instance)
             : this(instance, null, null)
         {
@@ -57,6 +61,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     new dictionary, preventing consumers from modifying the original dictionary.
         /// </param>
         /// <exception cref="ArgumentNullException">When <paramref name="instance" /> is <c>null</c></exception>
+        [RequiresUnreferencedCode(InstanceTypeNotStaticallyDiscovered)]
         public ValidationContext(object instance, IDictionary<object, object?>? items)
             : this(instance, null, items)
         {
@@ -78,6 +83,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     new dictionary, preventing consumers from modifying the original dictionary.
         /// </param>
         /// <exception cref="ArgumentNullException">When <paramref name="instance" /> is <c>null</c></exception>
+        [RequiresUnreferencedCode(InstanceTypeNotStaticallyDiscovered)]
         public ValidationContext(object instance, IServiceProvider? serviceProvider, IDictionary<object, object?>? items)
         {
             if (instance == null)
@@ -174,6 +180,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     Looks up the display name using the DisplayAttribute attached to the respective type or property.
         /// </summary>
         /// <returns>A display-friendly name of the member represented by the <see cref="MemberName" />.</returns>
+        [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "The ctors are marked with RequiresUnreferencedCode.")]
         private string? GetDisplayName()
         {
             string? displayName = null;
index c756f49..d9a874e 100644 (file)
@@ -47,6 +47,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     When the <see cref="ValidationContext.MemberName" /> of <paramref name="validationContext" /> is not a valid
         ///     property.
         /// </exception>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         public static bool TryValidateProperty(object? value, ValidationContext validationContext,
             ICollection<ValidationResult>? validationResults)
         {
@@ -92,6 +93,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     When <paramref name="instance" /> doesn't match the
         ///     <see cref="ValidationContext.ObjectInstance" />on <paramref name="validationContext" />.
         /// </exception>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         public static bool TryValidateObject(
             object instance, ValidationContext validationContext, ICollection<ValidationResult>? validationResults) =>
             TryValidateObject(instance, validationContext, validationResults, false /*validateAllProperties*/);
@@ -129,6 +131,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     When <paramref name="instance" /> doesn't match the
         ///     <see cref="ValidationContext.ObjectInstance" />on <paramref name="validationContext" />.
         /// </exception>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         public static bool TryValidateObject(object instance, ValidationContext validationContext,
             ICollection<ValidationResult>? validationResults, bool validateAllProperties)
         {
@@ -212,6 +215,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </param>
         /// <exception cref="ArgumentNullException">When <paramref name="validationContext" /> is null.</exception>
         /// <exception cref="ValidationException">When <paramref name="value" /> is invalid for this property.</exception>
+        [RequiresUnreferencedCode("The Type of validationContext.ObjectType cannot be statically discovered.")]
         public static void ValidateProperty(object? value, ValidationContext validationContext)
         {
             // Throw if value cannot be assigned to this property.  That is not a validation exception.
@@ -242,6 +246,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     <see cref="ValidationContext.ObjectInstance" /> on <paramref name="validationContext" />.
         /// </exception>
         /// <exception cref="ValidationException">When <paramref name="instance" /> is found to be invalid.</exception>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         public static void ValidateObject(object instance, ValidationContext validationContext)
         {
             ValidateObject(instance, validationContext, false /*validateAllProperties*/);
@@ -267,6 +272,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     <see cref="ValidationContext.ObjectInstance" /> on <paramref name="validationContext" />.
         /// </exception>
         /// <exception cref="ValidationException">When <paramref name="instance" /> is found to be invalid.</exception>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         public static void ValidateObject(object instance, ValidationContext validationContext,
             bool validateAllProperties)
         {
@@ -325,6 +331,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </param>
         /// <returns>A new <see cref="ValidationContext" /> for the <paramref name="instance" /> provided.</returns>
         /// <exception cref="ArgumentNullException">When <paramref name="validationContext" /> is null.</exception>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         private static ValidationContext CreateValidationContext(object instance, ValidationContext validationContext)
         {
             Debug.Assert(validationContext != null);
@@ -391,6 +398,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     When <paramref name="instance" /> doesn't match the
         ///     <see cref="ValidationContext.ObjectInstance" /> on <paramref name="validationContext" />.
         /// </exception>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         private static IEnumerable<ValidationError> GetObjectValidationErrors(object instance,
             ValidationContext validationContext, bool validateAllProperties, bool breakOnFirstError)
         {
@@ -450,6 +458,7 @@ namespace System.ComponentModel.DataAnnotations
         /// </param>
         /// <param name="breakOnFirstError">Whether to break on the first error or validate everything.</param>
         /// <returns>A list of <see cref="ValidationError" /> instances.</returns>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         private static IEnumerable<ValidationError> GetObjectPropertyValidationErrors(object instance,
             ValidationContext validationContext, bool validateAllProperties, bool breakOnFirstError)
         {
@@ -501,6 +510,7 @@ namespace System.ComponentModel.DataAnnotations
         ///     value.
         /// </returns>
         /// <remarks>Ignores indexed properties.</remarks>
+        [RequiresUnreferencedCode(ValidationContext.InstanceTypeNotStaticallyDiscovered)]
         private static ICollection<KeyValuePair<ValidationContext, object?>> GetPropertyValues(object instance,
             ValidationContext validationContext)
         {