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