2009-02-20 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / typemanager.cs
blob3c612372c7b28c951d51736be1efd3d145050819
1 //
2 // typemanager.cs: C# type manager
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2003-2008 Novell, Inc.
15 // We will eventually remove the SIMPLE_SPEEDUP, and should never change
16 // the behavior of the compilation. This can be removed if we rework
17 // the code to get a list of namespaces available.
19 #define SIMPLE_SPEEDUP
21 using System;
22 using System.IO;
23 using System.Globalization;
24 using System.Collections;
25 using System.Reflection;
26 using System.Reflection.Emit;
27 using System.Text;
28 using System.Runtime.CompilerServices;
29 using System.Diagnostics;
31 namespace Mono.CSharp {
33 #if GMCS_SOURCE
34 partial
35 #endif
36 class TypeManager {
38 // A list of core types that the compiler requires or uses
40 static public Type object_type;
41 static public Type value_type;
42 static public Type string_type;
43 static public Type int32_type;
44 static public Type uint32_type;
45 static public Type int64_type;
46 static public Type uint64_type;
47 static public Type float_type;
48 static public Type double_type;
49 static public Type char_type;
50 static public Type char_ptr_type;
51 static public Type short_type;
52 static public Type decimal_type;
53 static public Type bool_type;
54 static public Type sbyte_type;
55 static public Type byte_type;
56 static public Type ushort_type;
57 static public Type enum_type;
58 static public Type delegate_type;
59 static public Type multicast_delegate_type;
60 static public Type void_type;
61 static public Type null_type;
62 static public Type array_type;
63 static public Type runtime_handle_type;
64 static public Type type_type;
65 static public Type ienumerator_type;
66 static public Type ienumerable_type;
67 static public Type idisposable_type;
68 static public Type default_member_type;
69 static public Type iasyncresult_type;
70 static public Type asynccallback_type;
71 static public Type intptr_type;
72 static public Type uintptr_type;
73 static public Type runtime_field_handle_type;
74 static public Type runtime_argument_handle_type;
75 static public Type attribute_type;
76 static public Type attribute_usage_type;
77 static public Type decimal_constant_attribute_type;
78 static public Type dllimport_type;
79 static public Type methodimpl_attr_type;
80 #if !NET_2_0
81 static public Type marshal_as_attr_type;
82 #endif
83 static public Type param_array_type;
84 static public Type void_ptr_type;
85 static public Type indexer_name_type;
86 static public Type exception_type;
87 static public Type obsolete_attribute_type;
88 static public Type conditional_attribute_type;
89 static public Type in_attribute_type;
90 static public Type out_attribute_type;
91 static public Type extension_attribute_type;
92 static public Type default_parameter_value_attribute_type;
94 static public Type anonymous_method_type;
95 static public Type cls_compliant_attribute_type;
96 static public Type typed_reference_type;
97 static public Type arg_iterator_type;
98 static public Type mbr_type;
99 static public Type struct_layout_attribute_type;
100 static public Type field_offset_attribute_type;
101 static public Type security_attr_type;
102 static public Type required_attr_type;
103 static public Type guid_attr_type;
104 static public Type assembly_culture_attribute_type;
105 static public Type assembly_version_attribute_type;
106 static public Type coclass_attr_type;
107 static public Type comimport_attr_type;
108 public static Type runtime_helpers_type;
109 public static Type internals_visible_attr_type;
112 // C# 2.0
114 static internal Type fixed_buffer_attr_type;
115 static internal Type default_charset_type;
116 static internal Type type_forwarder_attr_type;
117 static internal Type isvolatile_type;
118 static public Type generic_ilist_type;
119 static public Type generic_icollection_type;
120 static public Type generic_ienumerator_type;
121 static public Type generic_ienumerable_type;
122 static public Type generic_nullable_type;
125 // C# 3.0
127 static internal Type expression_type;
128 public static Type parameter_expression_type;
131 // Expressions representing the internal types. Used during declaration
132 // definition.
134 static public TypeExpr system_object_expr, system_string_expr;
135 static public TypeExpr system_boolean_expr, system_decimal_expr;
136 static public TypeExpr system_single_expr, system_double_expr;
137 static public TypeExpr system_sbyte_expr, system_byte_expr;
138 static public TypeExpr system_int16_expr, system_uint16_expr;
139 static public TypeExpr system_int32_expr, system_uint32_expr;
140 static public TypeExpr system_int64_expr, system_uint64_expr;
141 static public TypeExpr system_char_expr, system_void_expr;
142 static public TypeExpr system_valuetype_expr;
143 static public TypeExpr system_intptr_expr;
144 public static TypeExpr expression_type_expr;
148 // These methods are called by code generated by the compiler
150 static public FieldInfo string_empty;
151 static public MethodInfo system_type_get_type_from_handle;
152 static public MethodInfo bool_movenext_void;
153 static public MethodInfo void_dispose_void;
154 static public MethodInfo void_monitor_enter_object;
155 static public MethodInfo void_monitor_exit_object;
156 static public MethodInfo void_initializearray_array_fieldhandle;
157 static public MethodInfo delegate_combine_delegate_delegate;
158 static public MethodInfo delegate_remove_delegate_delegate;
159 static public MethodInfo int_get_offset_to_string_data;
160 static public MethodInfo int_interlocked_compare_exchange;
161 static public PropertyInfo ienumerator_getcurrent;
162 public static MethodInfo methodbase_get_type_from_handle;
163 public static MethodInfo methodbase_get_type_from_handle_generic;
164 public static MethodInfo fieldinfo_get_field_from_handle;
165 static public MethodInfo activator_create_instance;
168 // The attribute constructors.
170 static public ConstructorInfo void_decimal_ctor_five_args;
171 static public ConstructorInfo void_decimal_ctor_int_arg;
172 static public ConstructorInfo default_member_ctor;
173 static public ConstructorInfo decimal_constant_attribute_ctor;
174 static internal ConstructorInfo struct_layout_attribute_ctor;
175 static public ConstructorInfo field_offset_attribute_ctor;
176 public static ConstructorInfo invalid_operation_exception_ctor;
178 static public CustomAttributeBuilder param_array_attr;
179 static CustomAttributeBuilder compiler_generated_attr;
180 static CustomAttributeBuilder debugger_hidden_attr;
182 // C# 2.0
183 static internal ConstructorInfo fixed_buffer_attr_ctor;
184 static internal CustomAttributeBuilder unsafe_value_type_attr;
186 // C# 3.0
187 static internal CustomAttributeBuilder extension_attribute_attr;
189 static PtrHashtable builder_to_declspace;
191 static PtrHashtable builder_to_member_cache;
193 // <remarks>
194 // Tracks the interfaces implemented by typebuilders. We only
195 // enter those who do implement or or more interfaces
196 // </remarks>
197 static PtrHashtable builder_to_ifaces;
199 // <remarks>
200 // Maps a MethodBase to its ParameterData (either InternalParameters or ReflectionParameters)
201 // <remarks>
202 static Hashtable method_params;
204 // <remarks>
205 // A hash table from override methods to their base virtual method.
206 // <remarks>
207 static Hashtable method_overrides;
209 // <remarks>
210 // Keeps track of methods
211 // </remarks>
213 static Hashtable builder_to_method;
215 // <remarks>
216 // Contains all public types from referenced assemblies.
217 // This member is used only if CLS Compliance verification is required.
218 // </remarks>
219 public static Hashtable AllClsTopLevelTypes;
221 static Hashtable fieldbuilders_to_fields;
222 static Hashtable propertybuilder_to_property;
223 static Hashtable fields;
224 static Hashtable events;
225 static PtrHashtable assembly_internals_vis_attrs;
227 public static void CleanUp ()
229 // Lets get everything clean so that we can collect before generating code
230 builder_to_declspace = null;
231 builder_to_member_cache = null;
232 builder_to_ifaces = null;
233 builder_to_type_param = null;
234 method_params = null;
235 builder_to_method = null;
237 fields = null;
238 events = null;
239 type_hash = null;
240 propertybuilder_to_property = null;
242 TypeHandle.CleanUp ();
246 // These are expressions that represent some of the internal data types, used
247 // elsewhere
249 static void InitExpressionTypes ()
251 system_object_expr = new TypeLookupExpression ("System", "Object");
252 system_string_expr = new TypeLookupExpression ("System", "String");
253 system_boolean_expr = new TypeLookupExpression ("System", "Boolean");
254 system_decimal_expr = new TypeLookupExpression ("System", "Decimal");
255 system_single_expr = new TypeLookupExpression ("System", "Single");
256 system_double_expr = new TypeLookupExpression ("System", "Double");
257 system_sbyte_expr = new TypeLookupExpression ("System", "SByte");
258 system_byte_expr = new TypeLookupExpression ("System", "Byte");
259 system_int16_expr = new TypeLookupExpression ("System", "Int16");
260 system_uint16_expr = new TypeLookupExpression ("System", "UInt16");
261 system_int32_expr = new TypeLookupExpression ("System", "Int32");
262 system_uint32_expr = new TypeLookupExpression ("System", "UInt32");
263 system_int64_expr = new TypeLookupExpression ("System", "Int64");
264 system_uint64_expr = new TypeLookupExpression ("System", "UInt64");
265 system_char_expr = new TypeLookupExpression ("System", "Char");
266 system_void_expr = new TypeLookupExpression ("System", "Void");
267 system_valuetype_expr = new TypeLookupExpression ("System", "ValueType");
268 system_intptr_expr = new TypeLookupExpression ("System", "IntPtr");
271 static TypeManager ()
273 Reset ();
276 static public void Reset ()
278 InitExpressionTypes ();
280 builder_to_declspace = new PtrHashtable ();
281 builder_to_member_cache = new PtrHashtable ();
282 builder_to_method = new PtrHashtable ();
283 builder_to_type_param = new PtrHashtable ();
284 method_params = new PtrHashtable ();
285 method_overrides = new PtrHashtable ();
286 builder_to_ifaces = new PtrHashtable ();
288 fieldbuilders_to_fields = new Hashtable ();
289 propertybuilder_to_property = new Hashtable ();
290 fields = new Hashtable ();
291 type_hash = new DoubleHash ();
292 assembly_internals_vis_attrs = new PtrHashtable ();
293 iface_cache = new PtrHashtable ();
295 closure = new Closure ();
296 FilterWithClosure_delegate = new MemberFilter (closure.Filter);
298 // TODO: I am really bored by all this static stuff
299 system_type_get_type_from_handle =
300 bool_movenext_void =
301 void_dispose_void =
302 void_monitor_enter_object =
303 void_monitor_exit_object =
304 void_initializearray_array_fieldhandle =
305 delegate_combine_delegate_delegate =
306 delegate_remove_delegate_delegate =
307 int_get_offset_to_string_data =
308 int_interlocked_compare_exchange =
309 methodbase_get_type_from_handle =
310 methodbase_get_type_from_handle_generic =
311 fieldinfo_get_field_from_handle =
312 activator_create_instance = null;
314 ienumerator_getcurrent = null;
316 void_decimal_ctor_five_args =
317 void_decimal_ctor_int_arg =
318 default_member_ctor =
319 decimal_constant_attribute_ctor =
320 struct_layout_attribute_ctor =
321 field_offset_attribute_ctor =
322 invalid_operation_exception_ctor =
323 fixed_buffer_attr_ctor = null;
325 param_array_attr =
326 compiler_generated_attr =
327 unsafe_value_type_attr =
328 extension_attribute_attr = null;
330 isvolatile_type = null;
332 // to uncover regressions
333 AllClsTopLevelTypes = null;
336 public static void AddUserType (DeclSpace ds)
338 builder_to_declspace.Add (ds.TypeBuilder, ds);
342 // This entry point is used by types that we define under the covers
344 public static void RegisterBuilder (Type tb, Type [] ifaces)
346 if (ifaces != null)
347 builder_to_ifaces [tb] = ifaces;
350 public static void AddMethod (MethodBase builder, IMethodData method)
352 builder_to_method.Add (builder, method);
353 method_params.Add (builder, method.ParameterInfo);
356 public static IMethodData GetMethod (MethodBase builder)
358 return (IMethodData) builder_to_method [builder];
361 /// <summary>
362 /// Returns the DeclSpace whose Type is `t' or null if there is no
363 /// DeclSpace for `t' (ie, the Type comes from a library)
364 /// </summary>
365 public static DeclSpace LookupDeclSpace (Type t)
367 return builder_to_declspace [t] as DeclSpace;
370 /// <summary>
371 /// Returns the TypeContainer whose Type is `t' or null if there is no
372 /// TypeContainer for `t' (ie, the Type comes from a library)
373 /// </summary>
374 public static TypeContainer LookupTypeContainer (Type t)
376 return builder_to_declspace [t] as TypeContainer;
379 public static MemberCache LookupMemberCache (Type t)
381 if (t.Module == CodeGen.Module.Builder) {
382 DeclSpace container = (DeclSpace)builder_to_declspace [t];
383 if (container != null)
384 return container.MemberCache;
387 #if GMCS_SOURCE
388 if (t is GenericTypeParameterBuilder) {
389 TypeParameter container = builder_to_type_param [t] as TypeParameter;
391 if (container != null)
392 return container.MemberCache;
394 #endif
396 return TypeHandle.GetMemberCache (t);
399 public static MemberCache LookupBaseInterfacesCache (Type t)
401 Type [] ifaces = GetInterfaces (t);
403 if (ifaces != null && ifaces.Length == 1)
404 return LookupMemberCache (ifaces [0]);
406 // TODO: the builder_to_member_cache should be indexed by 'ifaces', not 't'
407 MemberCache cache = builder_to_member_cache [t] as MemberCache;
408 if (cache != null)
409 return cache;
411 cache = new MemberCache (ifaces);
412 builder_to_member_cache.Add (t, cache);
413 return cache;
416 public static TypeContainer LookupInterface (Type t)
418 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
419 if ((tc == null) || (tc.Kind != Kind.Interface))
420 return null;
422 return tc;
425 public static Delegate LookupDelegate (Type t)
427 return builder_to_declspace [t] as Delegate;
430 public static Class LookupClass (Type t)
432 return (Class) builder_to_declspace [t];
436 // We use this hash for multiple kinds of constructed types:
438 // (T, "&") Given T, get T &
439 // (T, "*") Given T, get T *
440 // (T, "[]") Given T and a array dimension, get T []
441 // (T, X) Given a type T and a simple name X, get the type T+X
443 // Accessibility tests, if necessary, should be done by the user
445 static DoubleHash type_hash = new DoubleHash ();
448 // Gets the reference to T version of the Type (T&)
450 public static Type GetReferenceType (Type t)
452 #if GMCS_SOURCE
453 return t.MakeByRefType ();
454 #else
455 return GetConstructedType (t, "&");
456 #endif
460 // Gets the pointer to T version of the Type (T*)
462 public static Type GetPointerType (Type t)
464 return GetConstructedType (t, "*");
467 public static Type GetConstructedType (Type t, string dim)
469 object ret = null;
470 if (type_hash.Lookup (t, dim, out ret))
471 return (Type) ret;
473 ret = t.Module.GetType (t.ToString () + dim);
474 if (ret != null) {
475 type_hash.Insert (t, dim, ret);
476 return (Type) ret;
479 if (dim == "&") {
480 ret = GetReferenceType (t);
481 type_hash.Insert (t, dim, ret);
482 return (Type) ret;
485 #if GMCS_SOURCE
486 if (t.IsGenericParameter || t.IsGenericType) {
487 int pos = 0;
488 Type result = t;
489 while ((pos < dim.Length) && (dim [pos] == '[')) {
490 pos++;
492 if (dim [pos] == ']') {
493 result = result.MakeArrayType ();
494 pos++;
496 if (pos < dim.Length)
497 continue;
499 type_hash.Insert (t, dim, result);
500 return result;
503 int rank = 0;
504 while (dim [pos] == ',') {
505 pos++; rank++;
508 if ((dim [pos] != ']') || (pos != dim.Length-1))
509 break;
511 result = result.MakeArrayType (rank + 1);
512 type_hash.Insert (t, dim, result);
513 return result;
516 #endif
518 type_hash.Insert (t, dim, null);
519 return null;
522 public static CustomAttributeBuilder GetCompilerGeneratedAttribute (Location loc)
524 if (compiler_generated_attr != null)
525 return compiler_generated_attr;
527 Type t = TypeManager.CoreLookupType (
528 "System.Runtime.CompilerServices", "CompilerGeneratedAttribute", Kind.Class, true);
530 // TODO: it cannot be null
531 if (t == null)
532 return null;
534 compiler_generated_attr = new CustomAttributeBuilder (
535 GetPredefinedConstructor (t, loc, Type.EmptyTypes), new object[0]);
537 return compiler_generated_attr;
540 public static CustomAttributeBuilder GetDebuggerHiddenAttribute (Location loc)
542 if (debugger_hidden_attr != null)
543 return debugger_hidden_attr;
545 Type t = TypeManager.CoreLookupType (
546 "System.Diagnostics", "DebuggerHiddenAttribute", Kind.Class, true);
548 // TODO: it cannot be null
549 if (t == null)
550 return null;
552 debugger_hidden_attr = new CustomAttributeBuilder (
553 GetPredefinedConstructor (t, loc, Type.EmptyTypes), new object[0]);
555 return debugger_hidden_attr;
558 public static Type GetNestedType (Type t, string name)
560 object ret = null;
561 if (!type_hash.Lookup (t, name, out ret)) {
562 ret = t.GetNestedType (name,
563 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
564 type_hash.Insert (t, name, ret);
566 return (Type) ret;
569 /// <summary>
570 /// Fills static table with exported types from all referenced assemblies.
571 /// This information is required for CLS Compliance tests.
572 /// </summary>
573 public static void LoadAllImportedTypes ()
575 AllClsTopLevelTypes = new Hashtable (1500);
576 foreach (Assembly a in RootNamespace.Global.Assemblies) {
577 foreach (Type t in a.GetExportedTypes ()) {
578 AllClsTopLevelTypes [t.FullName.ToLower (System.Globalization.CultureInfo.InvariantCulture)] = null;
583 public static bool NamespaceClash (string name, Location loc)
585 if (! RootNamespace.Global.IsNamespace (name))
586 return false;
588 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
589 return true;
592 /// <summary>
593 /// Returns the C# name of a type if possible, or the full type name otherwise
594 /// </summary>
595 static public string CSharpName (Type t)
597 if (t == null_type)
598 return "null";
600 if (t == typeof (ArglistParameter))
601 return "__arglist";
603 if (t == typeof (AnonymousMethodBody))
604 return "anonymous method";
606 if (t == null)
607 return "internal error";
609 return CSharpName (GetFullName (t), t);
612 static readonly char [] elements = new char [] { '*', '[' };
614 public static string CSharpName (string name, Type type)
616 if (name.Length > 10) {
617 string s;
618 switch (name) {
619 case "System.Int32": s = "int"; break;
620 case "System.Int64": s = "long"; break;
621 case "System.String": s = "string"; break;
622 case "System.Boolean": s = "bool"; break;
623 case "System.Void": s = "void"; break;
624 case "System.Object": s = "object"; break;
625 case "System.UInt32": s = "uint"; break;
626 case "System.Int16": s = "short"; break;
627 case "System.UInt16": s = "ushort"; break;
628 case "System.UInt64": s = "ulong"; break;
629 case "System.Single": s = "float"; break;
630 case "System.Double": s = "double"; break;
631 case "System.Decimal": s = "decimal"; break;
632 case "System.Char": s = "char"; break;
633 case "System.Byte": s = "byte"; break;
634 case "System.SByte": s = "sbyte"; break;
635 default: s = null; break;
638 if (s != null) {
640 // Predefined names can come from mscorlib only
642 if (type == null || type.Module.Name == "mscorlib.dll" || !RootContext.StdLib)
643 return s;
645 return name;
648 if (name [0] == AnonymousTypeClass.ClassNamePrefix [0] && name.StartsWith (AnonymousTypeClass.ClassNamePrefix))
649 return AnonymousTypeClass.SignatureForError;
651 int idx = name.IndexOfAny (elements, 10);
652 if (idx > 0)
653 return CSharpName (name.Substring (0, idx), type) + name.Substring (idx);
656 return name.Replace ('+', '.');
659 static public string CSharpName (Type[] types)
661 if (types.Length == 0)
662 return string.Empty;
664 StringBuilder sb = new StringBuilder ();
665 for (int i = 0; i < types.Length; ++i) {
666 if (i > 0)
667 sb.Append (", ");
669 sb.Append (CSharpName (types [i]));
671 return sb.ToString ();
674 /// <summary>
675 /// Returns the signature of the method with full namespace classification
676 /// </summary>
677 static public string GetFullNameSignature (MemberInfo mi)
679 PropertyInfo pi = mi as PropertyInfo;
680 if (pi != null) {
681 MethodBase pmi = pi.GetGetMethod (true);
682 if (pmi == null)
683 pmi = pi.GetSetMethod (true);
684 if (GetParameterData (pmi).Count > 0)
685 mi = pmi;
687 return (mi is MethodBase)
688 ? CSharpSignature (mi as MethodBase)
689 : CSharpName (mi.DeclaringType) + '.' + mi.Name;
692 #if GMCS_SOURCE
693 private static int GetFullName (Type t, StringBuilder sb)
695 int pos = 0;
697 if (!t.IsGenericType) {
698 sb.Append (t.FullName);
699 return 0;
702 if (t.DeclaringType != null) {
703 pos = GetFullName (t.DeclaringType, sb);
704 sb.Append ('.');
705 } else if (t.Namespace != null && t.Namespace.Length != 0) {
706 sb.Append (t.Namespace);
707 sb.Append ('.');
709 sb.Append (RemoveGenericArity (t.Name));
711 Type[] this_args = GetTypeArguments (t);
713 if (this_args.Length < pos)
714 throw new InternalErrorException (
715 "Enclosing class " + t.DeclaringType + " has more type arguments than " + t);
716 if (this_args.Length == pos)
717 return pos;
719 sb.Append ('<');
720 for (;;) {
721 sb.Append (CSharpName (this_args [pos++]));
722 if (pos == this_args.Length)
723 break;
724 sb.Append (',');
726 sb.Append ('>');
727 return pos;
730 static string GetFullName (Type t)
732 if (t.IsArray) {
733 string dimension = t.Name.Substring (t.Name.LastIndexOf ('['));
734 return GetFullName (GetElementType (t)) + dimension;
737 if (IsNullableType (t) && !t.IsGenericTypeDefinition) {
738 t = GetTypeArguments (t)[0];
739 return CSharpName (t) + "?";
742 if (t.IsGenericParameter)
743 return t.Name;
744 if (!t.IsGenericType)
745 return t.FullName;
747 StringBuilder sb = new StringBuilder ();
748 int pos = GetFullName (t, sb);
749 if (pos <= 0)
750 throw new InternalErrorException ("Generic Type " + t + " doesn't have type arguments");
751 return sb.ToString ();
753 #else
754 public static string GetFullName (Type t)
756 return t.FullName;
758 #endif
760 public static string RemoveGenericArity (string from)
762 int i = from.IndexOf ('`');
763 if (i > 0)
764 return from.Substring (0, i);
765 return from;
768 /// <summary>
769 /// When we need to report accessors as well
770 /// </summary>
771 static public string CSharpSignature (MethodBase mb)
773 return CSharpSignature (mb, false);
776 /// <summary>
777 /// Returns the signature of the method
778 /// </summary>
779 static public string CSharpSignature (MethodBase mb, bool show_accessor)
781 StringBuilder sig = new StringBuilder (CSharpName (mb.DeclaringType));
782 sig.Append ('.');
784 AParametersCollection iparams = GetParameterData (mb);
785 string parameters = iparams.GetSignatureForError ();
786 int accessor_end = 0;
788 if (!mb.IsConstructor && TypeManager.IsSpecialMethod (mb)) {
789 string op_name = Operator.GetName (mb.Name);
790 if (op_name != null) {
791 if (op_name == "explicit" || op_name == "implicit") {
792 sig.Append (op_name);
793 sig.Append (" operator ");
794 sig.Append (CSharpName (((MethodInfo)mb).ReturnType));
795 } else {
796 sig.Append ("operator ");
797 sig.Append (op_name);
799 sig.Append (parameters);
800 return sig.ToString ();
803 bool is_getter = mb.Name.StartsWith ("get_");
804 bool is_setter = mb.Name.StartsWith ("set_");
805 if (is_getter || is_setter || mb.Name.StartsWith ("add_")) {
806 accessor_end = 3;
807 } else if (mb.Name.StartsWith ("remove_")) {
808 accessor_end = 6;
811 // Is indexer
812 if (iparams.Count > (is_getter ? 0 : 1)) {
813 sig.Append ("this[");
814 if (is_getter)
815 sig.Append (parameters.Substring (1, parameters.Length - 2));
816 else
817 sig.Append (parameters.Substring (1, parameters.LastIndexOf (',') - 1));
818 sig.Append (']');
819 } else {
820 sig.Append (mb.Name.Substring (accessor_end + 1));
822 } else {
823 if (mb.Name == ".ctor")
824 sig.Append (RemoveGenericArity (mb.DeclaringType.Name));
825 else {
826 sig.Append (mb.Name);
828 #if GMCS_SOURCE
829 if (TypeManager.IsGenericMethod (mb)) {
830 Type[] args = mb.GetGenericArguments ();
831 sig.Append ('<');
832 for (int i = 0; i < args.Length; i++) {
833 if (i > 0)
834 sig.Append (',');
835 sig.Append (CSharpName (args [i]));
837 sig.Append ('>');
839 #endif
842 sig.Append (parameters);
845 if (show_accessor && accessor_end > 0) {
846 sig.Append ('.');
847 sig.Append (mb.Name.Substring (0, accessor_end));
850 return sig.ToString ();
853 public static string GetMethodName (MethodInfo m)
855 #if GMCS_SOURCE
856 if (!IsGenericMethodDefinition (m) && !IsGenericMethod (m))
857 return m.Name;
859 return MemberName.MakeName (m.Name, m.GetGenericArguments ().Length);
860 #else
861 return m.Name;
862 #endif
865 static public string CSharpSignature (EventInfo ei)
867 return CSharpName (ei.DeclaringType) + "." + ei.Name;
871 // Looks up a type, and aborts if it is not found. This is used
872 // by predefined types required by the compiler
874 public static Type CoreLookupType (string ns_name, string name, Kind type_kind, bool required)
876 Namespace ns = RootNamespace.Global.GetNamespace (ns_name, true);
877 Expression expr = ns.Lookup (RootContext.ToplevelTypes, name, Location.Null);
879 if (expr == null) {
880 if (required) {
881 Report.Error (518, "The predefined type `{0}.{1}' is not defined or imported",
882 ns_name, name);
884 return null;
887 Type t = expr.Type;
888 if (RootContext.StdLib || t == null || !required)
889 return t;
891 // TODO: All predefined imported types have to have correct signature
892 if (t.Module != CodeGen.Module.Builder)
893 return t;
895 DeclSpace ds = (DeclSpace)RootContext.ToplevelTypes.GetDefinition (t.FullName);
896 if (ds is Delegate) {
897 if (type_kind == Kind.Delegate)
898 return t;
899 } else {
900 TypeContainer tc = (TypeContainer)ds;
901 if (tc.Kind == type_kind)
902 return t;
905 Report.Error (520, ds.Location, "The predefined type `{0}.{1}' is not declared correctly",
906 ns_name, name);
907 return null;
910 static MemberInfo GetPredefinedMember (Type t, string name, MemberTypes mt, Location loc, params Type [] args)
912 const BindingFlags flags = instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly;
914 MemberInfo [] members = MemberLookup (null, null, t, mt, flags, name, null);
915 if (members != null) {
916 for (int i = 0; i < members.Length; ++i) {
917 MemberInfo member = members [i];
918 if (mt == MemberTypes.Method || mt == MemberTypes.Constructor) {
919 MethodBase mb = member as MethodBase;
920 if (mb == null)
921 continue;
923 AParametersCollection pd = TypeManager.GetParameterData (mb);
924 if (IsEqual (pd.Types, args))
925 return member;
927 if (mt == MemberTypes.Field) {
928 FieldInfo fi = member as FieldInfo;
929 if (fi == null)
930 continue;
932 if (args.Length >= 1 && !IsEqual (TypeToCoreType (fi.FieldType), args [0]))
933 continue;
935 return member;
938 if (mt == MemberTypes.Property) {
939 PropertyInfo pi = member as PropertyInfo;
940 if (pi == null)
941 continue;
943 if (args.Length >= 1 && !IsEqual (TypeToCoreType (pi.PropertyType), args [0]))
944 continue;
946 return member;
951 string method_args = null;
952 if (mt == MemberTypes.Method || mt == MemberTypes.Constructor)
953 method_args = "(" + TypeManager.CSharpName (args) + ")";
955 Report.Error (656, loc, "The compiler required member `{0}.{1}{2}' could not be found or is inaccessible",
956 TypeManager.CSharpName (t), name, method_args);
958 return null;
962 // Returns the ConstructorInfo for "args"
964 public static ConstructorInfo GetPredefinedConstructor (Type t, Location loc, params Type [] args)
966 return (ConstructorInfo) GetPredefinedMember (t, ConstructorInfo.ConstructorName, MemberTypes.Constructor, loc, args);
970 // Returns the MethodInfo for a method named `name' defined
971 // in type `t' which takes arguments of types `args'
973 public static MethodInfo GetPredefinedMethod (Type t, string name, Location loc, params Type [] args)
975 return (MethodInfo)GetPredefinedMember (t, name, MemberTypes.Method, loc, args);
978 public static FieldInfo GetPredefinedField (Type t, string name, Location loc, params Type [] args)
980 return (FieldInfo) GetPredefinedMember (t, name, MemberTypes.Field, loc, args);
983 public static PropertyInfo GetPredefinedProperty (Type t, string name, Location loc, params Type [] args)
985 return (PropertyInfo) GetPredefinedMember (t, name, MemberTypes.Property, loc, args);
988 /// <remarks>
989 /// The types have to be initialized after the initial
990 /// population of the type has happened (for example, to
991 /// bootstrap the corlib.dll
992 /// </remarks>
993 public static bool InitCoreTypes ()
995 object_type = CoreLookupType ("System", "Object", Kind.Class, true);
996 system_object_expr.Type = object_type;
997 value_type = CoreLookupType ("System", "ValueType", Kind.Class, true);
998 system_valuetype_expr.Type = value_type;
999 attribute_type = CoreLookupType ("System", "Attribute", Kind.Class, true);
1001 int32_type = CoreLookupType ("System", "Int32", Kind.Struct, true);
1002 system_int32_expr.Type = int32_type;
1003 int64_type = CoreLookupType ("System", "Int64", Kind.Struct, true);
1004 system_int64_expr.Type = int64_type;
1005 uint32_type = CoreLookupType ("System", "UInt32", Kind.Struct, true);
1006 system_uint32_expr.Type = uint32_type;
1007 uint64_type = CoreLookupType ("System", "UInt64", Kind.Struct, true);
1008 system_uint64_expr.Type = uint64_type;
1009 byte_type = CoreLookupType ("System", "Byte", Kind.Struct, true);
1010 system_byte_expr.Type = byte_type;
1011 sbyte_type = CoreLookupType ("System", "SByte", Kind.Struct, true);
1012 system_sbyte_expr.Type = sbyte_type;
1013 short_type = CoreLookupType ("System", "Int16", Kind.Struct, true);
1014 system_int16_expr.Type = short_type;
1015 ushort_type = CoreLookupType ("System", "UInt16", Kind.Struct, true);
1016 system_uint16_expr.Type = ushort_type;
1018 ienumerator_type = CoreLookupType ("System.Collections", "IEnumerator", Kind.Interface, true);
1019 ienumerable_type = CoreLookupType ("System.Collections", "IEnumerable", Kind.Interface, true);
1020 idisposable_type = CoreLookupType ("System", "IDisposable", Kind.Interface, true);
1022 // HACK: DefineType immediately resolves iterators (very wrong)
1023 generic_ienumerator_type = CoreLookupType ("System.Collections.Generic", "IEnumerator`1", Kind.Interface, false);
1025 char_type = CoreLookupType ("System", "Char", Kind.Struct, true);
1026 system_char_expr.Type = char_type;
1027 string_type = CoreLookupType ("System", "String", Kind.Class, true);
1028 system_string_expr.Type = string_type;
1029 float_type = CoreLookupType ("System", "Single", Kind.Struct, true);
1030 system_single_expr.Type = float_type;
1031 double_type = CoreLookupType ("System", "Double", Kind.Struct, true);
1032 system_double_expr.Type = double_type;
1033 decimal_type = CoreLookupType ("System", "Decimal", Kind.Struct, true);
1034 system_decimal_expr.Type = decimal_type;
1035 bool_type = CoreLookupType ("System", "Boolean", Kind.Struct, true);
1036 system_boolean_expr.Type = bool_type;
1037 intptr_type = CoreLookupType ("System", "IntPtr", Kind.Struct, true);
1038 system_intptr_expr.Type = intptr_type;
1039 uintptr_type = CoreLookupType ("System", "UIntPtr", Kind.Struct, true);
1041 multicast_delegate_type = CoreLookupType ("System", "MulticastDelegate", Kind.Class, true);
1042 delegate_type = CoreLookupType ("System", "Delegate", Kind.Class, true);
1044 enum_type = CoreLookupType ("System", "Enum", Kind.Class, true);
1045 array_type = CoreLookupType ("System", "Array", Kind.Class, true);
1046 void_type = CoreLookupType ("System", "Void", Kind.Struct, true);
1047 system_void_expr.Type = void_type;
1048 type_type = CoreLookupType ("System", "Type", Kind.Class, true);
1049 exception_type = CoreLookupType ("System", "Exception", Kind.Class, true);
1051 runtime_field_handle_type = CoreLookupType ("System", "RuntimeFieldHandle", Kind.Struct, true);
1052 runtime_handle_type = CoreLookupType ("System", "RuntimeTypeHandle", Kind.Struct, true);
1054 param_array_type = CoreLookupType ("System", "ParamArrayAttribute", Kind.Class, true);
1055 out_attribute_type = CoreLookupType ("System.Runtime.InteropServices", "OutAttribute", Kind.Class, true);
1057 return Report.Errors == 0;
1061 // Initializes optional core types
1063 public static void InitOptionalCoreTypes ()
1066 // These are only used for compare purposes
1068 anonymous_method_type = typeof (AnonymousMethodBody);
1069 null_type = typeof (NullLiteral);
1071 void_ptr_type = GetPointerType (void_type);
1072 char_ptr_type = GetPointerType (char_type);
1075 // Initialize InternalsVisibleTo as the very first optional type. Otherwise we would populate
1076 // types cache with incorrect accessiblity when any of optional types is internal.
1078 internals_visible_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute", Kind.Class, false);
1080 runtime_argument_handle_type = CoreLookupType ("System", "RuntimeArgumentHandle", Kind.Struct, false);
1081 asynccallback_type = CoreLookupType ("System", "AsyncCallback", Kind.Delegate, false);
1082 iasyncresult_type = CoreLookupType ("System", "IAsyncResult", Kind.Interface, false);
1083 typed_reference_type = CoreLookupType ("System", "TypedReference", Kind.Struct, false);
1084 arg_iterator_type = CoreLookupType ("System", "ArgIterator", Kind.Struct, false);
1085 mbr_type = CoreLookupType ("System", "MarshalByRefObject", Kind.Class, false);
1088 // Optional attributes, used for error reporting only
1090 obsolete_attribute_type = CoreLookupType ("System", "ObsoleteAttribute", Kind.Class, false);
1091 if (obsolete_attribute_type != null) {
1092 Class c = TypeManager.LookupClass (obsolete_attribute_type);
1093 if (c != null)
1094 c.Define ();
1097 dllimport_type = CoreLookupType ("System.Runtime.InteropServices", "DllImportAttribute", Kind.Class, false);
1098 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "MethodImplAttribute", Kind.Class, false);
1099 #if !NET_2_0
1100 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices", "MarshalAsAttribute", Kind.Class, false);
1101 #endif
1102 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices", "InAttribute", Kind.Class, false);
1103 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices", "IndexerNameAttribute", Kind.Class, false);
1104 conditional_attribute_type = CoreLookupType ("System.Diagnostics", "ConditionalAttribute", Kind.Class, false);
1105 cls_compliant_attribute_type = CoreLookupType ("System", "CLSCompliantAttribute", Kind.Class, false);
1106 security_attr_type = CoreLookupType ("System.Security.Permissions", "SecurityAttribute", Kind.Class, false);
1107 required_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "RequiredAttributeAttribute", Kind.Class, false);
1108 guid_attr_type = CoreLookupType ("System.Runtime.InteropServices", "GuidAttribute", Kind.Class, false);
1109 assembly_culture_attribute_type = CoreLookupType ("System.Reflection", "AssemblyCultureAttribute", Kind.Class, false);
1110 assembly_version_attribute_type = CoreLookupType ("System.Reflection", "AssemblyVersionAttribute", Kind.Class, false);
1111 comimport_attr_type = CoreLookupType ("System.Runtime.InteropServices", "ComImportAttribute", Kind.Class, false);
1112 coclass_attr_type = CoreLookupType ("System.Runtime.InteropServices", "CoClassAttribute", Kind.Class, false);
1113 attribute_usage_type = CoreLookupType ("System", "AttributeUsageAttribute", Kind.Class, false);
1114 default_parameter_value_attribute_type = CoreLookupType ("System.Runtime.InteropServices", "DefaultParameterValueAttribute", Kind.Class, false);
1116 // New in .NET 2.0
1117 default_charset_type = CoreLookupType ("System.Runtime.InteropServices", "DefaultCharSetAttribute", Kind.Class, false);
1118 type_forwarder_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "TypeForwardedToAttribute", Kind.Class, false);
1119 generic_ilist_type = CoreLookupType ("System.Collections.Generic", "IList`1", Kind.Interface, false);
1120 generic_icollection_type = CoreLookupType ("System.Collections.Generic", "ICollection`1", Kind.Interface, false);
1121 generic_ienumerable_type = CoreLookupType ("System.Collections.Generic", "IEnumerable`1", Kind.Interface, false);
1122 generic_nullable_type = CoreLookupType ("System", "Nullable`1", Kind.Struct, false);
1125 // Optional types which are used as types and for member lookup
1127 default_member_type = CoreLookupType ("System.Reflection", "DefaultMemberAttribute", Kind.Class, false);
1128 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices", "RuntimeHelpers", Kind.Class, false);
1129 decimal_constant_attribute_type = CoreLookupType ("System.Runtime.CompilerServices", "DecimalConstantAttribute", Kind.Class, false);
1130 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices", "StructLayoutAttribute", Kind.Class, false);
1131 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices", "FieldOffsetAttribute", Kind.Class, false);
1133 // New in .NET 2.0
1134 fixed_buffer_attr_type = CoreLookupType ("System.Runtime.CompilerServices", "FixedBufferAttribute", Kind.Class, false);
1136 // New in .NET 3.5
1137 // Note: extension_attribute_type is already loaded
1138 expression_type = CoreLookupType ("System.Linq.Expressions", "Expression`1", Kind.Class, false);
1140 if (!RootContext.StdLib) {
1142 // HACK: When building Mono corlib mcs uses loaded mscorlib which
1143 // has different predefined types and this method sets mscorlib types
1144 // to be same to avoid any type check errors.
1147 Type type = typeof (Type);
1148 Type [] system_4_type_arg = { type, type, type, type };
1150 MethodInfo set_corlib_type_builders =
1151 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
1152 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
1153 system_4_type_arg, null);
1155 if (set_corlib_type_builders != null) {
1156 object[] args = new object [4];
1157 args [0] = object_type;
1158 args [1] = value_type;
1159 args [2] = enum_type;
1160 args [3] = void_type;
1162 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1163 } else {
1164 Report.Warning (-26, 3, "The compilation may fail due to missing `{0}.SetCorlibTypeBuilders({1})' method",
1165 TypeManager.CSharpName (typeof (System.Reflection.Emit.AssemblyBuilder)),
1166 TypeManager.CSharpName (system_4_type_arg));
1171 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1173 /// <remarks>
1174 /// This is the "old", non-cache based FindMembers() function. We cannot use
1175 /// the cache here because there is no member name argument.
1176 /// </remarks>
1177 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1178 MemberFilter filter, object criteria)
1180 #if MS_COMPATIBLE && GMCS_SOURCE
1181 if (t.IsGenericType)
1182 t = t.GetGenericTypeDefinition ();
1183 #endif
1185 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1188 // `builder_to_declspace' contains all dynamic types.
1190 if (decl != null) {
1191 MemberList list;
1192 Timer.StartTimer (TimerType.FindMembers);
1193 list = decl.FindMembers (mt, bf, filter, criteria);
1194 Timer.StopTimer (TimerType.FindMembers);
1195 return list;
1199 // We have to take care of arrays specially, because GetType on
1200 // a TypeBuilder array will return a Type, not a TypeBuilder,
1201 // and we can not call FindMembers on this type.
1203 if (
1204 #if MS_COMPATIBLE && GMCS_SOURCE
1205 !t.IsGenericType &&
1206 #endif
1207 t.IsSubclassOf (TypeManager.array_type))
1208 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1210 #if GMCS_SOURCE
1211 if (t is GenericTypeParameterBuilder) {
1212 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1214 Timer.StartTimer (TimerType.FindMembers);
1215 MemberList list = tparam.FindMembers (
1216 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1217 Timer.StopTimer (TimerType.FindMembers);
1218 return list;
1220 #endif
1223 // Since FindMembers will not lookup both static and instance
1224 // members, we emulate this behaviour here.
1226 if ((bf & instance_and_static) == instance_and_static){
1227 MemberInfo [] i_members = t.FindMembers (
1228 mt, bf & ~BindingFlags.Static, filter, criteria);
1230 int i_len = i_members.Length;
1231 if (i_len == 1){
1232 MemberInfo one = i_members [0];
1235 // If any of these are present, we are done!
1237 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1238 return new MemberList (i_members);
1241 MemberInfo [] s_members = t.FindMembers (
1242 mt, bf & ~BindingFlags.Instance, filter, criteria);
1244 int s_len = s_members.Length;
1245 if (i_len > 0 || s_len > 0)
1246 return new MemberList (i_members, s_members);
1247 else {
1248 if (i_len > 0)
1249 return new MemberList (i_members);
1250 else
1251 return new MemberList (s_members);
1255 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1259 /// <summary>
1260 /// This method is only called from within MemberLookup. It tries to use the member
1261 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1262 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1263 /// our return value will already contain all inherited members and the caller don't need
1264 /// to check base classes and interfaces anymore.
1265 /// </summary>
1266 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1267 string name, out bool used_cache)
1269 MemberCache cache;
1272 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1273 // and we can ask the DeclSpace for the MemberCache.
1275 #if MS_COMPATIBLE
1276 if (t.Assembly == CodeGen.Assembly.Builder) {
1277 if (t.IsGenericParameter) {
1278 TypeParameter tparam = (TypeParameter) builder_to_type_param[t];
1280 used_cache = true;
1281 if (tparam.MemberCache == null)
1282 return new MemberInfo[0];
1284 return tparam.MemberCache.FindMembers (
1285 mt, bf, name, FilterWithClosure_delegate, null);
1289 // We have to take care of arrays specially, because GetType on
1290 // a TypeBuilder array will return a Type, not a TypeBuilder,
1291 // and we can not call FindMembers on this type.
1293 if (t.IsArray) {
1294 used_cache = true;
1295 return TypeHandle.ArrayType.MemberCache.FindMembers (
1296 mt, bf, name, FilterWithClosure_delegate, null);
1299 if (t.IsGenericType && !t.IsGenericTypeDefinition)
1300 t = t.GetGenericTypeDefinition ();
1301 #else
1302 if (t is TypeBuilder) {
1303 #endif
1304 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1305 cache = decl.MemberCache;
1308 // If this DeclSpace has a MemberCache, use it.
1311 if (cache != null) {
1312 used_cache = true;
1313 return cache.FindMembers (
1314 mt, bf, name, FilterWithClosure_delegate, null);
1317 // If there is no MemberCache, we need to use the "normal" FindMembers.
1318 // Note, this is a VERY uncommon route!
1320 MemberList list;
1321 Timer.StartTimer (TimerType.FindMembers);
1322 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1323 FilterWithClosure_delegate, name);
1324 Timer.StopTimer (TimerType.FindMembers);
1325 used_cache = false;
1326 return (MemberInfo []) list;
1330 // We have to take care of arrays specially, because GetType on
1331 // a TypeBuilder array will return a Type, not a TypeBuilder,
1332 // and we can not call FindMembers on this type.
1334 if (t.IsArray) {
1335 used_cache = true;
1336 return TypeHandle.ArrayType.MemberCache.FindMembers (
1337 mt, bf, name, FilterWithClosure_delegate, null);
1340 #if GMCS_SOURCE
1341 if (t is GenericTypeParameterBuilder) {
1342 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1344 used_cache = true;
1345 if (tparam.MemberCache == null)
1346 return new MemberInfo [0];
1348 return tparam.MemberCache.FindMembers (
1349 mt, bf, name, FilterWithClosure_delegate, null);
1351 #endif
1353 if (IsGenericType (t) && (mt == MemberTypes.NestedType)) {
1355 // This happens if we're resolving a class'es base class and interfaces
1356 // in TypeContainer.DefineType(). At this time, the types aren't
1357 // populated yet, so we can't use the cache.
1359 MemberInfo[] info = t.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1360 FilterWithClosure_delegate, name);
1361 used_cache = false;
1362 return info;
1366 // This call will always succeed. There is exactly one TypeHandle instance per
1367 // type, TypeHandle.GetMemberCache() will, if necessary, create a new one, and return
1368 // the corresponding MemberCache.
1370 cache = TypeHandle.GetMemberCache (t);
1372 used_cache = true;
1373 return cache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1376 public static bool IsBuiltinType (Type t)
1378 t = TypeToCoreType (t);
1379 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1380 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1381 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1382 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1383 return true;
1384 else
1385 return false;
1389 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1390 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1392 public static bool IsPrimitiveType (Type t)
1394 return (t == int32_type || t == uint32_type ||
1395 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1396 t == char_type || t == short_type || t == bool_type ||
1397 t == sbyte_type || t == byte_type || t == ushort_type);
1400 public static bool IsDelegateType (Type t)
1402 #if GMCS_SOURCE
1403 if (t.IsGenericParameter)
1404 return false;
1405 #endif
1407 if (t == TypeManager.delegate_type || t == TypeManager.multicast_delegate_type)
1408 return false;
1410 t = DropGenericTypeArguments (t);
1411 return IsSubclassOf (t, TypeManager.delegate_type);
1414 public static bool IsEnumType (Type t)
1416 t = DropGenericTypeArguments (t);
1417 return t.BaseType == TypeManager.enum_type;
1420 public static bool IsBuiltinOrEnum (Type t)
1422 if (IsBuiltinType (t))
1423 return true;
1425 if (IsEnumType (t))
1426 return true;
1428 return false;
1431 public static bool IsAttributeType (Type t)
1433 return t == attribute_type && t.BaseType != null || IsSubclassOf (t, attribute_type);
1437 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1439 // mcs4: delete, DeclSpace.IsUnmanagedType is replacement
1440 public static bool IsUnmanagedType (Type t)
1442 DeclSpace ds = TypeManager.LookupDeclSpace (t);
1443 if (ds != null)
1444 return ds.IsUnmanagedType ();
1446 // builtins that are not unmanaged types
1447 if (t == TypeManager.object_type || t == TypeManager.string_type)
1448 return false;
1450 if (IsGenericType (t) || IsGenericParameter (t))
1451 return false;
1453 if (IsBuiltinOrEnum (t))
1454 return true;
1456 // Someone did the work of checking if the ElementType of t is unmanaged. Let's not repeat it.
1457 if (t.IsPointer)
1458 return IsUnmanagedType (GetElementType (t));
1460 // Arrays are disallowed, even if we mark them with [MarshalAs(UnmanagedType.ByValArray, ...)]
1461 if (t.IsArray)
1462 return false;
1464 if (!IsValueType (t))
1465 return false;
1467 #if GMCS_SOURCE
1468 for (Type p = t.DeclaringType; p != null; p = p.DeclaringType) {
1469 if (p.IsGenericTypeDefinition)
1470 return false;
1472 #endif
1474 bool retval = true;
1476 FieldInfo [] fields = t.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
1478 foreach (FieldInfo f in fields){
1479 if (!IsUnmanagedType (f.FieldType)){
1480 retval = false;
1485 return retval;
1489 // Null is considered to be a reference type
1491 public static bool IsReferenceType (Type t)
1493 if (TypeManager.IsGenericParameter (t)) {
1494 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1495 if (constraints == null)
1496 return false;
1498 return constraints.IsReferenceType;
1501 return !IsStruct (t) && !IsEnumType (t);
1504 public static bool IsValueType (Type t)
1506 if (TypeManager.IsGenericParameter (t)) {
1507 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1508 if (constraints == null)
1509 return false;
1511 return constraints.IsValueType;
1514 return IsStruct (t) || IsEnumType (t);
1517 public static bool IsStruct (Type t)
1519 return t.BaseType == value_type && t != enum_type && t.IsSealed;
1522 public static bool IsInterfaceType (Type t)
1524 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1525 if (tc == null)
1526 return false;
1528 return tc.Kind == Kind.Interface;
1531 public static bool IsSubclassOf (Type type, Type base_type)
1533 TypeParameter tparam = LookupTypeParameter (type);
1534 TypeParameter pparam = LookupTypeParameter (base_type);
1536 if ((tparam != null) && (pparam != null)) {
1537 if (tparam == pparam)
1538 return true;
1540 return tparam.IsSubclassOf (base_type);
1543 #if MS_COMPATIBLE && GMCS_SOURCE
1544 if (type.IsGenericType)
1545 type = type.GetGenericTypeDefinition ();
1546 #endif
1548 if (type.IsSubclassOf (base_type))
1549 return true;
1551 do {
1552 if (IsEqual (type, base_type))
1553 return true;
1555 type = type.BaseType;
1556 } while (type != null);
1558 return false;
1561 public static bool IsPrivateAccessible (Type type, Type parent)
1563 if (type == null)
1564 return false;
1566 if (type.Equals (parent))
1567 return true;
1569 return DropGenericTypeArguments (type) == DropGenericTypeArguments (parent);
1572 public static bool IsFamilyAccessible (Type type, Type parent)
1574 TypeParameter tparam = LookupTypeParameter (type);
1575 TypeParameter pparam = LookupTypeParameter (parent);
1577 if ((tparam != null) && (pparam != null)) {
1578 if (tparam == pparam)
1579 return true;
1581 return tparam.IsSubclassOf (parent);
1584 do {
1585 if (IsInstantiationOfSameGenericType (type, parent))
1586 return true;
1588 type = type.BaseType;
1589 } while (type != null);
1591 return false;
1595 // Checks whether `type' is a subclass or nested child of `base_type'.
1597 public static bool IsNestedFamilyAccessible (Type type, Type base_type)
1599 do {
1600 if (IsFamilyAccessible (type, base_type))
1601 return true;
1603 // Handle nested types.
1604 type = type.DeclaringType;
1605 } while (type != null);
1607 return false;
1611 // Checks whether `type' is a nested child of `parent'.
1613 public static bool IsNestedChildOf (Type type, Type parent)
1615 if (type == null)
1616 return false;
1618 type = DropGenericTypeArguments (type);
1619 parent = DropGenericTypeArguments (parent);
1621 if (IsEqual (type, parent))
1622 return false;
1624 type = type.DeclaringType;
1625 while (type != null) {
1626 if (IsEqual (type, parent))
1627 return true;
1629 type = type.DeclaringType;
1632 return false;
1635 public static bool IsSpecialType (Type t)
1637 return t == arg_iterator_type || t == typed_reference_type;
1641 // Checks whether `extern_type' is friend of the output assembly
1643 public static bool IsThisOrFriendAssembly (Assembly assembly)
1645 if (assembly == CodeGen.Assembly.Builder)
1646 return true;
1648 if (assembly_internals_vis_attrs.Contains (assembly))
1649 return (bool)(assembly_internals_vis_attrs [assembly]);
1651 if (internals_visible_attr_type == null)
1652 return false;
1654 object [] attrs = assembly.GetCustomAttributes (internals_visible_attr_type, false);
1655 if (attrs.Length == 0) {
1656 assembly_internals_vis_attrs.Add (assembly, false);
1657 return false;
1660 bool is_friend = false;
1661 #if GMCS_SOURCE
1662 AssemblyName this_name = CodeGen.Assembly.Name;
1663 byte [] this_token = this_name.GetPublicKeyToken ();
1664 foreach (InternalsVisibleToAttribute attr in attrs) {
1665 if (attr.AssemblyName == null || attr.AssemblyName.Length == 0)
1666 continue;
1668 AssemblyName aname = null;
1669 try {
1670 aname = new AssemblyName (attr.AssemblyName);
1671 } catch (FileLoadException) {
1672 } catch (ArgumentException) {
1675 if (aname == null || aname.Name != this_name.Name)
1676 continue;
1678 byte [] key_token = aname.GetPublicKeyToken ();
1679 if (key_token != null) {
1680 if (this_token.Length == 0) {
1681 // Same name, but assembly is not strongnamed
1682 Error_FriendAccessNameNotMatching (aname.FullName);
1683 break;
1686 if (!CompareKeyTokens (this_token, key_token))
1687 continue;
1690 is_friend = true;
1691 break;
1693 #endif
1694 assembly_internals_vis_attrs.Add (assembly, is_friend);
1695 return is_friend;
1698 #if GMCS_SOURCE
1699 static bool CompareKeyTokens (byte [] token1, byte [] token2)
1701 for (int i = 0; i < token1.Length; i++)
1702 if (token1 [i] != token2 [i])
1703 return false;
1705 return true;
1708 static void Error_FriendAccessNameNotMatching (string other_name)
1710 Report.Error (281,
1711 "Friend access was granted to `{0}', but the output assembly is named `{1}'. Try adding a reference to `{0}' or change the output assembly name to match it",
1712 other_name, CodeGen.Assembly.Name.FullName);
1714 #endif
1717 // Do the right thing when returning the element type of an
1718 // array type based on whether we are compiling corlib or not
1720 public static Type GetElementType (Type t)
1722 if (RootContext.StdLib)
1723 return t.GetElementType ();
1724 else
1725 return TypeToCoreType (t.GetElementType ());
1728 /// <summary>
1729 /// This method is not implemented by MS runtime for dynamic types
1730 /// </summary>
1731 public static bool HasElementType (Type t)
1733 return t.IsArray || t.IsPointer || t.IsByRef;
1736 public static Type GetEnumUnderlyingType (Type t)
1738 t = DropGenericTypeArguments (t);
1739 Enum e = LookupTypeContainer (t) as Enum;
1740 if (e != null)
1741 return e.UnderlyingType;
1743 // TODO: cache it ?
1744 FieldInfo fi = GetPredefinedField (t, Enum.UnderlyingValueField, Location.Null, Type.EmptyTypes);
1745 if (fi == null)
1746 return TypeManager.int32_type;
1748 return TypeToCoreType (fi.FieldType);
1751 /// <summary>
1752 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1753 /// </summary>
1755 /// <remarks>
1756 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1757 /// for anything which is dynamic, and we need this in a number of places,
1758 /// we register this information here, and use it afterwards.
1759 /// </remarks>
1760 static public void RegisterMethod (MethodBase mb, AParametersCollection ip)
1762 method_params.Add (mb, ip);
1765 static public void RegisterIndexer (PropertyBuilder pb, AParametersCollection p)
1767 method_params.Add (pb, p);
1770 static public AParametersCollection GetParameterData (MethodBase mb)
1772 AParametersCollection pd = (AParametersCollection) method_params [mb];
1773 if (pd == null) {
1774 #if MS_COMPATIBLE
1775 if (mb.IsGenericMethod && !mb.IsGenericMethodDefinition) {
1776 MethodInfo mi = ((MethodInfo) mb).GetGenericMethodDefinition ();
1777 pd = GetParameterData (mi);
1779 if (mi.IsGenericMethod)
1780 pd = pd.InflateTypes (mi.GetGenericArguments (), mb.GetGenericArguments ());
1781 else
1782 pd = pd.InflateTypes (mi.DeclaringType.GetGenericArguments (), mb.GetGenericArguments ());
1784 method_params.Add (mb, pd);
1785 return pd;
1788 if (mb.DeclaringType.Assembly == CodeGen.Assembly.Builder) {
1789 throw new InternalErrorException ("Parameters are not registered for method `{0}'",
1790 TypeManager.CSharpName (mb.DeclaringType) + "." + mb.Name);
1793 pd = ParametersImported.Create (mb);
1794 #else
1795 MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
1796 if (generic != mb) {
1797 pd = TypeManager.GetParameterData (generic);
1798 pd = ParametersImported.Create (pd, mb);
1799 } else {
1800 pd = ParametersImported.Create (mb);
1802 #endif
1803 method_params.Add (mb, pd);
1805 return pd;
1808 public static AParametersCollection GetParameterData (PropertyInfo pi)
1810 AParametersCollection pd = (AParametersCollection)method_params [pi];
1811 if (pd == null) {
1812 if (pi is PropertyBuilder)
1813 return ParametersCompiled.EmptyReadOnlyParameters;
1815 ParameterInfo [] p = pi.GetIndexParameters ();
1816 if (p == null)
1817 return ParametersCompiled.EmptyReadOnlyParameters;
1819 pd = ParametersImported.Create (p, null);
1820 method_params.Add (pi, pd);
1823 return pd;
1826 public static AParametersCollection GetDelegateParameters (Type t)
1828 Delegate d = builder_to_declspace [t] as Delegate;
1829 if (d != null)
1830 return d.Parameters;
1832 MethodInfo invoke_mb = Delegate.GetInvokeMethod (t, t);
1833 return GetParameterData (invoke_mb);
1836 static public void RegisterOverride (MethodBase override_method, MethodBase base_method)
1838 if (!method_overrides.Contains (override_method))
1839 method_overrides [override_method] = base_method;
1840 if (method_overrides [override_method] != base_method)
1841 throw new InternalErrorException ("Override mismatch: " + override_method);
1844 static public bool IsOverride (MethodBase m)
1846 m = DropGenericMethodArguments (m);
1848 return m.IsVirtual &&
1849 (m.Attributes & MethodAttributes.NewSlot) == 0 &&
1850 (m is MethodBuilder || method_overrides.Contains (m));
1853 static public MethodBase TryGetBaseDefinition (MethodBase m)
1855 m = DropGenericMethodArguments (m);
1857 return (MethodBase) method_overrides [m];
1860 public static void RegisterConstant (FieldInfo fb, IConstant ic)
1862 fields.Add (fb, ic);
1865 public static IConstant GetConstant (FieldInfo fb)
1867 if (fb == null)
1868 return null;
1870 return (IConstant)fields [fb];
1873 public static void RegisterProperty (PropertyInfo pi, PropertyBase pb)
1875 propertybuilder_to_property.Add (pi, pb);
1878 public static PropertyBase GetProperty (PropertyInfo pi)
1880 return (PropertyBase)propertybuilder_to_property [pi];
1883 static public void RegisterFieldBase (FieldBuilder fb, FieldBase f)
1885 fieldbuilders_to_fields.Add (fb, f);
1889 // The return value can be null; This will be the case for
1890 // auxiliary FieldBuilders created by the compiler that have no
1891 // real field being declared on the source code
1893 static public FieldBase GetField (FieldInfo fb)
1895 #if GMCS_SOURCE
1896 fb = GetGenericFieldDefinition (fb);
1897 #endif
1898 return (FieldBase) fieldbuilders_to_fields [fb];
1901 static public MethodInfo GetAddMethod (EventInfo ei)
1903 if (ei is MyEventBuilder) {
1904 return ((MyEventBuilder)ei).GetAddMethod (true);
1906 return ei.GetAddMethod (true);
1909 static public MethodInfo GetRemoveMethod (EventInfo ei)
1911 if (ei is MyEventBuilder) {
1912 return ((MyEventBuilder)ei).GetRemoveMethod (true);
1914 return ei.GetRemoveMethod (true);
1917 static public void RegisterEventField (EventInfo einfo, EventField e)
1919 if (events == null)
1920 events = new Hashtable ();
1922 events.Add (einfo, e);
1925 static public EventField GetEventField (EventInfo ei)
1927 if (events == null)
1928 return null;
1930 return (EventField) events [ei];
1933 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
1935 Hashtable hash = new Hashtable ();
1936 return CheckStructCycles (tc, seen, hash);
1939 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
1940 Hashtable hash)
1942 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc.TypeBuilder))
1943 return true;
1946 // `seen' contains all types we've already visited.
1948 if (seen.Contains (tc))
1949 return true;
1950 seen.Add (tc, null);
1952 if (tc.Fields == null)
1953 return true;
1955 foreach (FieldBase field in tc.Fields) {
1956 if (field.FieldBuilder == null || field.FieldBuilder.IsStatic)
1957 continue;
1959 Type ftype = field.FieldBuilder.FieldType;
1960 TypeContainer ftc = LookupTypeContainer (ftype);
1961 if (ftc == null)
1962 continue;
1964 if (hash.Contains (ftc)) {
1965 Report.Error (523, tc.Location,
1966 "Struct member `{0}.{1}' of type `{2}' " +
1967 "causes a cycle in the struct layout",
1968 tc.Name, field.Name, ftc.Name);
1969 return false;
1973 // `hash' contains all types in the current path.
1975 hash.Add (tc, null);
1977 bool ok = CheckStructCycles (ftc, seen, hash);
1979 hash.Remove (tc);
1981 if (!ok)
1982 return false;
1984 if (!seen.Contains (ftc))
1985 seen.Add (ftc, null);
1988 return true;
1991 /// <summary>
1992 /// Given an array of interface types, expand and eliminate repeated ocurrences
1993 /// of an interface.
1994 /// </summary>
1996 /// <remarks>
1997 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1998 /// be IA, IB, IC.
1999 /// </remarks>
2000 public static Type[] ExpandInterfaces (TypeExpr [] base_interfaces)
2002 ArrayList new_ifaces = new ArrayList ();
2004 foreach (TypeExpr iface in base_interfaces){
2005 Type itype = iface.Type;
2007 if (new_ifaces.Contains (itype))
2008 continue;
2010 new_ifaces.Add (itype);
2012 Type [] implementing = GetInterfaces (itype);
2014 foreach (Type imp in implementing){
2015 if (!new_ifaces.Contains (imp))
2016 new_ifaces.Add (imp);
2019 Type [] ret = new Type [new_ifaces.Count];
2020 new_ifaces.CopyTo (ret, 0);
2021 return ret;
2024 public static Type[] ExpandInterfaces (Type [] base_interfaces)
2026 ArrayList new_ifaces = new ArrayList ();
2028 foreach (Type itype in base_interfaces){
2029 if (new_ifaces.Contains (itype))
2030 continue;
2032 new_ifaces.Add (itype);
2034 Type [] implementing = GetInterfaces (itype);
2036 foreach (Type imp in implementing){
2037 if (!new_ifaces.Contains (imp))
2038 new_ifaces.Add (imp);
2041 Type [] ret = new Type [new_ifaces.Count];
2042 new_ifaces.CopyTo (ret, 0);
2043 return ret;
2046 static PtrHashtable iface_cache;
2048 /// <summary>
2049 /// This function returns the interfaces in the type `t'. Works with
2050 /// both types and TypeBuilders.
2051 /// </summary>
2052 public static Type [] GetInterfaces (Type t)
2054 Type [] cached = iface_cache [t] as Type [];
2055 if (cached != null)
2056 return cached;
2059 // The reason for catching the Array case is that Reflection.Emit
2060 // will not return a TypeBuilder for Array types of TypeBuilder types,
2061 // but will still throw an exception if we try to call GetInterfaces
2062 // on the type.
2064 // Since the array interfaces are always constant, we return those for
2065 // the System.Array
2068 if (t.IsArray)
2069 t = TypeManager.array_type;
2071 if ((t is TypeBuilder) || IsGenericType (t)) {
2072 Type [] base_ifaces;
2074 if (t.BaseType == null)
2075 base_ifaces = Type.EmptyTypes;
2076 else
2077 base_ifaces = GetInterfaces (t.BaseType);
2078 Type[] type_ifaces;
2079 if (IsGenericType (t))
2080 #if MS_COMPATIBLE && GMCS_SOURCE
2081 type_ifaces = t.GetGenericTypeDefinition().GetInterfaces ();
2082 #else
2083 type_ifaces = t.GetInterfaces ();
2084 #endif
2085 else
2086 type_ifaces = (Type []) builder_to_ifaces [t];
2087 if (type_ifaces == null || type_ifaces.Length == 0)
2088 type_ifaces = Type.EmptyTypes;
2090 int base_count = base_ifaces.Length;
2091 Type [] result = new Type [base_count + type_ifaces.Length];
2092 base_ifaces.CopyTo (result, 0);
2093 type_ifaces.CopyTo (result, base_count);
2095 iface_cache [t] = result;
2096 return result;
2097 #if GMCS_SOURCE
2098 } else if (t is GenericTypeParameterBuilder){
2099 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2100 if (type_ifaces == null || type_ifaces.Length == 0)
2101 type_ifaces = Type.EmptyTypes;
2103 iface_cache [t] = type_ifaces;
2104 return type_ifaces;
2105 #endif
2106 } else {
2107 Type[] ifaces = t.GetInterfaces ();
2108 iface_cache [t] = ifaces;
2109 return ifaces;
2114 // gets the interfaces that are declared explicitly on t
2116 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2118 return (Type []) builder_to_ifaces [t];
2121 /// <remarks>
2122 /// The following is used to check if a given type implements an interface.
2123 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2124 /// </remarks>
2125 public static bool ImplementsInterface (Type t, Type iface)
2127 Type [] interfaces;
2130 // FIXME OPTIMIZATION:
2131 // as soon as we hit a non-TypeBuiler in the interface
2132 // chain, we could return, as the `Type.GetInterfaces'
2133 // will return all the interfaces implement by the type
2134 // or its bases.
2136 do {
2137 interfaces = GetInterfaces (t);
2139 if (interfaces != null){
2140 foreach (Type i in interfaces){
2141 if (i == iface || IsVariantOf (i, iface))
2142 return true;
2146 t = t.BaseType;
2147 } while (t != null);
2149 return false;
2152 public static bool IsVariantOf (Type type1, Type type2)
2154 #if GMCS_SOURCE
2155 if (type1.IsGenericType && type2.IsGenericType) {
2156 Type generic_target_type = type2.GetGenericTypeDefinition ();
2157 if (type1.GetGenericTypeDefinition () == generic_target_type) {
2158 Type [] t1 = type1.GetGenericArguments ();
2159 Type [] t2 = type2.GetGenericArguments ();
2160 int i = 0;
2161 foreach (Type t in generic_target_type.GetGenericArguments ()) {
2162 if ((t.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) != 0) {
2163 // FIXME this is not right
2164 if (IsValueType (t1[i]) || IsValueType (t2[i])) {
2165 return false;
2167 if ((t.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0 && !t2[i].IsAssignableFrom (t1[i])) {
2168 return false;
2170 if ((t.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0 && !t1[i].IsAssignableFrom (t2[i])) {
2171 return false;
2173 } else if (t1[i] != t2[i]) {
2174 return false;
2176 i++;
2178 return true;
2181 #endif
2182 return false;
2185 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2187 // This is a custom version of Convert.ChangeType() which works
2188 // with the TypeBuilder defined types when compiling corlib.
2189 public static object ChangeType (object value, Type conversionType, out bool error)
2191 IConvertible convert_value = value as IConvertible;
2193 if (convert_value == null){
2194 error = true;
2195 return null;
2199 // NOTE 1:
2200 // We must use Type.Equals() here since `conversionType' is
2201 // the TypeBuilder created version of a system type and not
2202 // the system type itself. You cannot use Type.GetTypeCode()
2203 // on such a type - it'd always return TypeCode.Object.
2205 // NOTE 2:
2206 // We cannot rely on build-in type conversions as they are
2207 // more limited than what C# supports.
2208 // See char -> float/decimal/double conversion
2211 error = false;
2212 try {
2213 if (conversionType.Equals (typeof (Boolean)))
2214 return (object)(convert_value.ToBoolean (nf_provider));
2215 if (conversionType.Equals (typeof (Byte)))
2216 return (object)(convert_value.ToByte (nf_provider));
2217 if (conversionType.Equals (typeof (Char)))
2218 return (object)(convert_value.ToChar (nf_provider));
2219 if (conversionType.Equals (typeof (DateTime)))
2220 return (object)(convert_value.ToDateTime (nf_provider));
2222 if (conversionType.Equals (decimal_type)) {
2223 if (convert_value.GetType () == TypeManager.char_type)
2224 return (decimal)convert_value.ToInt32 (nf_provider);
2225 return convert_value.ToDecimal (nf_provider);
2228 if (conversionType.Equals (typeof (Double))) {
2229 if (convert_value.GetType () == TypeManager.char_type)
2230 return (double)convert_value.ToInt32 (nf_provider);
2231 return convert_value.ToDouble (nf_provider);
2234 if (conversionType.Equals (typeof (Int16)))
2235 return (object)(convert_value.ToInt16 (nf_provider));
2236 if (conversionType.Equals (int32_type))
2237 return (object)(convert_value.ToInt32 (nf_provider));
2238 if (conversionType.Equals (int64_type))
2239 return (object)(convert_value.ToInt64 (nf_provider));
2240 if (conversionType.Equals (typeof (SByte)))
2241 return (object)(convert_value.ToSByte (nf_provider));
2243 if (conversionType.Equals (typeof (Single))) {
2244 if (convert_value.GetType () == TypeManager.char_type)
2245 return (float)convert_value.ToInt32 (nf_provider);
2246 return convert_value.ToSingle (nf_provider);
2249 if (conversionType.Equals (typeof (String)))
2250 return (object)(convert_value.ToString (nf_provider));
2251 if (conversionType.Equals (typeof (UInt16)))
2252 return (object)(convert_value.ToUInt16 (nf_provider));
2253 if (conversionType.Equals (typeof (UInt32)))
2254 return (object)(convert_value.ToUInt32 (nf_provider));
2255 if (conversionType.Equals (typeof (UInt64)))
2256 return (object)(convert_value.ToUInt64 (nf_provider));
2257 if (conversionType.Equals (typeof (Object)))
2258 return (object)(value);
2259 else
2260 error = true;
2261 } catch {
2262 error = true;
2264 return null;
2268 // When compiling with -nostdlib and the type is imported from an external assembly
2269 // SRE uses "wrong" type and we have to convert it to the right compiler instance.
2271 public static Type TypeToCoreType (Type t)
2273 if (RootContext.StdLib || t.Module != typeof (object).Module)
2274 return t;
2276 TypeCode tc = Type.GetTypeCode (t);
2278 switch (tc){
2279 case TypeCode.Boolean:
2280 return TypeManager.bool_type;
2281 case TypeCode.Byte:
2282 return TypeManager.byte_type;
2283 case TypeCode.SByte:
2284 return TypeManager.sbyte_type;
2285 case TypeCode.Char:
2286 return TypeManager.char_type;
2287 case TypeCode.Int16:
2288 return TypeManager.short_type;
2289 case TypeCode.UInt16:
2290 return TypeManager.ushort_type;
2291 case TypeCode.Int32:
2292 return TypeManager.int32_type;
2293 case TypeCode.UInt32:
2294 return TypeManager.uint32_type;
2295 case TypeCode.Int64:
2296 return TypeManager.int64_type;
2297 case TypeCode.UInt64:
2298 return TypeManager.uint64_type;
2299 case TypeCode.Single:
2300 return TypeManager.float_type;
2301 case TypeCode.Double:
2302 return TypeManager.double_type;
2303 case TypeCode.String:
2304 return TypeManager.string_type;
2305 case TypeCode.Decimal:
2306 return TypeManager.decimal_type;
2309 if (t == typeof (void))
2310 return TypeManager.void_type;
2311 if (t == typeof (object))
2312 return TypeManager.object_type;
2313 if (t == typeof (System.Type))
2314 return TypeManager.type_type;
2315 if (t == typeof (System.IntPtr))
2316 return TypeManager.intptr_type;
2317 if (t == typeof (System.UIntPtr))
2318 return TypeManager.uintptr_type;
2319 #if GMCS_SOURCE
2320 if (t.IsArray) {
2321 int dim = t.GetArrayRank ();
2322 t = GetElementType (t);
2323 return t.MakeArrayType (dim);
2325 if (t.IsByRef) {
2326 t = GetElementType (t);
2327 return t.MakeByRefType ();
2329 if (t.IsPointer) {
2330 t = GetElementType (t);
2331 return t.MakePointerType ();
2333 #endif
2334 return t;
2337 /// <summary>
2338 /// Utility function that can be used to probe whether a type
2339 /// is managed or not.
2340 /// </summary>
2341 public static bool VerifyUnManaged (Type t, Location loc)
2343 if (IsUnmanagedType (t))
2344 return true;
2346 while (t.IsPointer)
2347 t = GetElementType (t);
2349 Report.SymbolRelatedToPreviousError (t);
2350 Report.Error (208, loc, "Cannot take the address of, get the size of, or declare a pointer to a managed type `{0}'",
2351 CSharpName (t));
2353 return false;
2356 /// <summary>
2357 /// Returns the name of the indexer in a given type.
2358 /// </summary>
2359 /// <remarks>
2360 /// The default is not always `Item'. The user can change this behaviour by
2361 /// using the IndexerNameAttribute in the container.
2362 /// For example, the String class indexer is named `Chars' not `Item'
2363 /// </remarks>
2364 public static string IndexerPropertyName (Type t)
2366 t = DropGenericTypeArguments (t);
2367 if (t is TypeBuilder) {
2368 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2369 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2372 System.Attribute attr = System.Attribute.GetCustomAttribute (
2373 t, TypeManager.default_member_type);
2374 if (attr != null){
2375 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2376 return dma.MemberName;
2379 return TypeContainer.DefaultIndexerName;
2382 static MethodInfo declare_local_method = null;
2384 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2386 if (declare_local_method == null){
2387 declare_local_method = typeof (ILGenerator).GetMethod (
2388 "DeclareLocal",
2389 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2390 null,
2391 new Type [] { typeof (Type), typeof (bool)},
2392 null);
2393 if (declare_local_method == null){
2394 Report.RuntimeMissingSupport (Location.Null, "pinned local variables");
2395 return ig.DeclareLocal (t);
2398 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2401 private static bool IsSignatureEqual (Type a, Type b)
2404 /// Consider the following example (bug #77674):
2406 /// public abstract class A
2407 /// {
2408 /// public abstract T Foo<T> ();
2409 /// }
2411 /// public abstract class B : A
2412 /// {
2413 /// public override U Foo<T> ()
2414 /// { return default (U); }
2415 /// }
2417 /// Here, `T' and `U' are method type parameters from different methods
2418 /// (A.Foo and B.Foo), so both `==' and Equals() will fail.
2420 /// However, since we're determining whether B.Foo() overrides A.Foo(),
2421 /// we need to do a signature based comparision and consider them equal.
2423 if (a == b)
2424 return true;
2426 #if GMCS_SOURCE
2427 if (a.IsGenericParameter && b.IsGenericParameter &&
2428 (a.DeclaringMethod != null) && (b.DeclaringMethod != null)) {
2429 return a.GenericParameterPosition == b.GenericParameterPosition;
2431 #endif
2433 if (a.IsArray && b.IsArray) {
2434 if (a.GetArrayRank () != b.GetArrayRank ())
2435 return false;
2437 return IsSignatureEqual (GetElementType (a), GetElementType (b));
2440 if (a.IsByRef && b.IsByRef)
2441 return IsSignatureEqual (GetElementType (a), GetElementType (b));
2443 #if GMCS_SOURCE
2444 if (a.IsGenericType && b.IsGenericType) {
2445 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
2446 return false;
2448 Type[] aargs = a.GetGenericArguments ();
2449 Type[] bargs = b.GetGenericArguments ();
2451 if (aargs.Length != bargs.Length)
2452 return false;
2454 for (int i = 0; i < aargs.Length; i++) {
2455 if (!IsSignatureEqual (aargs [i], bargs [i]))
2456 return false;
2459 return true;
2461 #endif
2463 return false;
2467 // Returns whether the array of memberinfos contains the given method
2469 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method, bool ignoreDeclType)
2471 Type [] new_args = TypeManager.GetParameterData (new_method).Types;
2473 foreach (MethodBase method in array) {
2474 if (!ignoreDeclType && method.DeclaringType != new_method.DeclaringType)
2475 continue;
2477 if (method.Name != new_method.Name)
2478 continue;
2480 if (method is MethodInfo && new_method is MethodInfo &&
2481 !IsSignatureEqual (
2482 TypeToCoreType (((MethodInfo) method).ReturnType),
2483 TypeToCoreType (((MethodInfo) new_method).ReturnType)))
2484 continue;
2486 Type [] old_args = TypeManager.GetParameterData (method).Types;
2487 int old_count = old_args.Length;
2488 int i;
2490 if (new_args.Length != old_count)
2491 continue;
2493 for (i = 0; i < old_count; i++){
2494 if (!IsSignatureEqual (old_args [i], new_args [i]))
2495 break;
2497 if (i != old_count)
2498 continue;
2500 return true;
2503 return false;
2507 // We copy methods from `new_members' into `target_list' if the signature
2508 // for the method from in the new list does not exist in the target_list
2510 // The name is assumed to be the same.
2512 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2514 if (target_list == null){
2515 target_list = new ArrayList ();
2517 foreach (MemberInfo mi in new_members){
2518 if (mi is MethodBase)
2519 target_list.Add (mi);
2521 return target_list;
2524 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2525 target_list.CopyTo (target_array, 0);
2527 foreach (MemberInfo mi in new_members){
2528 MethodBase new_method = (MethodBase) mi;
2530 if (!ArrayContainsMethod (target_array, new_method, true))
2531 target_list.Add (new_method);
2533 return target_list;
2536 #region Generics
2537 // <remarks>
2538 // Tracks the generic parameters.
2539 // </remarks>
2540 static PtrHashtable builder_to_type_param;
2542 public static void AddTypeParameter (Type t, TypeParameter tparam)
2544 if (!builder_to_type_param.Contains (t))
2545 builder_to_type_param.Add (t, tparam);
2548 public static TypeParameter LookupTypeParameter (Type t)
2550 return (TypeParameter) builder_to_type_param [t];
2553 // This method always return false for non-generic compiler,
2554 // while Type.IsGenericParameter is returned if it is supported.
2555 public static bool IsGenericParameter (Type type)
2557 #if GMCS_SOURCE
2558 return type.IsGenericParameter;
2559 #else
2560 return false;
2561 #endif
2564 public static int GenericParameterPosition (Type type)
2566 #if GMCS_SOURCE
2567 return type.GenericParameterPosition;
2568 #else
2569 throw new InternalErrorException ("should not be called");
2570 #endif
2573 public static bool IsGenericType (Type type)
2575 #if GMCS_SOURCE
2576 return type.IsGenericType;
2577 #else
2578 return false;
2579 #endif
2582 public static bool IsGenericTypeDefinition (Type type)
2584 #if GMCS_SOURCE
2585 return type.IsGenericTypeDefinition;
2586 #else
2587 return false;
2588 #endif
2591 public static bool ContainsGenericParameters (Type type)
2593 #if GMCS_SOURCE
2594 return type.ContainsGenericParameters;
2595 #else
2596 return false;
2597 #endif
2600 public static FieldInfo GetGenericFieldDefinition (FieldInfo fi)
2602 #if GMCS_SOURCE
2603 if (fi.DeclaringType.IsGenericTypeDefinition ||
2604 !fi.DeclaringType.IsGenericType)
2605 return fi;
2607 Type t = fi.DeclaringType.GetGenericTypeDefinition ();
2608 BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
2609 BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
2611 // TODO: use CodeGen.Module.Builder.ResolveField (fi.MetadataToken);
2612 foreach (FieldInfo f in t.GetFields (bf))
2613 if (f.MetadataToken == fi.MetadataToken)
2614 return f;
2615 #endif
2617 return fi;
2620 public static bool IsEqual (Type a, Type b)
2622 if (a.Equals (b)) {
2623 // MS BCL returns true even if enum types are different
2624 if (a.BaseType == TypeManager.enum_type || b.BaseType == TypeManager.enum_type)
2625 return a.FullName == b.FullName;
2627 // Some types are never equal
2628 if (a == TypeManager.null_type || a == TypeManager.anonymous_method_type)
2629 return false;
2631 return true;
2634 #if GMCS_SOURCE
2635 if (a.IsGenericParameter && b.IsGenericParameter) {
2636 // TODO: needs more testing before cleaning up
2637 //if (a.DeclaringMethod != b.DeclaringMethod &&
2638 // (a.DeclaringMethod == null || b.DeclaringMethod == null))
2639 // return false;
2640 return a.GenericParameterPosition == b.GenericParameterPosition;
2643 if (a.IsArray && b.IsArray) {
2644 if (a.GetArrayRank () != b.GetArrayRank ())
2645 return false;
2646 return IsEqual (GetElementType (a), GetElementType (b));
2649 if (a.IsByRef && b.IsByRef)
2650 return IsEqual (a.GetElementType (), b.GetElementType ());
2652 if (a.IsGenericType && b.IsGenericType) {
2653 Type adef = a.GetGenericTypeDefinition ();
2654 Type bdef = b.GetGenericTypeDefinition ();
2656 if (adef != bdef)
2657 return false;
2659 if (adef.IsEnum && bdef.IsEnum)
2660 return true;
2662 Type[] aargs = a.GetGenericArguments ();
2663 Type[] bargs = b.GetGenericArguments ();
2665 if (aargs.Length != bargs.Length)
2666 return false;
2668 for (int i = 0; i < aargs.Length; i++) {
2669 if (!IsEqual (aargs [i], bargs [i]))
2670 return false;
2673 return true;
2675 #endif
2677 return false;
2680 public static bool IsEqual (Type[] a, Type[] b)
2682 if (a == null || b == null || a.Length != b.Length)
2683 return false;
2685 for (int i = 0; i < a.Length; ++i) {
2686 if (a [i] == null || b [i] == null) {
2687 if (a [i] == b [i])
2688 continue;
2690 return false;
2693 if (!IsEqual (a [i], b [i]))
2694 return false;
2697 return true;
2700 public static Type DropGenericTypeArguments (Type t)
2702 #if GMCS_SOURCE
2703 if (!t.IsGenericType)
2704 return t;
2705 // Micro-optimization: a generic typebuilder is always a generic type definition
2706 if (t is TypeBuilder)
2707 return t;
2708 return t.GetGenericTypeDefinition ();
2709 #else
2710 return t;
2711 #endif
2714 public static MethodBase DropGenericMethodArguments (MethodBase m)
2716 #if GMCS_SOURCE
2717 if (m.IsGenericMethod)
2718 m = ((MethodInfo) m).GetGenericMethodDefinition ();
2720 Type t = m.DeclaringType;
2721 if (!t.IsGenericType || t.IsGenericTypeDefinition)
2722 return m;
2724 t = t.GetGenericTypeDefinition ();
2725 BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
2726 BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
2728 #if MS_COMPATIBLE
2729 // TODO: use CodeGen.Module.Builder.ResolveMethod ()
2730 return m;
2731 #endif
2733 if (m is ConstructorInfo) {
2734 foreach (ConstructorInfo c in t.GetConstructors (bf))
2735 if (c.MetadataToken == m.MetadataToken)
2736 return c;
2737 } else {
2738 foreach (MethodBase mb in t.GetMethods (bf))
2739 if (mb.MetadataToken == m.MetadataToken)
2740 return mb;
2742 #endif
2744 return m;
2747 public static Type[] GetGenericArguments (MethodBase mi)
2749 #if GMCS_SOURCE
2750 return mi.GetGenericArguments ();
2751 #else
2752 return Type.EmptyTypes;
2753 #endif
2756 public static Type[] GetTypeArguments (Type t)
2758 #if GMCS_SOURCE
2759 DeclSpace tc = LookupDeclSpace (t);
2760 if (tc != null) {
2761 if (!tc.IsGeneric)
2762 return Type.EmptyTypes;
2764 TypeParameter[] tparam = tc.TypeParameters;
2765 Type[] ret = new Type [tparam.Length];
2766 for (int i = 0; i < tparam.Length; i++) {
2767 ret [i] = tparam [i].Type;
2768 if (ret [i] == null)
2769 throw new InternalErrorException ();
2772 return ret;
2773 } else
2774 return t.GetGenericArguments ();
2775 #else
2776 throw new InternalErrorException ();
2777 #endif
2780 public static GenericConstraints GetTypeParameterConstraints (Type t)
2782 #if GMCS_SOURCE
2783 if (!t.IsGenericParameter)
2784 throw new InvalidOperationException ();
2786 TypeParameter tparam = LookupTypeParameter (t);
2787 if (tparam != null)
2788 return tparam.GenericConstraints;
2790 return ReflectionConstraints.GetConstraints (t);
2791 #else
2792 throw new InternalErrorException ();
2793 #endif
2796 public static bool HasGenericArguments (Type t)
2798 return GetNumberOfTypeArguments (t) > 0;
2801 public static int GetNumberOfTypeArguments (Type t)
2803 #if GMCS_SOURCE
2804 if (t.IsGenericParameter)
2805 return 0;
2806 DeclSpace tc = LookupDeclSpace (t);
2807 if (tc != null)
2808 return tc.IsGeneric ? tc.CountTypeParameters : 0;
2809 else
2810 return t.IsGenericType ? t.GetGenericArguments ().Length : 0;
2811 #else
2812 return 0;
2813 #endif
2816 /// <summary>
2817 /// Check whether `type' and `parent' are both instantiations of the same
2818 /// generic type. Note that we do not check the type parameters here.
2819 /// </summary>
2820 public static bool IsInstantiationOfSameGenericType (Type type, Type parent)
2822 int tcount = GetNumberOfTypeArguments (type);
2823 int pcount = GetNumberOfTypeArguments (parent);
2825 if (tcount != pcount)
2826 return false;
2828 type = DropGenericTypeArguments (type);
2829 parent = DropGenericTypeArguments (parent);
2831 return type.Equals (parent);
2834 /// <summary>
2835 /// Whether `mb' is a generic method definition.
2836 /// </summary>
2837 public static bool IsGenericMethodDefinition (MethodBase mb)
2839 #if GMCS_SOURCE
2840 if (mb.DeclaringType is TypeBuilder) {
2841 IMethodData method = (IMethodData) builder_to_method [mb];
2842 if (method == null)
2843 return false;
2845 return method.GenericMethod != null;
2848 return mb.IsGenericMethodDefinition;
2849 #else
2850 return false;
2851 #endif
2854 /// <summary>
2855 /// Whether `mb' is a generic method.
2856 /// </summary>
2857 public static bool IsGenericMethod (MethodBase mb)
2859 #if GMCS_SOURCE
2860 return mb.IsGenericMethod;
2861 #else
2862 return false;
2863 #endif
2866 public static bool IsNullableType (Type t)
2868 #if GMCS_SOURCE
2869 return generic_nullable_type == DropGenericTypeArguments (t);
2870 #else
2871 return false;
2872 #endif
2875 public static bool IsNullableTypeOf (Type t, Type nullable)
2877 #if GMCS_SOURCE
2878 if (!IsNullableType (t))
2879 return false;
2881 return GetTypeArguments (t) [0] == nullable;
2882 #else
2883 return false;
2884 #endif
2887 public static bool IsNullableValueType (Type t)
2889 #if GMCS_SOURCE
2890 if (!IsNullableType (t))
2891 return false;
2893 return IsValueType (GetTypeArguments (t) [0]);
2894 #else
2895 return false;
2896 #endif
2898 #endregion
2900 #region MemberLookup implementation
2903 // Whether we allow private members in the result (since FindMembers
2904 // uses NonPublic for both protected and private), we need to distinguish.
2907 internal class Closure {
2908 internal bool private_ok;
2910 // Who is invoking us and which type is being queried currently.
2911 internal Type invocation_type;
2912 internal Type qualifier_type;
2914 // The assembly that defines the type is that is calling us
2915 internal Assembly invocation_assembly;
2916 internal IList almost_match;
2918 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2920 if (invocation_type == null)
2921 return false;
2923 if (is_static && qualifier_type == null)
2924 // It resolved from a simple name, so it should be visible.
2925 return true;
2927 if (IsNestedChildOf (invocation_type, m.DeclaringType))
2928 return true;
2930 for (Type t = invocation_type; t != null; t = t.DeclaringType) {
2931 if (!IsFamilyAccessible (t, m.DeclaringType))
2932 continue;
2934 // Although a derived class can access protected members of its base class
2935 // it cannot do so through an instance of the base class (CS1540).
2936 // => Ancestry should be: declaring_type ->* invocation_type ->* qualified_type
2937 if (is_static || qualifier_type == null ||
2938 IsInstantiationOfSameGenericType (t, qualifier_type) ||
2939 IsFamilyAccessible (qualifier_type, t))
2940 return true;
2943 if (almost_match != null)
2944 almost_match.Add (m);
2946 return false;
2950 // This filter filters by name + whether it is ok to include private
2951 // members in the search
2953 internal bool Filter (MemberInfo m, object filter_criteria)
2956 // Hack: we know that the filter criteria will always be in the
2957 // `closure' // fields.
2960 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2961 return false;
2963 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2964 (invocation_type != null) &&
2965 IsPrivateAccessible (m.DeclaringType, invocation_type))
2966 return true;
2969 // Ugly: we need to find out the type of `m', and depending
2970 // on this, tell whether we accept or not
2972 if (m is MethodBase){
2973 MethodBase mb = (MethodBase) m;
2974 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2976 if (ma == MethodAttributes.Public)
2977 return true;
2979 if (ma == MethodAttributes.PrivateScope)
2980 return false;
2982 if (ma == MethodAttributes.Private)
2983 return private_ok ||
2984 IsPrivateAccessible (invocation_type, m.DeclaringType) ||
2985 IsNestedChildOf (invocation_type, m.DeclaringType);
2987 if (TypeManager.IsThisOrFriendAssembly (mb.DeclaringType.Assembly)) {
2988 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
2989 return true;
2990 } else {
2991 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
2992 return false;
2995 // Family, FamORAssem or FamANDAssem
2996 return CheckValidFamilyAccess (mb.IsStatic, m);
2999 if (m is FieldInfo){
3000 FieldInfo fi = (FieldInfo) m;
3001 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
3003 if (fa == FieldAttributes.Public)
3004 return true;
3006 if (fa == FieldAttributes.PrivateScope)
3007 return false;
3009 if (fa == FieldAttributes.Private)
3010 return private_ok ||
3011 IsPrivateAccessible (invocation_type, m.DeclaringType) ||
3012 IsNestedChildOf (invocation_type, m.DeclaringType);
3014 if (TypeManager.IsThisOrFriendAssembly (fi.DeclaringType.Assembly)) {
3015 if ((fa == FieldAttributes.Assembly) ||
3016 (fa == FieldAttributes.FamORAssem))
3017 return true;
3018 } else {
3019 if ((fa == FieldAttributes.Assembly) ||
3020 (fa == FieldAttributes.FamANDAssem))
3021 return false;
3024 // Family, FamORAssem or FamANDAssem
3025 return CheckValidFamilyAccess (fi.IsStatic, m);
3029 // EventInfos and PropertyInfos, return true because they lack
3030 // permission information, so we need to check later on the methods.
3032 return true;
3036 static Closure closure;
3037 static MemberFilter FilterWithClosure_delegate;
3040 // Looks up a member called `name' in the `queried_type'. This lookup
3041 // is done by code that is contained in the definition for `invocation_type'
3042 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
3044 // `invocation_type' is used to check whether we're allowed to access the requested
3045 // member wrt its protection level.
3047 // When called from MemberAccess, `qualifier_type' is the type which is used to access
3048 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
3049 // is B and qualifier_type is A). This is used to do the CS1540 check.
3051 // When resolving a SimpleName, `qualifier_type' is null.
3053 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
3054 // the same than `queried_type' - except when we're being called from BaseAccess;
3055 // in this case, `invocation_type' is the current type and `queried_type' the base
3056 // type, so this'd normally trigger a CS1540.
3058 // The binding flags are `bf' and the kind of members being looked up are `mt'
3060 // The return value always includes private members which code in `invocation_type'
3061 // is allowed to access (using the specified `qualifier_type' if given); only use
3062 // BindingFlags.NonPublic to bypass the permission check.
3064 // The 'almost_match' argument is used for reporting error CS1540.
3066 // Returns an array of a single element for everything but Methods/Constructors
3067 // that might return multiple matches.
3069 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
3070 Type queried_type, MemberTypes mt,
3071 BindingFlags original_bf, string name, IList almost_match)
3073 Timer.StartTimer (TimerType.MemberLookup);
3075 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
3076 queried_type, mt, original_bf, name, almost_match);
3078 Timer.StopTimer (TimerType.MemberLookup);
3080 return retval;
3083 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
3084 Type queried_type, MemberTypes mt,
3085 BindingFlags original_bf, string name, IList almost_match)
3087 BindingFlags bf = original_bf;
3089 ArrayList method_list = null;
3090 Type current_type = queried_type;
3091 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
3092 bool skip_iface_check = true, used_cache = false;
3093 bool always_ok_flag = invocation_type != null && IsNestedChildOf (invocation_type, queried_type);
3095 closure.invocation_type = invocation_type;
3096 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
3097 closure.qualifier_type = qualifier_type;
3098 closure.almost_match = almost_match;
3100 // This is from the first time we find a method
3101 // in most cases, we do not actually find a method in the base class
3102 // so we can just ignore it, and save the arraylist allocation
3103 MemberInfo [] first_members_list = null;
3104 bool use_first_members_list = false;
3106 do {
3107 MemberInfo [] list;
3110 // `NonPublic' is lame, because it includes both protected and
3111 // private methods, so we need to control this behavior by
3112 // explicitly tracking if a private method is ok or not.
3114 // The possible cases are:
3115 // public, private and protected (internal does not come into the
3116 // equation)
3118 if ((invocation_type != null) &&
3119 ((invocation_type == current_type) ||
3120 IsNestedChildOf (invocation_type, current_type)) ||
3121 always_ok_flag)
3122 bf = original_bf | BindingFlags.NonPublic;
3123 else
3124 bf = original_bf;
3126 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
3128 Timer.StopTimer (TimerType.MemberLookup);
3130 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
3132 Timer.StartTimer (TimerType.MemberLookup);
3135 // When queried for an interface type, the cache will automatically check all
3136 // inherited members, so we don't need to do this here. However, this only
3137 // works if we already used the cache in the first iteration of this loop.
3139 // If we used the cache in any further iteration, we can still terminate the
3140 // loop since the cache always looks in all base classes.
3143 if (used_cache)
3144 searching = false;
3145 else
3146 skip_iface_check = false;
3148 if (current_type == TypeManager.object_type)
3149 searching = false;
3150 else {
3151 current_type = current_type.BaseType;
3154 // This happens with interfaces, they have a null
3155 // basetype. Look members up in the Object class.
3157 if (current_type == null) {
3158 current_type = TypeManager.object_type;
3159 searching = true;
3163 if (list.Length == 0)
3164 continue;
3167 // Events and types are returned by both `static' and `instance'
3168 // searches, which means that our above FindMembers will
3169 // return two copies of the same.
3171 if (list.Length == 1 && !(list [0] is MethodBase)){
3172 return list;
3176 // Multiple properties: we query those just to find out the indexer
3177 // name
3179 if (list [0] is PropertyInfo)
3180 return list;
3183 // We found an event: the cache lookup returns both the event and
3184 // its private field.
3186 if (list [0] is EventInfo) {
3187 if ((list.Length == 2) && (list [1] is FieldInfo))
3188 return new MemberInfo [] { list [0] };
3190 return list;
3194 // We found methods, turn the search into "method scan"
3195 // mode.
3198 if (first_members_list != null) {
3199 if (use_first_members_list) {
3200 method_list = CopyNewMethods (method_list, first_members_list);
3201 use_first_members_list = false;
3204 method_list = CopyNewMethods (method_list, list);
3205 } else {
3206 first_members_list = list;
3207 use_first_members_list = true;
3208 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3210 } while (searching);
3212 if (use_first_members_list)
3213 return first_members_list;
3215 if (method_list != null && method_list.Count > 0) {
3216 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3219 // This happens if we already used the cache in the first iteration, in this case
3220 // the cache already looked in all interfaces.
3222 if (skip_iface_check)
3223 return null;
3226 // Interfaces do not list members they inherit, so we have to
3227 // scan those.
3229 if (!queried_type.IsInterface)
3230 return null;
3232 if (queried_type.IsArray)
3233 queried_type = TypeManager.array_type;
3235 Type [] ifaces = GetInterfaces (queried_type);
3236 if (ifaces == null)
3237 return null;
3239 foreach (Type itype in ifaces){
3240 MemberInfo [] x;
3242 x = MemberLookup (null, null, itype, mt, bf, name, null);
3243 if (x != null)
3244 return x;
3247 return null;
3250 const BindingFlags AllMembers = BindingFlags.Public | BindingFlags.NonPublic |
3251 BindingFlags.Static | BindingFlags.Instance |
3252 BindingFlags.DeclaredOnly;
3254 // Currently is designed to work with external types only
3255 public static PropertyInfo GetPropertyFromAccessor (MethodBase mb)
3257 if (!mb.IsSpecialName)
3258 return null;
3260 string name = mb.Name;
3261 if (name.Length < 5)
3262 return null;
3264 if (name [3] != '_')
3265 return null;
3267 if (name.StartsWith ("get") || name.StartsWith ("set")) {
3268 MemberInfo[] pi = mb.DeclaringType.FindMembers (MemberTypes.Property, AllMembers,
3269 Type.FilterName, name.Substring (4));
3271 if (pi == null)
3272 return null;
3274 // This can happen when property is indexer (it can have same name but different parameters)
3275 foreach (PropertyInfo p in pi) {
3276 foreach (MethodInfo p_mi in p.GetAccessors (true)) {
3277 if (p_mi == mb || TypeManager.GetParameterData (p_mi).Equals (TypeManager.GetParameterData (mb)))
3278 return p;
3283 return null;
3286 // Currently is designed to work with external types only
3287 public static MemberInfo GetEventFromAccessor (MethodBase mb)
3289 if (!mb.IsSpecialName)
3290 return null;
3292 string name = mb.Name;
3293 if (name.Length < 5)
3294 return null;
3296 if (name.StartsWith ("add_"))
3297 return mb.DeclaringType.GetEvent (name.Substring (4), AllMembers);
3299 if (name.StartsWith ("remove_"))
3300 return mb.DeclaringType.GetEvent (name.Substring (7), AllMembers);
3302 return null;
3305 // Tests whether external method is really special
3306 public static bool IsSpecialMethod (MethodBase mb)
3308 if (!mb.IsSpecialName)
3309 return false;
3311 IMethodData md = TypeManager.GetMethod (mb);
3312 if (md != null)
3313 return (md is AbstractPropertyEventMethod || md is Operator);
3315 PropertyInfo pi = GetPropertyFromAccessor (mb);
3316 if (pi != null)
3317 return IsValidProperty (pi);
3319 if (GetEventFromAccessor (mb) != null)
3320 return true;
3322 string name = mb.Name;
3323 if (name.StartsWith ("op_"))
3324 return Operator.GetName (name) != null;
3326 return false;
3329 // Tests whether imported property is valid C# property.
3330 // TODO: It seems to me that we should do a lot of sanity tests before
3331 // we accept property as C# property
3332 static bool IsValidProperty (PropertyInfo pi)
3334 MethodInfo get_method = pi.GetGetMethod (true);
3335 MethodInfo set_method = pi.GetSetMethod (true);
3336 int g_count = 0;
3337 int s_count = 0;
3338 if (get_method != null && set_method != null) {
3339 g_count = get_method.GetParameters ().Length;
3340 s_count = set_method.GetParameters ().Length;
3341 if (g_count + 1 != s_count)
3342 return false;
3343 } else if (get_method != null) {
3344 g_count = get_method.GetParameters ().Length;
3345 } else if (set_method != null) {
3346 s_count = set_method.GetParameters ().Length;
3350 // DefaultMemberName and indexer name has to match to identify valid C# indexer
3352 if ((s_count > 1 || g_count > 0) && TypeManager.default_member_type != null) {
3353 object[] o = pi.DeclaringType.GetCustomAttributes (TypeManager.default_member_type, false);
3354 if (o.Length == 0)
3355 return false;
3357 DefaultMemberAttribute dma = (DefaultMemberAttribute) o [0];
3358 if (dma.MemberName != pi.Name)
3359 return false;
3360 if (get_method != null && "get_" + dma.MemberName != get_method.Name)
3361 return false;
3362 if (set_method != null && "set_" + dma.MemberName != set_method.Name)
3363 return false;
3366 return true;
3369 #endregion
3373 /// <summary>
3374 /// There is exactly one instance of this class per type.
3375 /// </summary>
3376 public sealed class TypeHandle : IMemberContainer {
3377 public readonly IMemberContainer BaseType;
3379 readonly int id = ++next_id;
3380 static int next_id = 0;
3382 static TypeHandle ()
3384 Reset ();
3387 /// <summary>
3388 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3389 /// a TypeHandle yet, a new instance of it is created. This static method
3390 /// ensures that we'll only have one TypeHandle instance per type.
3391 /// </summary>
3392 private static TypeHandle GetTypeHandle (Type t)
3394 TypeHandle handle = (TypeHandle) type_hash [t];
3395 if (handle != null)
3396 return handle;
3398 handle = new TypeHandle (t);
3399 type_hash.Add (t, handle);
3400 return handle;
3403 public static MemberCache GetMemberCache (Type t)
3405 return GetTypeHandle (t).MemberCache;
3408 public static void CleanUp ()
3410 type_hash = null;
3413 public static void Reset ()
3415 type_hash = new PtrHashtable ();
3418 /// <summary>
3419 /// Returns the TypeHandle for TypeManager.object_type.
3420 /// </summary>
3421 public static IMemberContainer ObjectType {
3422 get {
3423 if (object_type != null)
3424 return object_type;
3426 object_type = GetTypeHandle (TypeManager.object_type);
3428 return object_type;
3432 /// <summary>
3433 /// Returns the TypeHandle for TypeManager.array_type.
3434 /// </summary>
3435 public static TypeHandle ArrayType {
3436 get {
3437 if (array_type != null)
3438 return array_type;
3440 array_type = GetTypeHandle (TypeManager.array_type);
3442 return array_type;
3446 private static PtrHashtable type_hash;
3448 private static TypeHandle object_type = null;
3449 private static TypeHandle array_type = null;
3451 private Type type;
3452 private string full_name;
3453 private bool is_interface;
3454 private MemberCache member_cache;
3455 private MemberCache base_cache;
3457 private TypeHandle (Type type)
3459 this.type = type;
3460 full_name = type.FullName != null ? type.FullName : type.Name;
3461 if (type.BaseType != null) {
3462 base_cache = TypeManager.LookupMemberCache (type.BaseType);
3463 BaseType = base_cache.Container;
3464 } else if (type.IsInterface)
3465 base_cache = TypeManager.LookupBaseInterfacesCache (type);
3466 this.is_interface = type.IsInterface || TypeManager.IsGenericParameter (type);
3467 this.member_cache = new MemberCache (this);
3470 // IMemberContainer methods
3472 public string Name {
3473 get {
3474 return full_name;
3478 public Type Type {
3479 get {
3480 return type;
3484 public MemberCache BaseCache {
3485 get {
3486 return base_cache;
3490 public bool IsInterface {
3491 get {
3492 return is_interface;
3496 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3498 MemberInfo [] members;
3500 #if GMCS_SOURCE
3501 if (type is GenericTypeParameterBuilder)
3502 return MemberList.Empty;
3503 #endif
3505 #if MS_COMPATIBLE
3506 type = TypeManager.DropGenericTypeArguments (type);
3507 #endif
3508 if (mt == MemberTypes.Event)
3509 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3510 else
3511 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3512 null, null);
3514 if (members.Length == 0)
3515 return MemberList.Empty;
3517 Array.Reverse (members);
3518 return new MemberList (members);
3521 // IMemberFinder methods
3523 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3524 MemberFilter filter, object criteria)
3526 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3529 public MemberCache MemberCache {
3530 get {
3531 return member_cache;
3535 public override string ToString ()
3537 if (BaseType != null)
3538 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3539 else
3540 return "TypeHandle (" + id + "," + Name + ")";