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 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 using System.Reflection;
15 using System.Collections;
16 using System.Reflection.Emit;
17 using System.Globalization;
19 namespace Mono.CSharp {
21 public interface ParameterData {
22 Type ParameterType (int pos);
23 Type [] Types { get; }
25 Type ExtensionMethodType { get; }
26 bool HasParams { get; }
27 string ParameterName (int pos);
28 string ParameterDesc (int pos);
30 Parameter.Modifier ParameterModifier (int pos);
31 string GetSignatureForError ();
34 ParameterData InflateTypes (Type[] genArguments, Type[] argTypes);
38 public class ReflectionParameters : ParameterData {
46 public ReflectionParameters (MethodBase mb)
48 ParameterInfo [] pi = mb.GetParameters ();
49 is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
52 int count = pi.Length;
55 types = Type.EmptyTypes;
59 types = new Type [count];
60 for (int i = 0; i < count; i++)
61 types [i] = pi [i].ParameterType;
63 // TODO: This (if) should be done one level higher to correctly use
64 // out caching facilities.
65 MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
67 gpd = TypeManager.GetParameterData (generic);
69 for (int i = gpd.Count; i != 0; --i) {
70 if ((gpd.ParameterModifier (i-1) & Parameter.Modifier.PARAMS) != 0) {
71 this.params_idx = i-1;
80 // So far, the params attribute can be used in C# for the last
81 // and next to last method parameters.
82 // If some other language can place it anywhere we will
83 // have to analyze all parameters and not just last 2.
86 for (int i = count; i >= 0 && i > count - 2; --i) {
87 if (!pi [i].ParameterType.IsArray)
90 if (pi [i].IsDefined (TypeManager.param_array_type, false)) {
96 if (TypeManager.extension_attribute_type != null && mb.IsStatic &&
97 (mb.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
98 mb.IsDefined (TypeManager.extension_attribute_type, false))
102 public override bool Equals (object obj)
104 ReflectionParameters rp = obj as ReflectionParameters;
108 if (Count != rp.Count)
111 for (int i = 0; i < Count; ++i) {
112 if (!types [i].Equals (rp.types [i]))
118 public override int GetHashCode ()
120 return base.GetHashCode ();
123 public string GetSignatureForError ()
125 StringBuilder sb = new StringBuilder ("(");
126 for (int i = 0; i < pi.Length; ++i) {
129 sb.Append (ParameterDesc (i));
134 sb.Append ("__arglist");
137 return sb.ToString ();
141 public ParameterData InflateTypes (Type[] genArguments, Type[] argTypes)
143 ReflectionParameters p = (ReflectionParameters)MemberwiseClone ();
145 for (int i = 0; i < types.Length; ++i) {
146 if (types[i].IsGenericParameter) {
147 for (int ii = 0; ii < genArguments.Length; ++ii) {
148 if (types[i] != genArguments[ii])
151 p.types[i] = argTypes[ii];
157 if (types[i].IsGenericType) {
158 Type[] gen_arguments_open = types[i].GetGenericTypeDefinition ().GetGenericArguments ();
159 Type[] gen_arguments = types[i].GetGenericArguments ();
160 for (int ii = 0; ii < gen_arguments_open.Length; ++ii) {
161 if (gen_arguments [ii].IsGenericParameter) {
162 for (int iii = 0; iii < genArguments.Length; ++iii) {
163 if (gen_arguments [ii] != genArguments [iii])
166 gen_arguments_open [ii] = argTypes [iii];
170 gen_arguments_open [ii] = gen_arguments [ii];
174 p.types[i] = types[i].GetGenericTypeDefinition ().MakeGenericType (gen_arguments_open);
181 public Type ParameterType (int pos)
183 if (is_varargs && pos >= pi.Length)
184 return TypeManager.runtime_argument_handle_type;
189 public string ParameterName (int pos)
192 return gpd.ParameterName (pos);
194 if (is_varargs && pos >= pi.Length)
197 return pi [pos].Name;
200 public string ParameterDesc (int pos)
202 if (is_varargs && pos >= pi.Length)
205 StringBuilder sb = new StringBuilder ();
210 Type partype = ParameterType (pos);
211 if (partype.IsByRef){
212 partype = TypeManager.GetElementType (partype);
219 if (params_idx == pos)
220 sb.Append ("params ");
222 if (pos == 0 && ExtensionMethodType != null)
225 sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
227 return sb.ToString ();
230 public Parameter.Modifier ParameterModifier (int pos)
232 if (pos == params_idx)
233 return Parameter.Modifier.PARAMS;
234 else if (is_varargs && pos >= pi.Length)
235 return Parameter.Modifier.ARGLIST;
238 return gpd.ParameterModifier (pos);
240 Type t = types [pos];
242 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
243 return Parameter.Modifier.OUT;
245 return Parameter.Modifier.REF;
248 return Parameter.Modifier.NONE;
252 get { return is_varargs ? pi.Length + 1 : pi.Length; }
255 public Type ExtensionMethodType {
264 public bool HasParams {
265 get { return params_idx != -1; }
268 public Type[] Types {
269 get { return types; }
274 public class ReflectionConstraints : GenericConstraints
276 GenericParameterAttributes attrs;
278 Type class_constraint;
279 Type[] iface_constraints;
282 public static GenericConstraints GetConstraints (Type t)
284 Type [] constraints = t.GetGenericParameterConstraints ();
285 GenericParameterAttributes attrs = t.GenericParameterAttributes;
286 if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
288 return new ReflectionConstraints (t.Name, constraints, attrs);
291 private ReflectionConstraints (string name, Type [] constraints, GenericParameterAttributes attrs)
296 if ((constraints.Length > 0) && !constraints [0].IsInterface) {
297 class_constraint = constraints [0];
298 iface_constraints = new Type [constraints.Length - 1];
299 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
301 iface_constraints = constraints;
303 if (HasValueTypeConstraint)
304 base_type = TypeManager.value_type;
305 else if (class_constraint != null)
306 base_type = class_constraint;
308 base_type = TypeManager.object_type;
311 public override string TypeParameter {
315 public override GenericParameterAttributes Attributes {
316 get { return attrs; }
319 public override Type ClassConstraint {
320 get { return class_constraint; }
323 public override Type EffectiveBaseClass {
324 get { return base_type; }
327 public override Type[] InterfaceConstraints {
328 get { return iface_constraints; }
333 class PtrHashtable : Hashtable {
334 sealed class PtrComparer : IComparer {
335 private PtrComparer () {}
337 public static PtrComparer Instance = new PtrComparer ();
339 public int Compare (object x, object y)
348 public PtrHashtable ()
350 comparer = PtrComparer.Instance;
355 * Hashtable whose keys are character arrays with the same length
357 class CharArrayHashtable : Hashtable {
358 sealed class ArrComparer : IComparer {
361 public ArrComparer (int len) {
365 public int Compare (object x, object y)
367 char[] a = (char[])x;
368 char[] b = (char[])y;
370 for (int i = 0; i < len; ++i)
379 protected override int GetHash (Object key)
381 char[] arr = (char[])key;
384 for (int i = 0; i < len; ++i)
385 h = (h << 5) - h + arr [i];
390 public CharArrayHashtable (int len)
393 comparer = new ArrComparer (len);
399 public object Second;
401 public Pair (object f, object s)
408 public class Accessors {
409 public Accessor get_or_add;
410 public Accessor set_or_remove;
412 // was 'set' declared before 'get'? was 'remove' declared before 'add'?
413 public bool declared_in_reverse;
415 public Accessors (Accessor get_or_add, Accessor set_or_remove)
417 this.get_or_add = get_or_add;
418 this.set_or_remove = set_or_remove;
423 /// This is a wrapper around StreamReader which is seekable backwards
424 /// within a window of around 2048 chars.
426 public class SeekableStreamReader
428 public SeekableStreamReader (TextReader reader)
430 this.reader = reader;
431 this.buffer = new char [AverageReadLength * 3];
433 // Let the StreamWriter autodetect the encoder
437 public SeekableStreamReader (Stream stream, Encoding encoding)
438 : this (new StreamReader (stream, encoding, true))
443 private const int AverageReadLength = 1024;
446 int buffer_start; // in chars
447 int char_count; // count buffer[] valid characters
448 int pos; // index into buffer[]
451 /// This value corresponds to the current position in a stream of characters.
452 /// The StreamReader hides its manipulation of the underlying byte stream and all
453 /// character set/decoding issues. Thus, we cannot use this position to guess at
454 /// the corresponding position in the underlying byte stream even though there is
455 /// a correlation between them.
457 public int Position {
458 get { return buffer_start + pos; }
461 if (value < buffer_start || value > buffer_start + char_count)
462 throw new InternalErrorException ("can't seek that far back: " + (pos - value));
463 pos = value - buffer_start;
467 private bool ReadBuffer ()
469 int slack = buffer.Length - char_count;
470 if (slack <= AverageReadLength / 2) {
471 // shift the buffer to make room for AverageReadLength number of characters
472 int shift = AverageReadLength - slack;
473 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
476 buffer_start += shift;
477 slack += shift; // slack == AverageReadLength
480 int chars_read = reader.Read (buffer, char_count, slack);
481 char_count += chars_read;
483 return pos < char_count;
488 if ((pos >= char_count) && !ReadBuffer ())
496 if ((pos >= char_count) && !ReadBuffer ())
499 return buffer [pos++];
503 public class DoubleHash {
504 const int DEFAULT_INITIAL_BUCKETS = 100;
506 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
508 public DoubleHash (int size)
511 buckets = new Entry [size];
525 public Entry (object key1, object key2, int hash, object value, Entry next)
535 public bool Lookup (object a, object b, out object res)
537 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
539 for (Entry e = buckets [h % count]; e != null; e = e.next) {
540 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
549 public void Insert (object a, object b, object value)
551 // Is it an existing one?
553 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
555 for (Entry e = buckets [h % count]; e != null; e = e.next) {
556 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
560 int bucket = h % count;
561 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
563 // Grow whenever we double in size
564 if (size++ == count) {
568 Entry [] newBuckets = new Entry [count];
569 foreach (Entry root in buckets) {
572 int newLoc = e.hash % count;
574 e.next = newBuckets [newLoc];
575 newBuckets [newLoc] = e;
580 buckets = newBuckets;