Annotate TypeConverterAttribute so that the ILLinker preserves the ctor on the conver...
authorLayomi Akinrinade <laakinri@microsoft.com>
Fri, 24 Jul 2020 00:54:19 +0000 (17:54 -0700)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2020 00:54:19 +0000 (17:54 -0700)
* Annotate TypeConverterAttribute so that the ILLinker preserves the ctor on the converter

* Address review feedback & add attributes to ref

* Use custom enum converter type

* Split tests

src/libraries/System.ObjectModel/ref/System.ObjectModel.cs
src/libraries/System.ObjectModel/src/System/ComponentModel/TypeConverterAttribute.cs
src/libraries/System.ObjectModel/tests/TrimmingTests/TypeConverterAttributeStringArgCtorTest.cs [new file with mode: 0644]
src/libraries/System.ObjectModel/tests/TrimmingTests/TypeConverterAttributeTypeArgCtorTest.cs [new file with mode: 0644]

index 6761a30..e29b22b 100644 (file)
@@ -198,8 +198,9 @@ namespace System.ComponentModel
     {
         public static readonly System.ComponentModel.TypeConverterAttribute Default;
         public TypeConverterAttribute() { }
-        public TypeConverterAttribute(string typeName) { }
-        public TypeConverterAttribute(System.Type type) { }
+        public TypeConverterAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] string typeName) { }
+        public TypeConverterAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type type) { }
+        [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)]
         public string ConverterTypeName { get { throw null; } }
         public override bool Equals(object? obj) { throw null; }
         public override int GetHashCode() { throw null; }
index 0d44850..df6569a 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
 {
     /// <summary>
@@ -30,7 +32,7 @@ namespace System.ComponentModel
         /// class, using the specified type as the data converter for the object this attribute
         /// is bound to.
         /// </summary>
-        public TypeConverterAttribute(Type type)
+        public TypeConverterAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type)
         {
             if (type == null)
             {
@@ -45,7 +47,7 @@ namespace System.ComponentModel
         /// class, using the specified type name as the data converter for the object this attribute
         /// is bound to.
         /// </summary>
-        public TypeConverterAttribute(string typeName)
+        public TypeConverterAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] string typeName)
         {
             if (typeName == null)
             {
@@ -59,6 +61,7 @@ namespace System.ComponentModel
         /// Gets the fully qualified type name of the <see cref='System.Type'/> to use as a
         /// converter for the object this attribute is bound to.
         /// </summary>
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
         public string ConverterTypeName { get; }
 
         public override bool Equals(object? obj)
diff --git a/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeConverterAttributeStringArgCtorTest.cs b/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeConverterAttributeStringArgCtorTest.cs
new file mode 100644 (file)
index 0000000..4803dce
--- /dev/null
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+
+namespace TypeConverterAttributeTest
+{
+    /// <summary>
+    /// Tests that the public constructors of types passed into System.ComponentModel.TypeConverterAttribute
+    /// are not trimmed out when needed in a trimmed application.
+    /// </summary>
+    class Program
+    {
+        static int Main(string[] args)
+        {
+            // String-based TypeConverterAttribute ctor overload, ensure public parameterless ctor of TypeConverter type is preserved.
+            TypeDescriptor.AddAttributes(typeof(string), new TypeConverterAttribute("TypeConverterAttributeTest.MyStringConverter, project, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"));
+            var attribute = new DefaultValueAttribute(typeof(string), "Hello, world!");
+            return (string)attribute.Value == "Hello, world!trivia" ? 100 : -1;
+        }
+    }
+
+    internal class MyStringConverter : StringConverter
+    {
+        /// <summary>
+        /// Converts the specified value object to a string object.
+        /// </summary>
+        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+        {
+            if (value is string str)
+            {
+                return str + "trivia";
+            }
+
+            throw new NotSupportedException();
+        }
+    }
+}
diff --git a/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeConverterAttributeTypeArgCtorTest.cs b/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeConverterAttributeTypeArgCtorTest.cs
new file mode 100644 (file)
index 0000000..bfa67dd
--- /dev/null
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+
+namespace TypeConverterAttributeTest
+{
+    /// <summary>
+    /// Tests that the public constructors of types passed into System.ComponentModel.TypeConverterAttribute
+    /// are not trimmed out when needed in a trimmed application.
+    /// </summary>
+    class Program
+    {
+        static int Main(string[] args)
+        {
+            // Type-based TypeConverterAttribute ctor overload, ensure public parameterized ctor of TypeConverter type is preserved.
+            TypeDescriptor.AddAttributes(typeof(DayOfWeek), new TypeConverterAttribute(typeof(MyDayOfWeekConverter)));
+            var attribute = new DefaultValueAttribute(typeof(DayOfWeek), "Friday");
+            return (DayOfWeek)attribute.Value == DayOfWeek.Monday ? 100 : -1;
+        }
+    }
+
+    internal class MyDayOfWeekConverter : TypeConverter
+    {
+        private readonly Type _type;
+
+        public MyDayOfWeekConverter(Type type)
+        {
+            _type = type;
+        }
+
+        /// <summary>
+        /// Converts the specified value object to a DayOfWeek value.
+        /// </summary>
+        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+        {
+            if (_type == typeof(DayOfWeek) && value is string str && str == "Friday")
+            {
+                return DayOfWeek.Monday;
+            }
+
+            throw new NotSupportedException();
+        }
+    }
+}