2008-07-29 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / class / corlib / System.Reflection / MonoGenericClass.cs
1 //
2 // System.Reflection.MonoGenericClass
3 //
4 // Sean MacIsaac (macisaac@ximian.com)
5 // Paolo Molaro (lupus@ximian.com)
6 // Patrik Torstensson (patrik.torstensson@labs2.com)
7 //
8 // (C) 2001 Ximian, Inc.
9 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System.Reflection;
35 using System.Reflection.Emit;
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Globalization;
39 using System.Runtime.Serialization;
40
41 #if NET_2_0 || BOOTSTRAP_NET_2_0
42
43 namespace System.Reflection
44 {
45         /*
46          * MonoGenericClass represents an instantiation of a generic TypeBuilder. MS
47          * calls this class TypeBuilderInstantiation (a much better name). MS returns 
48          * NotImplementedException for many of the methods but we can't do that as gmcs
49          * depends on them.
50          */
51         internal class MonoGenericClass : MonoType
52         {
53                 #region Keep in sync with object-internals.h
54 #pragma warning disable 649
55                 internal TypeBuilder generic_type;
56                 bool initialized;
57 #pragma warning restore 649
58                 #endregion
59
60                 Hashtable fields, ctors, methods;
61
62                 internal MonoGenericClass ()
63                         : base (null)
64                 {
65                         // this should not be used
66                         throw new InvalidOperationException ();
67                 }
68
69                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
70                 extern void initialize (MethodInfo[] methods, ConstructorInfo[] ctors, FieldInfo[] fields, PropertyInfo[] properties, EventInfo[] events);
71
72                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
73                 extern MethodInfo GetCorrespondingInflatedMethod (MethodInfo generic);
74                 
75                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
76                 extern EventInfo[] GetEvents_internal (Type reflected_type);
77
78                 private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
79                 BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
80
81                 void initialize ()
82                 {
83                         if (initialized)
84                                 return;
85
86                         MonoGenericClass parent = GetParentType () as MonoGenericClass;
87                         if (parent != null)
88                                 parent.initialize ();
89
90                         initialize (generic_type.GetMethods (flags),
91                                                 generic_type.GetConstructors (flags),
92                                                 generic_type.GetFields (flags),
93                                                 generic_type.GetProperties (flags),
94                                                 generic_type.GetEvents_internal (flags));
95
96                         initialized = true;
97                 }
98
99                 Type GetParentType ()
100                 {
101                         return InflateType (generic_type.BaseType);             
102                 }
103
104                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
105                 private extern Type InflateType_internal (Type type);
106
107                 internal Type InflateType (Type type)
108                 {
109                         if (type == null)
110                                 return null;
111                         if (!type.IsGenericParameter && !type.ContainsGenericParameters)
112                                 return type;
113                         return InflateType_internal (type);
114                 }
115                 
116                 public override Type BaseType {
117                         get {
118                                 Type parent = GetParentType ();
119                                 return parent != null ? parent : generic_type.BaseType;
120                         }
121                 }
122
123                 Type[] GetInterfacesInternal ()
124                 {
125                         if (generic_type.interfaces == null)
126                                 return new Type [0];
127                         Type[] res = new Type [generic_type.interfaces.Length];
128                         for (int i = 0; i < res.Length; ++i)
129                                 res [i] = InflateType (generic_type.interfaces [i]);
130                         return res;
131                 }
132
133                 public override Type[] GetInterfaces ()
134                 {
135                         if (!generic_type.IsCompilerContext)
136                                 throw new NotSupportedException ();
137                         return GetInterfacesInternal ();
138                 }
139
140                 protected override bool IsValueTypeImpl ()
141                 {
142                         return generic_type.IsValueType;
143                 }
144
145                 internal override MethodInfo GetMethod (MethodInfo fromNoninstanciated)
146                 {
147                         initialize ();
148
149                         if (!(fromNoninstanciated is MethodBuilder))
150                                 throw new InvalidOperationException ("Inflating non MethodBuilder objects is not supported: " + fromNoninstanciated.GetType ());
151         
152                         if (fromNoninstanciated is MethodBuilder) {
153                                 MethodBuilder mb = (MethodBuilder)fromNoninstanciated;
154
155                                 // FIXME: We can't yet handle creating generic instantiations of
156                                 // MethodOnTypeBuilderInst objects
157                                 // Also, mono_image_get_method_on_inst_token () can't handle generic
158                                 // methods
159                                 if (!mb.IsGenericMethodDefinition) {
160                                         if (methods == null)
161                                                 methods = new Hashtable ();
162                                         if (!methods.ContainsKey (mb))
163                                                 methods [mb] = new MethodOnTypeBuilderInst (this, mb);
164                                         return (MethodInfo)methods [mb];
165                                 }
166                         }
167
168                         return GetCorrespondingInflatedMethod (fromNoninstanciated);
169                 }
170
171                 internal override ConstructorInfo GetConstructor (ConstructorInfo fromNoninstanciated)
172                 {
173                         initialize ();
174
175                         if (!(fromNoninstanciated is ConstructorBuilder))
176                                 throw new InvalidOperationException ("Inflating non ConstructorBuilder objects is not supported: " + fromNoninstanciated.GetType ());
177
178                         ConstructorBuilder cb = (ConstructorBuilder)fromNoninstanciated;
179                         if (ctors == null)
180                                 ctors = new Hashtable ();
181                         if (!ctors.ContainsKey (cb))
182                                 ctors [cb] = new ConstructorOnTypeBuilderInst (this, cb);
183                         return (ConstructorInfo)ctors [cb];
184                 }
185
186                 internal override FieldInfo GetField (FieldInfo fromNoninstanciated)
187                 {
188                         initialize ();
189
190                         if (!(fromNoninstanciated is FieldBuilder))
191                                 throw new InvalidOperationException ("Inflating non FieldBuilder objects is not supported: " + fromNoninstanciated.GetType ());
192
193                         FieldBuilder fb = (FieldBuilder)fromNoninstanciated;
194                         if (fields == null)
195                                 fields = new Hashtable ();
196                         if (!fields.ContainsKey (fb))
197                                 fields [fb] = new FieldOnTypeBuilderInst (this, fb);
198                         return (FieldInfo)fields [fb];
199                 }
200                 
201                 public override MethodInfo[] GetMethods (BindingFlags bf)
202                 {
203                         if (!generic_type.IsCompilerContext)
204                                 throw new NotSupportedException ();
205
206                         ArrayList l = new ArrayList ();
207
208                         //
209                         // Walk up our class hierarchy and retrieve methods from our
210                         // parent classes.
211                         //
212
213                         Type current_type = this;
214                         do {
215                                 MonoGenericClass gi = current_type as MonoGenericClass;
216                                 if (gi != null)
217                                         l.AddRange (gi.GetMethodsInternal (bf, this));
218                                 else if (current_type is TypeBuilder)
219                                         l.AddRange (current_type.GetMethods (bf));
220                                 else {
221                                         // If we encounter a `MonoType', its
222                                         // GetMethodsByName() will return all the methods
223                                         // from its parent type(s), so we can stop here.
224                                         MonoType mt = (MonoType) current_type;
225                                         l.AddRange (mt.GetMethodsByName (null, bf, false, this));
226                                         break;
227                                 }
228
229                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
230                                         break;
231                                 current_type = current_type.BaseType;
232                         } while (current_type != null);
233
234                         MethodInfo[] result = new MethodInfo [l.Count];
235                         l.CopyTo (result);
236                         return result;
237                 }
238
239                 MethodInfo[] GetMethodsInternal (BindingFlags bf, MonoGenericClass reftype)
240                 {
241                         if (generic_type.num_methods == 0)
242                                 return new MethodInfo [0];
243
244                         ArrayList l = new ArrayList ();
245                         bool match;
246                         MethodAttributes mattrs;
247                         MethodInfo accessor;
248
249                         initialize ();
250
251                         for (int i = 0; i < generic_type.num_methods; ++i) {
252                                 MethodInfo c = generic_type.methods [i];
253
254                                 match = false;
255                                 mattrs = c.Attributes;
256                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
257                                         if ((bf & BindingFlags.Public) != 0)
258                                                 match = true;
259                                 } else {
260                                         if ((bf & BindingFlags.NonPublic) != 0)
261                                                 match = true;
262                                 }
263                                 if (!match)
264                                         continue;
265                                 match = false;
266                                 if ((mattrs & MethodAttributes.Static) != 0) {
267                                         if ((bf & BindingFlags.Static) != 0)
268                                                 match = true;
269                                 } else {
270                                         if ((bf & BindingFlags.Instance) != 0)
271                                                 match = true;
272                                 }
273                                 if (!match)
274                                         continue;
275                                 c = TypeBuilder.GetMethod (this, c);
276                                 l.Add (c);
277                         }
278
279                         MethodInfo[] result = new MethodInfo [l.Count];
280                         l.CopyTo (result);
281                         return result;
282                 }
283
284                 public override ConstructorInfo[] GetConstructors (BindingFlags bf)
285                 {
286                         if (!generic_type.IsCompilerContext)
287                                 throw new NotSupportedException ();
288
289                         ArrayList l = new ArrayList ();
290
291                         Type current_type = this;
292                         do {
293                                 MonoGenericClass gi = current_type as MonoGenericClass;
294                                 if (gi != null)
295                                         l.AddRange (gi.GetConstructorsInternal (bf, this));
296                                 else if (current_type is TypeBuilder)
297                                         l.AddRange (current_type.GetConstructors (bf));
298                                 else {
299                                         MonoType mt = (MonoType) current_type;
300                                         l.AddRange (mt.GetConstructors_internal (bf, this));
301                                         break;
302                                 }
303
304                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
305                                         break;
306                                 current_type = current_type.BaseType;
307                         } while (current_type != null);
308
309                         ConstructorInfo[] result = new ConstructorInfo [l.Count];
310                         l.CopyTo (result);
311                         return result;
312                 }
313
314                 ConstructorInfo[] GetConstructorsInternal (BindingFlags bf, MonoGenericClass reftype)
315                 {
316                         if (generic_type.ctors == null)
317                                 return new ConstructorInfo [0];
318
319                         ArrayList l = new ArrayList ();
320                         bool match;
321                         MethodAttributes mattrs;
322
323                         initialize ();
324
325                         for (int i = 0; i < generic_type.ctors.Length; i++) {
326                                 ConstructorInfo c = generic_type.ctors [i];
327
328                                 match = false;
329                                 mattrs = c.Attributes;
330                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
331                                         if ((bf & BindingFlags.Public) != 0)
332                                                 match = true;
333                                 } else {
334                                         if ((bf & BindingFlags.NonPublic) != 0)
335                                                 match = true;
336                                 }
337                                 if (!match)
338                                         continue;
339                                 match = false;
340                                 if ((mattrs & MethodAttributes.Static) != 0) {
341                                         if ((bf & BindingFlags.Static) != 0)
342                                                 match = true;
343                                 } else {
344                                         if ((bf & BindingFlags.Instance) != 0)
345                                                 match = true;
346                                 }
347                                 if (!match)
348                                         continue;
349                                 l.Add (TypeBuilder.GetConstructor (this, c));
350                         }
351
352                         ConstructorInfo[] result = new ConstructorInfo [l.Count];
353                         l.CopyTo (result);
354                         return result;
355                 }
356
357                 public override FieldInfo[] GetFields (BindingFlags bf)
358                 {
359                         if (!generic_type.IsCompilerContext)
360                                 throw new NotSupportedException ();
361
362                         ArrayList l = new ArrayList ();
363
364                         Type current_type = this;
365                         do {
366                                 MonoGenericClass gi = current_type as MonoGenericClass;
367                                 if (gi != null)
368                                         l.AddRange (gi.GetFieldsInternal (bf, this));
369                                 else if (current_type is TypeBuilder)
370                                         l.AddRange (current_type.GetFields (bf));
371                                 else {
372                                         MonoType mt = (MonoType) current_type;
373                                         l.AddRange (mt.GetFields_internal (bf, this));
374                                         break;
375                                 }
376
377                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
378                                         break;
379                                 current_type = current_type.BaseType;
380                         } while (current_type != null);
381
382                         FieldInfo[] result = new FieldInfo [l.Count];
383                         l.CopyTo (result);
384                         return result;
385                 }
386
387                 FieldInfo[] GetFieldsInternal (BindingFlags bf, MonoGenericClass reftype)
388                 {
389                         if (generic_type.num_fields == 0)
390                                 return new FieldInfo [0];
391
392                         ArrayList l = new ArrayList ();
393                         bool match;
394                         FieldAttributes fattrs;
395
396                         initialize ();
397
398                         for (int i = 0; i < generic_type.num_fields; i++) {
399                                 FieldInfo c = generic_type.fields [i];
400
401                                 match = false;
402                                 fattrs = c.Attributes;
403                                 if ((fattrs & FieldAttributes.FieldAccessMask) == FieldAttributes.Public) {
404                                         if ((bf & BindingFlags.Public) != 0)
405                                                 match = true;
406                                 } else {
407                                         if ((bf & BindingFlags.NonPublic) != 0)
408                                                 match = true;
409                                 }
410                                 if (!match)
411                                         continue;
412                                 match = false;
413                                 if ((fattrs & FieldAttributes.Static) != 0) {
414                                         if ((bf & BindingFlags.Static) != 0)
415                                                 match = true;
416                                 } else {
417                                         if ((bf & BindingFlags.Instance) != 0)
418                                                 match = true;
419                                 }
420                                 if (!match)
421                                         continue;
422                                 l.Add (TypeBuilder.GetField (this, c));
423                         }
424
425                         FieldInfo[] result = new FieldInfo [l.Count];
426                         l.CopyTo (result);
427                         return result;
428                 }
429
430                 public override PropertyInfo[] GetProperties (BindingFlags bf)
431                 {
432                         if (!generic_type.IsCompilerContext)
433                                 throw new NotSupportedException ();
434
435                         ArrayList l = new ArrayList ();
436
437                         Type current_type = this;
438                         do {
439                                 MonoGenericClass gi = current_type as MonoGenericClass;
440                                 if (gi != null)
441                                         l.AddRange (gi.GetPropertiesInternal (bf, this));
442                                 else if (current_type is TypeBuilder)
443                                         l.AddRange (current_type.GetProperties (bf));
444                                 else {
445                                         MonoType mt = (MonoType) current_type;
446                                         l.AddRange (mt.GetPropertiesByName (null, bf, false, this));
447                                         break;
448                                 }
449
450                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
451                                         break;
452                                 current_type = current_type.BaseType;
453                         } while (current_type != null);
454
455                         PropertyInfo[] result = new PropertyInfo [l.Count];
456                         l.CopyTo (result);
457                         return result;
458                 }
459
460                 PropertyInfo[] GetPropertiesInternal (BindingFlags bf, MonoGenericClass reftype)
461                 {
462                         if (generic_type.properties == null)
463                                 return new PropertyInfo [0];
464
465                         ArrayList l = new ArrayList ();
466                         bool match;
467                         MethodAttributes mattrs;
468                         MethodInfo accessor;
469
470                         initialize ();
471
472                         foreach (PropertyInfo pinfo in generic_type.properties) {
473                                 match = false;
474                                 accessor = pinfo.GetGetMethod (true);
475                                 if (accessor == null)
476                                         accessor = pinfo.GetSetMethod (true);
477                                 if (accessor == null)
478                                         continue;
479                                 mattrs = accessor.Attributes;
480                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
481                                         if ((bf & BindingFlags.Public) != 0)
482                                                 match = true;
483                                 } else {
484                                         if ((bf & BindingFlags.NonPublic) != 0)
485                                                 match = true;
486                                 }
487                                 if (!match)
488                                         continue;
489                                 match = false;
490                                 if ((mattrs & MethodAttributes.Static) != 0) {
491                                         if ((bf & BindingFlags.Static) != 0)
492                                                 match = true;
493                                 } else {
494                                         if ((bf & BindingFlags.Instance) != 0)
495                                                 match = true;
496                                 }
497                                 if (!match)
498                                         continue;
499                                 l.Add (new PropertyOnTypeBuilderInst (reftype, pinfo));
500                         }
501                         PropertyInfo[] result = new PropertyInfo [l.Count];
502                         l.CopyTo (result);
503                         return result;
504                 }
505
506                 public override EventInfo[] GetEvents (BindingFlags bf)
507                 {
508                         if (!generic_type.IsCompilerContext)
509                                 throw new NotSupportedException ();
510
511                         ArrayList l = new ArrayList ();
512
513                         Type current_type = this;
514                         do {
515                                 MonoGenericClass gi = current_type as MonoGenericClass;
516                                 if (gi != null)
517                                         l.AddRange (gi.GetEvents_impl (bf, this));
518                                 else if (current_type is TypeBuilder)
519                                         l.AddRange (current_type.GetEvents (bf));
520                                 else {
521                                         MonoType mt = (MonoType) current_type;
522                                         l.AddRange (mt.GetEvents (bf));
523                                         break;
524                                 }
525
526                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
527                                         break;
528                                 current_type = current_type.BaseType;
529                         } while (current_type != null);
530
531                         EventInfo[] result = new EventInfo [l.Count];
532                         l.CopyTo (result);
533                         return result;
534                 }
535
536                 protected EventInfo[] GetEvents_impl (BindingFlags bf, Type reftype)
537                 {
538                         ArrayList l = new ArrayList ();
539                         bool match;
540                         MethodAttributes mattrs;
541                         MethodInfo accessor;
542
543                         initialize ();
544
545                         EventInfo[] events = GetEvents_internal (reftype);
546
547                         for (int i = 0; i < events.Length; i++) {
548                                 EventInfo c = events [i];
549
550                                 match = false;
551                                 accessor = c.GetAddMethod (true);
552                                 if (accessor == null)
553                                         accessor = c.GetRemoveMethod (true);
554                                 if (accessor == null)
555                                         continue;
556                                 mattrs = accessor.Attributes;
557                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
558                                         if ((bf & BindingFlags.Public) != 0)
559                                                 match = true;
560                                 } else {
561                                         if ((bf & BindingFlags.NonPublic) != 0)
562                                                 match = true;
563                                 }
564                                 if (!match)
565                                         continue;
566                                 match = false;
567                                 if ((mattrs & MethodAttributes.Static) != 0) {
568                                         if ((bf & BindingFlags.Static) != 0)
569                                                 match = true;
570                                 } else {
571                                         if ((bf & BindingFlags.Instance) != 0)
572                                                 match = true;
573                                 }
574                                 if (!match)
575                                         continue;
576                                 l.Add (c);
577                         }
578                         EventInfo[] result = new EventInfo [l.Count];
579                         l.CopyTo (result);
580                         return result;
581                 }
582
583                 public override Type[] GetNestedTypes (BindingFlags bf)
584                 {
585                         return generic_type.GetNestedTypes (bf);
586                 }
587
588                 public override bool IsAssignableFrom (Type c)
589                 {
590                         if (c == this)
591                                 return true;
592
593                         Type[] interfaces = GetInterfacesInternal ();
594
595                         if (c.IsInterface) {
596                                 if (interfaces == null)
597                                         return false;
598                                 foreach (Type t in interfaces)
599                                         if (c.IsAssignableFrom (t))
600                                                 return true;
601                                 return false;
602                         }
603
604                         Type parent = GetParentType ();
605                         if (parent == null)
606                                 return c == typeof (object);
607                         else
608                                 return c.IsAssignableFrom (parent);
609                 }
610         }
611 }
612
613 #endif