Skip to content

Commit

Permalink
Add ILLink annotations to S.D.Common related to DbConnectionStringBui…
Browse files Browse the repository at this point in the history
…lder (#54280)

* Add ILLink annotations to S.D.Common related to DbConnectionStringBuilder

* address some feedback

* Make GetEvents() safe

* make GetProperties safe

* Mark GetProperties with RUC
  • Loading branch information
krwq authored Jun 23, 2021
1 parent ea3f403 commit 2b7927f
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 55 deletions.
2 changes: 2 additions & 0 deletions src/libraries/System.Data.Common/ref/System.Data.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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() { }
Expand Down Expand Up @@ -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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,59 +103,5 @@
<property name="Scope">member</property>
<property name="Target">M:System.Data.ProviderBase.SchemaMapping.SetupSchemaWithoutKeyInfo(System.Data.MissingMappingAction,System.Data.MissingSchemaAction,System.Boolean,System.Data.DataColumn,System.Object)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.GetProperties(System.Collections.Hashtable)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetAttributes</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetClassName</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetComponentName</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetConverter</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetDefaultEvent</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetDefaultProperty</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetEditor(System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2026</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Data.Common.DbConnectionStringBuilder.System#ComponentModel#ICustomTypeDescriptor#GetEvents</property>
</attribute>
</assembly>
</linker>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace System.Data.Common
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public class DbConnectionStringBuilder : IDictionary, ICustomTypeDescriptor
{
// keyword->value currently listed in the connection string
Expand Down Expand Up @@ -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;
Expand All @@ -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("<comm.DbConnectionStringBuilder.GetProperties|API> {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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.")]
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<Project DefaultTargets="Build">
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" />

<ItemGroup>
<TestConsoleAppSourceFiles Include="CreateSqlXmlReader.cs" />
<TestConsoleAppSourceFiles Include="DbConnectionStringBuilder.cs" />
</ItemGroup>

<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.targets))" />
</Project>

0 comments on commit 2b7927f

Please sign in to comment.