2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
6 // Miguel de Icaza (miguel@ximian.com)
8 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
9 // Copyright 2003-2008 Novell, Inc
15 using System.Reflection;
16 using System.Collections;
17 using System.Reflection.Emit;
18 using System.Globalization;
20 namespace Mono.CSharp {
22 public interface ParameterData {
23 Type ParameterType (int pos);
24 Type [] Types { get; }
26 Type ExtensionMethodType { get; }
27 bool HasParams { get; }
28 string ParameterName (int pos);
29 string ParameterDesc (int pos);
31 Parameter.Modifier ParameterModifier (int pos);
32 string GetSignatureForError ();
35 ParameterData InflateTypes (Type[] genArguments, Type[] argTypes);
39 public class ReflectionParameters : ParameterData {
42 int params_idx = int.MaxValue;
47 public ReflectionParameters (MethodBase mb)
49 ParameterInfo [] pi = mb.GetParameters ();
50 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
53 int count = pi.Length;
56 types = Type.EmptyTypes;
60 types = new Type [count];
61 for (int i = 0; i < count; i++)
62 types [i] = TypeManager.TypeToCoreType (pi [i].ParameterType);
64 // TODO: This (if) should be done one level higher to correctly use
65 // out caching facilities.
66 MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
68 gpd = TypeManager.GetParameterData (generic);
70 for (int i = gpd.Count; i != 0; --i) {
71 if ((gpd.ParameterModifier (i-1) & Parameter.Modifier.PARAMS) != 0) {
72 this.params_idx = i-1;
81 // So far, the params attribute can be used in C# for the last
82 // and next to last method parameters.
83 // If some other language can place it anywhere we will
84 // have to analyze all parameters and not just last 2.
87 for (int i = count; i >= 0 && i > count - 2; --i) {
88 if (!pi [i].ParameterType.IsArray)
91 if (pi [i].IsDefined (TypeManager.param_array_type, false)) {
97 if (TypeManager.extension_attribute_type != null && mb.IsStatic &&
98 (mb.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
99 mb.IsDefined (TypeManager.extension_attribute_type, false))
103 public override bool Equals (object obj)
105 ReflectionParameters rp = obj as ReflectionParameters;
109 if (Count != rp.Count)
112 for (int i = 0; i < Count; ++i) {
113 if (!types [i].Equals (rp.types [i]))
119 public override int GetHashCode ()
121 return base.GetHashCode ();
124 public string GetSignatureForError ()
126 StringBuilder sb = new StringBuilder ("(");
127 for (int i = 0; i < pi.Length; ++i) {
130 sb.Append (ParameterDesc (i));
135 sb.Append ("__arglist");
138 return sb.ToString ();
142 public ParameterData InflateTypes (Type[] genArguments, Type[] argTypes)
144 ReflectionParameters p = (ReflectionParameters)MemberwiseClone ();
146 for (int i = 0; i < types.Length; ++i) {
147 if (types[i].IsGenericParameter) {
148 for (int ii = 0; ii < genArguments.Length; ++ii) {
149 if (types[i] != genArguments[ii])
152 p.types[i] = argTypes[ii];
158 if (types[i].IsGenericType) {
159 Type[] gen_arguments_open = types[i].GetGenericTypeDefinition ().GetGenericArguments ();
160 Type[] gen_arguments = types[i].GetGenericArguments ();
161 for (int ii = 0; ii < gen_arguments_open.Length; ++ii) {
162 if (gen_arguments [ii].IsGenericParameter) {
163 for (int iii = 0; iii < genArguments.Length; ++iii) {
164 if (gen_arguments [ii] != genArguments [iii])
167 gen_arguments_open [ii] = argTypes [iii];
171 gen_arguments_open [ii] = gen_arguments [ii];
175 p.types[i] = types[i].GetGenericTypeDefinition ().MakeGenericType (gen_arguments_open);
182 public Type ParameterType (int pos)
184 if (is_varargs && pos >= pi.Length)
185 return TypeManager.runtime_argument_handle_type;
190 public string ParameterName (int pos)
193 return gpd.ParameterName (pos);
195 if (is_varargs && pos >= pi.Length)
198 return pi [pos].Name;
201 public string ParameterDesc (int pos)
203 if (is_varargs && pos >= pi.Length)
206 StringBuilder sb = new StringBuilder ();
211 Type partype = ParameterType (pos);
212 if (partype.IsByRef){
213 partype = TypeManager.GetElementType (partype);
220 if (params_idx == pos)
221 sb.Append ("params ");
223 if (pos == 0 && ExtensionMethodType != null)
226 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
228 return sb.ToString ();
231 public Parameter.Modifier ParameterModifier (int pos)
233 if (pos >= params_idx)
234 return Parameter.Modifier.PARAMS;
235 if (is_varargs && pos >= pi.Length)
236 return Parameter.Modifier.ARGLIST;
239 return gpd.ParameterModifier (pos);
241 Type t = types [pos];
243 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
244 return Parameter.Modifier.OUT;
246 return Parameter.Modifier.REF;
249 return Parameter.Modifier.NONE;
253 get { return is_varargs ? pi.Length + 1 : pi.Length; }
256 public Type ExtensionMethodType {
265 public bool HasParams {
266 get { return params_idx != int.MaxValue; }
269 public Type[] Types {
270 get { return types; }
275 public class ReflectionConstraints : GenericConstraints
277 GenericParameterAttributes attrs;
279 Type class_constraint;
280 Type[] iface_constraints;
283 public static GenericConstraints GetConstraints (Type t)
285 Type [] constraints = t.GetGenericParameterConstraints ();
286 GenericParameterAttributes attrs = t.GenericParameterAttributes;
287 if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
289 return new ReflectionConstraints (t.Name, constraints, attrs);
292 private ReflectionConstraints (string name, Type [] constraints, GenericParameterAttributes attrs)
297 if ((constraints.Length > 0) && !constraints [0].IsInterface) {
298 class_constraint = constraints [0];
299 iface_constraints = new Type [constraints.Length - 1];
300 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
302 iface_constraints = constraints;
304 if (HasValueTypeConstraint)
305 base_type = TypeManager.value_type;
306 else if (class_constraint != null)
307 base_type = class_constraint;
309 base_type = TypeManager.object_type;
312 public override string TypeParameter {
316 public override GenericParameterAttributes Attributes {
317 get { return attrs; }
320 public override Type ClassConstraint {
321 get { return class_constraint; }
324 public override Type EffectiveBaseClass {
325 get { return base_type; }
328 public override Type[] InterfaceConstraints {
329 get { return iface_constraints; }
334 class PtrHashtable : Hashtable {
335 sealed class PtrComparer : IComparer {
336 private PtrComparer () {}
338 public static PtrComparer Instance = new PtrComparer ();
340 public int Compare (object x, object y)
349 public PtrHashtable ()
351 comparer = PtrComparer.Instance;
356 // Workaround System.InvalidOperationException for enums
358 protected override int GetHash (object key)
360 TypeBuilder tb = key as TypeBuilder;
361 if (tb != null && tb.BaseType == TypeManager.enum_type)
364 return base.GetHash (key);
370 * Hashtable whose keys are character arrays with the same length
372 class CharArrayHashtable : Hashtable {
373 sealed class ArrComparer : IComparer {
376 public ArrComparer (int len) {
380 public int Compare (object x, object y)
382 char[] a = (char[])x;
383 char[] b = (char[])y;
385 for (int i = 0; i < len; ++i)
394 protected override int GetHash (Object key)
396 char[] arr = (char[])key;
399 for (int i = 0; i < len; ++i)
400 h = (h << 5) - h + arr [i];
405 public CharArrayHashtable (int len)
408 comparer = new ArrComparer (len);
414 public object Second;
416 public Pair (object f, object s)
423 public class Accessors {
424 public Accessor get_or_add;
425 public Accessor set_or_remove;
427 // was 'set' declared before 'get'? was 'remove' declared before 'add'?
428 public bool declared_in_reverse;
430 public Accessors (Accessor get_or_add, Accessor set_or_remove)
432 this.get_or_add = get_or_add;
433 this.set_or_remove = set_or_remove;
438 /// This is a wrapper around StreamReader which is seekable backwards
439 /// within a window of around 2048 chars.
441 public class SeekableStreamReader
443 const int AverageReadLength = 1024;
449 int buffer_start; // in chars
450 int char_count; // count buffer[] valid characters
451 int pos; // index into buffer[]
453 public SeekableStreamReader (Stream stream, Encoding encoding)
455 this.stream = stream;
456 this.encoding = encoding;
458 this.reader = new StreamReader (stream, encoding, true);
459 this.buffer = new char [AverageReadLength * 3];
461 // Let the StreamWriter autodetect the encoder
466 /// This value corresponds to the current position in a stream of characters.
467 /// The StreamReader hides its manipulation of the underlying byte stream and all
468 /// character set/decoding issues. Thus, we cannot use this position to guess at
469 /// the corresponding position in the underlying byte stream even though there is
470 /// a correlation between them.
472 public int Position {
473 get { return buffer_start + pos; }
476 if (value > buffer_start + char_count)
477 throw new InternalErrorException ("can't seek that far forward: " + (pos - value));
479 if (value < buffer_start){
482 reader = new StreamReader (stream, encoding, true);
488 while (value > buffer_start + char_count){
492 pos = value - buffer_start;
495 pos = value - buffer_start;
499 private bool ReadBuffer ()
501 int slack = buffer.Length - char_count;
502 if (slack <= AverageReadLength / 2) {
503 // shift the buffer to make room for AverageReadLength number of characters
504 int shift = AverageReadLength - slack;
505 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
508 buffer_start += shift;
509 slack += shift; // slack == AverageReadLength
512 int chars_read = reader.Read (buffer, char_count, slack);
513 char_count += chars_read;
515 return pos < char_count;
520 if ((pos >= char_count) && !ReadBuffer ())
528 if ((pos >= char_count) && !ReadBuffer ())
531 return buffer [pos++];
535 public class DoubleHash {
536 const int DEFAULT_INITIAL_BUCKETS = 100;
538 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
540 public DoubleHash (int size)
543 buckets = new Entry [size];
557 public Entry (object key1, object key2, int hash, object value, Entry next)
567 public bool Lookup (object a, object b, out object res)
569 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
571 for (Entry e = buckets [h % count]; e != null; e = e.next) {
572 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
581 public void Insert (object a, object b, object value)
583 // Is it an existing one?
585 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
587 for (Entry e = buckets [h % count]; e != null; e = e.next) {
588 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
592 int bucket = h % count;
593 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
595 // Grow whenever we double in size
596 if (size++ == count) {
600 Entry [] newBuckets = new Entry [count];
601 foreach (Entry root in buckets) {
604 int newLoc = e.hash % count;
606 e.next = newBuckets [newLoc];
607 newBuckets [newLoc] = e;
612 buckets = newBuckets;
617 class PartialMethodDefinitionInfo : MethodInfo
620 MethodAttributes attrs;
622 public PartialMethodDefinitionInfo (MethodOrOperator mc)
625 if ((mc.ModFlags & Modifiers.STATIC) != 0)
626 attrs = MethodAttributes.Static;
629 public override MethodInfo GetBaseDefinition ()
631 throw new NotImplementedException ();
634 public override ICustomAttributeProvider ReturnTypeCustomAttributes
636 get { throw new NotImplementedException (); }
639 public override MethodAttributes Attributes
641 get { return attrs; }
644 public override MethodImplAttributes GetMethodImplementationFlags ()
646 throw new NotImplementedException ();
649 public override ParameterInfo [] GetParameters ()
651 throw new NotImplementedException ();
654 public override object Invoke (object obj, BindingFlags invokeAttr, Binder binder, object [] parameters, CultureInfo culture)
656 throw new NotImplementedException ();
659 public override RuntimeMethodHandle MethodHandle
661 get { throw new NotImplementedException (); }
664 public override Type DeclaringType
666 get { return mc.Parent.TypeBuilder; }
669 public override object [] GetCustomAttributes (Type attributeType, bool inherit)
671 throw new NotImplementedException ();
674 public override object [] GetCustomAttributes (bool inherit)
676 throw new NotImplementedException ();
679 public override Type ReturnType {
681 return mc.MemberType;
685 public override bool IsDefined (Type attributeType, bool inherit)
687 throw new NotImplementedException ();
690 public override string Name
692 get { return mc.Name; }
695 public override Type ReflectedType
697 get { throw new NotImplementedException (); }