Skip to content

Commit 0c64e66

Browse files
authored
TypeDescriptor-related trimming supportType descriptor (#102094)
1 parent 1df4111 commit 0c64e66

26 files changed

+1978
-156
lines changed

src/coreclr/tools/aot/crossgen2/crossgen2_publish.csproj

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@
44
<_IsPublishing>true</_IsPublishing>
55
</PropertyGroup>
66

7+
<PropertyGroup>
8+
<_ComObjectDescriptorSupport>false</_ComObjectDescriptorSupport>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<RuntimeHostConfigurationOption Include="System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported"
13+
Condition="'$(_ComObjectDescriptorSupport)' != ''"
14+
Value="$(_ComObjectDescriptorSupport)"
15+
Trim="true" />
16+
</ItemGroup>
17+
718
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
819

920
<PropertyGroup>

src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs

Lines changed: 67 additions & 44 deletions
Large diffs are not rendered by default.

src/libraries/System.ComponentModel.TypeConverter/src/CompatibilitySuppressions.xml

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/libraries/System.ComponentModel.TypeConverter/src/Resources/Strings.resx

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,64 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<root>
3+
<!--
4+
Microsoft ResX Schema
5+
6+
Version 2.0
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
11+
associated with the data types.
12+
13+
Example:
14+
15+
... ado.net/XML headers & schema ...
16+
<resheader name="resmimetype">text/microsoft-resx</resheader>
17+
<resheader name="version">2.0</resheader>
18+
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19+
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20+
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21+
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22+
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23+
<value>[base64 mime encoded serialized .NET Framework object]</value>
24+
</data>
25+
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26+
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27+
<comment>This is a comment</comment>
28+
</data>
29+
30+
There are any number of "resheader" rows that contain simple
31+
name/value pairs.
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
37+
mimetype set.
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
41+
extensible. For a given mimetype the value must be set accordingly:
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
45+
read any of the formats listed below.
46+
47+
mimetype: application/x-microsoft.net.object.binary.base64
48+
value : The object must be serialized with
49+
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50+
: and then encoded with base64 encoding.
51+
52+
mimetype: application/x-microsoft.net.object.soap.base64
53+
value : The object must be serialized with
54+
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55+
: and then encoded with base64 encoding.
56+
57+
mimetype: application/x-microsoft.net.object.bytearray.base64
58+
value : The object must be serialized into a byte array
59+
: using a System.ComponentModel.TypeConverter
60+
: and then encoded with base64 encoding.
61+
-->
362
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
463
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
564
<xsd:element name="root" msdata:IsDataSet="true">
@@ -262,4 +321,10 @@
262321
<data name="BinaryFormatterMessage" xml:space="preserve">
263322
<value>BinaryFormatter serialization is obsolete and should not be used. See https://aka.ms/binaryformatter for more information.</value>
264323
</data>
265-
</root>
324+
<data name="TypeIsNotRegistered" xml:space="preserve">
325+
<value>The type {0} is not registered. Call 'TypeDescriptor.RegisterType()' to register the type.</value>
326+
</data>
327+
<data name="CustomTypeProviderNotImplemented" xml:space="preserve">
328+
<value>Custom type providers must implement member {0}.</value>
329+
</data>
330+
</root>

src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,14 @@
9292
<Compile Include="System\ComponentModel\Design\IDictionaryService.cs" />
9393
<Compile Include="System\ComponentModel\Design\IExtenderListService.cs" />
9494
<Compile Include="System\ComponentModel\Design\ITypeDescriptorFilterService.cs" />
95-
<Compile Include="$(CommonPath)System\Drawing\ColorConverterCommon.cs"
96-
Link="System\Drawing\ColorConverterCommon.cs" />
97-
<Compile Include="$(CommonPath)System\Drawing\ColorTable.cs"
98-
Link="System\Drawing\ColorTable.cs" />
95+
<Compile Include="$(CommonPath)System\Drawing\ColorConverterCommon.cs" Link="System\Drawing\ColorConverterCommon.cs" />
96+
<Compile Include="$(CommonPath)System\Drawing\ColorTable.cs" Link="System\Drawing\ColorTable.cs" />
9997
<Compile Include="System\Drawing\ColorConverter.cs" />
10098
<Compile Include="System\Drawing\PointConverter.cs" />
10199
<Compile Include="System\Drawing\RectangleConverter.cs" />
102100
<Compile Include="System\Drawing\SizeConverter.cs" />
103101
<Compile Include="System\Drawing\SizeFConverter.cs" />
104-
<Compile Include="$(CommonPath)System\Obsoletions.cs"
105-
Link="Common\System\Obsoletions.cs" />
102+
<Compile Include="$(CommonPath)System\Obsoletions.cs" Link="Common\System\Obsoletions.cs" />
106103
<!-- New code introduced for netcoreapp 2.0 -->
107104
<Compile Include="System\ComponentModel\AddingNewEventArgs.cs" />
108105
<Compile Include="System\ComponentModel\AddingNewEventHandler.cs" />
@@ -184,6 +181,7 @@
184181
<Compile Include="System\ComponentModel\ToolboxItemAttribute.cs" />
185182
<Compile Include="System\ComponentModel\ToolboxItemFilterAttribute.cs" />
186183
<Compile Include="System\ComponentModel\ToolboxItemFilterType.cs" />
184+
<Compile Include="System\ComponentModel\TrimSafeReflectionHelper.cs" />
187185
<Compile Include="System\ComponentModel\WarningException.cs" />
188186
<Compile Include="System\ComponentModel\Design\ActiveDesignerEventArgs.cs" />
189187
<Compile Include="System\ComponentModel\Design\ActiveDocumentEventHandler.cs" />
@@ -250,10 +248,7 @@
250248
</ItemGroup>
251249

252250
<ItemGroup>
253-
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.RegularExpressions\gen\System.Text.RegularExpressions.Generator.csproj"
254-
ReferenceOutputAssembly="false"
255-
SetTargetFramework="TargetFramework=netstandard2.0"
256-
OutputItemType="Analyzer" />
251+
<ProjectReference Include="$(LibrariesProjectRoot)System.Text.RegularExpressions\gen\System.Text.RegularExpressions.Generator.csproj" ReferenceOutputAssembly="false" SetTargetFramework="TargetFramework=netstandard2.0" OutputItemType="Analyzer" />
257252
<Reference Include="System.Collections" />
258253
<Reference Include="System.Collections.NonGeneric" />
259254
<Reference Include="System.Collections.Specialized" />

src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ComponentResourceManager.cs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,31 @@ private CultureInfo? NeutralResourcesCulture
6464
/// </summary>
6565
[RequiresUnreferencedCode("The Type of value cannot be statically discovered.")]
6666
public virtual void ApplyResources(object value, string objectName, CultureInfo? culture)
67+
{
68+
ArgumentNullException.ThrowIfNull(value);
69+
ArgumentNullException.ThrowIfNull(objectName);
70+
ApplyResources(value, value.GetType(), objectName, culture);
71+
}
72+
73+
/// <summary>
74+
/// This method examines all the resources for the provided culture.
75+
/// When it finds a resource with a key in the format of
76+
/// &quot;[objectName].[property name]&quot; or &quot;[objectName]-[property name]&quot; it will apply that resource's value
77+
/// to the corresponding property on the object. If there is no matching
78+
/// property the resource will be ignored.
79+
/// </summary>
80+
public virtual void ApplyResourcesToRegisteredType(object value, string objectName, CultureInfo? culture)
6781
{
6882
ArgumentNullException.ThrowIfNull(value);
6983
ArgumentNullException.ThrowIfNull(objectName);
7084

85+
Type typeFromValue = value.GetType();
86+
TypeDescriptor.ValidateRegisteredType(typeFromValue);
87+
ApplyResources(value, typeFromValue, objectName, culture);
88+
}
89+
90+
private void ApplyResources(object value, Type typeFromValue, string objectName, CultureInfo? culture)
91+
{
7192
culture ??= CultureInfo.CurrentUICulture;
7293

7394
// The general case here will be to always use the same culture, so optimize for
@@ -148,7 +169,7 @@ public virtual void ApplyResources(object value, string objectName, CultureInfo?
148169

149170
if (componentReflect)
150171
{
151-
PropertyDescriptor? prop = TypeDescriptor.GetProperties(value).Find(propName, IgnoreCase);
172+
PropertyDescriptor? prop = TypeDescriptorGetProperties(value).Find(propName, IgnoreCase);
152173

153174
if (prop != null && !prop.IsReadOnly && (kvp.Value == null || prop.PropertyType.IsInstanceOfType(kvp.Value)))
154175
{
@@ -161,16 +182,16 @@ public virtual void ApplyResources(object value, string objectName, CultureInfo?
161182

162183
try
163184
{
164-
prop = value.GetType().GetProperty(propName, flags);
185+
prop = prop = TrimSafeReflectionHelper.GetProperty(typeFromValue, propName, flags);
165186
}
166187
catch (AmbiguousMatchException)
167188
{
168189
// Looks like we ran into a conflict between a declared property and an inherited one.
169190
// In such cases, we choose the most declared one.
170-
Type? t = value.GetType();
191+
Type? t = typeFromValue;
171192
do
172193
{
173-
prop = t.GetProperty(propName, flags | BindingFlags.DeclaredOnly);
194+
prop = TrimSafeReflectionHelper.GetProperty(t, propName, flags | BindingFlags.DeclaredOnly);
174195
t = t.BaseType;
175196
} while (prop == null && t != null && t != typeof(object));
176197
}
@@ -181,6 +202,10 @@ public virtual void ApplyResources(object value, string objectName, CultureInfo?
181202
}
182203
}
183204
}
205+
206+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
207+
Justification = "Calling method either has RequiresUnreferencedCode or has registered types.")]
208+
static PropertyDescriptorCollection TypeDescriptorGetProperties(object value) => TypeDescriptor.GetProperties(value);
184209
}
185210

186211
/// <summary>

src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/CustomTypeDescriptor.cs

Lines changed: 113 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,36 @@ public virtual AttributeCollection GetAttributes()
8080
return new TypeConverter();
8181
}
8282

