2009-07-24 Rodrigo Kumpera <rkumpera@novell.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                 int event_count;
62
63                 internal MonoGenericClass ()
64                         : base (null)
65                 {
66                         // this should not be used
67                         throw new InvalidOperationException ();
68                 }
69
70                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
71                 extern void initialize (MethodInfo[] methods, ConstructorInfo[] ctors, FieldInfo[] fields, PropertyInfo[] properties, EventInfo[] events);
72
73                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
74                 extern MethodInfo GetCorrespondingInflatedMethod (MethodInfo generic);
75
76                 private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
77                 BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
78
79                 void initialize ()
80                 {
81                         if (initialized)
82                                 return;
83
84                         MonoGenericClass parent = GetParentType () as MonoGenericClass;
85                         if (parent != null)
86                                 parent.initialize ();
87
88                         EventInfo[] events = generic_type.GetEvents_internal (flags);
89                         event_count = events.Length;
90
91                         initialize (generic_type.GetMethods (flags),
92                                                 generic_type.GetConstructors (flags),
93                                                 generic_type.GetFields (flags),
94                                                 generic_type.GetProperties (flags),
95                                                 events);
96
97                         initialized = true;
98                 }
99
100                 Type GetParentType ()
101                 {
102                         return InflateType (generic_type.BaseType);             
103                 }
104
105                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
106                 private extern Type InflateType_internal (Type type);
107
108                 internal Type InflateType (Type type)
109                 {
110                         if (type == null)
111                                 return null;
112                         if (!type.IsGenericParameter && !type.ContainsGenericParameters)
113                                 return type;
114                         return InflateType_internal (type);
115                 }
116                 
117                 public override Type BaseType {
118                         get {
119                                 Type parent = GetParentType ();
120                                 return parent != null ? parent : generic_type.BaseType;
121                         }
122                 }
123
124                 Type[] GetInterfacesInternal ()
125                 {
126                         if (generic_type.interfaces == null)
127                                 return new Type [0];
128                         Type[] res = new Type [generic_type.interfaces.Length];
129                         for (int i = 0; i < res.Length; ++i)
130                                 res [i] = InflateType (generic_type.interfaces [i]);
131                         return res;
132                 }
133
134                 public override Type[] GetInterfaces ()
135                 {
136                         if (!generic_type.IsCompilerContext)
137                                 throw new NotSupportedException ();
138                         return GetInterfacesInternal ();
139                 }
140
141                 protected override bool IsValueTypeImpl ()
142                 {
143                         return generic_type.IsValueType;
144                 }
145
146                 internal override MethodInfo GetMethod (MethodInfo fromNoninstanciated)
147                 {
148                         initialize ();
149
150                         if (!(fromNoninstanciated is MethodBuilder))
151                                 throw new InvalidOperationException ("Inflating non MethodBuilder objects is not supported: " + fromNoninstanciated.GetType ());
152         
153                         if (fromNoninstanciated is MethodBuilder) {
154                                 MethodBuilder mb = (MethodBuilder)fromNoninstanciated;
155
156                                 // FIXME: We can't yet handle creating generic instantiations of
157                                 // MethodOnTypeBuilderInst objects
158                                 // Also, mono_image_get_method_on_inst_token () can't handle generic
159                                 // methods
160                                 if (!mb.IsGenericMethodDefinition) {
161                                         if (methods == null)
162                                                 methods = new Hashtable ();
163                                         if (!methods.ContainsKey (mb))
164                                                 methods [mb] = new MethodOnTypeBuilderInst (this, mb);
165                                         return (MethodInfo)methods [mb];
166                                 }
167                         }
168
169                         return GetCorrespondingInflatedMethod (fromNoninstanciated);
170                 }
171
172                 internal override ConstructorInfo GetConstructor (ConstructorInfo fromNoninstanciated)
173                 {
174                         initialize ();
175
176                         if (!(fromNoninstanciated is ConstructorBuilder))
177                                 throw new InvalidOperationException ("Inflating non ConstructorBuilder objects is not supported: " + fromNoninstanciated.GetType ());
178
179                         ConstructorBuilder cb = (ConstructorBuilder)fromNoninstanciated;
180                         if (ctors == null)
181                                 ctors = new Hashtable ();
182                         if (!ctors.ContainsKey (cb))
183                                 ctors [cb] = new ConstructorOnTypeBuilderInst (this, cb);
184                         return (ConstructorInfo)ctors [cb];
185                 }
186
187                 internal override FieldInfo GetField (FieldInfo fromNoninstanciated)
188                 {
189                         initialize ();
190
191                         if (fromNoninstanciated is FieldOnTypeBuilderInst && generic_type.IsCompilerContext) {
192                                 FieldOnTypeBuilderInst finst = (FieldOnTypeBuilderInst)fromNoninstanciated;
193                                 fromNoninstanciated = finst.fb;
194                         }
195
196                         if (!(fromNoninstanciated is FieldBuilder))
197                                 throw new InvalidOperationException ("Inflating non FieldBuilder objects is not supported: " + fromNoninstanciated.GetType ());
198
199                         FieldBuilder fb = (FieldBuilder)fromNoninstanciated;
200                         if (fields == null)
201                                 fields = new Hashtable ();
202                         if (!fields.ContainsKey (fb))
203                                 fields [fb] = new FieldOnTypeBuilderInst (this, fb);
204                         return (FieldInfo)fields [fb];
205                 }
206                 
207                 public override MethodInfo[] GetMethods (BindingFlags bf)
208                 {
209                         if (!generic_type.IsCompilerContext)
210                                 throw new NotSupportedException ();
211
212                         ArrayList l = new ArrayList ();
213
214                         //
215                         // Walk up our class hierarchy and retrieve methods from our
216                         // parent classes.
217                         //
218
219                         Type current_type = this;
220                         do {
221                                 MonoGenericClass gi = current_type as MonoGenericClass;
222                                 if (gi != null)
223                                         l.AddRange (gi.GetMethodsInternal (bf, this));
224                                 else if (current_type is TypeBuilder)
225                                         l.AddRange (current_type.GetMethods (bf));
226                                 else {
227                                         // If we encounter a `MonoType', its
228                                         // GetMethodsByName() will return all the methods
229                                         // from its parent type(s), so we can stop here.
230                                         MonoType mt = (MonoType) current_type;
231                                         l.AddRange (mt.GetMethodsByName (null, bf, false, this));
232                                         break;
233                                 }
234
235                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
236                                         break;
237                                 current_type = current_type.BaseType;
238                         } while (current_type != null);
239
240                         MethodInfo[] result = new MethodInfo [l.Count];
241                         l.CopyTo (result);
242                         return result;
243                 }
244
245                 MethodInfo[] GetMethodsInternal (BindingFlags bf, MonoGenericClass reftype)
246                 {
247                         if (generic_type.num_methods == 0)
248                                 return new MethodInfo [0];
249
250                         ArrayList l = new ArrayList ();
251                         bool match;
252                         MethodAttributes mattrs;
253                         MethodInfo accessor;
254
255                         initialize ();
256
257                         for (int i = 0; i < generic_type.num_methods; ++i) {
258                                 MethodInfo c = generic_type.methods [i];
259
260                                 match = false;
261                                 mattrs = c.Attributes;
262                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
263                                         if ((bf & BindingFlags.Public) != 0)
264                                                 match = true;
265                                 } else {
266                                         if ((bf & BindingFlags.NonPublic) != 0)
267                                                 match = true;
268                                 }
269                                 if (!match)
270                                         continue;
271                                 match = false;
272                                 if ((mattrs & MethodAttributes.Static) != 0) {
273                                         if ((bf & BindingFlags.Static) != 0)
274                                                 match = true;
275                                 } else {
276                                         if ((bf & BindingFlags.Instance) != 0)
277                                                 match = true;
278                                 }
279                                 if (!match)
280                                         continue;
281                                 c = TypeBuilder.GetMethod (this, c);
282                                 l.Add (c);
283                         }
284
285                         MethodInfo[] result = new MethodInfo [l.Count];
286                         l.CopyTo (result);
287                         return result;
288                 }
289
290                 public override ConstructorInfo[] GetConstructors (BindingFlags bf)
291                 {
292                         if (!generic_type.IsCompilerContext)
293                                 throw new NotSupportedException ();
294
295                         ArrayList l = new ArrayList ();
296
297                         Type current_type = this;
298                         do {
299                                 MonoGenericClass gi = current_type as MonoGenericClass;
300                                 if (gi != null)
301                                         l.AddRange (gi.GetConstructorsInternal (bf, this));
302                                 else if (current_type is TypeBuilder)
303                                         l.AddRange (current_type.GetConstructors (bf));
304                                 else {
305                                         MonoType mt = (MonoType) current_type;
306                                         l.AddRange (mt.GetConstructors_internal (bf, this));
307                                         break;
308                                 }
309
310                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
311                                         break;
312                                 current_type = current_type.BaseType;
313                         } while (current_type != null);
314
315                         ConstructorInfo[] result = new ConstructorInfo [l.Count];
316                         l.CopyTo (result);
317                         return result;
318                 }
319
320                 ConstructorInfo[] GetConstructorsInternal (BindingFlags bf, MonoGenericClass reftype)
321                 {
322                         if (generic_type.ctors == null)
323                                 return new ConstructorInfo [0];
324
325                         ArrayList l = new ArrayList ();
326                         bool match;
327                         MethodAttributes mattrs;
328
329                         initialize ();
330
331                         for (int i = 0; i < generic_type.ctors.Length; i++) {
332                                 ConstructorInfo c = generic_type.ctors [i];
333
334                                 match = false;
335                                 mattrs = c.Attributes;
336                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
337                                         if ((bf & BindingFlags.Public) != 0)
338                                                 match = true;
339                                 } else {
340                                         if ((bf & BindingFlags.NonPublic) != 0)
341                                                 match = true;
342                                 }
343                                 if (!match)
344                                         continue;
345                                 match = false;
346                                 if ((mattrs & MethodAttributes.Static) != 0) {
347                                         if ((bf & BindingFlags.Static) != 0)
348                                                 match = true;
349                                 } else {
350                                         if ((bf & BindingFlags.Instance) != 0)
351                                                 match = true;
352                                 }
353                                 if (!match)
354                                         continue;
355                                 l.Add (TypeBuilder.GetConstructor (this, c));
356                         }
357
358                         ConstructorInfo[] result = new ConstructorInfo [l.Count];
359                         l.CopyTo (result);
360                         return result;
361                 }
362
363                 public override FieldInfo[] GetFields (BindingFlags bf)
364                 {
365                         if (!generic_type.IsCompilerContext)
366                                 throw new NotSupportedException ();
367
368                         ArrayList l = new ArrayList ();
369
370                         Type current_type = this;
371                         do {
372                                 MonoGenericClass gi = current_type as MonoGenericClass;
373                                 if (gi != null)
374                                         l.AddRange (gi.GetFieldsInternal (bf, this));
375                                 else if (current_type is TypeBuilder)
376                                         l.AddRange (current_type.GetFields (bf));
377                                 else {
378                                         MonoType mt = (MonoType) current_type;
379                                         l.AddRange (mt.GetFields_internal (bf, this));
380                                         break;
381                                 }
382
383                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
384                                         break;
385                                 current_type = current_type.BaseType;
386                         } while (current_type != null);
387
388                         FieldInfo[] result = new FieldInfo [l.Count];
389                         l.CopyTo (result);
390                         return result;
391                 }
392
393                 FieldInfo[] GetFieldsInternal (BindingFlags bf, MonoGenericClass reftype)
394                 {
395                         if (generic_type.num_fields == 0)
396                                 return new FieldInfo [0];
397
398                         ArrayList l = new ArrayList ();
399                         bool match;
400                         FieldAttributes fattrs;
401
402                         initialize ();
403
404                         for (int i = 0; i < generic_type.num_fields; i++) {
405                                 FieldInfo c = generic_type.fields [i];
406
407                                 match = false;
408                                 fattrs = c.Attributes;
409                                 if ((fattrs & FieldAttributes.FieldAccessMask) == FieldAttributes.Public) {
410                                         if ((bf & BindingFlags.Public) != 0)
411                                                 match = true;
412                                 } else {
413                                         if ((bf & BindingFlags.NonPublic) != 0)
414                                                 match = true;
415                                 }
416                                 if (!match)
417                                         continue;
418                                 match = false;
419                                 if ((fattrs & FieldAttributes.Static) != 0) {
420                                         if ((bf & BindingFlags.Static) != 0)
421                                                 match = true;
422                                 } else {
423                                         if ((bf & BindingFlags.Instance) != 0)
424                                                 match = true;
425                                 }
426                                 if (!match)
427                                         continue;
428                                 l.Add (TypeBuilder.GetField (this, c));
429                         }
430
431                         FieldInfo[] result = new FieldInfo [l.Count];
432                         l.CopyTo (result);
433                         return result;
434                 }
435
436                 public override PropertyInfo[] GetProperties (BindingFlags bf)
437                 {
438                         if (!generic_type.IsCompilerContext)
439                                 throw new NotSupportedException ();
440
441                         ArrayList l = new ArrayList ();
442
443                         Type current_type = this;
444                         do {
445                                 MonoGenericClass gi = current_type as MonoGenericClass;
446                                 if (gi != null)
447                                         l.AddRange (gi.GetPropertiesInternal (bf, this));
448                                 else if (current_type is TypeBuilder)
449                                         l.AddRange (current_type.GetProperties (bf));
450                                 else {
451                                         MonoType mt = (MonoType) current_type;
452                                         l.AddRange (mt.GetPropertiesByName (null, bf, false, this));
453                                         break;
454                                 }
455
456                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
457                                         break;
458                                 current_type = current_type.BaseType;
459                         } while (current_type != null);
460
461                         PropertyInfo[] result = new PropertyInfo [l.Count];
462                         l.CopyTo (result);
463                         return result;
464                 }
465
466                 PropertyInfo[] GetPropertiesInternal (BindingFlags bf, MonoGenericClass reftype)
467                 {
468                         if (generic_type.properties == null)
469                                 return new PropertyInfo [0];
470
471                         ArrayList l = new ArrayList ();
472                         bool match;
473                         MethodAttributes mattrs;
474                         MethodInfo accessor;
475
476                         initialize ();
477
478                         foreach (PropertyInfo pinfo in generic_type.properties) {
479                                 match = false;
480                                 accessor = pinfo.GetGetMethod (true);
481                                 if (accessor == null)
482                                         accessor = pinfo.GetSetMethod (true);
483                                 if (accessor == null)
484                                         continue;
485                                 mattrs = accessor.Attributes;
486                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
487                                         if ((bf & BindingFlags.Public) != 0)
488                                                 match = true;
489                                 } else {
490                                         if ((bf & BindingFlags.NonPublic) != 0)
491                                                 match = true;
492                                 }
493                                 if (!match)
494                                         continue;
495                                 match = false;
496                                 if ((mattrs & MethodAttributes.Static) != 0) {
497                                         if ((bf & BindingFlags.Static) != 0)
498                                                 match = true;
499                                 } else {
500                                         if ((bf & BindingFlags.Instance) != 0)
501                                                 match = true;
502                                 }
503                                 if (!match)
504                                         continue;
505                                 l.Add (new PropertyOnTypeBuilderInst (reftype, pinfo));
506                         }
507                         PropertyInfo[] result = new PropertyInfo [l.Count];
508                         l.CopyTo (result);
509                         return result;
510                 }
511
512                 public override EventInfo[] GetEvents (BindingFlags bf)
513                 {
514                         if (!generic_type.IsCompilerContext)
515                                 throw new NotSupportedException ();
516
517                         ArrayList l = new ArrayList ();
518
519                         Type current_type = this;
520                         do {
521                                 MonoGenericClass gi = current_type as MonoGenericClass;
522                                 if (gi != null)
523                                         l.AddRange (gi.GetEventsInternal (bf, this));
524                                 else if (current_type is TypeBuilder)
525                                         l.AddRange (current_type.GetEvents (bf));
526                                 else {
527                                         MonoType mt = (MonoType) current_type;
528                                         l.AddRange (mt.GetEvents (bf));
529                                         break;
530                                 }
531
532                                 if ((bf & BindingFlags.DeclaredOnly) != 0)
533                                         break;
534                                 current_type = current_type.BaseType;
535                         } while (current_type != null);
536
537                         EventInfo[] result = new EventInfo [l.Count];
538                         l.CopyTo (result);
539                         return result;
540                 }
541         
542                 EventInfo[] GetEventsInternal (BindingFlags bf, MonoGenericClass reftype) {
543                         if (generic_type.events == null)
544                                 return new EventInfo [0];
545
546                         initialize ();
547
548                         ArrayList l = new ArrayList ();
549                         bool match;
550                         MethodAttributes mattrs;
551                         MethodInfo accessor;
552
553                         for (int i = 0; i < event_count; ++i) {
554                                 EventBuilder ev = generic_type.events [i];
555
556                                 match = false;
557                                 accessor = ev.add_method;
558                                 if (accessor == null)
559                                         accessor = ev.remove_method;
560                                 if (accessor == null)
561                                         continue;
562                                 mattrs = accessor.Attributes;
563                                 if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
564                                         if ((bf & BindingFlags.Public) != 0)
565                                                 match = true;
566                                 } else {
567                                         if ((bf & BindingFlags.NonPublic) != 0)
568                                                 match = true;
569                                 }
570                                 if (!match)
571                                         continue;
572                                 match = false;
573                                 if ((mattrs & MethodAttributes.Static) != 0) {
574                                         if ((bf & BindingFlags.Static) != 0)
575                                                 match = true;
576                                 } else {
577                                         if ((bf & BindingFlags.Instance) != 0)
578                                                 match = true;
579                                 }
580                                 if (!match)
581                                         continue;
582                                 l.Add (new EventOnTypeBuilderInst (reftype, ev));
583                         }
584                         EventInfo[] result = new EventInfo [l.Count];
585                         l.CopyTo (result);
586                         return result;
587                 }
588
589                 public override Type[] GetNestedTypes (BindingFlags bf)
590                 {
591                         return generic_type.GetNestedTypes (bf);
592                 }
593
594                 public override bool IsAssignableFrom (Type c)
595                 {
596                         if (c == this)
597                                 return true;
598
599                         Type[] interfaces = GetInterfacesInternal ();
600
601                         if (c.IsInterface) {
602                                 if (interfaces == null)
603                                         return false;
604                                 foreach (Type t in interfaces)
605                                         if (c.IsAssignableFrom (t))
606                                                 return true;
607                                 return false;
608                         }
609
610                         Type parent = GetParentType ();
611                         if (parent == null)
612                                 return c == typeof (object);
613                         else
614                                 return c.IsAssignableFrom (parent);
615                 }
616         }
617 }
618
619 #endif