| File: System\Xml\Serialization\SourceInfo.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// 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.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; using System.Text.RegularExpressions; namespace System.Xml.Serialization { internal sealed partial class SourceInfo { //a[ia] //((global::System.Xml.Serialization.XmlSerializerNamespaces)p[0]) [GeneratedRegex("([(][(](?<t>[^)]+)[)])?(?<a>[^[]+)[[](?<ia>.+)[]][)]?")] private static partial Regex Regex1 { get; } //((global::Microsoft.CFx.Test.Common.TypeLibrary.IXSType_9)o), @"IXSType_9", @"", true, true); [GeneratedRegex("[(][(](?<cast>[^)]+)[)](?<arg>[^)]+)[)]")] private static partial Regex Regex2 { get; } private static readonly Lazy<MethodInfo> s_iListGetItemMethod = new Lazy<MethodInfo>( () => { return typeof(IList).GetMethod( "get_Item", new Type[] { typeof(int) } )!; }); public string Source; public readonly string Arg; public readonly MemberInfo? MemberInfo; public readonly Type? Type; public readonly CodeGenerator ILG; public SourceInfo(string source, string? arg, MemberInfo? memberInfo, Type? type, CodeGenerator ilg) { this.Source = source; this.Arg = arg ?? source; this.MemberInfo = memberInfo; this.Type = type; this.ILG = ilg; } public SourceInfo CastTo(TypeDesc td) { return new SourceInfo($"(({td.CSharpName}){Source})", Arg, MemberInfo, td.Type!, ILG); } [RequiresUnreferencedCode("calls InternalLoad")] public void LoadAddress(Type? elementType) { InternalLoad(elementType, asAddress: true); } [RequiresUnreferencedCode("calls InternalLoad")] public void Load(Type? elementType) { InternalLoad(elementType); } [RequiresUnreferencedCode("calls LoadMemberAddress")] private void InternalLoad(Type? elementType, bool asAddress = false) { Match match = Regex1.Match(Arg); if (match.Success) { object varA = ILG.GetVariable(match.Groups["a"].Value); Type varType = CodeGenerator.GetVariableType(varA); object varIA = ILG.GetVariable(match.Groups["ia"].Value); if (varType.IsArray) { ILG.Load(varA); ILG.Load(varIA); Type eType = varType.GetElementType()!; if (CodeGenerator.IsNullableGenericType(eType)) { ILG.Ldelema(eType); ConvertNullableValue(eType, elementType!); } else { if (eType.IsValueType) { ILG.Ldelema(eType); if (!asAddress) { ILG.Ldobj(eType); } } else ILG.Ldelem(eType); if (elementType != null) ILG.ConvertValue(eType, elementType); } } else { ILG.LoadAddress(varA); ILG.Load(varIA); MethodInfo get_Item = varType.GetMethod( "get_Item", CodeGenerator.InstanceBindingFlags, new Type[] { typeof(int) } )!; if (get_Item == null && typeof(IList).IsAssignableFrom(varType)) { get_Item = s_iListGetItemMethod.Value; } Debug.Assert(get_Item != null); ILG.Call(get_Item); Type eType = get_Item.ReturnType; if (CodeGenerator.IsNullableGenericType(eType)) { LocalBuilder localTmp = ILG.GetTempLocal(eType); ILG.Stloc(localTmp); ILG.Ldloca(localTmp); ConvertNullableValue(eType, elementType!); } else if ((elementType != null) && !(eType.IsAssignableFrom(elementType) || elementType.IsAssignableFrom(eType))) { throw new CodeGeneratorConversionException(eType, elementType, asAddress, "IsNotAssignableFrom"); } else { Convert(eType, elementType, asAddress); } } } else if (Source == "null") { ILG.Load(null); } else { object var; Type varType; if (Arg.StartsWith("o.@", StringComparison.Ordinal) || MemberInfo != null) { var = ILG.GetVariable(Arg.StartsWith("o.@", StringComparison.Ordinal) ? "o" : Arg); varType = CodeGenerator.GetVariableType(var); if (varType.IsValueType) ILG.LoadAddress(var); else ILG.Load(var); } else { var = ILG.GetVariable(Arg); varType = CodeGenerator.GetVariableType(var); if (CodeGenerator.IsNullableGenericType(varType) && varType.GetGenericArguments()[0] == elementType) { ILG.LoadAddress(var); ConvertNullableValue(varType, elementType); } else { if (asAddress) ILG.LoadAddress(var); else ILG.Load(var); } } if (MemberInfo != null) { Type memberType = (MemberInfo is FieldInfo) ? ((FieldInfo)MemberInfo).FieldType : ((PropertyInfo)MemberInfo).PropertyType; if (CodeGenerator.IsNullableGenericType(memberType)) { ILG.LoadMemberAddress(MemberInfo); ConvertNullableValue(memberType, elementType!); } else { ILG.LoadMember(MemberInfo); Convert(memberType, elementType, asAddress); } } else { match = Regex2.Match(Source); if (match.Success) { Debug.Assert(match.Groups["arg"].Value == Arg); Debug.Assert(match.Groups["cast"].Value == CodeIdentifier.GetCSharpName(Type!)); if (asAddress) ILG.ConvertAddress(varType, Type!); else ILG.ConvertValue(varType, Type!); varType = Type!; } Convert(varType!, elementType, asAddress); } } } private void Convert(Type sourceType, Type? targetType, bool asAddress) { if (targetType != null) { if (asAddress) ILG.ConvertAddress(sourceType, targetType); else ILG.ConvertValue(sourceType, targetType); } } private void ConvertNullableValue( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type nullableType, Type targetType) { System.Diagnostics.Debug.Assert(targetType == nullableType || targetType.IsAssignableFrom(nullableType.GetGenericArguments()[0])); if (targetType != nullableType) { MethodInfo Nullable_get_Value = nullableType.GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, Type.EmptyTypes )!; ILG.Call(Nullable_get_Value); if (targetType != null) { ILG.ConvertValue(Nullable_get_Value.ReturnType, targetType); } } } public static implicit operator string(SourceInfo source) { return source.Source; } public static bool operator !=(SourceInfo? a, SourceInfo? b) { if (a is not null) return !a.Equals(b); return b is not null; } public static bool operator ==(SourceInfo? a, SourceInfo? b) { if (a is not null) return a.Equals(b); return b is null; } public override bool Equals([NotNullWhen(true)] object? obj) { if (obj == null) return Source == null; SourceInfo? info = obj as SourceInfo; if (info != null) return Source == info.Source; return false; } public override int GetHashCode() { return (Source == null) ? 0 : Source.GetHashCode(); } } }