83+
/// <summary>
84+
/// The GetConverterFromRegisteredType method returns a type converter for the type this type
85+
/// descriptor is representing.
86+
/// </summary>
87+
public virtual TypeConverter? GetConverterFromRegisteredType()
88+
{
89+
if (_parent != null)
90+
{
91+
return _parent.GetConverterFromRegisteredType();
92+
}
93+
94+
if (RequireRegisteredTypes is null)
95+
{
96+
if (TypeDescriptor.RequireRegisteredTypes)
97+
{
98+
TypeDescriptor.ThrowHelper.ThrowNotImplementedException_CustomTypeProviderMustImplememtMember(nameof(GetConverterFromRegisteredType));
99+
}
100+
}
101+
else if (RequireRegisteredTypes == true)
102+
{
103+
TypeDescriptor.ThrowHelper.ThrowNotImplementedException_CustomTypeProviderMustImplememtMember(nameof(GetConverterFromRegisteredType));
104+
}
105+
106+
return Forward();
107+
108+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
109+
Justification = TypeDescriptionProvider.ForwardFromRegisteredMessage)]
110+
TypeConverter? Forward() => GetConverter();
111+
}
112+
83113
/// <summary>
84114
/// The GetDefaultEvent method returns the event descriptor for the default
85115
/// event on the object this type descriptor is representing.
@@ -103,10 +133,7 @@ public virtual AttributeCollection GetAttributes()
103133

