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 * Hashtable whose keys are character arrays with the same length
358 class CharArrayHashtable : Hashtable {
359 sealed class ArrComparer : IComparer {
362 public ArrComparer (int len) {
366 public int Compare (object x, object y)
368 char[] a = (char[])x;
369 char[] b = (char[])y;
371 for (int i = 0; i < len; ++i)
380 protected override int GetHash (Object key)
382 char[] arr = (char[])key;
385 for (int i = 0; i < len; ++i)
386 h = (h << 5) - h + arr [i];
391 public CharArrayHashtable (int len)
394 comparer = new ArrComparer (len);
400 public object Second;
402 public Pair (object f, object s)
409 public class Accessors {
410 public Accessor get_or_add;
411 public Accessor set_or_remove;
413 // was 'set' declared before 'get'? was 'remove' declared before 'add'?
414 public bool declared_in_reverse;
416 public Accessors (Accessor get_or_add, Accessor set_or_remove)
418 this.get_or_add = get_or_add;
419 this.set_or_remove = set_or_remove;
424 /// This is a wrapper around StreamReader which is seekable backwards
425 /// within a window of around 2048 chars.
427 public class SeekableStreamReader
429 const int AverageReadLength = 1024;
435 int buffer_start; // in chars
436 int char_count; // count buffer[] valid characters
437 int pos; // index into buffer[]
439 public SeekableStreamReader (Stream stream, Encoding encoding)
441 this.stream = stream;
442 this.encoding = encoding;
444 this.reader = new StreamReader (stream, encoding, true);
445 this.buffer = new char [AverageReadLength * 3];
447 // Let the StreamWriter autodetect the encoder
452 /// This value corresponds to the current position in a stream of characters.
453 /// The StreamReader hides its manipulation of the underlying byte stream and all
454 /// character set/decoding issues. Thus, we cannot use this position to guess at
455 /// the corresponding position in the underlying byte stream even though there is
456 /// a correlation between them.
458 public int Position {
459 get { return buffer_start + pos; }
462 if (value > buffer_start + char_count)
463 throw new InternalErrorException ("can't seek that far forward: " + (pos - value));
465 if (value < buffer_start){
468 reader = new StreamReader (stream, encoding, true);
474 while (value > buffer_start + char_count){
478 pos = value - buffer_start;
481 pos = value - buffer_start;
485 private bool ReadBuffer ()
487 int slack = buffer.Length - char_count;
488 if (slack <= AverageReadLength / 2) {
489 // shift the buffer to make room for AverageReadLength number of characters
490 int shift = AverageReadLength - slack;
491 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
494 buffer_start += shift;
495 slack += shift; // slack == AverageReadLength
498 int chars_read = reader.Read (buffer, char_count, slack);
499 char_count += chars_read;
501 return pos < char_count;
506 if ((pos >= char_count) && !ReadBuffer ())
514 if ((pos >= char_count) && !ReadBuffer ())
517 return buffer [pos++];
521 public class DoubleHash {
522 const int DEFAULT_INITIAL_BUCKETS = 100;
524 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
526 public DoubleHash (int size)
529 buckets = new Entry [size];
543 public Entry (object key1, object key2, int hash, object value, Entry next)
553 public bool Lookup (object a, object b, out object res)
555 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
557 for (Entry e = buckets [h % count]; e != null; e = e.next) {
558 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
567 public void Insert (object a, object b, object value)
569 // Is it an existing one?
571 int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
573 for (Entry e = buckets [h % count]; e != null; e = e.next) {
574 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
578 int bucket = h % count;
579 buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
581 // Grow whenever we double in size
582 if (size++ == count) {
586 Entry [] newBuckets = new Entry [count];
587 foreach (Entry root in buckets) {
590 int newLoc = e.hash % count;
592 e.next = newBuckets [newLoc];
593 newBuckets [newLoc] = e;
598 buckets = newBuckets;
603 class PartialMethodDefinitionInfo : MethodInfo
606 MethodAttributes attrs;
608 public PartialMethodDefinitionInfo (MethodOrOperator mc)
611 if ((mc.ModFlags & Modifiers.STATIC) != 0)
612 attrs = MethodAttributes.Static;
615 public override MethodInfo GetBaseDefinition ()
617 throw new NotImplementedException ();
620 public override ICustomAttributeProvider ReturnTypeCustomAttributes
622 get { throw new NotImplementedException (); }
625 public override MethodAttributes Attributes
627 get { return attrs; }
630 public override MethodImplAttributes GetMethodImplementationFlags ()
632 throw new NotImplementedException ();
635 public override ParameterInfo [] GetParameters ()
637 throw new NotImplementedException ();
640 public override object Invoke (object obj, BindingFlags invokeAttr, Binder binder, object [] parameters, CultureInfo culture)
642 throw new NotImplementedException ();
645 public override RuntimeMethodHandle MethodHandle
647 get { throw new NotImplementedException (); }
650 public override Type DeclaringType
652 get { return mc.Parent.TypeBuilder; }
655 public override object [] GetCustomAttributes (Type attributeType, bool inherit)
657 throw new NotImplementedException ();
660 public override object [] GetCustomAttributes (bool inherit)
662 throw new NotImplementedException ();
665 public override Type ReturnType {
667 return mc.MemberType;
671 public override bool IsDefined (Type attributeType, bool inherit)
673 throw new NotImplementedException ();
676 public override string Name
678 get { return mc.Name; }
681 public override Type ReflectedType
683 get { throw new NotImplementedException (); }