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