diff --git a/src/libraries/System.Data.Common/ref/System.Data.Common.cs b/src/libraries/System.Data.Common/ref/System.Data.Common.cs index a4bc1f651f202b..ce7de38a7aefd2 100644 --- a/src/libraries/System.Data.Common/ref/System.Data.Common.cs +++ b/src/libraries/System.Data.Common/ref/System.Data.Common.cs @@ -2095,6 +2095,7 @@ protected virtual void OnStateChange(System.Data.StateChangeEventArgs stateChang System.Data.IDbTransaction System.Data.IDbConnection.BeginTransaction(System.Data.IsolationLevel isolationLevel) { throw null; } System.Data.IDbCommand System.Data.IDbConnection.CreateCommand() { throw null; } } + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] public partial class DbConnectionStringBuilder : System.Collections.ICollection, System.Collections.IDictionary, System.Collections.IEnumerable, System.ComponentModel.ICustomTypeDescriptor { public DbConnectionStringBuilder() { } @@ -2130,6 +2131,7 @@ public virtual void Clear() { } protected internal void ClearPropertyDescriptors() { } public virtual bool ContainsKey(string keyword) { throw null; } public virtual bool EquivalentTo(System.Data.Common.DbConnectionStringBuilder connectionStringBuilder) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("PropertyDescriptor's PropertyType cannot be statically discovered.")] protected virtual void GetProperties(System.Collections.Hashtable propertyDescriptors) { } public virtual bool Remove(string keyword) { throw null; } public virtual bool ShouldSerialize(string keyword) { throw null; } diff --git a/src/libraries/System.Data.Common/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Data.Common/src/ILLink/ILLink.Suppressions.xml index ffcb7d78381c4e..3e47be79791de4 100644 --- a/src/libraries/System.Data.Common/src/ILLink/ILLink.Suppressions.xml +++ b/src/libraries/System.Data.Common/src/ILLink/ILLink.Suppressions.xml @@ -103,59 +103,5 @@ member M:System.Data.ProviderBase.SchemaMapping.SetupSchemaWithoutKeyInfo(System.Data.MissingMappingAction,System.Data.MissingSchemaAction,System.Boolean,System.Data.DataColumn,System.Object) - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.GetProperties(System.Collections.Hashtable) - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetAttributes - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetClassName - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetComponentName - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetConverter - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetDefaultEvent - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetDefaultProperty - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetEditor(System.Type) - - - ILLink - IL2026 - member - M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetEvents - diff --git a/src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs b/src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs index 3c3ac63548ef8a..027fe42f0b08ef 100644 --- a/src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs +++ b/src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs @@ -12,6 +12,7 @@ namespace System.Data.Common { + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] public class DbConnectionStringBuilder : IDictionary, ICustomTypeDescriptor { // keyword->value currently listed in the connection string @@ -387,6 +388,7 @@ internal Attribute[] GetAttributesFromCollection(AttributeCollection collection) return attributes; } + [RequiresUnreferencedCode("PropertyDescriptor's PropertyType cannot be statically discovered.")] private PropertyDescriptorCollection GetProperties() { PropertyDescriptorCollection? propertyDescriptors = _propertyDescriptors; @@ -412,11 +414,16 @@ private PropertyDescriptorCollection GetProperties() return propertyDescriptors; } + [RequiresUnreferencedCode("PropertyDescriptor's PropertyType cannot be statically discovered.")] protected virtual void GetProperties(Hashtable propertyDescriptors) { long logScopeId = DataCommonEventSource.Log.EnterScope(" {0}", ObjectID); try { + // Below call is necessary to tell the trimmer that it should mark derived types appropriately. + // We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor. + Type thisType = GetType(); + // show all strongly typed properties (not already added) // except ConnectionString iff BrowsableConnectionString Attribute[]? attributes; @@ -562,16 +569,28 @@ private PropertyDescriptorCollection GetProperties(Attribute[]? attributes) return new PropertyDescriptorCollection(filteredPropertiesArray); } -// TODO: Enable after System.ComponentModel.TypeConverter is annotated + // TODO-NULLABLE: Enable after System.ComponentModel.TypeConverter is annotated #nullable disable + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")] string ICustomTypeDescriptor.GetClassName() { + // Below call is necessary to tell the trimmer that it should mark derived types appropriately. + // We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor. + Type thisType = GetType(); return TypeDescriptor.GetClassName(this, true); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")] string ICustomTypeDescriptor.GetComponentName() { + // Below call is necessary to tell the trimmer that it should mark derived types appropriately. + // We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor. + Type thisType = GetType(); return TypeDescriptor.GetComponentName(this, true); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")] AttributeCollection ICustomTypeDescriptor.GetAttributes() { return TypeDescriptor.GetAttributes(this, true); @@ -606,8 +625,13 @@ EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { return TypeDescriptor.GetDefaultEvent(this, true); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")] EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { + // Below call is necessary to tell the trimmer that it should mark derived types appropriately. + // We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor. + Type thisType = GetType(); return TypeDescriptor.GetEvents(this, true); } [RequiresUnreferencedCode("The public parameterless constructor or the 'Default' static field may be trimmed from the Attribute's Type.")] diff --git a/src/libraries/System.Data.Common/tests/TrimmingTests/DbConnectionStringBuilder.cs b/src/libraries/System.Data.Common/tests/TrimmingTests/DbConnectionStringBuilder.cs new file mode 100644 index 00000000000000..78ac56e9f751a2 --- /dev/null +++ b/src/libraries/System.Data.Common/tests/TrimmingTests/DbConnectionStringBuilder.cs @@ -0,0 +1,159 @@ +// 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.Data.Common; +using System.ComponentModel; +using System.Collections; + +namespace DbConnectionStringBuilderTrimmingTests +{ + class Program + { + static int Main(string[] args) + { + DbConnectionStringBuilder2 dcsb2 = new(); + ICustomTypeDescriptor td = dcsb2; + + if (td.GetClassName() != "DbConnectionStringBuilderTrimmingTests.DbConnectionStringBuilder2") + { + throw new Exception("Class name got trimmed"); + } + + if (td.GetComponentName() != "Test Component Name") + { + throw new Exception("Component name got trimmed"); + } + + bool foundAttr = false; + + foreach (Attribute attr in td.GetAttributes()) + { + if (attr.GetType().Name == "TestAttribute") + { + if (attr.ToString() != "Test Attribute Value") + { + throw new Exception("Test attribute value differs"); + } + + if (foundAttr) + { + throw new Exception("More than one attribute found"); + } + + foundAttr = true; + } + } + + if (!foundAttr) + { + throw new Exception("Attribute not found"); + } + + bool foundEvent = false; + bool foundEventWithDisplayName = false; + + foreach (EventDescriptor ev in td.GetEvents()) + { + if (ev.DisplayName == "TestEvent") + { + if (foundEvent) + { + throw new Exception("More than one event TestEvent found."); + } + + foundEvent = true; + } + + if (ev.DisplayName == "Event With DisplayName") + { + if (foundEventWithDisplayName) + { + throw new Exception("More than one event with display name found."); + } + + foundEventWithDisplayName = true; + } + } + + if (!foundEvent) + { + throw new Exception("Event not found"); + } + + if (!foundEventWithDisplayName) + { + throw new Exception("Event with DisplayName not found"); + } + + bool propertyFound = false; + foreach (DictionaryEntry kv in dcsb2.GetProperties2()) + { + PropertyDescriptor val = (PropertyDescriptor)kv.Value; + if (val.Name == "TestProperty") + { + if (propertyFound) + { + throw new Exception("More than one property TestProperty found."); + } + + propertyFound = true; + } + } + + if (!propertyFound) + { + throw new Exception("Property not found"); + } + + return 100; + } + } + + [Test("Test Attribute Value")] + class DbConnectionStringBuilder2 : DbConnectionStringBuilder, IComponent + { +#pragma warning disable CS0067 // The event is never used + public event EventHandler Disposed; + public event Action TestEvent; + [DisplayName("Event With DisplayName")] + public event Action TestEvent2; +#pragma warning restore CS0067 + + public string TestProperty { get; set; } + public ISite Site { get => new TestSite(); set => throw new NotImplementedException(); } + public void Dispose() { } + + public Hashtable GetProperties2() + { + Hashtable propertyDescriptors = new Hashtable(); + GetProperties(propertyDescriptors); + return propertyDescriptors; + } + } + + class TestSite : INestedSite + { + public string FullName => null; + public IComponent Component => throw new NotImplementedException(); + public IContainer Container => throw new NotImplementedException(); + public bool DesignMode => throw new NotImplementedException(); + public string Name { get => "Test Component Name"; set => throw new NotImplementedException(); } + public object GetService(Type serviceType) => null; + } + + class TestAttribute : Attribute + { + public string Test { get; private set; } + + public TestAttribute(string test) + { + Test = test; + } + + public override string ToString() + { + return Test; + } + } +} diff --git a/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj b/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj index da4a46f2ae141a..7254c33fc9c7ba 100644 --- a/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj +++ b/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj @@ -1,5 +1,10 @@ + + + + +