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 void 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 void InflateTypes (Type
[] genArguments
, Type
[] argTypes
)
143 for (int i
= 0; i
< types
.Length
; ++i
) {
144 if (types
[i
].IsGenericParameter
) {
145 for (int ii
= 0; ii
< genArguments
.Length
; ++ii
) {
146 if (types
[i
] != genArguments
[ii
])
149 types
[i
] = argTypes
[ii
];
155 if (types
[i
].IsGenericType
) {
156 Type
[] gen_arguments
= types
[i
].GetGenericTypeDefinition ().GetGenericArguments ();
157 for (int ii
= 0; ii
< gen_arguments
.Length
; ++ii
) {
158 gen_arguments
[ii
] = argTypes
[gen_arguments
[ii
].GenericParameterPosition
];
161 types
[i
] = types
[i
].GetGenericTypeDefinition ().MakeGenericType (gen_arguments
);
167 public Type
ParameterType (int pos
)
169 if (is_varargs
&& pos
>= pi
.Length
)
170 return TypeManager
.runtime_argument_handle_type
;
175 public string ParameterName (int pos
)
178 return gpd
.ParameterName (pos
);
180 if (is_varargs
&& pos
>= pi
.Length
)
183 return pi
[pos
].Name
;
186 public string ParameterDesc (int pos
)
188 if (is_varargs
&& pos
>= pi
.Length
)
191 StringBuilder sb
= new StringBuilder ();
196 Type partype
= ParameterType (pos
);
197 if (partype
.IsByRef
){
198 partype
= TypeManager
.GetElementType (partype
);
205 if (params_idx
== pos
)
206 sb
.Append ("params ");
208 if (ExtensionMethodType
!= null)
211 sb
.Append (TypeManager
.CSharpName (partype
).Replace ("&", ""));
213 return sb
.ToString ();
216 public Parameter
.Modifier
ParameterModifier (int pos
)
218 if (pos
== params_idx
)
219 return Parameter
.Modifier
.PARAMS
;
220 else if (is_varargs
&& pos
>= pi
.Length
)
221 return Parameter
.Modifier
.ARGLIST
;
224 return gpd
.ParameterModifier (pos
);
226 Type t
= types
[pos
];
228 if ((pi
[pos
].Attributes
& (ParameterAttributes
.Out
|ParameterAttributes
.In
)) == ParameterAttributes
.Out
)
229 return Parameter
.Modifier
.OUT
;
231 return Parameter
.Modifier
.REF
;
234 return Parameter
.Modifier
.NONE
;
238 get { return is_varargs ? pi.Length + 1 : pi.Length; }
241 public Type ExtensionMethodType
{
250 public bool HasParams
{
251 get { return params_idx != -1; }
254 public Type
[] Types
{
255 get { return types; }
260 public class ReflectionConstraints
: GenericConstraints
262 GenericParameterAttributes attrs
;
264 Type class_constraint
;
265 Type
[] iface_constraints
;
268 public static GenericConstraints
GetConstraints (Type t
)
270 Type
[] constraints
= t
.GetGenericParameterConstraints ();
271 GenericParameterAttributes attrs
= t
.GenericParameterAttributes
;
272 if (constraints
.Length
== 0 && attrs
== GenericParameterAttributes
.None
)
274 return new ReflectionConstraints (t
.Name
, constraints
, attrs
);
277 private ReflectionConstraints (string name
, Type
[] constraints
, GenericParameterAttributes attrs
)
282 if ((constraints
.Length
> 0) && !constraints
[0].IsInterface
) {
283 class_constraint
= constraints
[0];
284 iface_constraints
= new Type
[constraints
.Length
- 1];
285 Array
.Copy (constraints
, 1, iface_constraints
, 0, constraints
.Length
- 1);
287 iface_constraints
= constraints
;
289 if (HasValueTypeConstraint
)
290 base_type
= TypeManager
.value_type
;
291 else if (class_constraint
!= null)
292 base_type
= class_constraint
;
294 base_type
= TypeManager
.object_type
;
297 public override string TypeParameter
{
301 public override GenericParameterAttributes Attributes
{
302 get { return attrs; }
305 public override Type ClassConstraint
{
306 get { return class_constraint; }
309 public override Type EffectiveBaseClass
{
310 get { return base_type; }
313 public override Type
[] InterfaceConstraints
{
314 get { return iface_constraints; }
319 class PtrHashtable
: Hashtable
{
320 sealed class PtrComparer
: IComparer
{
321 private PtrComparer () {}
323 public static PtrComparer Instance
= new PtrComparer ();
325 public int Compare (object x
, object y
)
334 public PtrHashtable ()
336 comparer
= PtrComparer
.Instance
;
341 * Hashtable whose keys are character arrays with the same length
343 class CharArrayHashtable
: Hashtable
{
344 sealed class ArrComparer
: IComparer
{
347 public ArrComparer (int len
) {
351 public int Compare (object x
, object y
)
353 char[] a
= (char[])x
;
354 char[] b
= (char[])y
;
356 for (int i
= 0; i
< len
; ++i
)
365 protected override int GetHash (Object key
)
367 char[] arr
= (char[])key
;
370 for (int i
= 0; i
< len
; ++i
)
371 h
= (h
<< 5) - h
+ arr
[i
];
376 public CharArrayHashtable (int len
)
379 comparer
= new ArrComparer (len
);
385 public object Second
;
387 public Pair (object f
, object s
)
394 public class Accessors
{
395 public Accessor get_or_add
;
396 public Accessor set_or_remove
;
398 // was 'set' declared before 'get'? was 'remove' declared before 'add'?
399 public bool declared_in_reverse
;
401 public Accessors (Accessor get_or_add
, Accessor set_or_remove
)
403 this.get_or_add
= get_or_add
;
404 this.set_or_remove
= set_or_remove
;
409 /// This is a wrapper around StreamReader which is seekable backwards
410 /// within a window of around 2048 chars.
412 public class SeekableStreamReader
414 public SeekableStreamReader (TextReader reader
)
416 this.reader
= reader
;
417 this.buffer
= new char [AverageReadLength
* 3];
419 // Let the StreamWriter autodetect the encoder
423 public SeekableStreamReader (Stream stream
, Encoding encoding
)
424 : this (new StreamReader (stream
, encoding
, true))
429 private const int AverageReadLength
= 1024;
432 int buffer_start
; // in chars
433 int char_count
; // count buffer[] valid characters
434 int pos
; // index into buffer[]
437 /// This value corresponds to the current position in a stream of characters.
438 /// The StreamReader hides its manipulation of the underlying byte stream and all
439 /// character set/decoding issues. Thus, we cannot use this position to guess at
440 /// the corresponding position in the underlying byte stream even though there is
441 /// a correlation between them.
443 public int Position
{
444 get { return buffer_start + pos; }
447 if (value < buffer_start
|| value > buffer_start
+ char_count
)
448 throw new InternalErrorException ("can't seek that far back: " + (pos
- value));
449 pos
= value - buffer_start
;
453 private bool ReadBuffer ()
455 int slack
= buffer
.Length
- char_count
;
456 if (slack
<= AverageReadLength
/ 2) {
457 // shift the buffer to make room for AverageReadLength number of characters
458 int shift
= AverageReadLength
- slack
;
459 Array
.Copy (buffer
, shift
, buffer
, 0, char_count
- shift
);
462 buffer_start
+= shift
;
463 slack
+= shift
; // slack == AverageReadLength
466 int chars_read
= reader
.Read (buffer
, char_count
, slack
);
467 char_count
+= chars_read
;
469 return pos
< char_count
;
474 if ((pos
>= char_count
) && !ReadBuffer ())
482 if ((pos
>= char_count
) && !ReadBuffer ())
485 return buffer
[pos
++];
489 public class DoubleHash
{
490 const int DEFAULT_INITIAL_BUCKETS
= 100;
492 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS
) {}
494 public DoubleHash (int size
)
497 buckets
= new Entry
[size
];
511 public Entry (object key1
, object key2
, int hash
, object value, Entry next
)
521 public bool Lookup (object a
, object b
, out object res
)
523 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
525 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
526 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
)) {
535 public void Insert (object a
, object b
, object value)
537 // Is it an existing one?
539 int h
= (a
.GetHashCode () ^ b
.GetHashCode ()) & 0x7FFFFFFF;
541 for (Entry e
= buckets
[h
% count
]; e
!= null; e
= e
.next
) {
542 if (e
.hash
== h
&& e
.key1
.Equals (a
) && e
.key2
.Equals (b
))
546 int bucket
= h
% count
;
547 buckets
[bucket
] = new Entry (a
, b
, h
, value, buckets
[bucket
]);
549 // Grow whenever we double in size
550 if (size
++ == count
) {
554 Entry
[] newBuckets
= new Entry
[count
];
555 foreach (Entry root
in buckets
) {
558 int newLoc
= e
.hash
% count
;
560 e
.next
= newBuckets
[newLoc
];
561 newBuckets
[newLoc
] = e
;
566 buckets
= newBuckets
;