Skip to content

Commit

Permalink
XmlSerializer.Serialize doesn't work when using TrimMode=link (#44772)
Browse files Browse the repository at this point in the history
* XmlSerializer.Serialize doesn't work when using TrimMode=link

Make XmlSerializer work correctly with ILLinker trimming.

1. Use constant BindingFlags to work around dotnet/linker#1617
2. Annotate CodeGenerator.CreateTypeBuilder correctly to preserve base class members

Fix #41389

* Update ILLinker suppressions file.

* PR feedback.

Fix ILLinker suppresions.
  • Loading branch information
eerhardt authored Dec 4, 2020
1 parent a259ec2 commit be9d38c
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.XmlAttributes.get_IgnoreAttribute</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2057</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.XmlSerializationWriterCodeGen.WriteCheckDefault(System.Xml.Serialization.TypeMapping,System.String,System.Object,System.Boolean)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2057</argument>
Expand All @@ -41,13 +47,25 @@
<argument>ILLink</argument>
<argument>IL2067</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.CodeGenerator.CreateTypeBuilder(System.Reflection.Emit.ModuleBuilder,System.String,System.Reflection.TypeAttributes,System.Type,System.Type[])</property>
<property name="Target">M:System.Xml.Serialization.ReflectionXmlSerializationReader.ReflectionCreateObject(System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2067</argument>
<argument>IL2070</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.ReflectionXmlSerializationReader.ReflectionCreateObject(System.Type)</property>
<property name="Target">M:System.Xml.Serialization.Compiler.AddImport(System.Type,System.Collections.Hashtable)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2070</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.ReflectionAwareCodeGen.WriteMappingInfo(System.Xml.Serialization.TypeMapping,System.String,System.Type)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2070</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.ReflectionAwareCodeGen.WriteMemberInfo(System.Type,System.String,System.String,System.String)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
Expand Down Expand Up @@ -193,6 +211,12 @@
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.TempAssembly.LoadGeneratedAssembly(System.Type,System.String,System.Xml.Serialization.XmlSerializerImplementation@)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2072</argument>
<property name="Scope">member</property>
<property name="Target">M:System.Xml.Serialization.XmlSerializationILGen.GenerateTypedSerializer(System.String,System.String,System.Xml.Serialization.XmlMapping,System.Xml.Serialization.CodeIdentifiers,System.String,System.String,System.String)</property>
</attribute>
<attribute fullname="System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute">
<argument>ILLink</argument>
<argument>IL2072</argument>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ namespace System.Xml.Serialization
{
internal class CodeGenerator
{
internal static BindingFlags InstancePublicBindingFlags = BindingFlags.Instance | BindingFlags.Public;
internal static BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
internal static BindingFlags StaticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
internal static MethodAttributes PublicMethodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig;
internal static MethodAttributes PublicOverrideMethodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
internal static MethodAttributes ProtectedOverrideMethodAttributes = MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig;
internal static MethodAttributes PrivateMethodAttributes = MethodAttributes.Private | MethodAttributes.HideBySig;
internal const BindingFlags InstancePublicBindingFlags = BindingFlags.Instance | BindingFlags.Public;
internal const BindingFlags InstanceBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
internal const BindingFlags StaticBindingFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
internal const MethodAttributes PublicMethodAttributes = MethodAttributes.Public | MethodAttributes.HideBySig;
internal const MethodAttributes PublicOverrideMethodAttributes = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig;
internal const MethodAttributes ProtectedOverrideMethodAttributes = MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig;
internal const MethodAttributes PrivateMethodAttributes = MethodAttributes.Private | MethodAttributes.HideBySig;

private readonly TypeBuilder _typeBuilder;
private MethodBuilder? _methodBuilder;
Expand Down Expand Up @@ -1242,7 +1242,13 @@ internal static ModuleBuilder CreateModuleBuilder(AssemblyBuilder assemblyBuilde
{
return assemblyBuilder.DefineDynamicModule(name);
}
internal static TypeBuilder CreateTypeBuilder(ModuleBuilder moduleBuilder, string name, TypeAttributes attributes, Type parent, Type[] interfaces)

internal static TypeBuilder CreateTypeBuilder(
ModuleBuilder moduleBuilder,
string name,
TypeAttributes attributes,
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type parent,
Type[] interfaces)
{
// parent is nullable if no base class
return moduleBuilder.DefineType(TempAssembly.GeneratedAssemblyNamespace + "." + name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project DefaultTargets="Build">
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props))" />

<ItemGroup>
<TestConsoleAppSourceFiles Include="XmlSerializer.Deserialize.cs" />
<TestConsoleAppSourceFiles Include="XmlSerializer.Serialize.cs" />
</ItemGroup>

<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.targets))" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Xml.Schema;

namespace System.Xml.Serialization.TrimmingTests
{
internal class Program
{
// Preserve these types until XmlSerializer is fully trim-safe.
// see https://github.com/dotnet/runtime/issues/44768
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Response))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DataUpdates))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DataUpdatesDataUpdateInfo))]
public static int Main()
{
using StringReader stringReader = new StringReader(@"<?xml version=""1.0"" encoding=""UTF-8""?>
<Response>
<DataUpdates>
<DataUpdateInfo DataDate=""2009-04-13T00:00:00"" DataType=""Data"" LastUpdatedDate=""2010-12-12T02:53:19.257"" />
<DataUpdateInfo DataDate=""2009-04-14T00:00:00"" DataType=""Data"" LastUpdatedDate=""2010-12-12T02:53:19.257"" />
<DataUpdateInfo DataDate=""2009-04-15T00:00:00"" DataType=""Data"" LastUpdatedDate=""2010-12-12T01:52:51.047"" />
</DataUpdates>
</Response>");

Response obj = (Response)new XmlSerializer(typeof(Response)).Deserialize(stringReader);
if (obj.DataUpdates.DataUpdateInfo.Count == 3 &&
obj.DataUpdates.DataUpdateInfo.All(i => i.DataDate.Year == 2009 && i.LastUpdatedDate.Year == 2010))
{
return 100;
}

return -1;
}
}

