Merge pull request #201 from QuickJack/master
[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 CustomModifiers[] __GetGenericArgumentsCustomModifiers()
301                 {
302                         PopulateGenericArguments();
303                         return new CustomModifiers[typeArgs.Length];
304                 }
305
306                 public override bool IsGenericType
307                 {
308                         get { return IsGenericTypeDefinition; }
309                 }
310
311                 public override bool IsGenericTypeDefinition
312                 {
313                         get { return module.GenericParam.FindFirstByOwner(this.MetadataToken) != -1; }
314                 }
315
316                 public override Type GetGenericTypeDefinition()
317                 {
318                         if (IsGenericTypeDefinition)
319                         {
320                                 return this;
321                         }
322                         throw new InvalidOperationException();
323                 }
324
325                 public override string ToString()
326                 {
327                         StringBuilder sb = new StringBuilder(this.FullName);
328                         string sep = "[";
329                         foreach (Type arg in GetGenericArguments())
330                         {
331                                 sb.Append(sep);
332                                 sb.Append(arg);
333                                 sep = ",";
334                         }
335                         if (sep != "[")
336                         {
337                                 sb.Append(']');
338                         }
339                         return sb.ToString();
340                 }
341
342                 internal bool IsNestedByFlags
343                 {
344                         get { return (this.Attributes & TypeAttributes.VisibilityMask & ~TypeAttributes.Public) != 0; }
345                 }
346
347                 public override Type DeclaringType
348                 {
349                         get
350                         {
351                                 // note that we cannot use Type.IsNested for this, because that calls DeclaringType
352                                 if (!IsNestedByFlags)
353                                 {
354                                         return null;
355                                 }
356                                 // TODO use binary search (if sorted)
357                                 int token = this.MetadataToken;
358                                 for (int i = 0; i < module.NestedClass.records.Length; i++)
359                                 {
360                                         if (module.NestedClass.records[i].NestedClass == token)
361                                         {
362                                                 return module.ResolveType(module.NestedClass.records[i].EnclosingClass, null, null);
363                                         }
364                                 }
365                                 throw new InvalidOperationException();
366                         }
367                 }
368
369                 public override StructLayoutAttribute StructLayoutAttribute
370                 {
371                         get
372                         {
373                                 StructLayoutAttribute layout;
374                                 switch (this.Attributes & TypeAttributes.LayoutMask)
375                                 {
376                                         case TypeAttributes.AutoLayout:
377                                                 layout = new StructLayoutAttribute(LayoutKind.Auto);
378                                                 break;
379                                         case TypeAttributes.SequentialLayout:
380                                                 layout = new StructLayoutAttribute(LayoutKind.Sequential);
381                                                 break;
382                                         case TypeAttributes.ExplicitLayout:
383                                                 layout = new StructLayoutAttribute(LayoutKind.Explicit);
384                                                 break;
385                                         default:
386                                                 throw new BadImageFormatException();
387                                 }
388                                 switch (this.Attributes & TypeAttributes.StringFormatMask)
389                                 {
390                                         case TypeAttributes.AnsiClass:
391                                                 layout.CharSet = CharSet.Ansi;
392                                                 break;
393                                         case TypeAttributes.UnicodeClass:
394                                                 layout.CharSet = CharSet.Unicode;
395                                                 break;
396                                         case TypeAttributes.AutoClass:
397                                                 layout.CharSet = CharSet.Auto;
398                                                 break;
399                                         default:
400                                                 layout.CharSet = CharSet.None;
401                                                 break;
402                                 }
403                                 if (!__GetLayout(out layout.Pack, out layout.Size))
404                                 {
405                                         // compatibility with System.Reflection
406                                         layout.Pack = 8;
407                                 }
408                                 return layout;
409                         }
410                 }
411
412                 public override bool __GetLayout(out int packingSize, out int typeSize)
413                 {
414                         int token = this.MetadataToken;
415                         // TODO use binary search?
416                         for (int i = 0; i < module.ClassLayout.records.Length; i++)
417                         {
418                                 if (module.ClassLayout.records[i].Parent == token)
419                                 {
420                                         packingSize = module.ClassLayout.records[i].PackingSize;
421                                         typeSize = module.ClassLayout.records[i].ClassSize;
422                                         return true;
423                                 }
424                         }
425                         packingSize = 0;
426                         typeSize = 0;
427                         return false;
428                 }
429
430                 public override Module Module
431                 {
432                         get { return module; }
433                 }
434
435                 internal override bool IsModulePseudoType
436                 {
437                         get { return index == 0; }
438                 }
439
440                 internal override IList<CustomAttributeData> GetInterfaceImplCustomAttributes(Type interfaceType, Type attributeType)
441                 {
442                         int token = this.MetadataToken;
443                         // TODO use binary search?
444                         for (int i = 0; i < module.InterfaceImpl.records.Length; i++)
445                         {
446                                 if (module.InterfaceImpl.records[i].Class == token
447                                         && module.ResolveType(module.InterfaceImpl.records[i].Interface, this) == interfaceType)
448                                 {
449                                         return module.GetCustomAttributes((InterfaceImplTable.Index << 24) | (i + 1), attributeType);
450                                 }
451                         }
452                         return Empty<CustomAttributeData>.Array;
453                 }
454         }
455 }