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