1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections; 7 using System.Diagnostics; 8 using System.Reflection; 9 using System.Reflection.Emit; 10 using System.Text.RegularExpressions; 11 using System.Xml.Extensions; 12 13 #if !FEATURE_SERIALIZATION_UAPAOT 14 namespace System.Xml.Serialization 15 { 16 internal class SourceInfo 17 { 18 //a[ia] 19 //((global::System.Xml.Serialization.XmlSerializerNamespaces)p[0]) 20 private static Regex s_regex = new Regex("([(][(](?<t>[^)]+)[)])?(?<a>[^[]+)[[](?<ia>.+)[]][)]?"); 21 //((global::Microsoft.CFx.Test.Common.TypeLibrary.IXSType_9)o), @"IXSType_9", @"", true, true); 22 private static Regex s_regex2 = new Regex("[(][(](?<cast>[^)]+)[)](?<arg>[^)]+)[)]"); 23 24 private static readonly Lazy<MethodInfo> s_iListGetItemMethod = new Lazy<MethodInfo>( 25 () => 26 { 27 return typeof(IList).GetMethod( 28 "get_Item", 29 new Type[] { typeof(Int32) } 30 ); 31 }); 32 33 public string Source; 34 public readonly string Arg; 35 public readonly MemberInfo MemberInfo; 36 public readonly Type Type; 37 public readonly CodeGenerator ILG; 38 SourceInfo(string source, string arg, MemberInfo memberInfo, Type type, CodeGenerator ilg)39 public SourceInfo(string source, string arg, MemberInfo memberInfo, Type type, CodeGenerator ilg) 40 { 41 this.Source = source; 42 this.Arg = arg ?? source; 43 this.MemberInfo = memberInfo; 44 this.Type = type; 45 this.ILG = ilg; 46 } 47 CastTo(TypeDesc td)48 public SourceInfo CastTo(TypeDesc td) 49 { 50 return new SourceInfo("((" + td.CSharpName + ")" + Source + ")", Arg, MemberInfo, td.Type, ILG); 51 } 52 LoadAddress(Type elementType)53 public void LoadAddress(Type elementType) 54 { 55 InternalLoad(elementType, asAddress: true); 56 } 57 Load(Type elementType)58 public void Load(Type elementType) 59 { 60 InternalLoad(elementType); 61 } 62 InternalLoad(Type elementType, bool asAddress = false)63 private void InternalLoad(Type elementType, bool asAddress = false) 64 { 65 Match match = s_regex.Match(Arg); 66 if (match.Success) 67 { 68 object varA = ILG.GetVariable(match.Groups["a"].Value); 69 Type varType = ILG.GetVariableType(varA); 70 object varIA = ILG.GetVariable(match.Groups["ia"].Value); 71 if (varType.IsArray) 72 { 73 ILG.Load(varA); 74 ILG.Load(varIA); 75 Type eType = varType.GetElementType(); 76 if (CodeGenerator.IsNullableGenericType(eType)) 77 { 78 ILG.Ldelema(eType); 79 ConvertNullableValue(eType, elementType); 80 } 81 else 82 { 83 if (eType.IsValueType) 84 { 85 ILG.Ldelema(eType); 86 if (!asAddress) 87 { 88 ILG.Ldobj(eType); 89 } 90 } 91 else 92 ILG.Ldelem(eType); 93 if (elementType != null) 94 ILG.ConvertValue(eType, elementType); 95 } 96 } 97 else 98 { 99 ILG.Load(varA); 100 ILG.Load(varIA); 101 MethodInfo get_Item = varType.GetMethod( 102 "get_Item", 103 CodeGenerator.InstanceBindingFlags, 104 new Type[] { typeof(Int32) } 105 ); 106 107 if (get_Item == null && typeof(IList).IsAssignableFrom(varType)) 108 { 109 get_Item = s_iListGetItemMethod.Value; 110 } 111 112 Debug.Assert(get_Item != null); 113 ILG.Call(get_Item); 114 Type eType = get_Item.ReturnType; 115 if (CodeGenerator.IsNullableGenericType(eType)) 116 { 117 LocalBuilder localTmp = ILG.GetTempLocal(eType); 118 ILG.Stloc(localTmp); 119 ILG.Ldloca(localTmp); 120 ConvertNullableValue(eType, elementType); 121 } 122 else if ((elementType != null) && !(eType.IsAssignableFrom(elementType) || elementType.IsAssignableFrom(eType))) 123 { 124 throw new CodeGeneratorConversionException(eType, elementType, asAddress, "IsNotAssignableFrom"); 125 } 126 else 127 { 128 Convert(eType, elementType, asAddress); 129 } 130 } 131 } 132 else if (Source == "null") 133 { 134 ILG.Load(null); 135 } 136 else 137 { 138 object var; 139 Type varType; 140 if (Arg.StartsWith("o.@", StringComparison.Ordinal) || MemberInfo != null) 141 { 142 var = ILG.GetVariable(Arg.StartsWith("o.@", StringComparison.Ordinal) ? "o" : Arg); 143 varType = ILG.GetVariableType(var); 144 if (varType.IsValueType) 145 ILG.LoadAddress(var); 146 else 147 ILG.Load(var); 148 } 149 else 150 { 151 var = ILG.GetVariable(Arg); 152 varType = ILG.GetVariableType(var); 153 154 if (CodeGenerator.IsNullableGenericType(varType) && 155 varType.GetGenericArguments()[0] == elementType) 156 { 157 ILG.LoadAddress(var); 158 ConvertNullableValue(varType, elementType); 159 } 160 else 161 { 162 if (asAddress) 163 ILG.LoadAddress(var); 164 else 165 ILG.Load(var); 166 } 167 } 168 169 if (MemberInfo != null) 170 { 171 Type memberType = (MemberInfo is FieldInfo) ? 172 ((FieldInfo)MemberInfo).FieldType : ((PropertyInfo)MemberInfo).PropertyType; 173 if (CodeGenerator.IsNullableGenericType(memberType)) 174 { 175 ILG.LoadMemberAddress(MemberInfo); 176 ConvertNullableValue(memberType, elementType); 177 } 178 else 179 { 180 ILG.LoadMember(MemberInfo); 181 Convert(memberType, elementType, asAddress); 182 } 183 } 184 else 185 { 186 match = s_regex2.Match(Source); 187 if (match.Success) 188 { 189 Debug.Assert(match.Groups["arg"].Value == Arg); 190 Debug.Assert(match.Groups["cast"].Value == CodeIdentifier.GetCSharpName(Type)); 191 if (asAddress) 192 ILG.ConvertAddress(varType, Type); 193 else 194 ILG.ConvertValue(varType, Type); 195 varType = Type; 196 } 197 Convert(varType, elementType, asAddress); 198 } 199 } 200 } 201 Convert(Type sourceType, Type targetType, bool asAddress)202 private void Convert(Type sourceType, Type targetType, bool asAddress) 203 { 204 if (targetType != null) 205 { 206 if (asAddress) 207 ILG.ConvertAddress(sourceType, targetType); 208 else 209 ILG.ConvertValue(sourceType, targetType); 210 } 211 } 212 ConvertNullableValue(Type nullableType, Type targetType)213 private void ConvertNullableValue(Type nullableType, Type targetType) 214 { 215 System.Diagnostics.Debug.Assert(targetType == nullableType || targetType.IsAssignableFrom(nullableType.GetGenericArguments()[0])); 216 if (targetType != nullableType) 217 { 218 MethodInfo Nullable_get_Value = nullableType.GetMethod( 219 "get_Value", 220 CodeGenerator.InstanceBindingFlags, 221 CodeGenerator.EmptyTypeArray 222 ); 223 ILG.Call(Nullable_get_Value); 224 if (targetType != null) 225 { 226 ILG.ConvertValue(Nullable_get_Value.ReturnType, targetType); 227 } 228 } 229 } 230 operator string(SourceInfo source)231 public static implicit operator string (SourceInfo source) 232 { 233 return source.Source; 234 } 235 operator !=(SourceInfo a, SourceInfo b)236 public static bool operator !=(SourceInfo a, SourceInfo b) 237 { 238 if ((object)a != null) 239 return !a.Equals(b); 240 return (object)b != null; 241 } 242 operator ==(SourceInfo a, SourceInfo b)243 public static bool operator ==(SourceInfo a, SourceInfo b) 244 { 245 if ((object)a != null) 246 return a.Equals(b); 247 return (object)b == null; 248 } 249 Equals(object obj)250 public override bool Equals(object obj) 251 { 252 if (obj == null) 253 return Source == null; 254 SourceInfo info = obj as SourceInfo; 255 if (info != null) 256 return Source == info.Source; 257 return false; 258 } 259 GetHashCode()260 public override int GetHashCode() 261 { 262 return (Source == null) ? 0 : Source.GetHashCode(); 263 } 264 } 265 } 266 #endif 267