[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class Response
{
public Response()
{
this.DataUpdates = new DataUpdates();
}

[XmlElement(Order = 0)]
public DataUpdates DataUpdates { get; set; }
}

[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class DataUpdates
{
public DataUpdates()
{
this.DataUpdateInfo = new List<DataUpdatesDataUpdateInfo>();
}

[XmlElement("DataUpdateInfo", Form = XmlSchemaForm.Unqualified, Order = 0)]
public List<DataUpdatesDataUpdateInfo> DataUpdateInfo { get; set; }
}

[Serializable]
[XmlType(AnonymousType = true)]
public class DataUpdatesDataUpdateInfo
{
public DataUpdatesDataUpdateInfo()
{
}

[XmlAttribute]
public DateTime DataDate { get; set; }

[XmlAttribute]
public string DataType { get; set; }

[XmlAttribute]
public DateTime LastUpdatedDate { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml.Schema;

namespace System.Xml.Serialization.TrimmingTests
{
internal class Program
{
// Preserve these types until XmlSerializer is fully trim-safe.
// see https://github.com/dotnet/runtime/issues/44768
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(Response))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DataUpdates))]
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(DataUpdatesDataUpdateInfo))]
public static int Main()
{
Response obj = new Response();
obj.DataUpdates.DataUpdateInfo.Add(new DataUpdatesDataUpdateInfo()
{
DataDate = new DateTime(2009, 4, 13),
DataType = "Data",
LastUpdatedDate = new DateTime(2010, 12, 12)
});
obj.DataUpdates.DataUpdateInfo.Add(new DataUpdatesDataUpdateInfo()
{
DataDate = new DateTime(2009, 4, 14),
DataType = "Data",
LastUpdatedDate = new DateTime(2010, 12, 12)
});

using StringWriter writer = new StringWriter();
new XmlSerializer(typeof(Response)).Serialize(writer, obj);
string serialized = writer.ToString();

if (serialized.Contains("<Response") &&
serialized.Contains("<DataUpdates>") &&
serialized.Contains(@"<DataUpdateInfo DataDate=""2009-04-13T00:00:00"" DataType=""Data"" LastUpdatedDate=""2010-12-12T00:00:00"" />") &&
serialized.Contains(@"<DataUpdateInfo DataDate=""2009-04-14T00:00:00"" DataType=""Data"" LastUpdatedDate=""2010-12-12T00:00:00"" />"))
{
return 100;
}

return -1;
}
}

[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class Response
{
public Response()
{
this.DataUpdates = new DataUpdates();
}

[XmlElement(Order = 0)]
public DataUpdates DataUpdates { get; set; }
}

[Serializable]
[XmlType(AnonymousType = true)]
[XmlRoot(Namespace = "", IsNullable = false)]
public class DataUpdates
{
public DataUpdates()
{
this.DataUpdateInfo = new List<DataUpdatesDataUpdateInfo>();
}

[XmlElement("DataUpdateInfo", Form = XmlSchemaForm.Unqualified, Order = 0)]
public List<DataUpdatesDataUpdateInfo> DataUpdateInfo { get; set; }
}

[Serializable]
[XmlType(AnonymousType = true)]
public class DataUpdatesDataUpdateInfo
{
public DataUpdatesDataUpdateInfo()
{
}

[XmlAttribute]
public DateTime DataDate { get; set; }

[XmlAttribute]
public string DataType { get; set; }

[XmlAttribute]
public DateTime LastUpdatedDate { get; set; }
}
}

0 comments on commit be9d38c

Please sign in to comment.