Skip to content

Commit 2b7927f

Browse files
authored
Add ILLink annotations to S.D.Common related to DbConnectionStringBuilder (#54280)
* Add ILLink annotations to S.D.Common related to DbConnectionStringBuilder * address some feedback * Make GetEvents() safe * make GetProperties safe * Mark GetProperties with RUC
1 parent ea3f403 commit 2b7927f

File tree

5 files changed

+191
-55
lines changed

5 files changed

+191
-55
lines changed

src/libraries/System.Data.Common/ref/System.Data.Common.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2095,6 +2095,7 @@ protected virtual void OnStateChange(System.Data.StateChangeEventArgs stateChang
20952095
System.Data.IDbTransaction System.Data.IDbConnection.BeginTransaction(System.Data.IsolationLevel isolationLevel) { throw null; }
20962096
System.Data.IDbCommand System.Data.IDbConnection.CreateCommand() { throw null; }
20972097
}
2098+
[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)]
20982099
public partial class DbConnectionStringBuilder : System.Collections.ICollection, System.Collections.IDictionary, System.Collections.IEnumerable, System.ComponentModel.ICustomTypeDescriptor
20992100
{
21002101
public DbConnectionStringBuilder() { }
@@ -2130,6 +2131,7 @@ public virtual void Clear() { }
21302131
protected internal void ClearPropertyDescriptors() { }
21312132
public virtual bool ContainsKey(string keyword) { throw null; }
21322133
public virtual bool EquivalentTo(System.Data.Common.DbConnectionStringBuilder connectionStringBuilder) { throw null; }
2134+
[System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("PropertyDescriptor's PropertyType cannot be statically discovered.")]
21332135
protected virtual void GetProperties(System.Collections.Hashtable propertyDescriptors) { }
21342136
public virtual bool Remove(string keyword) { throw null; }
21352137
public virtual bool ShouldSerialize(string keyword) { throw null; }

src/libraries/System.Data.Common/src/ILLink/ILLink.Suppressions.xml

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -103,59 +103,5 @@
103103
<property name="Scope">member</property>
104104
<property name="Target">M:System.Data.ProviderBase.SchemaMapping.SetupSchemaWithoutKeyInfo(System.Data.MissingMappingAction,System.Data.MissingSchemaAction,System.Boolean,System.Data.DataColumn,System.Object)</property>
105105
</attribute>
106-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
107-
<argument>ILLink</argument>
108-
<argument>IL2026</argument>
109-
<property name="Scope">member</property>
110-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.GetProperties(System.Collections.Hashtable)</property>
111-
</attribute>
112-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
113-
<argument>ILLink</argument>
114-
<argument>IL2026</argument>
115-
<property name="Scope">member</property>
116-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetAttributes</property>
117-
</attribute>
118-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
119-
<argument>ILLink</argument>
120-
<argument>IL2026</argument>
121-
<property name="Scope">member</property>
122-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetClassName</property>
123-
</attribute>
124-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
125-
<argument>ILLink</argument>
126-
<argument>IL2026</argument>
127-
<property name="Scope">member</property>
128-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetComponentName</property>
129-
</attribute>
130-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
131-
<argument>ILLink</argument>
132-
<argument>IL2026</argument>
133-
<property name="Scope">member</property>
134-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetConverter</property>
135-
</attribute>
136-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
137-
<argument>ILLink</argument>
138-
<argument>IL2026</argument>
139-
<property name="Scope">member</property>
140-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetDefaultEvent</property>
141-
</attribute>
142-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
143-
<argument>ILLink</argument>
144-
<argument>IL2026</argument>
145-
<property name="Scope">member</property>
146-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetDefaultProperty</property>
147-
</attribute>
148-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
149-
<argument>ILLink</argument>
150-
<argument>IL2026</argument>
151-
<property name="Scope">member</property>
152-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetEditor(System.Type)</property>
153-
</attribute>
154-
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
155-
<argument>ILLink</argument>
156-
<argument>IL2026</argument>
157-
<property name="Scope">member</property>
158-
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetEvents</property>
159-
</attribute>
160106
</assembly>
161107
</linker>

src/libraries/System.Data.Common/src/System/Data/Common/DbConnectionStringBuilder.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
namespace System.Data.Common
1414
{
15+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
1516
public class DbConnectionStringBuilder : IDictionary, ICustomTypeDescriptor
1617
{
1718
// keyword->value currently listed in the connection string
@@ -387,6 +388,7 @@ internal Attribute[] GetAttributesFromCollection(AttributeCollection collection)
387388
return attributes;
388389
}
389390

391+
[RequiresUnreferencedCode("PropertyDescriptor's PropertyType cannot be statically discovered.")]
390392
private PropertyDescriptorCollection GetProperties()
391393
{
392394
PropertyDescriptorCollection? propertyDescriptors = _propertyDescriptors;
@@ -412,11 +414,16 @@ private PropertyDescriptorCollection GetProperties()
412414
return propertyDescriptors;
413415
}
414416

417+
[RequiresUnreferencedCode("PropertyDescriptor's PropertyType cannot be statically discovered.")]
415418
protected virtual void GetProperties(Hashtable propertyDescriptors)
416419
{
417420
long logScopeId = DataCommonEventSource.Log.EnterScope("<comm.DbConnectionStringBuilder.GetProperties|API> {0}", ObjectID);
418421
try
419422
{
423+
// Below call is necessary to tell the trimmer that it should mark derived types appropriately.
424+
// We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor.
425+
Type thisType = GetType();
426+
420427
// show all strongly typed properties (not already added)
421428
// except ConnectionString iff BrowsableConnectionString
422429
Attribute[]? attributes;
@@ -562,16 +569,28 @@ private PropertyDescriptorCollection GetProperties(Attribute[]? attributes)
562569
return new PropertyDescriptorCollection(filteredPropertiesArray);
563570
}
564571

565-
// TODO: Enable after System.ComponentModel.TypeConverter is annotated
572+
// TODO-NULLABLE: Enable after System.ComponentModel.TypeConverter is annotated
566573
#nullable disable
574+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
575+
Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")]
567576
string ICustomTypeDescriptor.GetClassName()
568577
{
578+
// Below call is necessary to tell the trimmer that it should mark derived types appropriately.
579+
// We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor.
580+
Type thisType = GetType();
569581
return TypeDescriptor.GetClassName(this, true);
570582
}
583+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
584+
Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")]
571585
string ICustomTypeDescriptor.GetComponentName()
572586
{
587+
// Below call is necessary to tell the trimmer that it should mark derived types appropriately.
588+
// We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor.
589+
Type thisType = GetType();
573590
return TypeDescriptor.GetComponentName(this, true);
574591
}
592+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
593+
Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")]
575594
AttributeCollection ICustomTypeDescriptor.GetAttributes()
576595
{
577596
return TypeDescriptor.GetAttributes(this, true);
@@ -606,8 +625,13 @@ EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
606625
{
607626
return TypeDescriptor.GetDefaultEvent(this, true);
608627
}
628+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
629+
Justification = "The type of component is statically known. This class is marked with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]")]
609630
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
610631
{
632+
// Below call is necessary to tell the trimmer that it should mark derived types appropriately.
633+
// We cannot use overload which takes type because the result might differ if derived class implements ICustomTypeDescriptor.
634+
Type thisType = GetType();
611635
return TypeDescriptor.GetEvents(this, true);
612636
}
613637
[RequiresUnreferencedCode("The public parameterless constructor or the 'Default' static field may be trimmed from the Attribute's Type.")]
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Data.Common;
6+
using System.ComponentModel;
7+
using System.Collections;
8+
9+
namespace DbConnectionStringBuilderTrimmingTests
10+
{
11+
class Program
12+
{
13+
static int Main(string[] args)
14+
{
15+
DbConnectionStringBuilder2 dcsb2 = new();
16+
ICustomTypeDescriptor td = dcsb2;
17+
18+
if (td.GetClassName() != "DbConnectionStringBuilderTrimmingTests.DbConnectionStringBuilder2")
19+
{
20+
throw new Exception("Class name got trimmed");
21+
}
22+
23+
if (td.GetComponentName() != "Test Component Name")
24+
{
25+
throw new Exception("Component name got trimmed");
26+
}
27+
28+
bool foundAttr = false;
29+
30+
foreach (Attribute attr in td.GetAttributes())
31+
{
32+
if (attr.GetType().Name == "TestAttribute")
33+
{
34+
if (attr.ToString() != "Test Attribute Value")
35+
{
36+
throw new Exception("Test attribute value differs");
37+
}
38+
39+
if (foundAttr)
40+
{
41+
throw new Exception("More than one attribute found");
42+
}
43+
44+
foundAttr = true;
45+
}
46+
}
47+
48+
if (!foundAttr)
49+
{
50+
throw new Exception("Attribute not found");
51+
}
52+
53+
bool foundEvent = false;
54+
bool foundEventWithDisplayName = false;
55+
56+
foreach (EventDescriptor ev in td.GetEvents())
57+
{
58+
if (ev.DisplayName == "TestEvent")
59+
{
60+
if (foundEvent)
61+
{
62+
throw new Exception("More than one event TestEvent found.");
63+
}
64+
65+
foundEvent = true;
66+
}
67+
68+
if (ev.DisplayName == "Event With DisplayName")
69+
{
70+
if (foundEventWithDisplayName)
71+
{
72+
throw new Exception("More than one event with display name found.");
73+
}
74+
75+
foundEventWithDisplayName = true;
76+
}
77+
}
78+
79+
if (!foundEvent)
80+
{
81+
throw new Exception("Event not found");
82+
}
83+
84+
if (!foundEventWithDisplayName)
85+
{
86+
throw new Exception("Event with DisplayName not found");
87+
}
88+
89+
bool propertyFound = false;
90+
foreach (DictionaryEntry kv in dcsb2.GetProperties2())
91+
{
92+
PropertyDescriptor val = (PropertyDescriptor)kv.Value;
93+
if (val.Name == "TestProperty")
94+
{
95+
if (propertyFound)
96+
{
97+
throw new Exception("More than one property TestProperty found.");
98+
}
99+
100+
propertyFound = true;
101+
}
102+
}
103+
104+
if (!propertyFound)
105+
{
106+
throw new Exception("Property not found");
107+
}
108+
109+
return 100;
110+
}
111+
}
112+
113+
[Test("Test Attribute Value")]
114+
class DbConnectionStringBuilder2 : DbConnectionStringBuilder, IComponent
115+
{
116+
#pragma warning disable CS0067 // The event is never used
117+
public event EventHandler Disposed;
118+
public event Action TestEvent;
119+
[DisplayName("Event With DisplayName")]
120+
public event Action TestEvent2;
121+
#pragma warning restore CS0067
122+
123+
public string TestProperty { get; set; }
124+
public ISite Site { get => new TestSite(); set => throw new NotImplementedException(); }
125+
public void Dispose() { }
126+
127+
public Hashtable GetProperties2()
128+
{
129+
Hashtable propertyDescriptors = new Hashtable();
130+
GetProperties(propertyDescriptors);
131+
return propertyDescriptors;
132+
}
133+
}
134+
135+
class TestSite : INestedSite
136+
{
137+
public string FullName => null;
138+
public IComponent Component => throw new NotImplementedException();
139+
public IContainer Container => throw new NotImplementedException();
140+
public bool DesignMode => throw new NotImplementedException();
141+
public string Name { get => "Test Component Name"; set => throw new NotImplementedException(); }
142+
public object GetService(Type serviceType) => null;
143+
}
144+
145+
class TestAttribute : Attribute
146+
{
147+
public string Test { get; private set; }
148+
149+
public TestAttribute(string test)
150+
{
151+
Test = test;
152+
}
153+
154+
public override string ToString()
155+
{
156+
return Test;
157+
}
158+
}
159+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<Project DefaultTargets="Build">
22
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" />
33

4+
<ItemGroup>
5+
<TestConsoleAppSourceFiles Include="CreateSqlXmlReader.cs" />
6+
<TestConsoleAppSourceFiles Include="DbConnectionStringBuilder.cs" />
7+
</ItemGroup>
8+
49
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.targets))" />
510
</Project>

0 commit comments

Comments
 (0)