2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / typemanager.cs
blobddd960106782ca8df1a7426ae02332fdd0b4f422
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.Generic;
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 partial class TypeManager {
35 // A list of core types that the compiler requires or uses
37 static public Type object_type;
38 static public Type value_type;
39 static public Type string_type;
40 static public Type int32_type;
41 static public Type uint32_type;
42 static public Type int64_type;
43 static public Type uint64_type;
44 static public Type float_type;
45 static public Type double_type;
46 static public Type char_type;
47 static public Type short_type;
48 static public Type decimal_type;
49 static public Type bool_type;
50 static public Type sbyte_type;
51 static public Type byte_type;
52 static public Type ushort_type;
53 static public Type enum_type;
54 static public Type delegate_type;
55 static public Type multicast_delegate_type;
56 static public Type void_type;
57 static public Type null_type;
58 static public Type array_type;
59 static public Type runtime_handle_type;
60 static public Type type_type;
61 static public Type ienumerator_type;
62 static public Type ienumerable_type;
63 static public Type idisposable_type;
64 static public Type iasyncresult_type;
65 static public Type asynccallback_type;
66 static public Type intptr_type;
67 static public Type uintptr_type;
68 static public Type runtime_field_handle_type;
69 static public Type runtime_argument_handle_type;
70 static public Type attribute_type;
71 static public Type void_ptr_type;
72 static public Type exception_type;
74 static public Type typed_reference_type;
75 static public Type arg_iterator_type;
76 static public Type mbr_type;
77 public static Type runtime_helpers_type;
79 //
80 // C# 2.0
82 static internal Type isvolatile_type;
83 static public Type generic_ilist_type;
84 static public Type generic_icollection_type;
85 static public Type generic_ienumerator_type;
86 static public Type generic_ienumerable_type;
87 static public Type generic_nullable_type;
90 // C# 3.0
92 static internal Type expression_type;
93 public static Type parameter_expression_type;
94 public static Type fieldinfo_type;
95 public static Type methodinfo_type;
96 public static Type ctorinfo_type;
99 // C# 4.0
101 public static Type call_site_type;
102 public static Type generic_call_site_type;
103 public static TypeExpr binder_type;
104 public static Type binder_flags;
107 // Expressions representing the internal types. Used during declaration
108 // definition.
110 static public TypeExpr system_object_expr, system_string_expr;
111 static public TypeExpr system_boolean_expr, system_decimal_expr;
112 static public TypeExpr system_single_expr, system_double_expr;
113 static public TypeExpr system_sbyte_expr, system_byte_expr;
114 static public TypeExpr system_int16_expr, system_uint16_expr;
115 static public TypeExpr system_int32_expr, system_uint32_expr;
116 static public TypeExpr system_int64_expr, system_uint64_expr;
117 static public TypeExpr system_char_expr, system_void_expr;
118 static public TypeExpr system_valuetype_expr;
119 static public TypeExpr system_intptr_expr;
120 public static TypeExpr expression_type_expr;
124 // These methods are called by code generated by the compiler
126 static public FieldInfo string_empty;
127 static public MethodSpec system_type_get_type_from_handle;
128 static public MethodSpec bool_movenext_void;
129 static public MethodSpec void_dispose_void;
130 static public MethodSpec void_monitor_enter_object;
131 static public MethodSpec void_monitor_exit_object;
132 static public MethodSpec void_initializearray_array_fieldhandle;
133 static public MethodSpec delegate_combine_delegate_delegate;
134 static public MethodSpec delegate_remove_delegate_delegate;
135 static public PropertySpec int_get_offset_to_string_data;
136 static public MethodSpec int_interlocked_compare_exchange;
137 static public PropertySpec ienumerator_getcurrent;
138 public static MethodSpec methodbase_get_type_from_handle;
139 public static MethodSpec methodbase_get_type_from_handle_generic;
140 public static MethodSpec fieldinfo_get_field_from_handle;
141 public static MethodSpec fieldinfo_get_field_from_handle_generic;
142 static public MethodSpec activator_create_instance;
145 // The constructors.
147 static public ConstructorInfo void_decimal_ctor_five_args;
148 static public ConstructorInfo void_decimal_ctor_int_arg;
149 public static ConstructorInfo void_decimal_ctor_long_arg;
151 static Dictionary<TypeBuilder, DeclSpace> builder_to_declspace;
153 static Dictionary<Type, MemberCache> builder_to_member_cache;
155 // <remarks>
156 // Tracks the interfaces implemented by typebuilders. We only
157 // enter those who do implement or or more interfaces
158 // </remarks>
159 static Dictionary<Type, Type[]> builder_to_ifaces;
161 // <remarks>
162 // Maps a MethodBase to its ParameterData (either InternalParameters or ReflectionParameters)
163 // <remarks>
164 static Dictionary<MemberInfo, AParametersCollection> method_params;
166 // <remarks>
167 // A hash table from override methods to their base virtual method.
168 // <remarks>
169 static Dictionary<MethodBase, MethodBase> method_overrides;
171 // <remarks>
172 // Keeps track of methods
173 // </remarks>
175 static Dictionary<MethodBase, IMethodData> builder_to_method;
177 // <remarks>
178 // Contains all public types from referenced assemblies.
179 // This member is used only if CLS Compliance verification is required.
180 // </remarks>
181 public static Dictionary<string, object> AllClsTopLevelTypes;
183 static Dictionary<FieldInfo, FieldBase> fieldbuilders_to_fields;
184 static Dictionary<PropertyInfo, PropertyBase> propertybuilder_to_property;
185 static Dictionary<FieldInfo, ConstSpec> fields;
186 static Dictionary<EventInfo, EventSpec> events;
187 static Dictionary<Assembly, bool> assembly_internals_vis_attrs;
188 static Dictionary<GenericTypeParameterBuilder, TypeParameter> builder_to_type_param;
189 static Dictionary<Type, Type[]> iface_cache;
191 public static void CleanUp ()
193 // Lets get everything clean so that we can collect before generating code
194 builder_to_declspace = null;
195 builder_to_member_cache = null;
196 builder_to_ifaces = null;
197 builder_to_type_param = null;
198 method_params = null;
199 builder_to_method = null;
200 iface_cache = null;
202 fields = null;
203 events = null;
204 type_hash = null;
205 propertybuilder_to_property = null;
207 TypeHandle.CleanUp ();
211 // These are expressions that represent some of the internal data types, used
212 // elsewhere
214 static void InitExpressionTypes ()
216 system_object_expr = new TypeLookupExpression ("System", "Object");
217 system_string_expr = new TypeLookupExpression ("System", "String");
218 system_boolean_expr = new TypeLookupExpression ("System", "Boolean");
219 system_decimal_expr = new TypeLookupExpression ("System", "Decimal");
220 system_single_expr = new TypeLookupExpression ("System", "Single");
221 system_double_expr = new TypeLookupExpression ("System", "Double");
222 system_sbyte_expr = new TypeLookupExpression ("System", "SByte");
223 system_byte_expr = new TypeLookupExpression ("System", "Byte");
224 system_int16_expr = new TypeLookupExpression ("System", "Int16");
225 system_uint16_expr = new TypeLookupExpression ("System", "UInt16");
226 system_int32_expr = new TypeLookupExpression ("System", "Int32");
227 system_uint32_expr = new TypeLookupExpression ("System", "UInt32");
228 system_int64_expr = new TypeLookupExpression ("System", "Int64");
229 system_uint64_expr = new TypeLookupExpression ("System", "UInt64");
230 system_char_expr = new TypeLookupExpression ("System", "Char");
231 system_void_expr = new TypeLookupExpression ("System", "Void");
232 system_valuetype_expr = new TypeLookupExpression ("System", "ValueType");
233 system_intptr_expr = new TypeLookupExpression ("System", "IntPtr");
236 static TypeManager ()
238 Reset ();
241 static public void Reset ()
243 object_type = null;
245 InitExpressionTypes ();
247 builder_to_declspace = new Dictionary<TypeBuilder, DeclSpace> (ReferenceEquality<TypeBuilder>.Default);
248 builder_to_member_cache = new Dictionary<Type, MemberCache> (ReferenceEquality<Type>.Default);
249 builder_to_method = new Dictionary<MethodBase, IMethodData> (ReferenceEquality<MethodBase>.Default);
250 builder_to_type_param = new Dictionary<GenericTypeParameterBuilder, TypeParameter> (ReferenceEquality<GenericTypeParameterBuilder>.Default);
251 method_params = new Dictionary<MemberInfo, AParametersCollection> (ReferenceEquality<MemberInfo>.Default);
252 method_overrides = new Dictionary<MethodBase, MethodBase> (ReferenceEquality<MethodBase>.Default);
253 builder_to_ifaces = new Dictionary<Type, Type[]> (ReferenceEquality<Type>.Default);
255 fieldbuilders_to_fields = new Dictionary<FieldInfo, FieldBase> (ReferenceEquality<FieldInfo>.Default);
256 propertybuilder_to_property = new Dictionary<PropertyInfo, PropertyBase> (ReferenceEquality<PropertyInfo>.Default);
257 fields = new Dictionary<FieldInfo, ConstSpec> (ReferenceEquality<FieldInfo>.Default);
258 type_hash = new DoubleHash ();
259 assembly_internals_vis_attrs = new Dictionary<Assembly, bool> ();
260 iface_cache = new Dictionary<Type, Type[]> (ReferenceEquality<Type>.Default);
262 closure = new Closure ();
263 FilterWithClosure_delegate = new MemberFilter (closure.Filter);
265 // TODO: I am really bored by all this static stuff
266 system_type_get_type_from_handle =
267 bool_movenext_void =
268 void_dispose_void =
269 void_monitor_enter_object =
270 void_monitor_exit_object =
271 void_initializearray_array_fieldhandle =
272 int_interlocked_compare_exchange =
273 methodbase_get_type_from_handle =
274 methodbase_get_type_from_handle_generic =
275 fieldinfo_get_field_from_handle =
276 fieldinfo_get_field_from_handle_generic =
277 activator_create_instance =
278 delegate_combine_delegate_delegate =
279 delegate_remove_delegate_delegate = null;
281 int_get_offset_to_string_data =
282 ienumerator_getcurrent = null;
284 void_decimal_ctor_five_args =
285 void_decimal_ctor_int_arg =
286 void_decimal_ctor_long_arg = null;
288 isvolatile_type = null;
290 call_site_type =
291 generic_call_site_type =
292 binder_flags = null;
294 binder_type = null;
296 // to uncover regressions
297 AllClsTopLevelTypes = null;
300 public static void AddUserType (DeclSpace ds)
302 builder_to_declspace.Add (ds.TypeBuilder, ds);
306 // This entry point is used by types that we define under the covers
308 public static void RegisterBuilder (Type tb, Type [] ifaces)
310 if (ifaces != null)
311 builder_to_ifaces [tb] = ifaces;
314 public static void AddMethod (MethodBase builder, IMethodData method)
316 builder_to_method.Add (builder, method);
317 method_params.Add (builder, method.ParameterInfo);
320 public static IMethodData GetMethod (MethodBase builder)
322 IMethodData md;
323 if (builder_to_method.TryGetValue (builder, out md))
324 return md;
325 return null;
328 /// <summary>
329 /// Returns the DeclSpace whose Type is `t' or null if there is no
330 /// DeclSpace for `t' (ie, the Type comes from a library)
331 /// </summary>
332 public static DeclSpace LookupDeclSpace (Type t)
334 DeclSpace ds;
335 var tb = t as TypeBuilder;
336 if (tb != null && builder_to_declspace.TryGetValue (tb, out ds))
337 return ds;
339 return null;
342 /// <summary>
343 /// Returns the TypeContainer whose Type is `t' or null if there is no
344 /// TypeContainer for `t' (ie, the Type comes from a library)
345 /// </summary>
346 public static TypeContainer LookupTypeContainer (Type t)
348 return LookupDeclSpace (t) as TypeContainer;
351 public static MemberCache LookupMemberCache (Type t)
353 if (IsBeingCompiled (t)) {
354 DeclSpace container = LookupDeclSpace (t);
355 if (container != null)
356 return container.MemberCache;
359 if (t is GenericTypeParameterBuilder) {
360 TypeParameter container;
361 if (builder_to_type_param.TryGetValue ((GenericTypeParameterBuilder) t, out container))
362 return container.MemberCache;
365 return TypeHandle.GetMemberCache (t);
368 public static MemberCache LookupBaseInterfacesCache (Type t)
370 Type [] ifaces = GetInterfaces (t);
372 if (ifaces != null && ifaces.Length == 1)
373 return LookupMemberCache (ifaces [0]);
375 // TODO: the builder_to_member_cache should be indexed by 'ifaces', not 't'
376 MemberCache cache;
377 if (builder_to_member_cache.TryGetValue (t, out cache))
378 return cache;
380 cache = new MemberCache (ifaces);
381 builder_to_member_cache.Add (t, cache);
382 return cache;
385 public static TypeContainer LookupInterface (Type t)
387 TypeContainer tc = LookupTypeContainer (t);
388 if ((tc == null) || (tc.Kind != MemberKind.Interface))
389 return null;
391 return tc;
394 public static Delegate LookupDelegate (Type t)
396 return LookupDeclSpace (t) as Delegate;
399 public static Class LookupClass (Type t)
401 return LookupDeclSpace (t) as Class;
405 // We use this hash for multiple kinds of constructed types:
407 // (T, "&") Given T, get T &
408 // (T, "*") Given T, get T *
409 // (T, "[]") Given T and a array dimension, get T []
410 // (T, X) Given a type T and a simple name X, get the type T+X
412 // Accessibility tests, if necessary, should be done by the user
414 static DoubleHash type_hash = new DoubleHash ();
417 // Gets the reference to T version of the Type (T&)
419 public static Type GetReferenceType (Type t)
421 return t.MakeByRefType ();
425 // Gets the pointer to T version of the Type (T*)
427 public static Type GetPointerType (Type t)
429 return GetConstructedType (t, "*");
432 public static Type GetConstructedType (Type t, string dim)
434 object ret = null;
435 if (type_hash.Lookup (t, dim, out ret))
436 return (Type) ret;
438 if (IsDynamicType (t)) {
439 ret = new DynamicArrayType (dim.Length - 1);
440 type_hash.Insert (t, dim, ret);
441 return (Type) ret;
444 ret = t.Module.GetType (t.ToString () + dim);
445 if (ret != null) {
446 type_hash.Insert (t, dim, ret);
447 return (Type) ret;
450 if (dim == "&") {
451 ret = GetReferenceType (t);
452 type_hash.Insert (t, dim, ret);
453 return (Type) ret;
456 if (t.IsGenericParameter || t.IsGenericType) {
457 int pos = 0;
458 Type result = t;
459 while ((pos < dim.Length) && (dim [pos] == '[')) {
460 pos++;
462 if (dim [pos] == ']') {
463 result = result.MakeArrayType ();
464 pos++;
466 if (pos < dim.Length)
467 continue;
469 type_hash.Insert (t, dim, result);
470 return result;
473 int rank = 0;
474 while (dim [pos] == ',') {
475 pos++; rank++;
478 if ((dim [pos] != ']') || (pos != dim.Length-1))
479 break;
481 result = result.MakeArrayType (rank + 1);
482 type_hash.Insert (t, dim, result);
483 return result;
487 type_hash.Insert (t, dim, null);
488 return null;
491 public static Type GetNestedType (Type t, string name)
493 object ret = null;
494 if (!type_hash.Lookup (t, name, out ret)) {
495 ret = t.GetNestedType (name,
496 BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
497 type_hash.Insert (t, name, ret);
499 return (Type) ret;
502 /// <summary>
503 /// Fills static table with exported types from all referenced assemblies.
504 /// This information is required for CLS Compliance tests.
505 /// </summary>
506 public static void LoadAllImportedTypes ()
508 AllClsTopLevelTypes = new Dictionary<string, object> (1500);
509 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
510 foreach (Type t in a.GetExportedTypes ()) {
511 AllClsTopLevelTypes [t.FullName.ToLower (System.Globalization.CultureInfo.InvariantCulture)] = null;
516 /// <summary>
517 /// Returns the C# name of a type if possible, or the full type name otherwise
518 /// </summary>
519 static public string CSharpName (Type t)
521 if (t == null_type)
522 return "null";
524 if (t == typeof (ArglistAccess))
525 return "__arglist";
527 if (t == typeof (AnonymousMethodBody))
528 return "anonymous method";
530 if (t == typeof (MethodGroupExpr))
531 return "method group";
533 if (IsDynamicType (t))
534 return "dynamic";
536 if (t == null)
537 return "internal error";
539 return CSharpName (GetFullName (t), t);
542 static readonly char [] elements = new char [] { '*', '[' };
544 public static string CSharpName (string name, Type type)
546 if (name.Length > 10) {
547 string s;
548 switch (name) {
549 case "System.Int32": s = "int"; break;
550 case "System.Int64": s = "long"; break;
551 case "System.String": s = "string"; break;
552 case "System.Boolean": s = "bool"; break;
553 case "System.Void": s = "void"; break;
554 case "System.Object": s = "object"; break;
555 case "System.UInt32": s = "uint"; break;
556 case "System.Int16": s = "short"; break;
557 case "System.UInt16": s = "ushort"; break;
558 case "System.UInt64": s = "ulong"; break;
559 case "System.Single": s = "float"; break;
560 case "System.Double": s = "double"; break;
561 case "System.Decimal": s = "decimal"; break;
562 case "System.Char": s = "char"; break;
563 case "System.Byte": s = "byte"; break;
564 case "System.SByte": s = "sbyte"; break;
565 default: s = null; break;
568 if (s != null) {
570 // Predefined names can come from mscorlib only
572 if (type == null || type.Module.Name == "mscorlib.dll" || !RootContext.StdLib)
573 return s;
575 return name;
578 if (name [0] == AnonymousTypeClass.ClassNamePrefix [0] && name.StartsWith (AnonymousTypeClass.ClassNamePrefix))
579 return AnonymousTypeClass.SignatureForError;
581 int idx = name.IndexOfAny (elements, 10);
582 if (idx > 0)
583 return CSharpName (name.Substring (0, idx), type) + name.Substring (idx);
586 return name.Replace ('+', '.');
589 static public string CSharpName (Type[] types)
591 if (types.Length == 0)
592 return string.Empty;
594 StringBuilder sb = new StringBuilder ();
595 for (int i = 0; i < types.Length; ++i) {
596 if (i > 0)
597 sb.Append (", ");
599 sb.Append (CSharpName (types [i]));
601 return sb.ToString ();
604 /// <summary>
605 /// Returns the signature of the method with full namespace classification
606 /// </summary>
607 static public string GetFullNameSignature (MemberInfo mi)
609 PropertyInfo pi = mi as PropertyInfo;
610 if (pi != null) {
611 MethodBase pmi = pi.GetGetMethod (true);
612 if (pmi == null)
613 pmi = pi.GetSetMethod (true);
614 if (GetParameterData (pmi).Count > 0)
615 mi = pmi;
617 return (mi is MethodBase)
618 ? CSharpSignature (mi as MethodBase)
619 : CSharpName (mi.DeclaringType) + '.' + mi.Name;
622 private static int GetFullName (Type t, StringBuilder sb)
624 int pos = 0;
626 if (!t.IsGenericType) {
627 sb.Append (t.FullName);
628 return 0;
631 if (t.DeclaringType != null) {
632 pos = GetFullName (t.DeclaringType, sb);
633 sb.Append ('.');
634 } else if (t.Namespace != null && t.Namespace.Length != 0) {
635 sb.Append (t.Namespace);
636 sb.Append ('.');
638 sb.Append (RemoveGenericArity (t.Name));
640 Type[] this_args = GetTypeArguments (t);
642 if (this_args.Length < pos)
643 throw new InternalErrorException (
644 "Enclosing class " + t.DeclaringType + " has more type arguments than " + t);
645 if (this_args.Length == pos)
646 return pos;
648 sb.Append ('<');
649 for (;;) {
650 sb.Append (CSharpName (this_args [pos++]));
651 if (pos == this_args.Length)
652 break;
653 sb.Append (',');
655 sb.Append ('>');
656 return pos;
659 static string GetFullName (Type t)
661 if (t.IsArray) {
662 string dimension = t.Name.Substring (t.Name.LastIndexOf ('['));
663 return GetFullName (GetElementType (t)) + dimension;
666 if (IsNullableType (t) && !t.IsGenericTypeDefinition) {
667 t = TypeToCoreType (GetTypeArguments (t)[0]);
668 return CSharpName (t) + "?";
671 if (t.IsGenericParameter)
672 return t.Name;
673 if (!t.IsGenericType)
674 return t.FullName;
676 StringBuilder sb = new StringBuilder ();
677 int pos = GetFullName (t, sb);
678 if (pos <= 0)
679 throw new InternalErrorException ("Generic Type " + t + " doesn't have type arguments");
680 return sb.ToString ();
683 public static string RemoveGenericArity (string from)
685 int i = from.IndexOf ('`');
686 if (i > 0)
687 return from.Substring (0, i);
688 return from;
691 /// <summary>
692 /// When we need to report accessors as well
693 /// </summary>
694 static public string CSharpSignature (MethodBase mb)
696 return CSharpSignature (mb, false);
699 static public string CSharpSignature (MethodSpec ms)
701 return CSharpSignature (ms.MetaInfo);
704 /// <summary>
705 /// Returns the signature of the method
706 /// </summary>
707 static public string CSharpSignature (MethodBase mb, bool show_accessor)
709 StringBuilder sig = new StringBuilder (CSharpName (mb.DeclaringType));
710 sig.Append ('.');
712 AParametersCollection iparams = GetParameterData (mb);
713 string parameters = iparams.GetSignatureForError ();
714 int accessor_end = 0;
716 if (!mb.IsConstructor && TypeManager.IsSpecialMethod (mb)) {
717 string op_name = Operator.GetName (mb.Name);
718 if (op_name != null) {
719 if (op_name == "explicit" || op_name == "implicit") {
720 sig.Append (op_name);
721 sig.Append (" operator ");
722 sig.Append (CSharpName (((MethodInfo)mb).ReturnType));
723 } else {
724 sig.Append ("operator ");
725 sig.Append (op_name);
727 sig.Append (parameters);
728 return sig.ToString ();
731 bool is_getter = mb.Name.StartsWith ("get_");
732 bool is_setter = mb.Name.StartsWith ("set_");
733 if (is_getter || is_setter || mb.Name.StartsWith ("add_")) {
734 accessor_end = 3;
735 } else if (mb.Name.StartsWith ("remove_")) {
736 accessor_end = 6;
739 // Is indexer
740 if (iparams.Count > (is_getter ? 0 : 1)) {
741 sig.Append ("this[");
742 if (is_getter)
743 sig.Append (parameters.Substring (1, parameters.Length - 2));
744 else
745 sig.Append (parameters.Substring (1, parameters.LastIndexOf (',') - 1));
746 sig.Append (']');
747 } else {
748 sig.Append (mb.Name.Substring (accessor_end + 1));
750 } else {
751 if (mb.Name == ".ctor")
752 sig.Append (RemoveGenericArity (mb.DeclaringType.Name));
753 else {
754 sig.Append (mb.Name);
756 if (IsGenericMethod (mb)) {
757 Type[] args = GetGenericArguments (mb);
758 sig.Append ('<');
759 for (int i = 0; i < args.Length; i++) {
760 if (i > 0)
761 sig.Append (',');
762 sig.Append (CSharpName (args [i]));
764 sig.Append ('>');
768 sig.Append (parameters);
771 if (show_accessor && accessor_end > 0) {
772 sig.Append ('.');
773 sig.Append (mb.Name.Substring (0, accessor_end));
776 return sig.ToString ();
779 public static string GetMethodName (MethodInfo m)
781 if (!IsGenericMethodDefinition (m) && !IsGenericMethod (m))
782 return m.Name;
784 return MemberName.MakeName (m.Name, TypeManager.GetGenericArguments (m).Length);
787 static public string CSharpSignature (EventInfo ei)
789 return CSharpName (ei.DeclaringType) + "." + ei.Name;
793 // Looks up a type, and aborts if it is not found. This is used
794 // by predefined types required by the compiler
796 public static Type CoreLookupType (CompilerContext ctx, string ns_name, string name, MemberKind type_kind, bool required)
798 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, true);
799 Expression expr = ns.Lookup (ctx, name, Location.Null);
801 if (expr == null) {
802 if (required) {
803 ctx.Report.Error (518, "The predefined type `{0}.{1}' is not defined or imported",
804 ns_name, name);
806 return null;
809 Type t = expr.Type;
810 if (RootContext.StdLib || t == null || !required)
811 return t;
813 // TODO: All predefined imported types have to have correct signature
814 if (!IsBeingCompiled (t))
815 return t;
817 DeclSpace ds = (DeclSpace)RootContext.ToplevelTypes.GetDefinition (t.FullName);
818 if (ds is Delegate) {
819 if (type_kind == MemberKind.Delegate)
820 return t;
821 } else {
822 TypeContainer tc = (TypeContainer)ds;
823 if (tc.Kind == type_kind)
824 return t;
827 ctx.Report.Error (520, ds.Location, "The predefined type `{0}.{1}' is not declared correctly",
828 ns_name, name);
829 return null;
832 static MemberInfo GetPredefinedMember (Type t, string name, MemberTypes mt, Location loc, params Type [] args)
834 const BindingFlags flags = instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly;
836 MemberInfo [] members = MemberLookup (null, null, t, mt, flags, name, null);
837 if (members != null) {
838 for (int i = 0; i < members.Length; ++i) {
839 MemberInfo member = members [i];
840 if (mt == MemberTypes.Method || mt == MemberTypes.Constructor) {
841 MethodBase mb = member as MethodBase;
842 if (mb == null)
843 continue;
845 AParametersCollection pd = TypeManager.GetParameterData (mb);
846 if (IsEqual (pd.Types, args))
847 return member;
849 if (mt == MemberTypes.Field) {
850 FieldInfo fi = member as FieldInfo;
851 if (fi == null)
852 continue;
854 if (args.Length >= 1 && !IsEqual (TypeToCoreType (fi.FieldType), args [0]))
855 continue;
857 return member;
860 if (mt == MemberTypes.Property) {
861 PropertyInfo pi = member as PropertyInfo;
862 if (pi == null)
863 continue;
865 if (args.Length >= 1 && !IsEqual (TypeToCoreType (pi.PropertyType), args [0]))
866 continue;
868 return member;
873 string method_args = null;
874 if (mt == MemberTypes.Method || mt == MemberTypes.Constructor)
875 method_args = "(" + TypeManager.CSharpName (args) + ")";
877 RootContext.ToplevelTypes.Compiler.Report.Error (656, loc, "The compiler required member `{0}.{1}{2}' could not be found or is inaccessible",
878 TypeManager.CSharpName (t), name, method_args);
880 return null;
884 // Returns the ConstructorInfo for "args"
886 public static ConstructorInfo GetPredefinedConstructor (Type t, Location loc, params Type [] args)
888 return (ConstructorInfo) GetPredefinedMember (t, ConstructorInfo.ConstructorName, MemberTypes.Constructor, loc, args);
892 // Returns the MethodInfo for a method named `name' defined
893 // in type `t' which takes arguments of types `args'
895 public static MethodSpec GetPredefinedMethod (Type t, string name, Location loc, params Type [] args)
897 var m = GetPredefinedMember (t, name, MemberTypes.Method, loc, args) as MethodBase;
898 if (m == null)
899 return null;
901 return Import.CreateMethod (m);
904 public static FieldInfo GetPredefinedField (Type t, string name, Location loc, params Type [] args)
906 return (FieldInfo) GetPredefinedMember (t, name, MemberTypes.Field, loc, args);
909 public static PropertySpec GetPredefinedProperty (Type t, string name, Location loc, params Type [] args)
911 var p = GetPredefinedMember (t, name, MemberTypes.Property, loc, args) as PropertyInfo;
912 if (p == null)
913 return null;
914 return Import.CreateProperty (p);
917 /// <remarks>
918 /// The types have to be initialized after the initial
919 /// population of the type has happened (for example, to
920 /// bootstrap the corlib.dll
921 /// </remarks>
922 public static bool InitCoreTypes (CompilerContext ctx)
924 object_type = CoreLookupType (ctx, "System", "Object", MemberKind.Class, true);
925 system_object_expr.Type = object_type;
926 value_type = CoreLookupType (ctx, "System", "ValueType", MemberKind.Class, true);
927 system_valuetype_expr.Type = value_type;
928 attribute_type = CoreLookupType (ctx, "System", "Attribute", MemberKind.Class, true);
930 int32_type = CoreLookupType (ctx, "System", "Int32", MemberKind.Struct, true);
931 system_int32_expr.Type = int32_type;
932 int64_type = CoreLookupType (ctx, "System", "Int64", MemberKind.Struct, true);
933 system_int64_expr.Type = int64_type;
934 uint32_type = CoreLookupType (ctx, "System", "UInt32", MemberKind.Struct, true);
935 system_uint32_expr.Type = uint32_type;
936 uint64_type = CoreLookupType (ctx, "System", "UInt64", MemberKind.Struct, true);
937 system_uint64_expr.Type = uint64_type;
938 byte_type = CoreLookupType (ctx, "System", "Byte", MemberKind.Struct, true);
939 system_byte_expr.Type = byte_type;
940 sbyte_type = CoreLookupType (ctx, "System", "SByte", MemberKind.Struct, true);
941 system_sbyte_expr.Type = sbyte_type;
942 short_type = CoreLookupType (ctx, "System", "Int16", MemberKind.Struct, true);
943 system_int16_expr.Type = short_type;
944 ushort_type = CoreLookupType (ctx, "System", "UInt16", MemberKind.Struct, true);
945 system_uint16_expr.Type = ushort_type;
947 ienumerator_type = CoreLookupType (ctx, "System.Collections", "IEnumerator", MemberKind.Interface, true);
948 ienumerable_type = CoreLookupType (ctx, "System.Collections", "IEnumerable", MemberKind.Interface, true);
949 idisposable_type = CoreLookupType (ctx, "System", "IDisposable", MemberKind.Interface, true);
951 // HACK: DefineType immediately resolves iterators (very wrong)
952 generic_ienumerator_type = CoreLookupType (ctx, "System.Collections.Generic", "IEnumerator`1", MemberKind.Interface, false);
954 char_type = CoreLookupType (ctx, "System", "Char", MemberKind.Struct, true);
955 system_char_expr.Type = char_type;
956 string_type = CoreLookupType (ctx, "System", "String", MemberKind.Class, true);
957 system_string_expr.Type = string_type;
958 float_type = CoreLookupType (ctx, "System", "Single", MemberKind.Struct, true);
959 system_single_expr.Type = float_type;
960 double_type = CoreLookupType (ctx, "System", "Double", MemberKind.Struct, true);
961 system_double_expr.Type = double_type;
962 decimal_type = CoreLookupType (ctx, "System", "Decimal", MemberKind.Struct, true);
963 system_decimal_expr.Type = decimal_type;
964 bool_type = CoreLookupType (ctx, "System", "Boolean", MemberKind.Struct, true);
965 system_boolean_expr.Type = bool_type;
966 intptr_type = CoreLookupType (ctx, "System", "IntPtr", MemberKind.Struct, true);
967 system_intptr_expr.Type = intptr_type;
968 uintptr_type = CoreLookupType (ctx, "System", "UIntPtr", MemberKind.Struct, true);
970 multicast_delegate_type = CoreLookupType (ctx, "System", "MulticastDelegate", MemberKind.Class, true);
971 delegate_type = CoreLookupType (ctx, "System", "Delegate", MemberKind.Class, true);
973 enum_type = CoreLookupType (ctx, "System", "Enum", MemberKind.Class, true);
974 array_type = CoreLookupType (ctx, "System", "Array", MemberKind.Class, true);
975 void_type = CoreLookupType (ctx, "System", "Void", MemberKind.Struct, true);
976 system_void_expr.Type = void_type;
977 type_type = CoreLookupType (ctx, "System", "Type", MemberKind.Class, true);
978 exception_type = CoreLookupType (ctx, "System", "Exception", MemberKind.Class, true);
980 runtime_field_handle_type = CoreLookupType (ctx, "System", "RuntimeFieldHandle", MemberKind.Struct, true);
981 runtime_handle_type = CoreLookupType (ctx, "System", "RuntimeTypeHandle", MemberKind.Struct, true);
983 PredefinedAttributes.Get.ParamArray.Initialize (ctx, false);
984 PredefinedAttributes.Get.Out.Initialize (ctx, false);
986 return ctx.Report.Errors == 0;
990 // Initializes optional core types
992 public static void InitOptionalCoreTypes (CompilerContext ctx)
995 // These are only used for compare purposes
997 null_type = typeof (NullLiteral);
999 void_ptr_type = GetPointerType (void_type);
1002 // Initialize InternalsVisibleTo as the very first optional type. Otherwise we would populate
1003 // types cache with incorrect accessiblity when any of optional types is internal.
1005 PredefinedAttributes.Get.Initialize (ctx);
1007 runtime_argument_handle_type = CoreLookupType (ctx, "System", "RuntimeArgumentHandle", MemberKind.Struct, false);
1008 asynccallback_type = CoreLookupType (ctx, "System", "AsyncCallback", MemberKind.Delegate, false);
1009 iasyncresult_type = CoreLookupType (ctx, "System", "IAsyncResult", MemberKind.Interface, false);
1010 typed_reference_type = CoreLookupType (ctx, "System", "TypedReference", MemberKind.Struct, false);
1011 arg_iterator_type = CoreLookupType (ctx, "System", "ArgIterator", MemberKind.Struct, false);
1012 mbr_type = CoreLookupType (ctx, "System", "MarshalByRefObject", MemberKind.Class, false);
1015 // Optional attributes, used for error reporting only
1017 //if (PredefinedAttributes.Get.Obsolete.IsDefined) {
1018 // Class c = TypeManager.LookupClass (PredefinedAttributes.Get.Obsolete.Type);
1019 // if (c != null)
1020 // c.Define ();
1023 generic_ilist_type = CoreLookupType (ctx, "System.Collections.Generic", "IList`1", MemberKind.Interface, false);
1024 generic_icollection_type = CoreLookupType (ctx, "System.Collections.Generic", "ICollection`1", MemberKind.Interface, false);
1025 generic_ienumerable_type = CoreLookupType (ctx, "System.Collections.Generic", "IEnumerable`1", MemberKind.Interface, false);
1026 generic_nullable_type = CoreLookupType (ctx, "System", "Nullable`1", MemberKind.Struct, false);
1029 // Optional types which are used as types and for member lookup
1031 runtime_helpers_type = CoreLookupType (ctx, "System.Runtime.CompilerServices", "RuntimeHelpers", MemberKind.Class, false);
1033 // New in .NET 3.5
1034 // Note: extension_attribute_type is already loaded
1035 expression_type = CoreLookupType (ctx, "System.Linq.Expressions", "Expression`1", MemberKind.Class, false);
1037 if (!RootContext.StdLib) {
1039 // HACK: When building Mono corlib mcs uses loaded mscorlib which
1040 // has different predefined types and this method sets mscorlib types
1041 // to be same to avoid any type check errors.
1044 Type type = typeof (Type);
1045 Type [] system_4_type_arg = { type, type, type, type };
1047 MethodInfo set_corlib_type_builders =
1048 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
1049 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
1050 system_4_type_arg, null);
1052 if (set_corlib_type_builders != null) {
1053 object[] args = new object [4];
1054 args [0] = object_type;
1055 args [1] = value_type;
1056 args [2] = enum_type;
1057 args [3] = void_type;
1059 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1060 } else {
1061 ctx.Report.Warning (-26, 3, "The compilation may fail due to missing `{0}.SetCorlibTypeBuilders({1})' method",
1062 TypeManager.CSharpName (typeof (System.Reflection.Emit.AssemblyBuilder)),
1063 TypeManager.CSharpName (system_4_type_arg));
1068 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1070 /// <remarks>
1071 /// This is the "old", non-cache based FindMembers() function. We cannot use
1072 /// the cache here because there is no member name argument.
1073 /// </remarks>
1074 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1075 MemberFilter filter, object criteria)
1077 #if MS_COMPATIBLE
1078 if (t.IsGenericType)
1079 t = t.GetGenericTypeDefinition ();
1080 #endif
1082 DeclSpace decl = LookupDeclSpace (t);
1085 // `builder_to_declspace' contains all dynamic types.
1087 if (decl != null) {
1088 MemberList list;
1089 Timer.StartTimer (TimerType.FindMembers);
1090 list = decl.FindMembers (mt, bf, filter, criteria);
1091 Timer.StopTimer (TimerType.FindMembers);
1092 return list;
1096 // We have to take care of arrays specially, because GetType on
1097 // a TypeBuilder array will return a Type, not a TypeBuilder,
1098 // and we can not call FindMembers on this type.
1100 if (
1101 #if MS_COMPATIBLE
1102 !t.IsGenericType &&
1103 #endif
1104 t.IsSubclassOf (TypeManager.array_type))
1105 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1107 if (t is GenericTypeParameterBuilder) {
1108 TypeParameter tparam = builder_to_type_param [(GenericTypeParameterBuilder) t];
1110 Timer.StartTimer (TimerType.FindMembers);
1111 MemberList list = tparam.FindMembers (
1112 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1113 Timer.StopTimer (TimerType.FindMembers);
1114 return list;
1118 // Since FindMembers will not lookup both static and instance
1119 // members, we emulate this behaviour here.
1121 if ((bf & instance_and_static) == instance_and_static){
1122 MemberInfo [] i_members = t.FindMembers (
1123 mt, bf & ~BindingFlags.Static, filter, criteria);
1125 int i_len = i_members.Length;
1126 if (i_len == 1){
1127 MemberInfo one = i_members [0];
1130 // If any of these are present, we are done!
1132 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1133 return new MemberList (i_members);
1136 MemberInfo [] s_members = t.FindMembers (
1137 mt, bf & ~BindingFlags.Instance, filter, criteria);
1139 int s_len = s_members.Length;
1140 if (i_len > 0 || s_len > 0)
1141 return new MemberList (i_members, s_members);
1142 else {
1143 if (i_len > 0)
1144 return new MemberList (i_members);
1145 else
1146 return new MemberList (s_members);
1150 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1154 /// <summary>
1155 /// This method is only called from within MemberLookup. It tries to use the member
1156 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1157 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1158 /// our return value will already contain all inherited members and the caller don't need
1159 /// to check base classes and interfaces anymore.
1160 /// </summary>
1161 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1162 string name, out bool used_cache)
1164 MemberCache cache;
1167 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1168 // and we can ask the DeclSpace for the MemberCache.
1170 #if MS_COMPATIBLE
1171 if (t.Assembly == CodeGen.Assembly.Builder) {
1172 if (t.IsGenericParameter) {
1173 TypeParameter tparam = builder_to_type_param [(GenericTypeParameterBuilder) t];
1175 used_cache = true;
1176 if (tparam.MemberCache == null)
1177 return new MemberInfo[0];
1179 return tparam.MemberCache.FindMembers (
1180 mt, bf, name, FilterWithClosure_delegate, null);
1184 // We have to take care of arrays specially, because GetType on
1185 // a TypeBuilder array will return a Type, not a TypeBuilder,
1186 // and we can not call FindMembers on this type.
1188 if (t.IsArray) {
1189 used_cache = true;
1190 return TypeHandle.ArrayType.MemberCache.FindMembers (
1191 mt, bf, name, FilterWithClosure_delegate, null);
1194 if (t.IsGenericType && !t.IsGenericTypeDefinition)
1195 t = t.GetGenericTypeDefinition ();
1196 #else
1197 if (t is TypeBuilder) {
1198 #endif
1199 DeclSpace decl = LookupDeclSpace (t);
1200 cache = decl.MemberCache;
1203 // If this DeclSpace has a MemberCache, use it.
1206 if (cache != null) {
1207 used_cache = true;
1208 return cache.FindMembers (
1209 mt, bf, name, FilterWithClosure_delegate, null);
1212 // If there is no MemberCache, we need to use the "normal" FindMembers.
1213 // Note, this is a VERY uncommon route!
1215 MemberList list;
1216 Timer.StartTimer (TimerType.FindMembers);
1217 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1218 FilterWithClosure_delegate, name);
1219 Timer.StopTimer (TimerType.FindMembers);
1220 used_cache = false;
1221 return (MemberInfo []) list;
1225 // We have to take care of arrays specially, because GetType on
1226 // a TypeBuilder array will return a Type, not a TypeBuilder,
1227 // and we can not call FindMembers on this type.
1229 if (t.IsArray) {
1230 used_cache = true;
1231 return TypeHandle.ArrayType.MemberCache.FindMembers (
1232 mt, bf, name, FilterWithClosure_delegate, null);
1235 if (t is GenericTypeParameterBuilder) {
1236 TypeParameter tparam = builder_to_type_param [(GenericTypeParameterBuilder) t];
1238 used_cache = true;
1239 if (tparam.MemberCache == null)
1240 return new MemberInfo [0];
1242 return tparam.MemberCache.FindMembers (
1243 mt, bf, name, FilterWithClosure_delegate, null);
1246 if (IsGenericType (t) && (mt == MemberTypes.NestedType)) {
1248 // This happens if we're resolving a class'es base class and interfaces
1249 // in TypeContainer.DefineType(). At this time, the types aren't
1250 // populated yet, so we can't use the cache.
1252 MemberInfo[] info = t.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1253 FilterWithClosure_delegate, name);
1254 used_cache = false;
1255 return info;
1259 // This call will always succeed. There is exactly one TypeHandle instance per
1260 // type, TypeHandle.GetMemberCache() will, if necessary, create a new one, and return
1261 // the corresponding MemberCache.
1263 cache = TypeHandle.GetMemberCache (t);
1265 used_cache = true;
1266 return cache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1270 // Return true for SRE dynamic/unclosed members
1272 public static bool IsBeingCompiled (MemberInfo mi)
1274 return mi.Module.Assembly == CodeGen.Assembly.Builder;
1277 public static bool IsBuiltinType (Type t)
1279 t = TypeToCoreType (t);
1280 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1281 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1282 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1283 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1284 return true;
1285 else
1286 return false;
1290 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1291 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1293 public static bool IsPrimitiveType (Type t)
1295 return (t == int32_type || t == uint32_type ||
1296 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1297 t == char_type || t == short_type || t == bool_type ||
1298 t == sbyte_type || t == byte_type || t == ushort_type);
1301 public static bool IsDelegateType (Type t)
1303 if (TypeManager.IsGenericParameter (t))
1304 return false;
1306 if (t == TypeManager.delegate_type || t == TypeManager.multicast_delegate_type)
1307 return false;
1309 t = DropGenericTypeArguments (t);
1310 return IsSubclassOf (t, TypeManager.delegate_type);
1314 // Is a type of dynamic type
1316 public static bool IsDynamicType (Type t)
1318 if (object.ReferenceEquals (InternalType.Dynamic, t))
1319 return true;
1321 if (t != object_type)
1322 return false;
1324 if (IsBeingCompiled (t))
1325 return false;
1327 PredefinedAttribute pa = PredefinedAttributes.Get.Dynamic;
1328 if (pa == null || IsBeingCompiled (pa.Type))
1329 return false;
1331 object[] res = t.GetCustomAttributes (pa.Type, false);
1332 return res != null && res.Length != 0;
1336 // When any element of the type is a dynamic type
1338 // This method builds a transformation array for dynamic types
1339 // used in places where DynamicAttribute cannnot be applied to.
1340 // It uses bool flag when type is of dynamic type and each
1341 // section always starts with "false" for some reason.
1343 // LAMESPEC: This should be part of C# specification !
1345 // Example: Func<dynamic, int, dynamic[]>
1346 // Transformation: { false, true, false, false, true }
1348 public static bool[] HasDynamicTypeUsed (Type t)
1350 if (t is DynamicArrayType)
1351 return new bool[] { false, true };
1353 if (t == null)
1354 return null;
1356 if (IsGenericType (t)) {
1357 List<bool> transform = null;
1358 var targs = GetTypeArguments (t);
1359 for (int i = 0; i < targs.Length; ++i) {
1360 var element = HasDynamicTypeUsed (targs [i]);
1361 if (element != null) {
1362 if (transform == null) {
1363 transform = new List<bool> ();
1364 for (int ii = 0; ii <= i; ++ii)
1365 transform.Add (false);
1368 transform.AddRange (element);
1369 } else if (transform != null) {
1370 transform.Add (false);
1374 if (transform != null)
1375 return transform.ToArray ();
1378 if (object.ReferenceEquals (InternalType.Dynamic, t))
1379 return new bool [] { true };
1381 return null;
1384 public static bool IsEnumType (Type t)
1386 t = DropGenericTypeArguments (t);
1387 return t.BaseType == TypeManager.enum_type;
1390 public static bool IsBuiltinOrEnum (Type t)
1392 if (IsBuiltinType (t))
1393 return true;
1395 if (IsEnumType (t))
1396 return true;
1398 return false;
1401 public static bool IsAttributeType (Type t)
1403 return t == attribute_type && t.BaseType != null || IsSubclassOf (t, attribute_type);
1407 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1409 // mcs4: delete, DeclSpace.IsUnmanagedType is replacement
1410 public static bool IsUnmanagedType (Type t)
1412 DeclSpace ds = TypeManager.LookupDeclSpace (t);
1413 if (ds != null)
1414 return ds.IsUnmanagedType ();
1416 // builtins that are not unmanaged types
1417 if (t == TypeManager.object_type || t == TypeManager.string_type)
1418 return false;
1420 if (IsGenericType (t) || IsGenericParameter (t))
1421 return false;
1423 if (IsBuiltinOrEnum (t))
1424 return true;
1426 // Someone did the work of checking if the ElementType of t is unmanaged. Let's not repeat it.
1427 if (t.IsPointer)
1428 return IsUnmanagedType (GetElementType (t));
1430 // Arrays are disallowed, even if we mark them with [MarshalAs(UnmanagedType.ByValArray, ...)]
1431 if (t.IsArray)
1432 return false;
1434 if (!IsValueType (t))
1435 return false;
1437 for (Type p = t.DeclaringType; p != null; p = p.DeclaringType) {
1438 if (IsGenericTypeDefinition (p))
1439 return false;
1442 bool retval = true;
1444 FieldInfo [] fields = t.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
1446 foreach (FieldInfo f in fields){
1447 if (!IsUnmanagedType (f.FieldType)){
1448 retval = false;
1453 return retval;
1457 // Null is considered to be a reference type
1459 public static bool IsReferenceType (Type t)
1461 if (TypeManager.IsGenericParameter (t)) {
1462 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1463 if (constraints == null)
1464 return false;
1466 return constraints.IsReferenceType;
1469 return !IsStruct (t) && !IsEnumType (t);
1472 public static bool IsValueType (Type t)
1474 if (TypeManager.IsGenericParameter (t)) {
1475 GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
1476 if (constraints == null)
1477 return false;
1479 return constraints.IsValueType;
1482 return IsStruct (t) || IsEnumType (t);
1485 public static bool IsStruct (Type t)
1487 return t.BaseType == value_type && t != enum_type && t.IsSealed;
1490 public static bool IsInterfaceType (Type t)
1492 TypeContainer tc = LookupTypeContainer (t);
1493 if (tc == null)
1494 return false;
1496 return tc.Kind == MemberKind.Interface;
1499 public static bool IsSubclassOf (Type type, Type base_type)
1501 TypeParameter tparam = LookupTypeParameter (type);
1502 TypeParameter pparam = LookupTypeParameter (base_type);
1504 if ((tparam != null) && (pparam != null)) {
1505 if (tparam == pparam)
1506 return true;
1508 return tparam.IsSubclassOf (base_type);
1511 #if MS_COMPATIBLE
1512 if (tparam != pparam)
1513 return false;
1515 if (type.IsGenericType)
1516 type = type.GetGenericTypeDefinition ();
1517 #endif
1519 if (type.IsSubclassOf (base_type))
1520 return true;
1522 do {
1523 if (IsEqual (type, base_type))
1524 return true;
1526 type = type.BaseType;
1527 } while (type != null);
1529 return false;
1532 public static bool IsPrivateAccessible (Type type, Type parent)
1534 if (type == null)
1535 return false;
1537 if (type.Equals (parent))
1538 return true;
1540 return DropGenericTypeArguments (type) == DropGenericTypeArguments (parent);
1543 public static bool IsFamilyAccessible (Type type, Type parent)
1545 TypeParameter tparam = LookupTypeParameter (type);
1546 TypeParameter pparam = LookupTypeParameter (parent);
1548 if ((tparam != null) && (pparam != null)) {
1549 if (tparam == pparam)
1550 return true;
1552 return tparam.IsSubclassOf (parent);
1555 do {
1556 if (IsInstantiationOfSameGenericType (type, parent))
1557 return true;
1559 type = type.BaseType;
1560 } while (type != null);
1562 return false;
1566 // Checks whether `type' is a subclass or nested child of `base_type'.
1568 public static bool IsNestedFamilyAccessible (Type type, Type base_type)
1570 do {
1571 if (IsFamilyAccessible (type, base_type))
1572 return true;
1574 // Handle nested types.
1575 type = type.DeclaringType;
1576 } while (type != null);
1578 return false;
1582 // Checks whether `type' is a nested child of `parent'.
1584 public static bool IsNestedChildOf (Type type, Type parent)
1586 if (type == null)
1587 return false;
1589 type = DropGenericTypeArguments (type);
1590 parent = DropGenericTypeArguments (parent);
1592 if (IsEqual (type, parent))
1593 return false;
1595 type = type.DeclaringType;
1596 while (type != null) {
1597 if (IsEqual (type, parent))
1598 return true;
1600 type = type.DeclaringType;
1603 return false;
1606 public static bool IsSpecialType (Type t)
1608 return t == arg_iterator_type || t == typed_reference_type;
1612 // Checks whether `invocationAssembly' is same or a friend of the assembly
1614 public static bool IsThisOrFriendAssembly (Assembly invocationAssembly, Assembly assembly)
1616 if (assembly == null)
1617 throw new ArgumentNullException ("assembly");
1619 // TODO: This can happen for constants used at assembly level and
1620 // predefined members
1621 // But there is no way to test for it for now, so it could be abused
1622 // elsewhere too.
1623 if (invocationAssembly == null)
1624 invocationAssembly = CodeGen.Assembly.Builder;
1626 if (invocationAssembly == assembly)
1627 return true;
1629 bool value;
1630 if (assembly_internals_vis_attrs.TryGetValue (assembly, out value))
1631 return value;
1633 PredefinedAttribute pa = PredefinedAttributes.Get.InternalsVisibleTo;
1634 // HACK: Do very early resolve of SRE type checking
1635 if (pa.Type == null)
1636 pa.Resolve (true);
1638 if (!pa.IsDefined)
1639 return false;
1641 object [] attrs = assembly.GetCustomAttributes (pa.Type, false);
1642 if (attrs.Length == 0) {
1643 assembly_internals_vis_attrs.Add (assembly, false);
1644 return false;
1647 bool is_friend = false;
1649 AssemblyName this_name = CodeGen.Assembly.Name;
1650 byte [] this_token = this_name.GetPublicKeyToken ();
1651 foreach (InternalsVisibleToAttribute attr in attrs) {
1652 if (attr.AssemblyName == null || attr.AssemblyName.Length == 0)
1653 continue;
1655 AssemblyName aname = null;
1656 try {
1657 aname = new AssemblyName (attr.AssemblyName);
1658 } catch (FileLoadException) {
1659 } catch (ArgumentException) {
1662 if (aname == null || aname.Name != this_name.Name)
1663 continue;
1665 byte [] key_token = aname.GetPublicKeyToken ();
1666 if (key_token != null) {
1667 if (this_token.Length == 0) {
1668 // Same name, but assembly is not strongnamed
1669 Error_FriendAccessNameNotMatching (aname.FullName, RootContext.ToplevelTypes.Compiler.Report);
1670 break;
1673 if (!CompareKeyTokens (this_token, key_token))
1674 continue;
1677 is_friend = true;
1678 break;
1681 assembly_internals_vis_attrs.Add (assembly, is_friend);
1682 return is_friend;
1685 static bool CompareKeyTokens (byte [] token1, byte [] token2)
1687 for (int i = 0; i < token1.Length; i++)
1688 if (token1 [i] != token2 [i])
1689 return false;
1691 return true;
1694 static void Error_FriendAccessNameNotMatching (string other_name, Report Report)
1696 Report.Error (281,
1697 "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",
1698 other_name, CodeGen.Assembly.Name.FullName);
1702 // Do the right thing when returning the element type of an
1703 // array type based on whether we are compiling corlib or not
1705 public static Type GetElementType (Type t)
1707 if (RootContext.StdLib)
1708 return t.GetElementType ();
1709 else
1710 return TypeToCoreType (t.GetElementType ());
1713 /// <summary>
1714 /// This method is not implemented by MS runtime for dynamic types
1715 /// </summary>
1716 public static bool HasElementType (Type t)
1718 return t.IsArray || t.IsPointer || t.IsByRef;
1721 public static Type GetEnumUnderlyingType (Type t)
1723 t = DropGenericTypeArguments (t);
1724 Enum e = LookupTypeContainer (t) as Enum;
1725 if (e != null)
1726 return e.UnderlyingType;
1728 // TODO: cache it ?
1729 FieldInfo fi = GetPredefinedField (t, Enum.UnderlyingValueField, Location.Null, Type.EmptyTypes);
1730 if (fi == null)
1731 return TypeManager.int32_type;
1733 return TypeToCoreType (fi.FieldType);
1736 /// <summary>
1737 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1738 /// </summary>
1740 /// <remarks>
1741 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1742 /// for anything which is dynamic, and we need this in a number of places,
1743 /// we register this information here, and use it afterwards.
1744 /// </remarks>
1745 static public void RegisterMethod (MethodBase mb, AParametersCollection ip)
1747 method_params.Add (mb, ip);
1750 static public void RegisterIndexer (PropertyBuilder pb, AParametersCollection p)
1752 method_params.Add (pb, p);
1755 static public AParametersCollection GetParameterData (MethodBase mb)
1757 AParametersCollection pd;
1758 if (!method_params.TryGetValue (mb, out pd)) {
1759 #if MS_COMPATIBLE
1760 if (mb.IsGenericMethod && !mb.IsGenericMethodDefinition) {
1761 MethodInfo mi = ((MethodInfo) mb).GetGenericMethodDefinition ();
1762 pd = GetParameterData (mi);
1764 if (mi.IsGenericMethod)
1765 pd = pd.InflateTypes (mi.GetGenericArguments (), mb.GetGenericArguments ());
1766 else
1767 pd = pd.InflateTypes (mi.DeclaringType.GetGenericArguments (), mb.GetGenericArguments ());
1769 method_params.Add (mb, pd);
1770 return pd;
1773 if (mb.DeclaringType.Assembly == CodeGen.Assembly.Builder) {
1774 throw new InternalErrorException ("Parameters are not registered for method `{0}'",
1775 TypeManager.CSharpName (mb.DeclaringType) + "." + mb.Name);
1778 pd = ParametersImported.Create (mb);
1779 #else
1780 MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
1781 if (generic != mb) {
1782 pd = TypeManager.GetParameterData (generic);
1783 pd = ParametersImported.Create (pd, mb);
1784 } else {
1785 pd = ParametersImported.Create (mb);
1787 #endif
1788 method_params.Add (mb, pd);
1790 return pd;
1793 public static AParametersCollection GetParameterData (PropertyInfo pi)
1795 AParametersCollection pd;
1796 if (!method_params.TryGetValue (pi, out pd)) {
1797 if (pi is PropertyBuilder)
1798 return ParametersCompiled.EmptyReadOnlyParameters;
1800 ParameterInfo [] p = pi.GetIndexParameters ();
1801 if (p == null)
1802 return ParametersCompiled.EmptyReadOnlyParameters;
1804 pd = ParametersImported.Create (p, null);
1805 method_params.Add (pi, pd);
1808 return pd;
1811 public static AParametersCollection GetDelegateParameters (ResolveContext ec, Type t)
1813 Delegate d = LookupDelegate (t);
1814 if (d != null)
1815 return d.Parameters;
1817 var invoke_mb = Delegate.GetInvokeMethod (ec.Compiler, t, t);
1818 return invoke_mb.Parameters;
1821 static public void RegisterOverride (MethodBase override_method, MethodBase base_method)
1823 if (!method_overrides.ContainsKey (override_method))
1824 method_overrides [override_method] = base_method;
1825 if (method_overrides [override_method] != base_method)
1826 throw new InternalErrorException ("Override mismatch: " + override_method);
1829 static public bool IsOverride (MethodSpec ms)
1831 MethodBase m = ms.MetaInfo;
1832 m = DropGenericMethodArguments (m);
1834 return m.IsVirtual &&
1835 (m.Attributes & MethodAttributes.NewSlot) == 0 &&
1836 (m is MethodBuilder || method_overrides.ContainsKey (m));
1839 static public MethodBase TryGetBaseDefinition (MethodBase m)
1841 m = DropGenericMethodArguments (m);
1842 MethodBase mb;
1843 if (method_overrides.TryGetValue (m, out mb))
1844 return mb;
1846 return null;
1849 public static void RegisterConstant (FieldInfo fb, ConstSpec ic)
1851 fields.Add (fb, ic);
1854 public static ConstSpec GetConstant (FieldInfo fb)
1856 if (fb == null)
1857 return null;
1859 ConstSpec ic;
1860 if (fields.TryGetValue (fb, out ic))
1861 return ic;
1863 return null;
1866 public static void RegisterProperty (PropertyInfo pi, PropertyBase pb)
1868 propertybuilder_to_property.Add (pi, pb);
1871 public static PropertyBase GetProperty (PropertyInfo pi)
1873 PropertyBase pb;
1874 if (propertybuilder_to_property.TryGetValue (pi, out pb))
1875 return pb;
1877 return null;
1880 static public void RegisterFieldBase (FieldBuilder fb, FieldBase f)
1882 fieldbuilders_to_fields.Add (fb, f);
1886 // The return value can be null; This will be the case for
1887 // auxiliary FieldBuilders created by the compiler that have no
1888 // real field being declared on the source code
1890 static public FieldBase GetField (FieldInfo fb)
1892 return GetFieldCore (GetGenericFieldDefinition (fb));
1895 static public FieldBase GetFieldCore (FieldInfo fb)
1897 FieldBase f;
1898 if (fieldbuilders_to_fields.TryGetValue (fb, out f))
1899 return f;
1901 return null;
1904 static public MethodInfo GetAddMethod (EventInfo ei)
1906 if (ei is MyEventBuilder) {
1907 return ((MyEventBuilder)ei).GetAddMethod (true);
1909 return ei.GetAddMethod (true);
1912 static public MethodInfo GetRemoveMethod (EventInfo ei)
1914 if (ei is MyEventBuilder) {
1915 return ((MyEventBuilder)ei).GetRemoveMethod (true);
1917 return ei.GetRemoveMethod (true);
1920 static public void RegisterEventField (EventInfo einfo, EventSpec e)
1922 if (events == null)
1923 events = new Dictionary<EventInfo, EventSpec> (ReferenceEquality<EventInfo>.Default);
1925 events.Add (einfo, e);
1928 static public EventSpec GetEventField (EventInfo ei)
1930 if (events == null)
1931 return null;
1933 EventSpec value;
1934 if (events.TryGetValue (ei, out value))
1935 return value;
1937 return null;
1940 public static bool CheckStructCycles (TypeContainer tc, Dictionary<TypeContainer, object> seen)
1942 var hash = new Dictionary<TypeContainer, object> ();
1943 return CheckStructCycles (tc, seen, hash);
1946 public static bool CheckStructCycles (TypeContainer tc, Dictionary<TypeContainer, object> seen,
1947 Dictionary<TypeContainer, object> hash)
1949 if ((tc.Kind != MemberKind.Struct) || IsBuiltinType (tc.TypeBuilder))
1950 return true;
1953 // `seen' contains all types we've already visited.
1955 if (seen.ContainsKey (tc))
1956 return true;
1957 seen.Add (tc, null);
1959 if (tc.Fields == null)
1960 return true;
1962 foreach (FieldBase field in tc.Fields) {
1963 if (field.Spec == null || field.Spec.IsStatic)
1964 continue;
1966 Type ftype = field.Spec.FieldType;
1967 TypeContainer ftc = LookupTypeContainer (ftype);
1968 if (ftc == null)
1969 continue;
1971 if (hash.ContainsKey (ftc)) {
1972 tc.Compiler.Report.Error (523, tc.Location,
1973 "Struct member `{0}.{1}' of type `{2}' " +
1974 "causes a cycle in the struct layout",
1975 tc.Name, field.Name, ftc.Name);
1976 return false;
1980 // `hash' contains all types in the current path.
1982 hash.Add (tc, null);
1984 bool ok = CheckStructCycles (ftc, seen, hash);
1986 hash.Remove (tc);
1988 if (!ok)
1989 return false;
1991 if (!seen.ContainsKey (ftc))
1992 seen.Add (ftc, null);
1995 return true;
1998 /// <summary>
1999 /// Given an array of interface types, expand and eliminate repeated ocurrences
2000 /// of an interface.
2001 /// </summary>
2003 /// <remarks>
2004 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2005 /// be IA, IB, IC.
2006 /// </remarks>
2007 public static Type[] ExpandInterfaces (TypeExpr [] base_interfaces)
2009 var new_ifaces = new List<Type> ();
2011 foreach (TypeExpr iface in base_interfaces){
2012 Type itype = iface.Type;
2014 if (new_ifaces.Contains (itype))
2015 continue;
2017 new_ifaces.Add (itype);
2019 Type [] implementing = GetInterfaces (itype);
2021 foreach (Type imp in implementing){
2022 if (!new_ifaces.Contains (imp))
2023 new_ifaces.Add (imp);
2027 return new_ifaces.ToArray ();
2030 public static Type[] ExpandInterfaces (Type [] base_interfaces)
2032 var new_ifaces = new List<Type> ();
2034 foreach (Type itype in base_interfaces){
2035 if (new_ifaces.Contains (itype))
2036 continue;
2038 new_ifaces.Add (itype);
2040 Type [] implementing = GetInterfaces (itype);
2042 foreach (Type imp in implementing){
2043 if (!new_ifaces.Contains (imp))
2044 new_ifaces.Add (imp);
2048 return new_ifaces.ToArray ();
2051 /// <summary>
2052 /// This function returns the interfaces in the type `t'. Works with
2053 /// both types and TypeBuilders.
2054 /// </summary>
2055 public static Type [] GetInterfaces (Type t)
2057 Type [] cached;
2058 if (iface_cache.TryGetValue (t, out cached))
2059 if (cached != null)
2060 return cached;
2063 // The reason for catching the Array case is that Reflection.Emit
2064 // will not return a TypeBuilder for Array types of TypeBuilder types,
2065 // but will still throw an exception if we try to call GetInterfaces
2066 // on the type.
2068 // Since the array interfaces are always constant, we return those for
2069 // the System.Array
2072 if (t.IsArray)
2073 t = TypeManager.array_type;
2075 if ((t is TypeBuilder) || IsGenericType (t)) {
2076 Type [] base_ifaces;
2078 if (t.BaseType == null)
2079 base_ifaces = Type.EmptyTypes;
2080 else
2081 base_ifaces = GetInterfaces (t.BaseType);
2082 Type[] type_ifaces;
2083 if (IsGenericType (t))
2084 #if MS_COMPATIBLE
2085 type_ifaces = t.GetGenericTypeDefinition().GetInterfaces ();
2086 #else
2087 type_ifaces = t.GetInterfaces ();
2088 #endif
2089 else
2090 type_ifaces = GetExplicitInterfaces (t);
2091 if (type_ifaces == null || type_ifaces.Length == 0)
2092 type_ifaces = Type.EmptyTypes;
2094 int base_count = base_ifaces.Length;
2095 Type [] result = new Type [base_count + type_ifaces.Length];
2096 base_ifaces.CopyTo (result, 0);
2097 type_ifaces.CopyTo (result, base_count);
2099 iface_cache [t] = result;
2100 return result;
2101 } else if (t is GenericTypeParameterBuilder){
2102 Type[] type_ifaces = GetExplicitInterfaces (t);
2103 if (type_ifaces == null || type_ifaces.Length == 0)
2104 type_ifaces = Type.EmptyTypes;
2106 iface_cache [t] = type_ifaces;
2107 return type_ifaces;
2108 } else {
2109 Type[] ifaces = t.GetInterfaces ();
2110 iface_cache [t] = ifaces;
2111 return ifaces;
2116 // gets the interfaces that are declared explicitly on t
2118 public static Type[] GetExplicitInterfaces (Type t)
2120 Type[] ifaces;
2121 if (builder_to_ifaces.TryGetValue (t, out ifaces))
2122 return ifaces;
2124 return null;
2127 /// <remarks>
2128 /// The following is used to check if a given type implements an interface.
2129 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2130 /// </remarks>
2131 public static bool ImplementsInterface (Type t, Type iface)
2133 Type [] interfaces;
2136 // FIXME OPTIMIZATION:
2137 // as soon as we hit a non-TypeBuiler in the interface
2138 // chain, we could return, as the `Type.GetInterfaces'
2139 // will return all the interfaces implement by the type
2140 // or its bases.
2142 do {
2143 interfaces = GetInterfaces (t);
2145 if (interfaces != null){
2146 foreach (Type i in interfaces){
2147 if (i == iface || IsVariantOf (i, iface))
2148 return true;
2152 t = t.BaseType;
2153 } while (t != null);
2155 return false;
2158 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2160 // This is a custom version of Convert.ChangeType() which works
2161 // with the TypeBuilder defined types when compiling corlib.
2162 public static object ChangeType (object value, Type conversionType, out bool error)
2164 IConvertible convert_value = value as IConvertible;
2166 if (convert_value == null){
2167 error = true;
2168 return null;
2172 // NOTE 1:
2173 // We must use Type.Equals() here since `conversionType' is
2174 // the TypeBuilder created version of a system type and not
2175 // the system type itself. You cannot use Type.GetTypeCode()
2176 // on such a type - it'd always return TypeCode.Object.
2178 // NOTE 2:
2179 // We cannot rely on build-in type conversions as they are
2180 // more limited than what C# supports.
2181 // See char -> float/decimal/double conversion
2184 error = false;
2185 try {
2186 if (conversionType.Equals (typeof (Boolean)))
2187 return (object)(convert_value.ToBoolean (nf_provider));
2188 if (conversionType.Equals (typeof (Byte)))
2189 return (object)(convert_value.ToByte (nf_provider));
2190 if (conversionType.Equals (typeof (Char)))
2191 return (object)(convert_value.ToChar (nf_provider));
2192 if (conversionType.Equals (typeof (DateTime)))
2193 return (object)(convert_value.ToDateTime (nf_provider));
2195 if (conversionType.Equals (decimal_type)) {
2196 if (convert_value.GetType () == TypeManager.char_type)
2197 return (decimal)convert_value.ToInt32 (nf_provider);
2198 return convert_value.ToDecimal (nf_provider);
2201 if (conversionType.Equals (typeof (Double))) {
2202 if (convert_value.GetType () == TypeManager.char_type)
2203 return (double)convert_value.ToInt32 (nf_provider);
2204 return convert_value.ToDouble (nf_provider);
2207 if (conversionType.Equals (typeof (Int16)))
2208 return (object)(convert_value.ToInt16 (nf_provider));
2209 if (conversionType.Equals (int32_type))
2210 return (object)(convert_value.ToInt32 (nf_provider));
2211 if (conversionType.Equals (int64_type))
2212 return (object)(convert_value.ToInt64 (nf_provider));
2213 if (conversionType.Equals (typeof (SByte)))
2214 return (object)(convert_value.ToSByte (nf_provider));
2216 if (conversionType.Equals (typeof (Single))) {
2217 if (convert_value.GetType () == TypeManager.char_type)
2218 return (float)convert_value.ToInt32 (nf_provider);
2219 return convert_value.ToSingle (nf_provider);
2222 if (conversionType.Equals (typeof (String)))
2223 return (object)(convert_value.ToString (nf_provider));
2224 if (conversionType.Equals (typeof (UInt16)))
2225 return (object)(convert_value.ToUInt16 (nf_provider));
2226 if (conversionType.Equals (typeof (UInt32)))
2227 return (object)(convert_value.ToUInt32 (nf_provider));
2228 if (conversionType.Equals (typeof (UInt64)))
2229 return (object)(convert_value.ToUInt64 (nf_provider));
2230 if (conversionType.Equals (typeof (Object)))
2231 return (object)(value);
2232 else
2233 error = true;
2234 } catch {
2235 error = true;
2237 return null;
2241 // When compiling with -nostdlib and the type is imported from an external assembly
2242 // SRE uses "wrong" type and we have to convert it to the right compiler instance.
2244 public static Type TypeToCoreType (Type t)
2246 if (RootContext.StdLib || t.Module != typeof (object).Module)
2247 return t;
2249 // TODO: GetTypeCode returns underlying type for enums !!
2250 TypeCode tc = Type.GetTypeCode (t);
2252 switch (tc){
2253 case TypeCode.Boolean:
2254 return TypeManager.bool_type;
2255 case TypeCode.Byte:
2256 return TypeManager.byte_type;
2257 case TypeCode.SByte:
2258 return TypeManager.sbyte_type;
2259 case TypeCode.Char:
2260 return TypeManager.char_type;
2261 case TypeCode.Int16:
2262 return TypeManager.short_type;
2263 case TypeCode.UInt16:
2264 return TypeManager.ushort_type;
2265 case TypeCode.Int32:
2266 return TypeManager.int32_type;
2267 case TypeCode.UInt32:
2268 return TypeManager.uint32_type;
2269 case TypeCode.Int64:
2270 return TypeManager.int64_type;
2271 case TypeCode.UInt64:
2272 return TypeManager.uint64_type;
2273 case TypeCode.Single:
2274 return TypeManager.float_type;
2275 case TypeCode.Double:
2276 return TypeManager.double_type;
2277 case TypeCode.String:
2278 return TypeManager.string_type;
2279 case TypeCode.Decimal:
2280 return TypeManager.decimal_type;
2283 if (t == typeof (void))
2284 return TypeManager.void_type;
2285 if (t == typeof (object))
2286 return TypeManager.object_type;
2287 if (t == typeof (System.Type))
2288 return TypeManager.type_type;
2289 if (t == typeof (System.IntPtr))
2290 return TypeManager.intptr_type;
2291 if (t == typeof (System.UIntPtr))
2292 return TypeManager.uintptr_type;
2294 if (t.IsArray) {
2295 int dim = t.GetArrayRank ();
2296 t = GetElementType (t);
2297 return t.MakeArrayType (dim);
2299 if (t.IsByRef) {
2300 t = GetElementType (t);
2301 return t.MakeByRefType ();
2303 if (t.IsPointer) {
2304 t = GetElementType (t);
2305 return t.MakePointerType ();
2308 return t;
2312 // Converts any type to reflection supported type
2314 public static Type TypeToReflectionType (Type type)
2316 // TODO: Very lame and painful, GetReference () is enough for mcs-cecil
2317 if (IsDynamicType (type))
2318 return object_type;
2320 if (type is DynamicArrayType)
2321 return type.UnderlyingSystemType;
2323 return type;
2326 /// <summary>
2327 /// Utility function that can be used to probe whether a type
2328 /// is managed or not.
2329 /// </summary>
2330 public static bool VerifyUnmanaged (CompilerContext ctx, Type t, Location loc)
2332 if (IsUnmanagedType (t))
2333 return true;
2335 while (t.IsPointer)
2336 t = GetElementType (t);
2338 ctx.Report.SymbolRelatedToPreviousError (t);
2339 ctx.Report.Error (208, loc,
2340 "Cannot take the address of, get the size of, or declare a pointer to a managed type `{0}'",
2341 CSharpName (t));
2343 return false;
2346 /// <summary>
2347 /// Returns the name of the indexer in a given type.
2348 /// </summary>
2349 /// <remarks>
2350 /// The default is not always `Item'. The user can change this behaviour by
2351 /// using the IndexerNameAttribute in the container.
2352 /// For example, the String class indexer is named `Chars' not `Item'
2353 /// </remarks>
2354 public static string IndexerPropertyName (Type t)
2356 t = DropGenericTypeArguments (t);
2357 if (t is TypeBuilder) {
2358 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2359 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2362 PredefinedAttribute pa = PredefinedAttributes.Get.DefaultMember;
2363 if (pa.IsDefined) {
2364 System.Attribute attr = System.Attribute.GetCustomAttribute (
2365 t, pa.Type);
2366 if (attr != null) {
2367 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2368 return dma.MemberName;
2372 return TypeContainer.DefaultIndexerName;
2375 private static bool IsSignatureEqual (Type a, Type b)
2378 /// Consider the following example (bug #77674):
2380 /// public abstract class A
2381 /// {
2382 /// public abstract T Foo<T> ();
2383 /// }
2385 /// public abstract class B : A
2386 /// {
2387 /// public override U Foo<T> ()
2388 /// { return default (U); }
2389 /// }
2391 /// Here, `T' and `U' are method type parameters from different methods
2392 /// (A.Foo and B.Foo), so both `==' and Equals() will fail.
2394 /// However, since we're determining whether B.Foo() overrides A.Foo(),
2395 /// we need to do a signature based comparision and consider them equal.
2397 if (a == b)
2398 return true;
2400 if (a.IsGenericParameter && b.IsGenericParameter &&
2401 (a.DeclaringMethod != null) && (b.DeclaringMethod != null)) {
2402 return a.GenericParameterPosition == b.GenericParameterPosition;
2405 if (a.IsArray && b.IsArray) {
2406 if (a.GetArrayRank () != b.GetArrayRank ())
2407 return false;
2409 return IsSignatureEqual (GetElementType (a), GetElementType (b));
2412 if (a.IsByRef && b.IsByRef)
2413 return IsSignatureEqual (GetElementType (a), GetElementType (b));
2415 if (IsGenericType (a) && IsGenericType (b)) {
2416 if (DropGenericTypeArguments (a) != DropGenericTypeArguments (b))
2417 return false;
2419 Type[] aargs = GetTypeArguments (a);
2420 Type[] bargs = GetTypeArguments (b);
2422 if (aargs.Length != bargs.Length)
2423 return false;
2425 for (int i = 0; i < aargs.Length; i++) {
2426 if (!IsSignatureEqual (aargs [i], bargs [i]))
2427 return false;
2430 return true;
2433 return false;
2437 // Returns whether the array of memberinfos contains the given method
2439 public static bool ArrayContainsMethod (MethodBase [] array, MethodBase new_method, bool ignoreDeclType)
2441 Type [] new_args = TypeManager.GetParameterData (new_method).Types;
2443 foreach (MethodBase method in array) {
2444 if (!ignoreDeclType && method.DeclaringType != new_method.DeclaringType)
2445 continue;
2447 if (method.Name != new_method.Name)
2448 continue;
2450 if (method is MethodInfo && new_method is MethodInfo &&
2451 !IsSignatureEqual (
2452 TypeToCoreType (((MethodInfo) method).ReturnType),
2453 TypeToCoreType (((MethodInfo) new_method).ReturnType)))
2454 continue;
2456 Type [] old_args = TypeManager.GetParameterData (method).Types;
2457 int old_count = old_args.Length;
2458 int i;
2460 if (new_args.Length != old_count)
2461 continue;
2463 for (i = 0; i < old_count; i++){
2464 if (!IsSignatureEqual (old_args [i], new_args [i]))
2465 break;
2467 if (i != old_count)
2468 continue;
2470 return true;
2473 return false;
2477 // We copy methods from `new_members' into `target_list' if the signature
2478 // for the method from in the new list does not exist in the target_list
2480 // The name is assumed to be the same.
2482 public static List<MethodBase> CopyNewMethods (List<MethodBase> target_list, IList<MemberInfo> new_members)
2484 if (target_list == null){
2485 target_list = new List<MethodBase> ();
2487 foreach (MemberInfo mi in new_members){
2488 if (mi is MethodBase)
2489 target_list.Add ((MethodBase) mi);
2491 return target_list;
2494 MethodBase[] target_array = new MethodBase[target_list.Count];
2495 target_list.CopyTo (target_array, 0);
2497 foreach (MemberInfo mi in new_members){
2498 MethodBase new_method = (MethodBase) mi;
2500 if (!ArrayContainsMethod (target_array, new_method, true))
2501 target_list.Add (new_method);
2503 return target_list;
2506 #region Generics
2507 // <remarks>
2508 // Tracks the generic parameters.
2509 // </remarks>
2511 public static void AddTypeParameter (GenericTypeParameterBuilder t, TypeParameter tparam)
2513 builder_to_type_param [t] = tparam;
2516 public static TypeParameter LookupTypeParameter (Type t)
2518 TypeParameter tp;
2519 var gtp = t as GenericTypeParameterBuilder;
2520 if (gtp != null && builder_to_type_param.TryGetValue (gtp, out tp))
2521 return tp;
2523 return null;
2526 // This method always return false for non-generic compiler,
2527 // while Type.IsGenericParameter is returned if it is supported.
2528 public static bool IsGenericParameter (Type type)
2530 return type.IsGenericParameter;
2533 public static int GenericParameterPosition (Type type)
2535 return type.GenericParameterPosition;
2538 public static bool IsGenericType (Type type)
2540 return type.IsGenericType;
2543 public static bool IsGenericTypeDefinition (Type type)
2545 return type.IsGenericTypeDefinition;
2548 public static bool ContainsGenericParameters (Type type)
2550 return type.ContainsGenericParameters;
2553 public static FieldInfo GetGenericFieldDefinition (FieldInfo fi)
2555 if (fi.DeclaringType.IsGenericTypeDefinition ||
2556 !fi.DeclaringType.IsGenericType)
2557 return fi;
2559 Type t = fi.DeclaringType.GetGenericTypeDefinition ();
2560 BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
2561 BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
2563 // TODO: use CodeGen.Module.Builder.ResolveField (fi.MetadataToken);
2564 foreach (FieldInfo f in t.GetFields (bf))
2565 if (f.MetadataToken == fi.MetadataToken)
2566 return f;
2568 return fi;
2571 public static bool IsEqual (Type a, Type b)
2573 if (a.Equals (b)) {
2574 // MS BCL returns true even if enum types are different
2575 if (a.BaseType == TypeManager.enum_type || b.BaseType == TypeManager.enum_type)
2576 return a.FullName == b.FullName;
2578 // Some types are never equal
2579 if (a == TypeManager.null_type || a == InternalType.AnonymousMethod)
2580 return false;
2582 return true;
2585 if (IsGenericParameter (a) && IsGenericParameter (b)) {
2586 // TODO: needs more testing before cleaning up
2587 //if (a.DeclaringMethod != b.DeclaringMethod &&
2588 // (a.DeclaringMethod == null || b.DeclaringMethod == null))
2589 // return false;
2590 return a.GenericParameterPosition == b.GenericParameterPosition;
2593 if (a.IsArray && b.IsArray) {
2594 if (a.GetArrayRank () != b.GetArrayRank ())
2595 return false;
2596 return IsEqual (GetElementType (a), GetElementType (b));
2599 if (a.IsByRef && b.IsByRef)
2600 return IsEqual (a.GetElementType (), b.GetElementType ());
2602 if (IsGenericType (a) && IsGenericType (b)) {
2603 Type adef = DropGenericTypeArguments (a);
2604 Type bdef = DropGenericTypeArguments (b);
2606 if (adef != bdef)
2607 return false;
2609 if (adef.IsEnum && bdef.IsEnum)
2610 return true;
2612 Type[] aargs = GetTypeArguments (a);
2613 Type[] bargs = GetTypeArguments (b);
2615 if (aargs.Length != bargs.Length)
2616 return false;
2618 for (int i = 0; i < aargs.Length; i++) {
2619 if (!IsEqual (aargs [i], bargs [i]))
2620 return false;
2623 return true;
2626 return false;
2629 public static bool IsEqual (Type[] a, Type[] b)
2631 if (a == null || b == null || a.Length != b.Length)
2632 return false;
2634 for (int i = 0; i < a.Length; ++i) {
2635 if (a [i] == null || b [i] == null) {
2636 if (a [i] == b [i])
2637 continue;
2639 return false;
2642 if (!IsEqual (a [i], b [i]))
2643 return false;
2646 return true;
2649 public static Type DropGenericTypeArguments (Type t)
2651 if (!t.IsGenericType)
2652 return t;
2653 // Micro-optimization: a generic typebuilder is always a generic type definition
2654 if (t is TypeBuilder)
2655 return t;
2656 return t.GetGenericTypeDefinition ();
2659 public static MethodBase DropGenericMethodArguments (MethodSpec m)
2661 return DropGenericMethodArguments (m.MetaInfo);
2664 public static MethodBase DropGenericMethodArguments (MethodBase m)
2666 if (m.IsGenericMethod)
2667 m = ((MethodInfo) m).GetGenericMethodDefinition ();
2669 Type t = m.DeclaringType;
2670 if (!t.IsGenericType || t.IsGenericTypeDefinition)
2671 return m;
2673 t = t.GetGenericTypeDefinition ();
2674 BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
2675 BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
2677 #if MS_COMPATIBLE
2678 // TODO: use CodeGen.Module.Builder.ResolveMethod ()
2679 return m;
2680 #endif
2682 if (m is ConstructorInfo) {
2683 foreach (ConstructorInfo c in t.GetConstructors (bf))
2684 if (c.MetadataToken == m.MetadataToken)
2685 return c;
2686 } else {
2687 foreach (MethodBase mb in t.GetMethods (bf))
2688 if (mb.MetadataToken == m.MetadataToken)
2689 return mb;
2692 return m;
2695 public static Type[] GetGenericArguments (MethodBase mi)
2697 return mi.GetGenericArguments () ?? Type.EmptyTypes;
2700 public static Type[] GetTypeArguments (Type t)
2702 DeclSpace tc = LookupDeclSpace (t);
2703 if (tc != null) {
2704 if (!tc.IsGeneric)
2705 return Type.EmptyTypes;
2707 TypeParameter[] tparam = tc.TypeParameters;
2708 Type[] ret = new Type [tparam.Length];
2709 for (int i = 0; i < tparam.Length; i++) {
2710 ret [i] = tparam [i].Type;
2711 if (ret [i] == null)
2712 throw new InternalErrorException ();
2715 return ret;
2716 } else
2717 return t.GetGenericArguments ();
2720 public static GenericConstraints GetTypeParameterConstraints (Type t)
2722 if (!t.IsGenericParameter)
2723 throw new InvalidOperationException ();
2725 TypeParameter tparam = LookupTypeParameter (t);
2726 if (tparam != null)
2727 return tparam.GenericConstraints;
2729 return ReflectionConstraints.GetConstraints (t);
2732 public static bool HasGenericArguments (Type t)
2734 return GetNumberOfTypeArguments (t) > 0;
2737 public static int GetNumberOfTypeArguments (Type t)
2739 if (t.IsGenericParameter)
2740 return 0;
2741 DeclSpace tc = LookupDeclSpace (t);
2742 if (tc != null)
2743 return tc.IsGeneric ? tc.CountTypeParameters : 0;
2744 else
2745 return t.IsGenericType ? t.GetGenericArguments ().Length : 0;
2748 /// <summary>
2749 /// Check whether `type' and `parent' are both instantiations of the same
2750 /// generic type. Note that we do not check the type parameters here.
2751 /// </summary>
2752 public static bool IsInstantiationOfSameGenericType (Type type, Type parent)
2754 int tcount = GetNumberOfTypeArguments (type);
2755 int pcount = GetNumberOfTypeArguments (parent);
2757 if (tcount != pcount)
2758 return false;
2760 type = DropGenericTypeArguments (type);
2761 parent = DropGenericTypeArguments (parent);
2763 return type.Equals (parent);
2766 /// <summary>
2767 /// Whether `mb' is a generic method definition.
2768 /// </summary>
2769 public static bool IsGenericMethodDefinition (MethodBase mb)
2771 if (mb.DeclaringType is TypeBuilder) {
2772 IMethodData method = GetMethod (mb);
2773 if (method == null)
2774 return false;
2776 return method.GenericMethod != null;
2779 return mb.IsGenericMethodDefinition;
2782 /// <summary>
2783 /// Whether `mb' is a generic method.
2784 /// </summary>
2785 public static bool IsGenericMethod (MethodBase mb)
2787 return mb.IsGenericMethod;
2790 public static bool IsNullableType (Type t)
2792 return generic_nullable_type == DropGenericTypeArguments (t);
2795 public static MethodInfo MakeGenericMethod (MethodInfo gmd, Type[] methodArguments)
2797 if (!gmd.IsGenericMethodDefinition)
2798 gmd = gmd.GetGenericMethodDefinition ();
2799 return gmd.MakeGenericMethod (methodArguments);
2801 #endregion
2803 #region MemberLookup implementation
2806 // Whether we allow private members in the result (since FindMembers
2807 // uses NonPublic for both protected and private), we need to distinguish.
2810 internal class Closure {
2811 internal bool private_ok;
2813 // Who is invoking us and which type is being queried currently.
2814 internal Type invocation_type;
2815 internal Type qualifier_type;
2817 // The assembly that defines the type is that is calling us
2818 internal Assembly invocation_assembly;
2819 internal IList<MemberInfo> almost_match;
2821 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2823 if (invocation_type == null)
2824 return false;
2826 if (is_static && qualifier_type == null)
2827 // It resolved from a simple name, so it should be visible.
2828 return true;
2830 if (IsNestedChildOf (invocation_type, m.DeclaringType))
2831 return true;
2833 for (Type t = invocation_type; t != null; t = t.DeclaringType) {
2834 if (!IsFamilyAccessible (t, m.DeclaringType))
2835 continue;
2837 // Although a derived class can access protected members of its base class
2838 // it cannot do so through an instance of the base class (CS1540).
2839 // => Ancestry should be: declaring_type ->* invocation_type ->* qualified_type
2840 if (is_static || qualifier_type == null ||
2841 IsInstantiationOfSameGenericType (t, qualifier_type) ||
2842 IsFamilyAccessible (qualifier_type, t))
2843 return true;
2846 if (almost_match != null)
2847 almost_match.Add (m);
2849 return false;
2853 // This filter filters by name + whether it is ok to include private
2854 // members in the search
2856 internal bool Filter (MemberInfo m, object filter_criteria)
2859 // Hack: we know that the filter criteria will always be in the
2860 // `closure' // fields.
2863 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2864 return false;
2866 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2867 (invocation_type != null) &&
2868 IsPrivateAccessible (m.DeclaringType, invocation_type))
2869 return true;
2872 // Ugly: we need to find out the type of `m', and depending
2873 // on this, tell whether we accept or not
2875 if (m is MethodBase){
2876 MethodBase mb = (MethodBase) m;
2877 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2879 if (ma == MethodAttributes.Public)
2880 return true;
2882 if (ma == MethodAttributes.PrivateScope)
2883 return false;
2885 if (ma == MethodAttributes.Private)
2886 return private_ok ||
2887 IsPrivateAccessible (invocation_type, m.DeclaringType) ||
2888 IsNestedChildOf (invocation_type, m.DeclaringType);
2890 if (TypeManager.IsThisOrFriendAssembly (invocation_assembly, mb.DeclaringType.Assembly)) {
2891 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
2892 return true;
2893 } else {
2894 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
2895 return false;
2898 // Family, FamORAssem or FamANDAssem
2899 return CheckValidFamilyAccess (mb.IsStatic, m);
2902 if (m is FieldInfo){
2903 FieldInfo fi = (FieldInfo) m;
2904 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2906 if (fa == FieldAttributes.Public)
2907 return true;
2909 if (fa == FieldAttributes.PrivateScope)
2910 return false;
2912 if (fa == FieldAttributes.Private)
2913 return private_ok ||
2914 IsPrivateAccessible (invocation_type, m.DeclaringType) ||
2915 IsNestedChildOf (invocation_type, m.DeclaringType);
2917 if (TypeManager.IsThisOrFriendAssembly (invocation_assembly, fi.DeclaringType.Assembly)) {
2918 if ((fa == FieldAttributes.Assembly) ||
2919 (fa == FieldAttributes.FamORAssem))
2920 return true;
2921 } else {
2922 if ((fa == FieldAttributes.Assembly) ||
2923 (fa == FieldAttributes.FamANDAssem))
2924 return false;
2927 // Family, FamORAssem or FamANDAssem
2928 return CheckValidFamilyAccess (fi.IsStatic, m);
2932 // EventInfos and PropertyInfos, return true because they lack
2933 // permission information, so we need to check later on the methods.
2935 return true;
2939 static Closure closure;
2940 static MemberFilter FilterWithClosure_delegate;
2943 // Looks up a member called `name' in the `queried_type'. This lookup
2944 // is done by code that is contained in the definition for `invocation_type'
2945 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2947 // `invocation_type' is used to check whether we're allowed to access the requested
2948 // member wrt its protection level.
2950 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2951 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2952 // is B and qualifier_type is A). This is used to do the CS1540 check.
2954 // When resolving a SimpleName, `qualifier_type' is null.
2956 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2957 // the same than `queried_type' - except when we're being called from BaseAccess;
2958 // in this case, `invocation_type' is the current type and `queried_type' the base
2959 // type, so this'd normally trigger a CS1540.
2961 // The binding flags are `bf' and the kind of members being looked up are `mt'
2963 // The return value always includes private members which code in `invocation_type'
2964 // is allowed to access (using the specified `qualifier_type' if given); only use
2965 // BindingFlags.NonPublic to bypass the permission check.
2967 // The 'almost_match' argument is used for reporting error CS1540.
2969 // Returns an array of a single element for everything but Methods/Constructors
2970 // that might return multiple matches.
2972 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2973 Type queried_type, MemberTypes mt,
2974 BindingFlags original_bf, string name, IList<MemberInfo> almost_match)
2976 Timer.StartTimer (TimerType.MemberLookup);
2978 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2979 queried_type, mt, original_bf, name, almost_match);
2981 Timer.StopTimer (TimerType.MemberLookup);
2983 return retval;
2986 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2987 Type queried_type, MemberTypes mt,
2988 BindingFlags original_bf, string name, IList<MemberInfo> almost_match)
2990 BindingFlags bf = original_bf;
2992 List<MethodBase> method_list = null;
2993 Type current_type = queried_type;
2994 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2995 bool skip_iface_check = true, used_cache = false;
2996 bool always_ok_flag = invocation_type != null && IsNestedChildOf (invocation_type, queried_type);
2998 closure.invocation_type = invocation_type;
2999 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
3000 closure.qualifier_type = qualifier_type;
3001 closure.almost_match = almost_match;
3003 // This is from the first time we find a method
3004 // in most cases, we do not actually find a method in the base class
3005 // so we can just ignore it, and save the arraylist allocation
3006 MemberInfo [] first_members_list = null;
3007 bool use_first_members_list = false;
3009 do {
3010 MemberInfo [] list;
3013 // `NonPublic' is lame, because it includes both protected and
3014 // private methods, so we need to control this behavior by
3015 // explicitly tracking if a private method is ok or not.
3017 // The possible cases are:
3018 // public, private and protected (internal does not come into the
3019 // equation)
3021 if ((invocation_type != null) &&
3022 ((invocation_type == current_type) ||
3023 IsNestedChildOf (invocation_type, current_type)) ||
3024 always_ok_flag)
3025 bf = original_bf | BindingFlags.NonPublic;
3026 else
3027 bf = original_bf;
3029 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
3031 Timer.StopTimer (TimerType.MemberLookup);
3033 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
3035 Timer.StartTimer (TimerType.MemberLookup);
3038 // When queried for an interface type, the cache will automatically check all
3039 // inherited members, so we don't need to do this here. However, this only
3040 // works if we already used the cache in the first iteration of this loop.
3042 // If we used the cache in any further iteration, we can still terminate the
3043 // loop since the cache always looks in all base classes.
3046 if (used_cache)
3047 searching = false;
3048 else
3049 skip_iface_check = false;
3051 if (current_type == TypeManager.object_type)
3052 searching = false;
3053 else {
3054 current_type = current_type.BaseType;
3057 // This happens with interfaces, they have a null
3058 // basetype. Look members up in the Object class.
3060 if (current_type == null) {
3061 current_type = TypeManager.object_type;
3062 searching = true;
3066 if (list.Length == 0)
3067 continue;
3070 // Events and types are returned by both `static' and `instance'
3071 // searches, which means that our above FindMembers will
3072 // return two copies of the same.
3074 if (list.Length == 1 && !(list [0] is MethodBase)){
3075 return list;
3079 // Multiple properties: we query those just to find out the indexer
3080 // name
3082 if (list [0] is PropertyInfo)
3083 return list;
3086 // We found an event: the cache lookup returns both the event and
3087 // its private field.
3089 if (list [0] is EventInfo) {
3090 if ((list.Length == 2) && (list [1] is FieldInfo))
3091 return new MemberInfo [] { list [0] };
3093 return list;
3097 // We found methods, turn the search into "method scan"
3098 // mode.
3101 if (first_members_list != null) {
3102 if (use_first_members_list) {
3103 method_list = CopyNewMethods (method_list, first_members_list);
3104 use_first_members_list = false;
3107 method_list = CopyNewMethods (method_list, list);
3108 } else {
3109 first_members_list = list;
3110 use_first_members_list = true;
3111 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3113 } while (searching);
3115 if (use_first_members_list)
3116 return first_members_list;
3118 if (method_list != null && method_list.Count > 0) {
3119 return method_list.ToArray ();
3122 // This happens if we already used the cache in the first iteration, in this case
3123 // the cache already looked in all interfaces.
3125 if (skip_iface_check)
3126 return null;
3129 // Interfaces do not list members they inherit, so we have to
3130 // scan those.
3132 if (!queried_type.IsInterface)
3133 return null;
3135 if (queried_type.IsArray)
3136 queried_type = TypeManager.array_type;
3138 Type [] ifaces = GetInterfaces (queried_type);
3139 if (ifaces == null)
3140 return null;
3142 foreach (Type itype in ifaces){
3143 MemberInfo [] x;
3145 x = MemberLookup (null, null, itype, mt, bf, name, null);
3146 if (x != null)
3147 return x;
3150 return null;
3153 public const BindingFlags AllMembers = BindingFlags.Public | BindingFlags.NonPublic |
3154 BindingFlags.Static | BindingFlags.Instance |
3155 BindingFlags.DeclaredOnly;
3157 // Currently is designed to work with external types only
3158 public static PropertyInfo GetPropertyFromAccessor (MethodBase mb)
3160 if (!mb.IsSpecialName)
3161 return null;
3163 string name = mb.Name;
3164 if (name.Length < 5)
3165 return null;
3167 if (name [3] != '_')
3168 return null;
3170 if (name.StartsWith ("get") || name.StartsWith ("set")) {
3171 MemberInfo[] pi = mb.DeclaringType.FindMembers (MemberTypes.Property, AllMembers,
3172 Type.FilterName, name.Substring (4));
3174 if (pi == null)
3175 return null;
3177 // This can happen when property is indexer (it can have same name but different parameters)
3178 foreach (PropertyInfo p in pi) {
3179 foreach (MethodInfo p_mi in p.GetAccessors (true)) {
3180 if (p_mi == mb || TypeManager.GetParameterData (p_mi).Equals (TypeManager.GetParameterData (mb)))
3181 return p;
3186 return null;
3189 // Currently is designed to work with external types only
3190 public static MemberInfo GetEventFromAccessor (MethodBase mb)
3192 if (!mb.IsSpecialName)
3193 return null;
3195 string name = mb.Name;
3196 if (name.Length < 5)
3197 return null;
3199 if (name.StartsWith ("add_"))
3200 return mb.DeclaringType.GetEvent (name.Substring (4), AllMembers);
3202 if (name.StartsWith ("remove_"))
3203 return mb.DeclaringType.GetEvent (name.Substring (7), AllMembers);
3205 return null;
3208 // Tests whether external method is really special
3209 public static bool IsSpecialMethod (MethodBase mb)
3211 if (!mb.IsSpecialName)
3212 return false;
3214 IMethodData md = TypeManager.GetMethod (mb);
3215 if (md != null)
3216 return (md is AbstractPropertyEventMethod || md is Operator);
3218 PropertyInfo pi = GetPropertyFromAccessor (mb);
3219 if (pi != null)
3220 return IsValidProperty (pi);
3222 if (GetEventFromAccessor (mb) != null)
3223 return true;
3225 string name = mb.Name;
3226 if (name.StartsWith ("op_"))
3227 return Operator.GetName (name) != null;
3229 return false;
3232 // Tests whether imported property is valid C# property.
3233 // TODO: It seems to me that we should do a lot of sanity tests before
3234 // we accept property as C# property
3235 static bool IsValidProperty (PropertyInfo pi)
3237 MethodInfo get_method = pi.GetGetMethod (true);
3238 MethodInfo set_method = pi.GetSetMethod (true);
3239 int g_count = 0;
3240 int s_count = 0;
3241 if (get_method != null && set_method != null) {
3242 g_count = get_method.GetParameters ().Length;
3243 s_count = set_method.GetParameters ().Length;
3244 if (g_count + 1 != s_count)
3245 return false;
3246 } else if (get_method != null) {
3247 g_count = get_method.GetParameters ().Length;
3248 } else if (set_method != null) {
3249 s_count = set_method.GetParameters ().Length;
3253 // DefaultMemberName and indexer name has to match to identify valid C# indexer
3255 PredefinedAttribute pa = PredefinedAttributes.Get.DefaultMember;
3256 if ((s_count > 1 || g_count > 0) && pa.IsDefined) {
3257 object[] o = pi.DeclaringType.GetCustomAttributes (pa.Type, false);
3258 if (o.Length == 0)
3259 return false;
3261 DefaultMemberAttribute dma = (DefaultMemberAttribute) o [0];
3262 if (dma.MemberName != pi.Name)
3263 return false;
3264 if (get_method != null && "get_" + dma.MemberName != get_method.Name)
3265 return false;
3266 if (set_method != null && "set_" + dma.MemberName != set_method.Name)
3267 return false;
3270 return true;
3273 #endregion
3277 class InternalType
3279 public static readonly Type AnonymousMethod = typeof (AnonymousMethodBody);
3280 public static readonly Type Arglist = typeof (ArglistAccess);
3281 public static readonly Type Dynamic = new DynamicType ();
3282 public static readonly Type MethodGroup = typeof (MethodGroupExpr);
3285 /// <summary>
3286 /// There is exactly one instance of this class per type.
3287 /// </summary>
3288 sealed class TypeHandle : IMemberContainer {
3289 public readonly IMemberContainer BaseType;
3291 readonly int id = ++next_id;
3292 static int next_id = 0;
3294 static TypeHandle ()
3296 Reset ();
3299 /// <summary>
3300 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3301 /// a TypeHandle yet, a new instance of it is created. This static method
3302 /// ensures that we'll only have one TypeHandle instance per type.
3303 /// </summary>
3304 private static TypeHandle GetTypeHandle (Type t)
3306 TypeHandle handle;
3307 if (type_hash.TryGetValue (t, out handle))
3308 return handle;
3310 handle = new TypeHandle (t);
3311 type_hash.Add (t, handle);
3312 return handle;
3315 public static MemberCache GetMemberCache (Type t)
3317 return GetTypeHandle (t).MemberCache;
3320 public static void CleanUp ()
3322 type_hash = null;
3325 public static void Reset ()
3327 type_hash = new Dictionary<Type, TypeHandle> (ReferenceEquality<Type>.Default);
3330 /// <summary>
3331 /// Returns the TypeHandle for TypeManager.object_type.
3332 /// </summary>
3333 public static IMemberContainer ObjectType {
3334 get {
3335 if (object_type != null)
3336 return object_type;
3338 object_type = GetTypeHandle (TypeManager.object_type);
3340 return object_type;
3344 /// <summary>
3345 /// Returns the TypeHandle for TypeManager.array_type.
3346 /// </summary>
3347 public static TypeHandle ArrayType {
3348 get {
3349 if (array_type != null)
3350 return array_type;
3352 array_type = GetTypeHandle (TypeManager.array_type);
3354 return array_type;
3358 static Dictionary<Type, TypeHandle> type_hash;
3360 private static TypeHandle object_type;
3361 private static TypeHandle array_type;
3363 private Type type;
3364 private string full_name;
3365 private bool is_interface;
3366 private MemberCache member_cache;
3367 private MemberCache base_cache;
3369 private TypeHandle (Type type)
3371 this.type = type;
3372 full_name = type.FullName != null ? type.FullName : type.Name;
3373 if (type.BaseType != null) {
3374 base_cache = TypeManager.LookupMemberCache (type.BaseType);
3375 BaseType = base_cache.Container;
3376 } else if (type.IsInterface)
3377 base_cache = TypeManager.LookupBaseInterfacesCache (type);
3378 this.is_interface = type.IsInterface || TypeManager.IsGenericParameter (type);
3379 this.member_cache = new MemberCache (this);
3382 // IMemberContainer methods
3384 public string Name {
3385 get {
3386 return full_name;
3390 public Type Type {
3391 get {
3392 return type;
3396 public MemberCache BaseCache {
3397 get {
3398 return base_cache;
3402 public bool IsInterface {
3403 get {
3404 return is_interface;
3408 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3410 MemberInfo [] members;
3412 if (type is GenericTypeParameterBuilder)
3413 return MemberList.Empty;
3415 #if MS_COMPATIBLE
3416 type = TypeManager.DropGenericTypeArguments (type);
3417 #endif
3418 if (mt == MemberTypes.Event)
3419 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3420 else
3421 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3422 null, null);
3424 if (members.Length == 0)
3425 return MemberList.Empty;
3427 Array.Reverse (members);
3428 return new MemberList (members);
3431 // IMemberFinder methods
3433 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3434 MemberFilter filter, object criteria)
3436 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3439 public MemberCache MemberCache {
3440 get {
3441 return member_cache;
3445 public override string ToString ()
3447 if (BaseType != null)
3448 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3449 else
3450 return "TypeHandle (" + id + "," + Name + ")";