From 118eee973af81119fd00fe75bc9c14ce3192ff1e Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 30 Sep 2020 15:29:12 -0500 Subject: [PATCH] DataContractSerialization doesn't work with TrimMode - link (#42824) DataContractSerialization has some Reflection "shim" methods that the ILLinker can't see through. This causes critical methods to be trimmed and applications to fail. These methods were put in place in .NET Core 1.0 when the full Reflection API wasn't available. The fix is to remove these "shim" Reflection APIs and use Reflection directly. Fix #41525 Fix #42754 --- .../Serialization/ClassDataContract.cs | 6 +-- .../Runtime/Serialization/CodeGenerator.cs | 2 +- .../Serialization/CollectionDataContract.cs | 6 +-- .../Runtime/Serialization/DataContract.cs | 4 +- .../System/Runtime/Serialization/Globals.cs | 40 -------------- .../Json/JsonFormatGeneratorStatics.cs | 18 +++---- .../Json/JsonFormatReaderGenerator.cs | 4 +- .../Json/JsonFormatWriterGenerator.cs | 12 +++-- .../Serialization/PrimitiveDataContract.cs | 8 +-- .../Runtime/Serialization/ReflectionReader.cs | 2 +- .../Runtime/Serialization/XmlDataContract.cs | 10 ++-- .../XmlFormatGeneratorStatics.cs | 38 +++++++------- .../Serialization/XmlFormatReaderGenerator.cs | 2 +- .../Serialization/XmlFormatWriterGenerator.cs | 8 +-- .../tests/TrimmingTests/EndToEndTest.cs | 52 +++++++++++++++++++ ...ntime.Serialization.Xml.TrimmingTests.proj | 9 ++++ 16 files changed, 124 insertions(+), 97 deletions(-) create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/EndToEndTest.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/System.Runtime.Serialization.Xml.TrimmingTests.proj diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index fa8f950a9f868..22f02e15a9728 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -388,7 +388,7 @@ internal static bool IsNonAttributedTypeValidForSerialization(Type type) else { return (type.IsVisible && - type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()) != null); + type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null) != null); } } @@ -1368,7 +1368,7 @@ private void SetKeyValuePairAdapterFlags(Type type) { _isKeyValuePairAdapter = true; _keyValuePairGenericArguments = type.GetGenericArguments(); - _keyValuePairCtorInfo = type.GetConstructor(Globals.ScanAllMembers, new Type[] { Globals.TypeOfKeyValuePair.MakeGenericType(_keyValuePairGenericArguments) }); + _keyValuePairCtorInfo = type.GetConstructor(Globals.ScanAllMembers, null, new Type[] { Globals.TypeOfKeyValuePair.MakeGenericType(_keyValuePairGenericArguments) }, null); _getKeyValuePairMethodInfo = type.GetMethod("GetKeyValuePair", Globals.ScanAllMembers)!; } } @@ -1425,7 +1425,7 @@ internal MethodInfo? GetKeyValuePairMethodInfo if (type.IsValueType) return null; - ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()); + ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index 6d7033c5e9085..132a76b6da6a2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -38,7 +38,7 @@ private static MethodInfo ObjectEquals { if (s_objectEquals == null) { - s_objectEquals = Globals.TypeOfObject.GetMethod("Equals", BindingFlags.Public | BindingFlags.Static); + s_objectEquals = typeof(object).GetMethod("Equals", BindingFlags.Public | BindingFlags.Static); Debug.Assert(s_objectEquals != null); } return s_objectEquals; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index a67599003cbd7..430e7ba45df9b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -883,7 +883,7 @@ internal Type GetCollectionElementType() enumeratorType = GetEnumeratorMethod.ReturnType; } - MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); if (getCurrentMethod == null) { if (enumeratorType.IsInterface) @@ -1134,7 +1134,7 @@ private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataC } } - getEnumeratorMethod = Globals.TypeOfIEnumerable.GetMethod(Globals.GetEnumeratorMethodName)!; + getEnumeratorMethod = typeof(IEnumerable).GetMethod(Globals.GetEnumeratorMethodName)!; } if (tryCreate) dataContract = new CollectionDataContract(type, (CollectionKind)(i + 1), itemType, getEnumeratorMethod, addMethod, null/*defaultCtor*/); @@ -1364,7 +1364,7 @@ private static void GetCollectionMethods(Type type, Type interfaceType, Type[] a if (getEnumeratorMethod == null) { - getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); if (getEnumeratorMethod == null || !Globals.TypeOfIEnumerator.IsAssignableFrom(getEnumeratorMethod.ReturnType)) { Type? ienumerableInterface = interfaceType.GetInterfaces().Where(t => t.FullName!.StartsWith("System.Collections.Generic.IEnumerable")).FirstOrDefault(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 38e444c7cc29a..2099fc9f3fb9f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -1125,7 +1125,7 @@ internal MethodInfo? ParseMethod { if (!_parseMethodSet) { - MethodInfo? method = UnderlyingType.GetMethod(Globals.ParseMethodName, BindingFlags.Public | BindingFlags.Static, new Type[] { typeof(string) }); + MethodInfo? method = UnderlyingType.GetMethod(Globals.ParseMethodName, BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, null); if (method != null && method.ReturnType == UnderlyingType) { @@ -1978,7 +1978,7 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary if (methodName.Length == 0) DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeEmptyString, DataContract.GetClrTypeFullName(type)), type); - MethodInfo? method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()); + MethodInfo? method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null); if (method == null) DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeUnknownMethod, methodName, DataContract.GetClrTypeFullName(type)), type); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index 52b08bf3d5d18..eb24db27f6a77 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -785,46 +785,6 @@ internal static Uri DataContractXsdBaseNamespaceUri } } - #region Contract compliance for System.Type - - private static bool TypeSequenceEqual(Type[] seq1, Type[] seq2) - { - if (seq1 == null || seq2 == null || seq1.Length != seq2.Length) - return false; - for (int i = 0; i < seq1.Length; i++) - { - if (!seq1[i].Equals(seq2[i]) && !seq1[i].IsAssignableFrom(seq2[i])) - return false; - } - return true; - } - - private static MethodBase? FilterMethodBases(MethodBase[]? methodBases, Type[] parameterTypes, string methodName) - { - if (methodBases == null || string.IsNullOrEmpty(methodName)) - return null; - - var matchedMethods = methodBases.Where(method => method.Name.Equals(methodName)); - matchedMethods = matchedMethods.Where(method => TypeSequenceEqual(method.GetParameters().Select(param => param.ParameterType).ToArray(), parameterTypes)); - return matchedMethods.FirstOrDefault(); - } - - internal static ConstructorInfo? GetConstructor(this Type type, BindingFlags bindingFlags, Type[] parameterTypes) - { - ConstructorInfo[] constructorInfos = type.GetConstructors(bindingFlags); - var constructorInfo = FilterMethodBases(constructorInfos.Cast().ToArray()!, parameterTypes, ".ctor"); - return constructorInfo != null ? (ConstructorInfo)constructorInfo : null; - } - - internal static MethodInfo? GetMethod(this Type type, string methodName, BindingFlags bindingFlags, Type[] parameterTypes) - { - var methodInfos = type.GetMethods(bindingFlags); - var methodInfo = FilterMethodBases(methodInfos.Cast().ToArray()!, parameterTypes, methodName); - return methodInfo != null ? (MethodInfo)methodInfo : null; - } - - #endregion - private static readonly Type? s_typeOfScriptObject; internal static ClassDataContract CreateScriptObjectClassDataContract() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs index 85ba87d52c12f..2ed0acc31cd18 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs @@ -167,7 +167,7 @@ public static MethodInfo GetUninitializedObjectMethod { if (s_getUninitializedObjectMethod == null) { - s_getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod("UnsafeGetUninitializedObject", Globals.ScanAllMembers, new Type[] { typeof(Type) }); + s_getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod("UnsafeGetUninitializedObject", Globals.ScanAllMembers, null, new Type[] { typeof(Type) }, null); Debug.Assert(s_getUninitializedObjectMethod != null); } return s_getUninitializedObjectMethod; @@ -180,7 +180,7 @@ public static MethodInfo IsStartElementMethod0 { if (s_isStartElementMethod0 == null) { - s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, Array.Empty()); + s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, null, Array.Empty(), null); Debug.Assert(s_isStartElementMethod0 != null); } return s_isStartElementMethod0; @@ -192,7 +192,7 @@ public static MethodInfo IsStartElementMethod2 { if (s_isStartElementMethod2 == null) { - s_isStartElementMethod2 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }); + s_isStartElementMethod2 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, null, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); Debug.Assert(s_isStartElementMethod2 != null); } return s_isStartElementMethod2; @@ -371,7 +371,7 @@ public static MethodInfo WriteAttributeStringMethod { if (s_writeAttributeStringMethod == null) { - s_writeAttributeStringMethod = typeof(XmlWriterDelegator).GetMethod("WriteAttributeString", Globals.ScanAllMembers, new Type[] { typeof(string), typeof(string), typeof(string), typeof(string) }); + s_writeAttributeStringMethod = typeof(XmlWriterDelegator).GetMethod("WriteAttributeString", Globals.ScanAllMembers, null, new Type[] { typeof(string), typeof(string), typeof(string), typeof(string) }, null); Debug.Assert(s_writeAttributeStringMethod != null); } return s_writeAttributeStringMethod; @@ -383,7 +383,7 @@ public static MethodInfo WriteEndElementMethod { if (s_writeEndElementMethod == null) { - s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, Array.Empty()); + s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, null, Array.Empty(), null); Debug.Assert(s_writeEndElementMethod != null); } return s_writeEndElementMethod; @@ -431,7 +431,7 @@ public static MethodInfo WriteStartElementMethod { if (s_writeStartElementMethod == null) { - s_writeStartElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }); + s_writeStartElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, null, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); Debug.Assert(s_writeStartElementMethod != null); } return s_writeStartElementMethod; @@ -444,7 +444,7 @@ public static MethodInfo WriteStartElementStringMethod { if (s_writeStartElementStringMethod == null) { - s_writeStartElementStringMethod = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, new Type[] { typeof(string), typeof(string) }); + s_writeStartElementStringMethod = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, null, new Type[] { typeof(string), typeof(string) }, null); Debug.Assert(s_writeStartElementStringMethod != null); } return s_writeStartElementStringMethod; @@ -457,7 +457,7 @@ public static MethodInfo ParseEnumMethod { if (s_parseEnumMethod == null) { - s_parseEnumMethod = typeof(Enum).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, new Type[] { typeof(Type), typeof(string) }); + s_parseEnumMethod = typeof(Enum).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(Type), typeof(string) }, null); Debug.Assert(s_parseEnumMethod != null); } return s_parseEnumMethod; @@ -470,7 +470,7 @@ public static MethodInfo GetJsonMemberNameMethod { if (s_getJsonMemberNameMethod == null) { - s_getJsonMemberNameMethod = typeof(XmlObjectSerializerReadContextComplexJson).GetMethod("GetJsonMemberName", Globals.ScanAllMembers, new Type[] { typeof(XmlReaderDelegator) }); + s_getJsonMemberNameMethod = typeof(XmlObjectSerializerReadContextComplexJson).GetMethod("GetJsonMemberName", Globals.ScanAllMembers, null, new Type[] { typeof(XmlReaderDelegator) }, null); Debug.Assert(s_getJsonMemberNameMethod != null); } return s_getJsonMemberNameMethod; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index ca652209ba899..477ad9a7bb487 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -573,11 +573,11 @@ private void ReadCollection(CollectionDataContract collectionContract) { case CollectionKind.GenericDictionary: type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments()); - constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty())!; + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Array.Empty(), null)!; break; case CollectionKind.Dictionary: type = Globals.TypeOfHashtable; - constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty())!; + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Array.Empty(), null)!; break; case CollectionKind.Collection: case CollectionKind.GenericCollection: diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs index c219893b3d78a..68eaefbc45751 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs @@ -346,8 +346,8 @@ private void WriteCollection(CollectionDataContract collectionContract) { enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType; } - MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); - MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); + MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); if (moveNextMethod == null || getCurrentMethod == null) { if (enumeratorType.IsInterface) @@ -388,7 +388,7 @@ private void WriteCollection(CollectionDataContract collectionContract) _ilg.Call(_objectLocal, collectionContract.GetEnumeratorMethod); if (isDictionary) { - ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, new Type[] { Globals.TypeOfIDictionaryEnumerator })!; + ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { Globals.TypeOfIDictionaryEnumerator }, null)!; _ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, Globals.TypeOfIDictionaryEnumerator); _ilg.New(dictEnumCtor); } @@ -396,7 +396,7 @@ private void WriteCollection(CollectionDataContract collectionContract) { Debug.Assert(keyValueTypes != null); Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes)); - ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, new Type[] { ctorParam })!; + ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null)!; _ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam); _ilg.New(dictEnumCtor); } @@ -560,7 +560,9 @@ private bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value MethodInfo writeArrayMethodInfo = typeof(JsonWriterDelegator).GetMethod( writeArrayMethod, Globals.ScanAllMembers, - new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) })!; + null, + new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, + null)!; _ilg.Call(_xmlWriterArg, writeArrayMethodInfo, value, itemName, null); return true; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index c094c8d4fed4b..8bc6d130f3596 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -56,9 +56,9 @@ internal MethodInfo XmlFormatWriterMethod if (_helper.XmlFormatWriterMethod == null) { if (UnderlyingType.IsValueType) - _helper.XmlFormatWriterMethod = typeof(XmlWriterDelegator).GetMethod(WriteMethodName, Globals.ScanAllMembers, new Type[] { UnderlyingType, typeof(XmlDictionaryString), typeof(XmlDictionaryString) })!; + _helper.XmlFormatWriterMethod = typeof(XmlWriterDelegator).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { UnderlyingType, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null)!; else - _helper.XmlFormatWriterMethod = typeof(XmlObjectSerializerWriteContext).GetMethod(WriteMethodName, Globals.ScanAllMembers, new Type[] { typeof(XmlWriterDelegator), UnderlyingType, typeof(XmlDictionaryString), typeof(XmlDictionaryString) })!; + _helper.XmlFormatWriterMethod = typeof(XmlObjectSerializerWriteContext).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { typeof(XmlWriterDelegator), UnderlyingType, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null)!; } return _helper.XmlFormatWriterMethod; } @@ -71,9 +71,9 @@ internal MethodInfo XmlFormatContentWriterMethod if (_helper.XmlFormatContentWriterMethod == null) { if (UnderlyingType.IsValueType) - _helper.XmlFormatContentWriterMethod = typeof(XmlWriterDelegator).GetMethod(WriteMethodName, Globals.ScanAllMembers, new Type[] { UnderlyingType })!; + _helper.XmlFormatContentWriterMethod = typeof(XmlWriterDelegator).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { UnderlyingType }, null)!; else - _helper.XmlFormatContentWriterMethod = typeof(XmlObjectSerializerWriteContext).GetMethod(WriteMethodName, Globals.ScanAllMembers, new Type[] { typeof(XmlWriterDelegator), UnderlyingType })!; + _helper.XmlFormatContentWriterMethod = typeof(XmlObjectSerializerWriteContext).GetMethod(WriteMethodName, Globals.ScanAllMembers, null, new Type[] { typeof(XmlWriterDelegator), UnderlyingType }, null)!; } return _helper.XmlFormatContentWriterMethod; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs index f1392a84328f5..284d45dc8dae4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs @@ -441,7 +441,7 @@ private object ReflectionCreateCollection(CollectionDataContract collectionContr else if (collectionContract.Kind == CollectionKind.GenericDictionary && collectionContract.UnderlyingType.IsInterface) { Type type = Globals.TypeOfDictionaryGeneric.MakeGenericType(collectionContract.ItemType.GetGenericArguments()); - ConstructorInfo ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Array.Empty())!; + ConstructorInfo ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null)!; object newGenericDict = ci.Invoke(Array.Empty()); return newGenericDict; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 62a1b8bc0e513..6dfadbd82d391 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -241,7 +241,7 @@ internal CreateXmlSerializableDelegate? CreateXmlSerializableDelegate if (type.IsValueType) return null; - ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()); + ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.IXmlSerializableMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); @@ -288,11 +288,15 @@ internal CreateXmlSerializableDelegate GenerateCreateXmlSerializableDelegate() MethodInfo? XName_op_Implicit = xName.GetMethod( "op_Implicit", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, - new Type[] { typeof(string) } + null, + new Type[] { typeof(string) }, + null ); ConstructorInfo? XElement_ctor = type.GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, - new Type[] { xName } + null, + new Type[] { xName }, + null ); if (XName_op_Implicit != null && XElement_ctor != null) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs index fa9a69fdf0aa7..3cbcba6288fec 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs @@ -17,7 +17,7 @@ internal static MethodInfo WriteStartElementMethod2 { if (s_writeStartElementMethod2 == null) { - s_writeStartElementMethod2 = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }); + s_writeStartElementMethod2 = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, null, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); Debug.Assert(s_writeStartElementMethod2 != null); } return s_writeStartElementMethod2; @@ -31,7 +31,7 @@ internal static MethodInfo WriteStartElementMethod3 { if (s_writeStartElementMethod3 == null) { - s_writeStartElementMethod3 = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, new Type[] { typeof(string), typeof(XmlDictionaryString), typeof(XmlDictionaryString) }); + s_writeStartElementMethod3 = typeof(XmlWriterDelegator).GetMethod("WriteStartElement", Globals.ScanAllMembers, null, new Type[] { typeof(string), typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); Debug.Assert(s_writeStartElementMethod3 != null); } return s_writeStartElementMethod3; @@ -45,7 +45,7 @@ internal static MethodInfo WriteEndElementMethod { if (s_writeEndElementMethod == null) { - s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, Array.Empty()); + s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, null, Array.Empty(), null); Debug.Assert(s_writeEndElementMethod != null); } return s_writeEndElementMethod; @@ -59,7 +59,7 @@ internal static MethodInfo WriteNamespaceDeclMethod { if (s_writeNamespaceDeclMethod == null) { - s_writeNamespaceDeclMethod = typeof(XmlWriterDelegator).GetMethod("WriteNamespaceDecl", Globals.ScanAllMembers, new Type[] { typeof(XmlDictionaryString) }); + s_writeNamespaceDeclMethod = typeof(XmlWriterDelegator).GetMethod("WriteNamespaceDecl", Globals.ScanAllMembers, null, new Type[] { typeof(XmlDictionaryString) }, null); Debug.Assert(s_writeNamespaceDeclMethod != null); } return s_writeNamespaceDeclMethod; @@ -77,7 +77,7 @@ internal static ConstructorInfo DictionaryEnumeratorCtor { if (s_dictionaryEnumeratorCtor == null) { - s_dictionaryEnumeratorCtor = Globals.TypeOfDictionaryEnumerator.GetConstructor(Globals.ScanAllMembers, new Type[] { Globals.TypeOfIDictionaryEnumerator }); + s_dictionaryEnumeratorCtor = typeof(CollectionDataContract.DictionaryEnumerator).GetConstructor(Globals.ScanAllMembers, null, new Type[] { Globals.TypeOfIDictionaryEnumerator }, null); Debug.Assert(s_dictionaryEnumeratorCtor != null); } return s_dictionaryEnumeratorCtor; @@ -133,7 +133,7 @@ internal static MethodInfo IsStartElementMethod2 { if (s_isStartElementMethod2 == null) { - s_isStartElementMethod2 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }); + s_isStartElementMethod2 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, null, new Type[] { typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null); Debug.Assert(s_isStartElementMethod2 != null); } return s_isStartElementMethod2; @@ -147,7 +147,7 @@ internal static MethodInfo IsStartElementMethod0 { if (s_isStartElementMethod0 == null) { - s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, Array.Empty()); + s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, null, Array.Empty(), null); Debug.Assert(s_isStartElementMethod0 != null); } return s_isStartElementMethod0; @@ -161,7 +161,7 @@ internal static MethodInfo GetUninitializedObjectMethod { if (s_getUninitializedObjectMethod == null) { - s_getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod("UnsafeGetUninitializedObject", Globals.ScanAllMembers, new Type[] { typeof(int) }); + s_getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod("UnsafeGetUninitializedObject", Globals.ScanAllMembers, null, new Type[] { typeof(int) }, null); Debug.Assert(s_getUninitializedObjectMethod != null); } return s_getUninitializedObjectMethod; @@ -208,7 +208,7 @@ internal static ConstructorInfo HashtableCtor { if (s_hashtableCtor == null) { - s_hashtableCtor = Globals.TypeOfHashtable.GetConstructor(Globals.ScanAllMembers, Array.Empty()); + s_hashtableCtor = Globals.TypeOfHashtable.GetConstructor(Globals.ScanAllMembers, null, Array.Empty(), null); Debug.Assert(s_hashtableCtor != null); } return s_hashtableCtor; @@ -250,7 +250,7 @@ internal static MethodInfo StoreCollectionMemberInfoMethod { if (s_storeCollectionMemberInfoMethod == null) { - s_storeCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod("StoreCollectionMemberInfo", Globals.ScanAllMembers, new Type[] { typeof(object) }); + s_storeCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod("StoreCollectionMemberInfo", Globals.ScanAllMembers, null, new Type[] { typeof(object) }, null); Debug.Assert(s_storeCollectionMemberInfoMethod != null); } return s_storeCollectionMemberInfoMethod; @@ -264,7 +264,7 @@ internal static MethodInfo ResetCollectionMemberInfoMethod { if (s_resetCollectionMemberInfoMethod == null) { - s_resetCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ResetCollectionMemberInfo", Globals.ScanAllMembers, Array.Empty()); + s_resetCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ResetCollectionMemberInfo", Globals.ScanAllMembers, null, Array.Empty(), null); Debug.Assert(s_resetCollectionMemberInfoMethod != null); } return s_resetCollectionMemberInfoMethod; @@ -348,7 +348,7 @@ internal static MethodInfo InternalDeserializeMethod { if (s_internalDeserializeMethod == null) { - s_internalDeserializeMethod = typeof(XmlObjectSerializerReadContext).GetMethod("InternalDeserialize", Globals.ScanAllMembers, new Type[] { typeof(XmlReaderDelegator), typeof(int), typeof(RuntimeTypeHandle), typeof(string), typeof(string) }); + s_internalDeserializeMethod = typeof(XmlObjectSerializerReadContext).GetMethod("InternalDeserialize", Globals.ScanAllMembers, null, new Type[] { typeof(XmlReaderDelegator), typeof(int), typeof(RuntimeTypeHandle), typeof(string), typeof(string) }, null); Debug.Assert(s_internalDeserializeMethod != null); } return s_internalDeserializeMethod; @@ -432,7 +432,7 @@ internal static MethodInfo ReadIfNullOrRefMethod { if (s_readIfNullOrRefMethod == null) { - s_readIfNullOrRefMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ReadIfNullOrRef", Globals.ScanAllMembers, new Type[] { typeof(XmlReaderDelegator), typeof(Type), typeof(bool) }); + s_readIfNullOrRefMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ReadIfNullOrRef", Globals.ScanAllMembers, null, new Type[] { typeof(XmlReaderDelegator), typeof(Type), typeof(bool) }, null); Debug.Assert(s_readIfNullOrRefMethod != null); } return s_readIfNullOrRefMethod; @@ -614,7 +614,7 @@ internal static MethodInfo CreateSerializationExceptionMethod { if (s_createSerializationExceptionMethod == null) { - s_createSerializationExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod("CreateSerializationException", Globals.ScanAllMembers, new Type[] { typeof(string) }); + s_createSerializationExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod("CreateSerializationException", Globals.ScanAllMembers, null, new Type[] { typeof(string) }, null); Debug.Assert(s_createSerializationExceptionMethod != null); } return s_createSerializationExceptionMethod; @@ -642,7 +642,7 @@ internal static MethodInfo CreateUnexpectedStateExceptionMethod { if (s_createUnexpectedStateExceptionMethod == null) { - s_createUnexpectedStateExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod("CreateUnexpectedStateException", Globals.ScanAllMembers, new Type[] { typeof(XmlNodeType), typeof(XmlReaderDelegator) }); + s_createUnexpectedStateExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod("CreateUnexpectedStateException", Globals.ScanAllMembers, null, new Type[] { typeof(XmlNodeType), typeof(XmlReaderDelegator) }, null); Debug.Assert(s_createUnexpectedStateExceptionMethod != null); } return s_createUnexpectedStateExceptionMethod; @@ -684,7 +684,7 @@ internal static MethodInfo WriteNullMethod { if (s_writeNullMethod == null) { - s_writeNullMethod = typeof(XmlObjectSerializerWriteContext).GetMethod("WriteNull", Globals.ScanAllMembers, new Type[] { typeof(XmlWriterDelegator), typeof(Type), typeof(bool) }); + s_writeNullMethod = typeof(XmlObjectSerializerWriteContext).GetMethod("WriteNull", Globals.ScanAllMembers, null, new Type[] { typeof(XmlWriterDelegator), typeof(Type), typeof(bool) }, null); Debug.Assert(s_writeNullMethod != null); } return s_writeNullMethod; @@ -712,7 +712,7 @@ internal static MethodInfo IncrementCollectionCountMethod { if (s_incrementCollectionCountMethod == null) { - s_incrementCollectionCountMethod = typeof(XmlObjectSerializerWriteContext).GetMethod("IncrementCollectionCount", Globals.ScanAllMembers, new Type[] { typeof(XmlWriterDelegator), typeof(ICollection) }); + s_incrementCollectionCountMethod = typeof(XmlObjectSerializerWriteContext).GetMethod("IncrementCollectionCount", Globals.ScanAllMembers, null, new Type[] { typeof(XmlWriterDelegator), typeof(ICollection) }, null); Debug.Assert(s_incrementCollectionCountMethod != null); } return s_incrementCollectionCountMethod; @@ -816,7 +816,7 @@ internal static MethodInfo IsMemberTypeSameAsMemberValue { if (s_isMemberTypeSameAsMemberValue == null) { - s_isMemberTypeSameAsMemberValue = typeof(XmlObjectSerializerWriteContext).GetMethod("IsMemberTypeSameAsMemberValue", Globals.ScanAllMembers, new Type[] { typeof(object), typeof(Type) }); + s_isMemberTypeSameAsMemberValue = typeof(XmlObjectSerializerWriteContext).GetMethod("IsMemberTypeSameAsMemberValue", Globals.ScanAllMembers, null, new Type[] { typeof(object), typeof(Type) }, null); Debug.Assert(s_isMemberTypeSameAsMemberValue != null); } return s_isMemberTypeSameAsMemberValue; @@ -1006,7 +1006,7 @@ internal static MethodInfo ThrowInvalidDataContractExceptionMethod { if (s_throwInvalidDataContractExceptionMethod == null) { - s_throwInvalidDataContractExceptionMethod = typeof(DataContract).GetMethod("ThrowInvalidDataContractException", Globals.ScanAllMembers, new Type[] { typeof(string), typeof(Type) }); + s_throwInvalidDataContractExceptionMethod = typeof(DataContract).GetMethod("ThrowInvalidDataContractException", Globals.ScanAllMembers, null, new Type[] { typeof(string), typeof(Type) }, null); Debug.Assert(s_throwInvalidDataContractExceptionMethod != null); } return s_throwInvalidDataContractExceptionMethod; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index 095cd8278ce7d..4e5ea78c3e34d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -596,7 +596,7 @@ private void ReadCollection(CollectionDataContract collectionContract) { case CollectionKind.GenericDictionary: type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments()); - constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Array.Empty())!; + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null)!; break; case CollectionKind.Dictionary: type = Globals.TypeOfHashtable; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index ee7dbdba7a059..aa69ceb8e72e8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -409,8 +409,8 @@ private void WriteCollection(CollectionDataContract collectionContract) { enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType; } - MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); - MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); + MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, null, Array.Empty(), null); if (moveNextMethod == null || getCurrentMethod == null) { if (enumeratorType.IsInterface) @@ -457,7 +457,7 @@ private void WriteCollection(CollectionDataContract collectionContract) else if (isGenericDictionary) { Type ctorParam = Globals.TypeOfIEnumeratorGeneric.MakeGenericType(Globals.TypeOfKeyValuePair.MakeGenericType(keyValueTypes!)); - ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, new Type[] { ctorParam })!; + ConstructorInfo dictEnumCtor = enumeratorType.GetConstructor(Globals.ScanAllMembers, null, new Type[] { ctorParam }, null)!; _ilg.ConvertValue(collectionContract.GetEnumeratorMethod.ReturnType, ctorParam); _ilg.New(dictEnumCtor); } @@ -576,7 +576,7 @@ private bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value _ilg.Load(value); _ilg.Load(itemName); _ilg.Load(itemNamespace); - _ilg.Call(typeof(XmlWriterDelegator).GetMethod(writeArrayMethod, Globals.ScanAllMembers, new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) })!); + _ilg.Call(typeof(XmlWriterDelegator).GetMethod(writeArrayMethod, Globals.ScanAllMembers, null, new Type[] { type, typeof(XmlDictionaryString), typeof(XmlDictionaryString) }, null)!); return true; } return false; diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/EndToEndTest.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/EndToEndTest.cs new file mode 100644 index 0000000000000..8c6604e00ad00 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/EndToEndTest.cs @@ -0,0 +1,52 @@ +// 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.Diagnostics.CodeAnalysis; +using System.IO; +using System.Runtime.Serialization; +using System.Text; +using MyApplication.Shared.Types; + +class Program +{ + // Preserve the AuthState type until DataContractSerializer is fully trim-safe. + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(AuthState))] + static int Main(string[] args) + { + string data = @" Admin User true admin@fmdevsql.onmicrosoft.com "; + + var s = DeserializeDataContract(data); + if (s.GivenName != "Admin User" || + s.Name != "admin@fmdevsql.onmicrosoft.com" || + !s.IsAuthenticated) + { + return -1; + } + + return 100; + } + + private static T DeserializeDataContract(string serialized) + { + using (var inStream = new MemoryStream(Encoding.UTF8.GetBytes(serialized))) + { + var ser = new DataContractSerializer(typeof(T)); + return (T)ser.ReadObject(inStream); + } + } +} + +namespace MyApplication.Shared.Types +{ + public class AuthState + { + public AuthState() + { + } + + public bool IsAuthenticated { get; set; } + public string Name { get; set; } + public string GivenName { get; set; } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/System.Runtime.Serialization.Xml.TrimmingTests.proj b/src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/System.Runtime.Serialization.Xml.TrimmingTests.proj new file mode 100644 index 0000000000000..66e9abda01c80 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/TrimmingTests/System.Runtime.Serialization.Xml.TrimmingTests.proj @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file