104134
/// <summary>
105135
/// The GetEvents method returns a collection of event descriptors
106-
/// for the object this type descriptor is representing. An optional
107-
/// attribute array may be provided to filter the collection that is
108-
/// returned. If no parent is provided,this will return an empty
109-
/// event collection.
136+
/// for the object this type descriptor is representing.
110137
/// </summary>
111138
public virtual EventDescriptorCollection GetEvents()
112139
{
@@ -136,12 +163,35 @@ public virtual EventDescriptorCollection GetEvents(Attribute[]? attributes)
136163
return EventDescriptorCollection.Empty;
137164
}
138165

166+
/// <summary>
167+
/// Returns a collection of event descriptors
168+
/// for the object this type descriptor is representing.
169+
/// </summary>
170+
public virtual EventDescriptorCollection GetEventsFromRegisteredType()
171+
{
172+
if (_parent != null)
173+
{
174+
return _parent.GetEventsFromRegisteredType();
175+
}
176+
177+
if (RequireRegisteredTypes is null)
178+
{
179+
if (TypeDescriptor.RequireRegisteredTypes)
180+
{
181+
TypeDescriptor.ThrowHelper.ThrowNotImplementedException_CustomTypeProviderMustImplememtMember(nameof(GetEventsFromRegisteredType));
182+
}
183+
}
184+
else if (RequireRegisteredTypes == true)
185+
{
186+
TypeDescriptor.ThrowHelper.ThrowNotImplementedException_CustomTypeProviderMustImplememtMember(nameof(GetEventsFromRegisteredType));
187+
}
188+
189+
return GetEvents();
190+
}
191+
139192
/// <summary>
140193
/// The GetProperties method returns a collection of property descriptors
141-
/// for the object this type descriptor is representing. An optional
142-
/// attribute array may be provided to filter the collection that is returned.
143-
/// If no parent is provided,this will return an empty
144-
/// property collection.
194+
/// for the object this type descriptor is representing.
145195
/// </summary>
146196
[RequiresUnreferencedCode(PropertyDescriptor.PropertyDescriptorPropertyTypeMessage)]
147197
public virtual PropertyDescriptorCollection GetProperties()
@@ -154,6 +204,36 @@ public virtual PropertyDescriptorCollection GetProperties()
154204
return PropertyDescriptorCollection.Empty;
155205
}
156206

