SourceInfo.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. //------------------------------------------------------------------------------
  2. // <copyright file="SourceInfo.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. //------------------------------------------------------------------------------
  7. namespace System.Xml.Serialization {
  8. using System;
  9. using System.Collections;
  10. using System.Diagnostics;
  11. using System.Reflection;
  12. using System.Reflection.Emit;
  13. using System.Text.RegularExpressions;
  14. internal class SourceInfo {
  15. //a[ia]
  16. //((global::System.Xml.Serialization.XmlSerializerNamespaces)p[0])
  17. static Regex regex = new Regex("([(][(](?<t>[^)]+)[)])?(?<a>[^[]+)[[](?<ia>.+)[]][)]?");
  18. //((global::Microsoft.CFx.Test.Common.TypeLibrary.IXSType_9)o), @"IXSType_9", @"", true, true);
  19. static Regex regex2 = new Regex("[(][(](?<cast>[^)]+)[)](?<arg>[^)]+)[)]");
  20. static readonly Lazy<MethodInfo> iListGetItemMethod = new Lazy<MethodInfo>(
  21. () =>
  22. {
  23. return typeof(IList).GetMethod(
  24. "get_Item",
  25. CodeGenerator.InstanceBindingFlags,
  26. null,
  27. new Type[] { typeof(Int32) },
  28. null
  29. );
  30. });
  31. public string Source;
  32. public readonly string Arg;
  33. public readonly MemberInfo MemberInfo;
  34. public readonly Type Type;
  35. public readonly CodeGenerator ILG;
  36. public SourceInfo(string source, string arg, MemberInfo memberInfo, Type type, CodeGenerator ilg) {
  37. this.Source = source;
  38. this.Arg = arg ?? source;
  39. this.MemberInfo = memberInfo;
  40. this.Type = type;
  41. this.ILG = ilg;
  42. }
  43. public SourceInfo CastTo(TypeDesc td) {
  44. return new SourceInfo("((" + td.CSharpName + ")" + Source + ")", Arg, MemberInfo, td.Type, ILG);
  45. }
  46. public void LoadAddress(Type elementType) {
  47. InternalLoad(elementType, asAddress: true);
  48. }
  49. public void Load(Type elementType) {
  50. InternalLoad(elementType);
  51. }
  52. private void InternalLoad(Type elementType, bool asAddress = false) {
  53. Match match = regex.Match(Arg);
  54. if (match.Success) {
  55. object varA = ILG.GetVariable(match.Groups["a"].Value);
  56. Type varType = ILG.GetVariableType(varA);
  57. object varIA = ILG.GetVariable(match.Groups["ia"].Value);
  58. if (varType.IsArray) {
  59. ILG.Load(varA);
  60. ILG.Load(varIA);
  61. Type eType = varType.GetElementType();
  62. if (CodeGenerator.IsNullableGenericType(eType)) {
  63. ILG.Ldelema(eType);
  64. ConvertNullableValue(eType, elementType);
  65. }
  66. else {
  67. if (eType.IsValueType) {
  68. ILG.Ldelema(eType);
  69. if (!asAddress) {
  70. ILG.Ldobj(eType);
  71. }
  72. }
  73. else
  74. ILG.Ldelem(eType);
  75. if (elementType != null)
  76. ILG.ConvertValue(eType, elementType);
  77. }
  78. }
  79. else {
  80. ILG.Load(varA);
  81. ILG.Load(varIA);
  82. MethodInfo get_Item = varType.GetMethod(
  83. "get_Item",
  84. CodeGenerator.InstanceBindingFlags,
  85. null,
  86. new Type[] { typeof(Int32) },
  87. null
  88. );
  89. if (get_Item == null && typeof(IList).IsAssignableFrom(varType))
  90. {
  91. get_Item = iListGetItemMethod.Value;
  92. }
  93. Debug.Assert(get_Item != null);
  94. ILG.Call(get_Item);
  95. Type eType = get_Item.ReturnType;
  96. if (CodeGenerator.IsNullableGenericType(eType)) {
  97. LocalBuilder localTmp = ILG.GetTempLocal(eType);
  98. ILG.Stloc(localTmp);
  99. ILG.Ldloca(localTmp);
  100. ConvertNullableValue(eType, elementType);
  101. }
  102. else if ((elementType != null) && !(eType.IsAssignableFrom(elementType) || elementType.IsAssignableFrom(eType))) {
  103. throw new CodeGeneratorConversionException(eType, elementType, asAddress, "IsNotAssignableFrom");
  104. }
  105. else {
  106. Convert(eType, elementType, asAddress);
  107. }
  108. }
  109. }
  110. else if (Source == "null") {
  111. ILG.Load(null);
  112. }
  113. else {
  114. object var;
  115. Type varType;
  116. if (Arg.StartsWith("o.@", StringComparison.Ordinal) || MemberInfo != null) {
  117. var = ILG.GetVariable(Arg.StartsWith("o.@", StringComparison.Ordinal) ? "o" : Arg);
  118. varType = ILG.GetVariableType(var);
  119. if (varType.IsValueType)
  120. ILG.LoadAddress(var);
  121. else
  122. ILG.Load(var);
  123. }
  124. else {
  125. var = ILG.GetVariable(Arg);
  126. varType = ILG.GetVariableType(var);
  127. if (CodeGenerator.IsNullableGenericType(varType) &&
  128. varType.GetGenericArguments()[0] == elementType) {
  129. ILG.LoadAddress(var);
  130. ConvertNullableValue(varType, elementType);
  131. }
  132. else {
  133. if (asAddress)
  134. ILG.LoadAddress(var);
  135. else
  136. ILG.Load(var);
  137. }
  138. }
  139. if (MemberInfo != null) {
  140. Type memberType = (MemberInfo is FieldInfo) ?
  141. ((FieldInfo)MemberInfo).FieldType : ((PropertyInfo)MemberInfo).PropertyType;
  142. if (CodeGenerator.IsNullableGenericType(memberType)) {
  143. ILG.LoadMemberAddress(MemberInfo);
  144. ConvertNullableValue(memberType, elementType);
  145. }
  146. else {
  147. ILG.LoadMember(MemberInfo);
  148. Convert(memberType, elementType, asAddress);
  149. }
  150. }
  151. else {
  152. match = regex2.Match(Source);
  153. if (match.Success) {
  154. Debug.Assert(match.Groups["arg"].Value == Arg);
  155. Debug.Assert(match.Groups["cast"].Value == CodeIdentifier.GetCSharpName(Type));
  156. if (asAddress)
  157. ILG.ConvertAddress(varType, Type);
  158. else
  159. ILG.ConvertValue(varType, Type);
  160. varType = Type;
  161. }
  162. Convert(varType, elementType, asAddress);
  163. }
  164. }
  165. }
  166. private void Convert(Type sourceType, Type targetType, bool asAddress) {
  167. if (targetType != null) {
  168. if (asAddress)
  169. ILG.ConvertAddress(sourceType, targetType);
  170. else
  171. ILG.ConvertValue(sourceType, targetType);
  172. }
  173. }
  174. private void ConvertNullableValue(Type nullableType, Type targetType) {
  175. System.Diagnostics.Debug.Assert(targetType == nullableType || targetType.IsAssignableFrom(nullableType.GetGenericArguments()[0]));
  176. if (targetType != nullableType) {
  177. MethodInfo Nullable_get_Value = nullableType.GetMethod(
  178. "get_Value",
  179. CodeGenerator.InstanceBindingFlags,
  180. null,
  181. CodeGenerator.EmptyTypeArray,
  182. null
  183. );
  184. ILG.Call(Nullable_get_Value);
  185. if (targetType != null) {
  186. ILG.ConvertValue(Nullable_get_Value.ReturnType, targetType);
  187. }
  188. }
  189. }
  190. public static implicit operator string(SourceInfo source) {
  191. return source.Source;
  192. }
  193. public static bool operator !=(SourceInfo a, SourceInfo b) {
  194. if ((object)a != null)
  195. return !a.Equals(b);
  196. return (object)b != null;
  197. }
  198. public static bool operator ==(SourceInfo a, SourceInfo b) {
  199. if ((object)a != null)
  200. return a.Equals(b);
  201. return (object)b == null;
  202. }
  203. public override bool Equals(object obj) {
  204. if (obj == null)
  205. return Source == null;
  206. SourceInfo info = obj as SourceInfo;
  207. if (info != null)
  208. return Source == info.Source;
  209. return false;
  210. }
  211. public override int GetHashCode() {
  212. return (Source == null) ? 0 : Source.GetHashCode();
  213. }
  214. }
  215. }