BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / IKVM.Reflection / CustomModifiers.cs
1 /*
2   Copyright (C) 2011 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Diagnostics;
27 using System.Text;
28 using IKVM.Reflection.Emit;
29 using IKVM.Reflection.Reader;
30
31 namespace IKVM.Reflection
32 {
33         public struct CustomModifiers : IEquatable<CustomModifiers>, IEnumerable<CustomModifiers.Entry>
34         {
35                 private static readonly Type ModOpt = new MarkerType();
36                 private static readonly Type ModReq = new MarkerType();
37                 private static readonly Type Initial = ModOpt;
38                 private readonly Type[] types;
39
40                 internal CustomModifiers(List<CustomModifiersBuilder.Item> list)
41                 {
42                         bool required = Initial == ModReq;
43                         int count = list.Count;
44                         foreach (CustomModifiersBuilder.Item item in list)
45                         {
46                                 if (item.required != required)
47                                 {
48                                         required = item.required;
49                                         count++;
50                                 }
51                         }
52                         types = new Type[count];
53                         required = Initial == ModReq;
54                         int index = 0;
55                         foreach (CustomModifiersBuilder.Item item in list)
56                         {
57                                 if (item.required != required)
58                                 {
59                                         required = item.required;
60                                         types[index++] = required ? ModReq : ModOpt;
61                                 }
62                                 types[index++] = item.type;
63                         }
64                 }
65
66                 private CustomModifiers(Type[] types)
67                 {
68                         Debug.Assert(types == null || types.Length != 0);
69                         this.types = types;
70                 }
71
72                 public struct Enumerator : IEnumerator<Entry>
73                 {
74                         private readonly Type[] types;
75                         private int index;
76                         private bool required;
77
78                         internal Enumerator(Type[] types)
79                         {
80                                 this.types = types;
81                                 this.index = -1;
82                                 this.required = Initial == ModReq;
83                         }
84
85                         void System.Collections.IEnumerator.Reset()
86                         {
87                                 this.index = -1;
88                                 this.required = Initial == ModReq;
89                         }
90
91                         public Entry Current
92                         {
93                                 get { return new Entry(types[index], required); }
94                         }
95
96                         public bool MoveNext()
97                         {
98                                 if (types == null || index == types.Length)
99                                 {
100                                         return false;
101                                 }
102                                 index++;
103                                 if (index == types.Length)
104                                 {
105                                         return false;
106                                 }
107                                 else if (types[index] == ModOpt)
108                                 {
109                                         required = false;
110                                         index++;
111                                 }
112                                 else if (types[index] == ModReq)
113                                 {
114                                         required = true;
115                                         index++;
116                                 }
117                                 return true;
118                         }
119
120                         object System.Collections.IEnumerator.Current
121                         {
122                                 get { return Current; }
123                         }
124
125                         void IDisposable.Dispose()
126                         {
127                         }
128                 }
129
130                 public struct Entry
131                 {
132                         private readonly Type type;
133                         private readonly bool required;
134
135                         internal Entry(Type type, bool required)
136                         {
137                                 this.type = type;
138                                 this.required = required;
139                         }
140
141                         public Type Type
142                         {
143                                 get { return type; }
144                         }
145
146                         public bool IsRequired
147                         {
148                                 get { return required; }
149                         }
150                 }
151
152                 public Enumerator GetEnumerator()
153                 {
154                         return new Enumerator(types);
155                 }
156
157                 IEnumerator<Entry> IEnumerable<Entry>.GetEnumerator()
158                 {
159                         return GetEnumerator();
160                 }
161
162                 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
163                 {
164                         return GetEnumerator();
165                 }
166
167                 public bool IsEmpty
168                 {
169                         get { return types == null; }
170                 }
171
172                 public bool Equals(CustomModifiers other)
173                 {
174                         return Util.ArrayEquals(types, other.types);
175                 }
176
177                 public override bool Equals(object obj)
178                 {
179                         CustomModifiers? other = obj as CustomModifiers?;
180                         return other != null && Equals(other.Value);
181                 }
182
183                 public override int GetHashCode()
184                 {
185                         return Util.GetHashCode(types);
186                 }
187
188                 public override string ToString()
189                 {
190                         if (types == null)
191                         {
192                                 return string.Empty;
193                         }
194                         StringBuilder sb = new StringBuilder();
195                         string sep = "";
196                         foreach (Entry e in this)
197                         {
198                                 sb.Append(sep).Append(e.IsRequired ? "modreq(" : "modopt(").Append(e.Type.FullName).Append(')');
199                                 sep = " ";
200                         }
201                         return sb.ToString();
202                 }
203
204                 private Type[] GetRequiredOrOptional(bool required)
205                 {
206                         if (types == null)
207                         {
208                                 return Type.EmptyTypes;
209                         }
210                         int count = 0;
211                         foreach (Entry e in this)
212                         {
213                                 if (e.IsRequired == required)
214                                 {
215                                         count++;
216                                 }
217                         }
218                         Type[] result = new Type[count];
219                         foreach (Entry e in this)
220                         {
221                                 if (e.IsRequired == required)
222                                 {
223                                         // FXBUG reflection (and ildasm) return custom modifiers in reverse order
224                                         // while SRE writes them in the specified order
225                                         result[--count] = e.Type;
226                                 }
227                         }
228                         return result;
229                 }
230
231                 internal Type[] GetRequired()
232                 {
233                         return GetRequiredOrOptional(true);
234                 }
235
236                 internal Type[] GetOptional()
237                 {
238                         return GetRequiredOrOptional(false);
239                 }
240
241                 internal CustomModifiers Bind(IGenericBinder binder)
242                 {
243                         if (types == null)
244                         {
245                                 return this;
246                         }
247                         Type[] result = types;
248                         for (int i = 0; i < types.Length; i++)
249                         {
250                                 if (types[i] == ModOpt || types[i] == ModReq)
251                                 {
252                                         continue;
253                                 }
254                                 Type type = types[i].BindTypeParameters(binder);
255                                 if (!ReferenceEquals(type, types[i]))
256                                 {
257                                         if (result == types)
258                                         {
259                                                 result = (Type[])types.Clone();
260                                         }
261                                         result[i] = type;
262                                 }
263                         }
264                         return new CustomModifiers(result);
265                 }
266
267                 internal static CustomModifiers Read(ModuleReader module, ByteReader br, IGenericContext context)
268                 {
269                         byte b = br.PeekByte();
270                         if (!IsCustomModifier(b))
271                         {
272                                 return new CustomModifiers();
273                         }
274                         List<Type> list = new List<Type>();
275                         Type mode = Initial;
276                         do
277                         {
278                                 Type cmod = br.ReadByte() == Signature.ELEMENT_TYPE_CMOD_REQD ? ModReq : ModOpt;
279                                 if (mode != cmod)
280                                 {
281                                         mode = cmod;
282                                         list.Add(mode);
283                                 }
284                                 list.Add(Signature.ReadTypeDefOrRefEncoded(module, br, context));
285                                 b = br.PeekByte();
286                         }
287                         while (IsCustomModifier(b));
288                         return new CustomModifiers(list.ToArray());
289                 }
290
291                 internal static void Skip(ByteReader br)
292                 {
293                         byte b = br.PeekByte();
294                         while (IsCustomModifier(b))
295                         {
296                                 br.ReadByte();
297                                 br.ReadCompressedInt();
298                                 b = br.PeekByte();
299                         }
300                 }
301
302                 internal static CustomModifiers FromReqOpt(Type[] req, Type[] opt)
303                 {
304                         List<Type> list = null;
305                         if (opt != null && opt.Length != 0)
306                         {
307                                 list = new List<Type>(opt);
308                         }
309                         if (req != null && req.Length != 0)
310                         {
311                                 if (list == null)
312                                 {
313                                         list = new List<Type>();
314                                 }
315                                 list.Add(ModReq);
316                                 list.AddRange(req);
317                         }
318                         if (list == null)
319                         {
320                                 return new CustomModifiers();
321                         }
322                         else
323                         {
324                                 return new CustomModifiers(list.ToArray());
325                         }
326                 }
327
328                 private static bool IsCustomModifier(byte b)
329                 {
330                         return b == Signature.ELEMENT_TYPE_CMOD_OPT || b == Signature.ELEMENT_TYPE_CMOD_REQD;
331                 }
332
333                 internal static CustomModifiers Combine(CustomModifiers mods1, CustomModifiers mods2)
334                 {
335                         if (mods1.IsEmpty)
336                         {
337                                 return mods2;
338                         }
339                         else if (mods2.IsEmpty)
340                         {
341                                 return mods1;
342                         }
343                         else
344                         {
345                                 Type[] combo = new Type[mods1.types.Length + mods2.types.Length];
346                                 Array.Copy(mods1.types, combo, mods1.types.Length);
347                                 Array.Copy(mods2.types, 0, combo, mods1.types.Length, mods2.types.Length);
348                                 return new CustomModifiers(combo);
349                         }
350                 }
351         }
352 }