207+
/// <summary>
208+
/// The GetProperties method returns a collection of property descriptors
209+
/// for the object this type descriptor is representing.
210+
/// </summary>
211+
public virtual PropertyDescriptorCollection GetPropertiesFromRegisteredType()
212+
{
213+
if (_parent != null)
214+
{
215+
return _parent.GetPropertiesFromRegisteredType();
216+
}
217+
218+
if (RequireRegisteredTypes is null)
219+
{
220+
if (TypeDescriptor.RequireRegisteredTypes)
221+
{
222+
TypeDescriptor.ThrowHelper.ThrowNotImplementedException_CustomTypeProviderMustImplememtMember(nameof(GetPropertiesFromRegisteredType));
223+
}
224+
}
225+
else if (RequireRegisteredTypes == true)
226+
{
227+
TypeDescriptor.ThrowHelper.ThrowNotImplementedException_CustomTypeProviderMustImplememtMember(nameof(GetPropertiesFromRegisteredType));
228+
}
229+
230+
return Forward();
231+
232+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
233+
Justification = TypeDescriptionProvider.ForwardFromRegisteredMessage)]
234+
PropertyDescriptorCollection Forward() => GetProperties();
235+
}
236+
157237
/// <summary>
158238
/// The GetProperties method returns a collection of property descriptors
159239
/// for the object this type descriptor is representing. An optional
@@ -180,5 +260,30 @@ public virtual PropertyDescriptorCollection GetProperties(Attribute[]? attribute
180260
/// to use its default type description services.
181261
/// </summary>
182262
public virtual object? GetPropertyOwner(PropertyDescriptor? pd) => _parent?.GetPropertyOwner(pd);
263+
264+
/// <summary>
265+
/// Whether types are required to be registered through <see cref="TypeDescriptionProvider.RegisterType{T}"/>.
266+
/// </summary>
267+
/// <remarks>
268+
/// The default value is <see langword="null"/> which means that the type descriptor has not declared whether or not it is compatible registered types.
269+
/// A type descriptor needs to implement this to return <see langword="true"/> or <see langword="false"/> if the feature switch
270+
/// 'System.ComponentModel.TypeDescriptor.RequireRegisteredTypes' is enabled.
271+
/// If <see langword="true"/> is returned, then the type descriptor must also implement
272+
/// <see cref="ICustomTypeDescriptor.GetConverterFromRegisteredType()"/>,
273+
/// <see cref="ICustomTypeDescriptor.GetEventsFromRegisteredType()"/>, and
274+
/// <see cref="ICustomTypeDescriptor.GetPropertiesFromRegisteredType()"/>.
275+
/// </remarks>
276+
public virtual bool? RequireRegisteredTypes
277+
{
278+
get
279+
{
280+
if (_parent != null)
281+
{
282+
return _parent.RequireRegisteredTypes;
283+
}
284+
285+
return null;
286+
}
287+
}
183288
}
184289
}

src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/DelegatingTypeDescriptionProvider.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,13 @@ public override Type GetReflectionType(
120120
}
121121

122122
public override bool IsSupportedType(Type type) => Provider.IsSupportedType(type);
123+
124+
public override bool IsRegisteredType(Type type) => Provider.IsRegisteredType(type);
125+
126+
public override bool? RequireRegisteredTypes => Provider.RequireRegisteredTypes;
127+
128+
public override ICustomTypeDescriptor? GetTypeDescriptorFromRegisteredType(Type objectType, object? instance) => Provider.GetTypeDescriptorFromRegisteredType(objectType, instance);
129+
130+
public override void RegisterType<[DynamicallyAccessedMembers(TypeDescriptor.RegisteredTypesDynamicallyAccessedMembers)] T>() => Provider.RegisterType<T>();
123131
}
124132
}

0 commit comments

Comments
 (0)