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