Add IKVM.Reflection
[mono.git] / mcs / class / IKVM.Reflection / Reader / TypeDefImpl.cs
1 /*
2   Copyright (C) 2009 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 = TypeNameParser.Escape(module.GetString(module.TypeDef.records[index].TypeName));
45                         this.typeNamespace = TypeNameParser.Escape(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 Type UnderlyingSystemType
206                 {
207                         get { return this; }
208                 }
209
210                 public override int MetadataToken
211                 {
212                         get { return (TypeDefTable.Index << 24) + index + 1; }
213                 }
214
215                 public override Type[] GetGenericArguments()
216                 {
217                         PopulateGenericArguments();
218                         return Util.Copy(typeArgs);
219                 }
220
221                 private void PopulateGenericArguments()
222                 {
223                         if (typeArgs == null)
224                         {
225                                 int token = this.MetadataToken;
226                                 int first = module.GenericParam.FindFirstByOwner(token);
227                                 if (first == -1)
228                                 {
229                                         typeArgs = Type.EmptyTypes;
230                                 }
231                                 else
232                                 {
233                                         List<Type> list = new List<Type>();
234                                         int len = module.GenericParam.records.Length;
235                                         for (int i = first; i < len && module.GenericParam.records[i].Owner == token; i++)
236                                         {
237                                                 list.Add(new GenericTypeParameter(module, i));
238                                         }
239                                         typeArgs = list.ToArray();
240                                 }
241                         }
242                 }
243
244                 internal override Type GetGenericTypeArgument(int index)
245                 {
246                         PopulateGenericArguments();
247                         return typeArgs[index];
248                 }
249
250                 public override Type[][] __GetGenericArgumentsOptionalCustomModifiers()
251                 {
252                         PopulateGenericArguments();
253                         return Util.Copy(new Type[typeArgs.Length][]);
254                 }
255
256                 public override Type[][] __GetGenericArgumentsRequiredCustomModifiers()
257                 {
258                         PopulateGenericArguments();
259                         return Util.Copy(new Type[typeArgs.Length][]);
260                 }
261
262                 public override bool IsGenericType
263                 {
264                         get { return IsGenericTypeDefinition; }
265                 }
266
267                 public override bool IsGenericTypeDefinition
268                 {
269                         get { return module.GenericParam.FindFirstByOwner(this.MetadataToken) != -1; }
270                 }
271
272                 public override Type GetGenericTypeDefinition()
273                 {
274                         if (IsGenericTypeDefinition)
275                         {
276                                 return this;
277                         }
278                         throw new InvalidOperationException();
279                 }
280
281                 public override string ToString()
282                 {
283                         StringBuilder sb = new StringBuilder(this.FullName);
284                         string sep = "[";
285                         foreach (Type arg in GetGenericArguments())
286                         {
287                                 sb.Append(sep);
288                                 sb.Append(arg);
289                                 sep = ",";
290                         }
291                         if (sep != "[")
292                         {
293                                 sb.Append(']');
294                         }
295                         return sb.ToString();
296                 }
297
298                 public override Type DeclaringType
299                 {
300                         get
301                         {
302                                 // note that we cannot use Type.IsNested for this, because that calls DeclaringType
303                                 if ((this.Attributes & TypeAttributes.VisibilityMask & ~TypeAttributes.Public) == 0)
304                                 {
305                                         return null;
306                                 }
307                                 // TODO use binary search (if sorted)
308                                 int token = this.MetadataToken;
309                                 for (int i = 0; i < module.NestedClass.records.Length; i++)
310                                 {
311                                         if (module.NestedClass.records[i].NestedClass == token)
312                                         {
313                                                 return module.ResolveType(module.NestedClass.records[i].EnclosingClass, null, null);
314                                         }
315                                 }
316                                 throw new InvalidOperationException();
317                         }
318                 }
319
320                 public override StructLayoutAttribute StructLayoutAttribute
321                 {
322                         get
323                         {
324                                 StructLayoutAttribute layout;
325                                 switch (this.Attributes & TypeAttributes.LayoutMask)
326                                 {
327                                         case TypeAttributes.AutoLayout:
328                                                 return null;
329                                         case TypeAttributes.SequentialLayout:
330                                                 layout = new StructLayoutAttribute(LayoutKind.Sequential);
331                                                 break;
332                                         case TypeAttributes.ExplicitLayout:
333                                                 layout = new StructLayoutAttribute(LayoutKind.Explicit);
334                                                 break;
335                                         default:
336                                                 throw new BadImageFormatException();
337                                 }
338                                 int token = this.MetadataToken;
339                                 // TODO use binary search?
340                                 for (int i = 0; i < module.ClassLayout.records.Length; i++)
341                                 {
342                                         if (module.ClassLayout.records[i].Parent == token)
343                                         {
344                                                 layout.Pack = module.ClassLayout.records[i].PackingSize;
345                                                 layout.Size = module.ClassLayout.records[i].ClassSize;
346                                                 switch (this.Attributes & TypeAttributes.StringFormatMask)
347                                                 {
348                                                         case TypeAttributes.AnsiClass:
349                                                                 layout.CharSet = CharSet.Ansi;
350                                                                 break;
351                                                         case TypeAttributes.UnicodeClass:
352                                                                 layout.CharSet = CharSet.Unicode;
353                                                                 break;
354                                                         case TypeAttributes.AutoClass:
355                                                                 layout.CharSet = CharSet.Auto;
356                                                                 break;
357                                                         default:
358                                                                 layout.CharSet = CharSet.None;
359                                                                 break;
360                                                 }
361                                                 return layout;
362                                         }
363                                 }
364                                 return null;
365                         }
366                 }
367
368                 public override Module Module
369                 {
370                         get { return module; }
371                 }
372
373                 internal override bool IsModulePseudoType
374                 {
375                         get { return index == 0; }
376                 }
377         }
378 }