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