Update to the latest ikvm.reflection
[mono.git] / mcs / class / IKVM.Reflection / Reader / TypeDefImpl.cs
1 /*
2   Copyright (C) 2009-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.Text;
27 using System.Runtime.InteropServices;
28 using IKVM.Reflection.Metadata;
29
30 namespace IKVM.Reflection.Reader
31 {
32         sealed class TypeDefImpl : Type
33         {
34                 private readonly ModuleReader module;
35                 private readonly int index;
36                 private readonly string typeName;
37                 private readonly string typeNamespace;
38                 private Type[] typeArgs;
39
40                 internal TypeDefImpl(ModuleReader module, int index)
41                 {
42                         this.module = module;
43                         this.index = index;
44                         this.typeName = module.GetString(module.TypeDef.records[index].TypeName);
45                         this.typeNamespace = module.GetString(module.TypeDef.records[index].TypeNamespace);
46                         MarkEnumOrValueType(typeNamespace, typeName);
47                 }
48
49                 public override Type BaseType
50                 {
51                         get
52                         {
53                                 int extends = module.TypeDef.records[index].Extends;
54                                 if ((extends & 0xFFFFFF) == 0)
55                                 {
56                                         return null;
57                                 }
58                                 return module.ResolveType(extends, this);
59                         }
60                 }
61
62                 public override TypeAttributes Attributes
63                 {
64                         get { return (TypeAttributes)module.TypeDef.records[index].Flags; }
65                 }
66
67                 public override EventInfo[] __GetDeclaredEvents()
68                 {
69                         int token = this.MetadataToken;
70                         // TODO use binary search?
71                         for (int i = 0; i < module.EventMap.records.Length; i++)
72                         {
73                                 if (module.EventMap.records[i].Parent == token)
74                                 {
75                                         int evt = module.EventMap.records[i].EventList - 1;
76                                         int end = module.EventMap.records.Length > i + 1 ? module.EventMap.records[i + 1].EventList - 1 : module.Event.records.Length;
77                                         EventInfo[] events = new EventInfo[end - evt];
78                                         if (module.EventPtr.RowCount == 0)
79                                         {
80                                                 for (int j = 0; evt < end; evt++, j++)
81                                                 {
82                                                         events[j] = new EventInfoImpl(module, this, evt);
83                                                 }
84                                         }
85                                         else
86                                         {
87                                                 for (int j = 0; evt < end; evt++, j++)
88                                                 {
89                                                         events[j] = new EventInfoImpl(module, this, module.EventPtr.records[evt] - 1);
90                                                 }
91                                         }
92                                         return events;
93                                 }
94                         }
95                         return Empty<EventInfo>.Array;
96                 }
97
98                 public override FieldInfo[] __GetDeclaredFields()
99                 {
100                         int field = module.TypeDef.records[index].FieldList - 1;
101                         int end = module.TypeDef.records.Length > index + 1 ? module.TypeDef.records[index + 1].FieldList - 1 : module.Field.records.Length;
102                         FieldInfo[] fields = new FieldInfo[end - field];
103                         if (module.FieldPtr.RowCount == 0)
104                         {
105                                 for (int i = 0; field < end; i++, field++)
106                                 {
107                                         fields[i] = module.GetFieldAt(this, field);
108                                 }
109                         }
110                         else
111                         {
112                                 for (int i = 0; field < end; i++, field++)
113                                 {
114                                         fields[i] = module.GetFieldAt(this, module.FieldPtr.records[field] - 1);
115                                 }
116                         }
117                         return fields;
118                 }
119
120                 public override Type[] __GetDeclaredInterfaces()
121                 {
122                         int token = this.MetadataToken;
123                         List<Type> list = null;
124                         // TODO use binary search?
125                         for (int i = 0; i < module.InterfaceImpl.records.Length; i++)
126                         {
127                                 if (module.InterfaceImpl.records[i].Class == token)
128                                 {
129                                         if (list == null)
130                                         {
131                                                 list = new List<Type>();
132                                         }
133                                         list.Add(module.ResolveType(module.InterfaceImpl.records[i].Interface, this));
134                                 }
135                         }
136                         return Util.ToArray(list, Type.EmptyTypes);
137                 }
138
139                 public override MethodBase[] __GetDeclaredMethods()
140                 {
141                         int method = module.TypeDef.records[index].MethodList - 1;
142                         int end = module.TypeDef.records.Length > index + 1 ? module.TypeDef.records[index + 1].MethodList - 1 : module.MethodDef.records.Length;
143                         MethodBase[] methods = new MethodBase[end - method];
144                         if (module.MethodPtr.RowCount == 0)
145                         {
146                                 for (int i = 0; method < end; method++, i++)
147                                 {
148                                         methods[i] = module.GetMethodAt(this, method);
149                                 }
150                         }
151                         else
152                         {
153                                 for (int i = 0; method < end; method++, i++)
154                                 {
155                                         methods[i] = module.GetMethodAt(this, module.MethodPtr.records[method] - 1);
156                                 }
157                         }
158                         return methods;
159                 }
160
161                 public override __MethodImplMap __GetMethodImplMap()
162                 {
163                         List<MethodInfo> bodies = new List<MethodInfo>();
164                         List<List<MethodInfo>> declarations = new List<List<MethodInfo>>();
165                         int token = this.MetadataToken;
166                         // TODO use binary search?
167                         for (int i = 0; i < module.MethodImpl.records.Length; i++)
168                         {
169                                 if (module.MethodImpl.records[i].Class == token)
170                                 {
171                                         MethodInfo body = (MethodInfo)module.ResolveMethod(module.MethodImpl.records[i].MethodBody, typeArgs, null);
172                                         int index = bodies.IndexOf(body);
173                                         if (index == -1)
174                                         {
175                                                 index = bodies.Count;
176                                                 bodies.Add(body);
177                                                 declarations.Add(new List<MethodInfo>());
178                                         }
179                                         MethodInfo declaration = (MethodInfo)module.ResolveMethod(module.MethodImpl.records[i].MethodDeclaration, typeArgs, null);
180                                         declarations[index].Add(declaration);
181                                 }
182                         }
183                         __MethodImplMap map = new __MethodImplMap();
184                         map.TargetType = this;
185                         map.MethodBodies = bodies.ToArray();
186                         map.MethodDeclarations = new MethodInfo[declarations.Count][];
187                         for (int i = 0; i < map.MethodDeclarations.Length; i++)
188                         {
189                                 map.MethodDeclarations[i] = declarations[i].ToArray();
190                         }
191                         return map;
192                 }
193
194                 public override Type[] __GetDeclaredTypes()
195                 {
196                         int token = this.MetadataToken;
197                         List<Type> list = new List<Type>();
198                         // TODO use binary search?
199                         for (int i = 0; i < module.NestedClass.records.Length; i++)
200                         {
201                                 if (module.NestedClass.records[i].EnclosingClass == token)
202                                 {
203                                         list.Add(module.ResolveType(module.NestedClass.records[i].NestedClass));
204                                 }
205                         }
206                         return list.ToArray();
207                 }
208
209                 public override PropertyInfo[] __GetDeclaredProperties()
210                 {
211                         int token = this.MetadataToken;
212                         // TODO use binary search?
213                         for (int i = 0; i < module.PropertyMap.records.Length; i++)
214                         {
215                                 if (module.PropertyMap.records[i].Parent == token)
216                                 {
217                                         int property = module.PropertyMap.records[i].PropertyList - 1;
218                                         int end = module.PropertyMap.records.Length > i + 1 ? module.PropertyMap.records[i + 1].PropertyList - 1 : module.Property.records.Length;
219                                         PropertyInfo[] properties = new PropertyInfo[end - property];
220                                         if (module.PropertyPtr.RowCount == 0)
221                                         {
222                                                 for (int j = 0; property < end; property++, j++)
223                                                 {
224                                                         properties[j] = new PropertyInfoImpl(module, this, property);
225                                                 }
226                                         }
227                                         else
228                                         {
229                                                 for (int j = 0; property < end; property++, j++)
230                                                 {
231                                                         properties[j] = new PropertyInfoImpl(module, this, module.PropertyPtr.records[property] - 1);
232                                                 }
233                                         }
234                                         return properties;
235                                 }
236                         }
237                         return Empty<PropertyInfo>.Array;
238                 }
239
240                 public override string __Name
241                 {
242                         get { return typeName; }
243                 }
244
245                 public override string __Namespace
246                 {
247                         get { return typeNamespace; }
248                 }
249
250                 public override string Name
251                 {
252                         get { return TypeNameParser.Escape(typeName); }
253                 }
254
255                 public override string FullName
256                 {
257                         get { return GetFullName(); }
258                 }
259
260                 public override int MetadataToken
261                 {
262                         get { return (TypeDefTable.Index << 24) + index + 1; }
263                 }
264
265                 public override Type[] GetGenericArguments()
266                 {
267                         PopulateGenericArguments();
268                         return Util.Copy(typeArgs);
269                 }
270
271                 private void PopulateGenericArguments()
272                 {
273                         if (typeArgs == null)
274                         {
275                                 int token = this.MetadataToken;
276                                 int first = module.GenericParam.FindFirstByOwner(token);
277                                 if (first == -1)
278                                 {
279                                         typeArgs = Type.EmptyTypes;
280                                 }
281                                 else
282                                 {
283                                         List<Type> list = new List<Type>();
284                                         int len = module.GenericParam.records.Length;
285                                         for (int i = first; i < len && module.GenericParam.records[i].Owner == token; i++)
286                                         {
287                                                 list.Add(new GenericTypeParameter(module, i));
288                                         }
289                                         typeArgs = list.ToArray();
290                                 }
291                         }
292                 }
293
294                 internal override Type GetGenericTypeArgument(int index)
295                 {
296                         PopulateGenericArguments();
297                         return typeArgs[index];
298                 }
299
300                 public override Type[][] __GetGenericArgumentsOptionalCustomModifiers()
301                 {
302                         PopulateGenericArguments();
303                         return Util.Copy(new Type[typeArgs.Length][]);
304                 }
305
306                 public override Type[][] __GetGenericArgumentsRequiredCustomModifiers()
307                 {
308                         PopulateGenericArguments();
309                         return Util.Copy(new Type[typeArgs.Length][]);
310                 }
311
312                 public override bool IsGenericType
313                 {
314                         get { return IsGenericTypeDefinition; }
315                 }
316
317                 public override bool IsGenericTypeDefinition
318                 {
319                         get { return module.GenericParam.FindFirstByOwner(this.MetadataToken) != -1; }
320                 }
321
322                 public override Type GetGenericTypeDefinition()
323                 {
324                         if (IsGenericTypeDefinition)
325                         {
326                                 return this;
327                         }
328                         throw new InvalidOperationException();
329                 }
330
331                 public override string ToString()
332                 {
333                         StringBuilder sb = new StringBuilder(this.FullName);
334                         string sep = "[";
335                         foreach (Type arg in GetGenericArguments())
336                         {
337                                 sb.Append(sep);
338                                 sb.Append(arg);
339                                 sep = ",";
340                         }
341                         if (sep != "[")
342                         {
343                                 sb.Append(']');
344                         }
345                         return sb.ToString();
346                 }
347
348                 internal bool IsNestedByFlags
349                 {
350                         get { return (this.Attributes & TypeAttributes.VisibilityMask & ~TypeAttributes.Public) != 0; }
351                 }
352
353                 public override Type DeclaringType
354                 {
355                         get
356                         {
357                                 // note that we cannot use Type.IsNested for this, because that calls DeclaringType
358                                 if (!IsNestedByFlags)
359                                 {
360                                         return null;
361                                 }
362                                 // TODO use binary search (if sorted)
363                                 int token = this.MetadataToken;
364                                 for (int i = 0; i < module.NestedClass.records.Length; i++)
365                                 {
366                                         if (module.NestedClass.records[i].NestedClass == token)
367                                         {
368                                                 return module.ResolveType(module.NestedClass.records[i].EnclosingClass, null, null);
369                                         }
370                                 }
371                                 throw new InvalidOperationException();
372                         }
373                 }
374
375                 public override StructLayoutAttribute StructLayoutAttribute
376                 {
377                         get
378                         {
379                                 StructLayoutAttribute layout;
380                                 switch (this.Attributes & TypeAttributes.LayoutMask)
381                                 {
382                                         case TypeAttributes.AutoLayout:
383                                                 layout = new StructLayoutAttribute(LayoutKind.Auto);
384                                                 break;
385                                         case TypeAttributes.SequentialLayout:
386                                                 layout = new StructLayoutAttribute(LayoutKind.Sequential);
387                                                 break;
388                                         case TypeAttributes.ExplicitLayout:
389                                                 layout = new StructLayoutAttribute(LayoutKind.Explicit);
390                                                 break;
391                                         default:
392                                                 throw new BadImageFormatException();
393                                 }
394                                 switch (this.Attributes & TypeAttributes.StringFormatMask)
395                                 {
396                                         case TypeAttributes.AnsiClass:
397                                                 layout.CharSet = CharSet.Ansi;
398                                                 break;
399                                         case TypeAttributes.UnicodeClass:
400                                                 layout.CharSet = CharSet.Unicode;
401                                                 break;
402                                         case TypeAttributes.AutoClass:
403                                                 layout.CharSet = CharSet.Auto;
404                                                 break;
405                                         default:
406                                                 layout.CharSet = CharSet.None;
407                                                 break;
408                                 }
409                                 if (!__GetLayout(out layout.Pack, out layout.Size))
410                                 {
411                                         // compatibility with System.Reflection
412                                         layout.Pack = 8;
413                                 }
414                                 return layout;
415                         }
416                 }
417
418                 public override bool __GetLayout(out int packingSize, out int typeSize)
419                 {
420                         int token = this.MetadataToken;
421                         // TODO use binary search?
422                         for (int i = 0; i < module.ClassLayout.records.Length; i++)
423                         {
424                                 if (module.ClassLayout.records[i].Parent == token)
425                                 {
426                                         packingSize = module.ClassLayout.records[i].PackingSize;
427                                         typeSize = module.ClassLayout.records[i].ClassSize;
428                                         return true;
429                                 }
430                         }
431                         packingSize = 0;
432                         typeSize = 0;
433                         return false;
434                 }
435
436                 public override Module Module
437                 {
438                         get { return module; }
439                 }
440
441                 internal override bool IsModulePseudoType
442                 {
443                         get { return index == 0; }
444                 }
445         }
446 }