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