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