* Version.cs (CompareTo, Equals): Make sure the versions for
[mono-project.git] / mcs / gmcs / typemanager.cs
blob2acf526722e78ef5140479788daf2b226b1d2317
1 //
2 // typemanager.cs: C# type manager
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
14 // We will eventually remove the SIMPLE_SPEEDUP, and should never change
15 // the behavior of the compilation. This can be removed if we rework
16 // the code to get a list of namespaces available.
18 #define SIMPLE_SPEEDUP
20 using System;
21 using System.IO;
22 using System.Globalization;
23 using System.Collections;
24 using System.Reflection;
25 using System.Reflection.Emit;
26 using System.Text;
27 using System.Text.RegularExpressions;
28 using System.Runtime.CompilerServices;
29 using System.Diagnostics;
31 namespace Mono.CSharp {
33 public 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 char_ptr_type;
48 static public Type short_type;
49 static public Type decimal_type;
50 static public Type bool_type;
51 static public Type sbyte_type;
52 static public Type byte_type;
53 static public Type ushort_type;
54 static public Type enum_type;
55 static public Type delegate_type;
56 static public Type multicast_delegate_type;
57 static public Type void_type;
58 static public Type null_type;
59 static public Type enumeration_type;
60 static public Type array_type;
61 static public Type runtime_handle_type;
62 static public Type icloneable_type;
63 static public Type type_type;
64 static public Type ienumerator_type;
65 static public Type ienumerable_type;
66 static public Type idisposable_type;
67 static public Type iconvertible_type;
68 static public Type default_member_type;
69 static public Type iasyncresult_type;
70 static public Type asynccallback_type;
71 static public Type intptr_type;
72 static public Type monitor_type;
73 static public Type runtime_field_handle_type;
74 static public Type runtime_argument_handle_type;
75 static public Type attribute_type;
76 static public Type attribute_usage_type;
77 static public Type decimal_constant_attribute_type;
78 static public Type dllimport_type;
79 static public Type unverifiable_code_type;
80 static public Type methodimpl_attr_type;
81 static public Type marshal_as_attr_type;
82 static public Type param_array_type;
83 static public Type guid_attr_type;
84 static public Type void_ptr_type;
85 static public Type indexer_name_type;
86 static public Type exception_type;
87 static public Type invalid_operation_exception_type;
88 static public Type not_supported_exception_type;
89 static public Type obsolete_attribute_type;
90 static public Type conditional_attribute_type;
91 static public Type in_attribute_type;
92 static public Type out_attribute_type;
93 static public Type anonymous_method_type;
94 static public Type cls_compliant_attribute_type;
95 static public Type typed_reference_type;
96 static public Type arg_iterator_type;
97 static public Type mbr_type;
98 static public Type struct_layout_attribute_type;
99 static public Type field_offset_attribute_type;
100 static public Type security_attr_type;
103 // An empty array of types
105 static public Type [] NoTypes;
106 static public TypeExpr [] NoTypeExprs;
110 // Expressions representing the internal types. Used during declaration
111 // definition.
113 static public TypeExpr system_object_expr, system_string_expr;
114 static public TypeExpr system_boolean_expr, system_decimal_expr;
115 static public TypeExpr system_single_expr, system_double_expr;
116 static public TypeExpr system_sbyte_expr, system_byte_expr;
117 static public TypeExpr system_int16_expr, system_uint16_expr;
118 static public TypeExpr system_int32_expr, system_uint32_expr;
119 static public TypeExpr system_int64_expr, system_uint64_expr;
120 static public TypeExpr system_char_expr, system_void_expr;
121 static public TypeExpr system_asynccallback_expr;
122 static public TypeExpr system_iasyncresult_expr;
123 static public TypeExpr system_valuetype_expr;
124 static public TypeExpr system_intptr_expr;
127 // This is only used when compiling corlib
129 static public Type system_int32_type;
130 static public Type system_array_type;
131 static public Type system_type_type;
132 static public Type system_assemblybuilder_type;
133 static public MethodInfo system_int_array_get_length;
134 static public MethodInfo system_int_array_get_rank;
135 static public MethodInfo system_object_array_clone;
136 static public MethodInfo system_int_array_get_length_int;
137 static public MethodInfo system_int_array_get_lower_bound_int;
138 static public MethodInfo system_int_array_get_upper_bound_int;
139 static public MethodInfo system_void_array_copyto_array_int;
143 // Internal, not really used outside
145 static Type runtime_helpers_type;
148 // These methods are called by code generated by the compiler
150 static public MethodInfo string_concat_string_string;
151 static public MethodInfo string_concat_string_string_string;
152 static public MethodInfo string_concat_string_string_string_string;
153 static public MethodInfo string_concat_string_dot_dot_dot;
154 static public MethodInfo string_concat_object_object;
155 static public MethodInfo string_concat_object_object_object;
156 static public MethodInfo string_concat_object_dot_dot_dot;
157 static public MethodInfo string_isinterneted_string;
158 static public MethodInfo system_type_get_type_from_handle;
159 static public MethodInfo object_getcurrent_void;
160 static public MethodInfo bool_movenext_void;
161 static public MethodInfo ienumerable_getenumerator_void;
162 static public MethodInfo void_reset_void;
163 static public MethodInfo void_dispose_void;
164 static public MethodInfo void_monitor_enter_object;
165 static public MethodInfo void_monitor_exit_object;
166 static public MethodInfo void_initializearray_array_fieldhandle;
167 static public MethodInfo int_getlength_int;
168 static public MethodInfo delegate_combine_delegate_delegate;
169 static public MethodInfo delegate_remove_delegate_delegate;
170 static public MethodInfo int_get_offset_to_string_data;
171 static public MethodInfo int_array_get_length;
172 static public MethodInfo int_array_get_rank;
173 static public MethodInfo object_array_clone;
174 static public MethodInfo int_array_get_length_int;
175 static public MethodInfo int_array_get_lower_bound_int;
176 static public MethodInfo int_array_get_upper_bound_int;
177 static public MethodInfo void_array_copyto_array_int;
180 // The attribute constructors.
182 static public ConstructorInfo object_ctor;
183 static public ConstructorInfo cons_param_array_attribute;
184 static public ConstructorInfo void_decimal_ctor_five_args;
185 static public ConstructorInfo void_decimal_ctor_int_arg;
186 static public ConstructorInfo unverifiable_code_ctor;
187 static public ConstructorInfo invalid_operation_ctor;
188 static public ConstructorInfo default_member_ctor;
189 static public ConstructorInfo decimal_constant_attribute_ctor;
191 // <remarks>
192 // Holds the Array of Assemblies that have been loaded
193 // (either because it is the default or the user used the
194 // -r command line option)
195 // </remarks>
196 static Assembly [] assemblies;
198 // <remarks>
199 // Keeps a list of modules. We used this to do lookups
200 // on the module using GetType -- needed for arrays
201 // </remarks>
202 static Module [] modules;
204 // <remarks>
205 // This is the type_cache from the assemblies to avoid
206 // hitting System.Reflection on every lookup.
207 // </summary>
208 static Hashtable types;
210 // <remarks>
211 // This is used to hotld the corresponding TypeContainer objects
212 // since we need this in FindMembers
213 // </remarks>
214 static Hashtable typecontainers;
216 // <remarks>
217 // Keeps track of those types that are defined by the
218 // user's program
219 // </remarks>
220 static ArrayList user_types;
222 static PtrHashtable builder_to_declspace;
224 static PtrHashtable builder_to_member_cache;
226 // <remarks>
227 // Tracks the interfaces implemented by typebuilders. We only
228 // enter those who do implement or or more interfaces
229 // </remarks>
230 static PtrHashtable builder_to_ifaces;
232 // <remarks>
233 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
234 // the arguments to the method
235 // </remarks>
236 static Hashtable method_arguments;
238 // <remarks>
239 // Maps PropertyBuilder to a Type array that contains
240 // the arguments to the indexer
241 // </remarks>
242 static Hashtable indexer_arguments;
244 // <remarks>
245 // Maybe `method_arguments' should be replaced and only
246 // method_internal_params should be kept?
247 // <remarks>
248 static Hashtable method_internal_params;
250 // <remarks>
251 // Keeps track of methods
252 // </remarks>
254 static Hashtable builder_to_method;
256 // <remarks>
257 // Contains all public types from referenced assemblies.
258 // This member is used only if CLS Compliance verification is required.
259 // </remarks>
260 public static Hashtable all_imported_types;
262 struct Signature {
263 public string name;
264 public Type [] args;
267 public static void CleanUp ()
269 // Lets get everything clean so that we can collect before generating code
270 assemblies = null;
271 modules = null;
272 types = null;
273 typecontainers = null;
274 user_types = null;
275 builder_to_declspace = null;
276 builder_to_member_cache = null;
277 builder_to_ifaces = null;
278 method_arguments = null;
279 indexer_arguments = null;
280 method_internal_params = null;
281 builder_to_method = null;
283 fields = null;
284 references = null;
285 negative_hits = null;
286 builder_to_constant = null;
287 fieldbuilders_to_fields = null;
288 events = null;
289 priv_fields_events = null;
290 properties = null;
292 CleanUpGenerics ();
293 TypeHandle.CleanUp ();
296 /// <summary>
297 /// A filter for Findmembers that uses the Signature object to
298 /// extract objects
299 /// </summary>
300 static bool SignatureFilter (MemberInfo mi, object criteria)
302 Signature sig = (Signature) criteria;
304 if (!(mi is MethodBase))
305 return false;
307 if (mi.Name != sig.name)
308 return false;
310 int count = sig.args.Length;
312 if (mi is MethodBuilder || mi is ConstructorBuilder){
313 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
315 if (candidate_args.Length != count)
316 return false;
318 for (int i = 0; i < count; i++)
319 if (candidate_args [i] != sig.args [i])
320 return false;
322 return true;
323 } else {
324 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
326 if (pars.Length != count)
327 return false;
329 for (int i = 0; i < count; i++)
330 if (pars [i].ParameterType != sig.args [i])
331 return false;
332 return true;
336 // A delegate that points to the filter above.
337 static MemberFilter signature_filter;
340 // These are expressions that represent some of the internal data types, used
341 // elsewhere
343 static void InitExpressionTypes ()
345 system_object_expr = new TypeLookupExpression ("System.Object");
346 system_string_expr = new TypeLookupExpression ("System.String");
347 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
348 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
349 system_single_expr = new TypeLookupExpression ("System.Single");
350 system_double_expr = new TypeLookupExpression ("System.Double");
351 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
352 system_byte_expr = new TypeLookupExpression ("System.Byte");
353 system_int16_expr = new TypeLookupExpression ("System.Int16");
354 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
355 system_int32_expr = new TypeLookupExpression ("System.Int32");
356 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
357 system_int64_expr = new TypeLookupExpression ("System.Int64");
358 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
359 system_char_expr = new TypeLookupExpression ("System.Char");
360 system_void_expr = new TypeLookupExpression ("System.Void");
361 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
362 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
363 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
364 system_intptr_expr = new TypeLookupExpression ("System.IntPtr");
367 static TypeManager ()
369 assemblies = new Assembly [0];
370 modules = null;
371 user_types = new ArrayList ();
373 types = new Hashtable ();
374 typecontainers = new Hashtable ();
376 builder_to_declspace = new PtrHashtable ();
377 builder_to_member_cache = new PtrHashtable ();
378 builder_to_method = new PtrHashtable ();
379 method_arguments = new PtrHashtable ();
380 method_internal_params = new PtrHashtable ();
381 indexer_arguments = new PtrHashtable ();
382 builder_to_ifaces = new PtrHashtable ();
384 NoTypes = new Type [0];
385 NoTypeExprs = new TypeExpr [0];
387 signature_filter = new MemberFilter (SignatureFilter);
388 InitGenerics ();
389 InitExpressionTypes ();
392 public static void HandleDuplicate (string name, Type t)
394 Type prev = (Type) types [name];
395 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
397 if (tc != null){
399 // This probably never happens, as we catch this before
401 Report.Error (-17, "The type `" + name + "' has already been defined.");
402 return;
405 tc = builder_to_declspace [t] as TypeContainer;
406 if (tc != null){
407 Report.Warning (
408 1595, "The type `" + name + "' is defined in an existing assembly;"+
409 " Using the new definition from: " + tc.Location);
410 } else {
411 Report.Warning (
412 1595, "The type `" + name + "' is defined in an existing assembly;");
415 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
417 types.Remove (name);
418 types.Add (name, t);
421 public static void AddUserType (string name, TypeBuilder t)
423 try {
424 types.Add (name, t);
425 } catch {
426 HandleDuplicate (name, t);
428 user_types.Add (t);
432 // This entry point is used by types that we define under the covers
434 public static void RegisterBuilder (Type tb, Type [] ifaces)
436 if (ifaces != null)
437 builder_to_ifaces [tb] = ifaces;
440 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc)
442 builder_to_declspace.Add (t, tc);
443 typecontainers.Add (name, tc);
444 AddUserType (name, t);
447 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
449 try {
450 types.Add (name, t);
451 } catch {
452 HandleDuplicate (name, t);
455 builder_to_declspace.Add (t, del);
458 public static void AddEnumType (string name, TypeBuilder t, Enum en)
460 try {
461 types.Add (name, t);
462 } catch {
463 HandleDuplicate (name, t);
465 builder_to_declspace.Add (t, en);
468 public static void AddMethod (MethodBase builder, IMethodData method)
470 builder_to_method.Add (builder, method);
473 public static IMethodData GetMethod (MethodBase builder)
475 return (IMethodData) builder_to_method [builder];
478 /// <summary>
479 /// Returns the DeclSpace whose Type is `t' or null if there is no
480 /// DeclSpace for `t' (ie, the Type comes from a library)
481 /// </summary>
482 public static DeclSpace LookupDeclSpace (Type t)
484 return builder_to_declspace [t] as DeclSpace;
487 /// <summary>
488 /// Returns the TypeContainer whose Type is `t' or null if there is no
489 /// TypeContainer for `t' (ie, the Type comes from a library)
490 /// </summary>
491 public static TypeContainer LookupTypeContainer (Type t)
493 return builder_to_declspace [t] as TypeContainer;
496 public static MemberCache LookupMemberCache (Type t)
498 if (t is TypeBuilder) {
499 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
500 if (container != null)
501 return container.MemberCache;
504 if (t is GenericTypeParameterBuilder) {
505 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
507 if (container != null)
508 return container.MemberCache;
511 return TypeHandle.GetMemberCache (t);
514 public static MemberCache LookupBaseInterfacesCache (Type t)
516 Type [] ifaces = t.GetInterfaces ();
518 if (ifaces != null && ifaces.Length == 1)
519 return LookupMemberCache (ifaces [0]);
521 // TODO: the builder_to_member_cache should be indexed by 'ifaces', not 't'
522 MemberCache cache = builder_to_member_cache [t] as MemberCache;
523 if (cache != null)
524 return cache;
526 cache = new MemberCache (ifaces);
527 builder_to_member_cache.Add (t, cache);
528 return cache;
531 public static TypeContainer LookupInterface (Type t)
533 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
534 if ((tc == null) || (tc.Kind != Kind.Interface))
535 return null;
537 return tc;
540 public static Delegate LookupDelegate (Type t)
542 return builder_to_declspace [t] as Delegate;
545 public static Enum LookupEnum (Type t)
547 return builder_to_declspace [t] as Enum;
550 public static Class LookupClass (Type t)
552 return (Class) builder_to_declspace [t];
555 /// <summary>
556 /// Registers an assembly to load types from.
557 /// </summary>
558 public static void AddAssembly (Assembly a)
560 foreach (Assembly assembly in assemblies) {
561 if (a == assembly)
562 return;
565 int top = assemblies.Length;
566 Assembly [] n = new Assembly [top + 1];
568 assemblies.CopyTo (n, 0);
570 n [top] = a;
571 assemblies = n;
574 public static Assembly [] GetAssemblies ()
576 return assemblies;
579 /// <summary>
580 /// Registers a module builder to lookup types from
581 /// </summary>
582 public static void AddModule (Module mb)
584 int top = modules != null ? modules.Length : 0;
585 Module [] n = new Module [top + 1];
587 if (modules != null)
588 modules.CopyTo (n, 0);
589 n [top] = mb;
590 modules = n;
593 public static Module[] Modules {
594 get {
595 return modules;
599 static Hashtable references = new Hashtable ();
602 // Gets the reference to T version of the Type (T&)
604 public static Type GetReferenceType (Type t)
606 return t.MakeByRefType ();
609 static Hashtable pointers = new Hashtable ();
612 // Gets the pointer to T version of the Type (T*)
614 public static Type GetPointerType (Type t)
616 string tname = t.FullName + "*";
618 Type ret = t.Assembly.GetType (tname);
621 // If the type comes from the assembly we are building
622 // We need the Hashtable, because .NET 1.1 will return different instance types
623 // every time we call ModuleBuilder.GetType.
625 if (ret == null){
626 if (pointers [t] == null)
627 pointers [t] = CodeGen.Module.Builder.GetType (tname);
629 ret = (Type) pointers [t];
632 return ret;
636 // Low-level lookup, cache-less
638 static Type LookupTypeReflection (string name)
640 Type t;
642 foreach (Assembly a in assemblies){
643 t = a.GetType (name);
644 if (t == null)
645 continue;
647 do {
648 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
649 if (ta == TypeAttributes.NotPublic ||
650 ta == TypeAttributes.NestedPrivate ||
651 ta == TypeAttributes.NestedAssembly ||
652 ta == TypeAttributes.NestedFamANDAssem){
655 // In .NET pointers turn out to be private, even if their
656 // element type is not
658 if (t.IsPointer){
659 t = t.GetElementType ();
660 continue;
661 } else
662 t = null;
663 } else {
664 return t;
666 } while (t != null);
669 foreach (Module mb in modules) {
670 t = mb.GetType (name);
671 if (t != null)
672 return t;
675 return null;
678 static Hashtable negative_hits = new Hashtable ();
681 // This function is used when you want to avoid the lookups, and want to go
682 // directly to the source. This will use the cache.
684 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
685 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
686 // way to test things other than doing a fullname compare
688 public static Type LookupTypeDirect (string name)
690 Type t = (Type) types [name];
691 if (t != null)
692 return t;
694 t = LookupTypeReflection (name);
695 if (t == null)
696 return null;
698 types [name] = t;
699 return t;
702 static readonly char [] dot_array = { '.' };
704 /// <summary>
705 /// Returns the Type associated with @name, takes care of the fact that
706 /// reflection expects nested types to be separated from the main type
707 /// with a "+" instead of a "."
708 /// </summary>
709 public static Type LookupType (string name)
711 Type t;
714 // First lookup in user defined and cached values
717 t = (Type) types [name];
718 if (t != null)
719 return t;
721 // Two thirds of the failures are caught here.
722 if (negative_hits.Contains (name))
723 return null;
725 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
726 string [] elements = name.Split (dot_array);
727 int count = elements.Length;
729 for (int n = 1; n <= count; n++){
730 string top_level_type = String.Join (".", elements, 0, n);
732 // One third of the failures are caught here.
733 if (negative_hits.Contains (top_level_type))
734 continue;
736 t = (Type) types [top_level_type];
737 if (t == null){
738 t = LookupTypeReflection (top_level_type);
739 if (t == null){
740 negative_hits [top_level_type] = null;
741 continue;
745 if (count == n){
746 types [name] = t;
747 return t;
751 // We know that System.Object does not have children, and since its the base of
752 // all the objects, it always gets probbed for inner classes.
754 if (top_level_type == "System.Object")
755 return null;
757 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
758 //Console.WriteLine ("Looking up: " + newt + " " + name);
759 t = LookupTypeReflection (newt);
760 if (t == null)
761 negative_hits [name] = null;
762 else
763 types [name] = t;
764 return t;
766 negative_hits [name] = null;
767 return null;
770 /// <summary>
771 /// Computes the namespaces that we import from the assemblies we reference.
772 /// </summary>
773 public static void ComputeNamespaces ()
775 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
778 // First add the assembly namespaces
780 if (assembly_get_namespaces != null){
781 int count = assemblies.Length;
783 for (int i = 0; i < count; i++){
784 Assembly a = assemblies [i];
785 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
786 foreach (string ns in namespaces){
787 if (ns == "")
788 continue;
789 Namespace.LookupNamespace (ns, true);
792 } else {
793 Hashtable cache = new Hashtable ();
794 cache.Add ("", null);
795 foreach (Assembly a in assemblies) {
796 foreach (Type t in a.GetExportedTypes ()) {
797 string ns = t.Namespace;
798 if (ns == null || cache.Contains (ns))
799 continue;
801 Namespace.LookupNamespace (ns, true);
802 cache.Add (ns, null);
808 /// <summary>
809 /// Fills static table with exported types from all referenced assemblies.
810 /// This information is required for CLS Compliance tests.
811 /// </summary>
812 public static void LoadAllImportedTypes ()
814 all_imported_types = new Hashtable ();
815 foreach (Assembly a in assemblies) {
816 foreach (Type t in a.GetExportedTypes ()) {
817 all_imported_types [t.FullName] = t;
822 public static bool NamespaceClash (string name, Location loc)
824 if (Namespace.LookupNamespace (name, false) == null)
825 return false;
827 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
828 return true;
831 /// <summary>
832 /// Returns the C# name of a type if possible, or the full type name otherwise
833 /// </summary>
834 static public string CSharpName (Type t)
836 if (t.FullName == null)
837 return t.Name;
839 return Regex.Replace (t.FullName,
840 @"^System\." +
841 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
842 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
843 @"Boolean|String|Void|Null)" +
844 @"(\W+|\b)",
845 new MatchEvaluator (CSharpNameMatch)).Replace ('+', '.');
848 static String CSharpNameMatch (Match match)
850 string s = match.Groups [1].Captures [0].Value;
851 return s.ToLower ().
852 Replace ("int32", "int").
853 Replace ("uint32", "uint").
854 Replace ("int16", "short").
855 Replace ("uint16", "ushort").
856 Replace ("int64", "long").
857 Replace ("uint64", "ulong").
858 Replace ("single", "float").
859 Replace ("boolean", "bool")
860 + match.Groups [2].Captures [0].Value;
863 /// <summary>
864 /// Returns the signature of the method with full namespace classification
865 /// </summary>
866 static public string GetFullNameSignature (MemberInfo mi)
868 // Unfortunately, there's no dynamic dispatch on the arguments of a function.
869 return (mi is MethodBase)
870 ? GetFullNameSignature (mi as MethodBase)
871 : mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
874 static public string GetFullNameSignature (MethodBase mb)
876 string name = mb.Name;
877 if (name == ".ctor")
878 name = mb.DeclaringType.Name;
880 if (mb.IsSpecialName) {
881 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
882 name = name.Remove (0, 4);
885 if (name == "Item")
886 name = "this";
889 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
892 static public string GetFullName (Type t)
894 if (t.FullName == null)
895 return t.Name;
897 string name = t.FullName.Replace ('+', '.');
899 DeclSpace tc = LookupDeclSpace (t);
900 if ((tc != null) && tc.IsGeneric) {
901 TypeParameter[] tparam = tc.TypeParameters;
903 StringBuilder sb = new StringBuilder (name);
904 sb.Append ("<");
905 for (int i = 0; i < tparam.Length; i++) {
906 if (i > 0)
907 sb.Append (",");
908 sb.Append (tparam [i].Name);
910 sb.Append (">");
911 return sb.ToString ();
912 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
913 Type[] tparam = t.GetGenericArguments ();
915 StringBuilder sb = new StringBuilder (name);
916 sb.Append ("<");
917 for (int i = 0; i < tparam.Length; i++) {
918 if (i > 0)
919 sb.Append (",");
920 sb.Append (tparam [i].Name);
922 sb.Append (">");
923 return sb.ToString ();
926 return name;
929 /// <summary>
930 /// Returns the signature of the property and indexer
931 /// </summary>
932 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
934 if (!is_indexer) {
935 return GetFullNameSignature (pb);
938 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
939 string signature = GetFullNameSignature (mb);
940 string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
941 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
944 /// <summary>
945 /// Returns the signature of the method
946 /// </summary>
947 static public string CSharpSignature (MethodBase mb)
949 StringBuilder sig = new StringBuilder ("(");
952 // FIXME: We should really have a single function to do
953 // everything instead of the following 5 line pattern
955 ParameterData iparams = LookupParametersByBuilder (mb);
957 if (iparams == null)
958 iparams = new ReflectionParameters (mb);
960 // Is property
961 if (mb.IsSpecialName && iparams.Count == 0 && !mb.IsConstructor)
962 return GetFullNameSignature (mb);
964 for (int i = 0; i < iparams.Count; i++) {
965 if (i > 0) {
966 sig.Append (", ");
968 sig.Append (iparams.ParameterDesc (i));
970 sig.Append (")");
972 // Is indexer
973 if (mb.IsSpecialName && iparams.Count == 1 && !mb.IsConstructor) {
974 sig.Replace ('(', '[');
975 sig.Replace (')', ']');
978 return GetFullNameSignature (mb) + sig.ToString ();
981 public static string GetMethodName (MethodInfo m)
983 if (!IsGenericMethod (m))
984 return m.Name;
986 return MemberName.MakeName (m.Name, m.GetGenericArguments ().Length);
989 /// <summary>
990 /// Looks up a type, and aborts if it is not found. This is used
991 /// by types required by the compiler
992 /// </summary>
993 static Type CoreLookupType (string name)
995 Type t = LookupTypeDirect (name);
997 if (t == null){
998 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
999 Environment.Exit (1);
1002 return t;
1005 /// <summary>
1006 /// Returns the MethodInfo for a method named `name' defined
1007 /// in type `t' which takes arguments of types `args'
1008 /// </summary>
1009 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1011 MemberList list;
1012 Signature sig;
1013 BindingFlags flags = instance_and_static | BindingFlags.Public;
1015 sig.name = name;
1016 sig.args = args;
1018 if (is_private)
1019 flags |= BindingFlags.NonPublic;
1021 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1022 if (list.Count == 0) {
1023 if (report_errors)
1024 Report.Error (-19, "Can not find the core function `" + name + "'");
1025 return null;
1028 MethodInfo mi = list [0] as MethodInfo;
1029 if (mi == null) {
1030 if (report_errors)
1031 Report.Error (-19, "Can not find the core function `" + name + "'");
1032 return null;
1035 return mi;
1038 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1040 return GetMethod (t, name, args, false, report_errors);
1043 static MethodInfo GetMethod (Type t, string name, Type [] args)
1045 return GetMethod (t, name, args, true);
1049 /// <summary>
1050 /// Returns the ConstructorInfo for "args"
1051 /// </summary>
1052 static ConstructorInfo GetConstructor (Type t, Type [] args)
1054 MemberList list;
1055 Signature sig;
1057 sig.name = ".ctor";
1058 sig.args = args;
1060 list = FindMembers (t, MemberTypes.Constructor,
1061 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1062 signature_filter, sig);
1063 if (list.Count == 0){
1064 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1065 return null;
1068 ConstructorInfo ci = list [0] as ConstructorInfo;
1069 if (ci == null){
1070 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1071 return null;
1074 return ci;
1077 public static void InitEnumUnderlyingTypes ()
1080 int32_type = CoreLookupType ("System.Int32");
1081 int64_type = CoreLookupType ("System.Int64");
1082 uint32_type = CoreLookupType ("System.UInt32");
1083 uint64_type = CoreLookupType ("System.UInt64");
1084 byte_type = CoreLookupType ("System.Byte");
1085 sbyte_type = CoreLookupType ("System.SByte");
1086 short_type = CoreLookupType ("System.Int16");
1087 ushort_type = CoreLookupType ("System.UInt16");
1090 /// <remarks>
1091 /// The types have to be initialized after the initial
1092 /// population of the type has happened (for example, to
1093 /// bootstrap the corlib.dll
1094 /// </remarks>
1095 public static void InitCoreTypes ()
1097 object_type = CoreLookupType ("System.Object");
1098 value_type = CoreLookupType ("System.ValueType");
1100 InitEnumUnderlyingTypes ();
1102 char_type = CoreLookupType ("System.Char");
1103 string_type = CoreLookupType ("System.String");
1104 float_type = CoreLookupType ("System.Single");
1105 double_type = CoreLookupType ("System.Double");
1106 char_ptr_type = CoreLookupType ("System.Char*");
1107 decimal_type = CoreLookupType ("System.Decimal");
1108 bool_type = CoreLookupType ("System.Boolean");
1109 enum_type = CoreLookupType ("System.Enum");
1111 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1112 delegate_type = CoreLookupType ("System.Delegate");
1114 array_type = CoreLookupType ("System.Array");
1115 void_type = CoreLookupType ("System.Void");
1116 type_type = CoreLookupType ("System.Type");
1118 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1119 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1120 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1121 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1122 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1123 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1124 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1125 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1126 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1127 idisposable_type = CoreLookupType ("System.IDisposable");
1128 icloneable_type = CoreLookupType ("System.ICloneable");
1129 iconvertible_type = CoreLookupType ("System.IConvertible");
1130 monitor_type = CoreLookupType ("System.Threading.Monitor");
1131 intptr_type = CoreLookupType ("System.IntPtr");
1133 attribute_type = CoreLookupType ("System.Attribute");
1134 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1135 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1136 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1137 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1138 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1139 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1140 out_attribute_type = CoreLookupType ("System.Runtime.InteropServices.OutAttribute");
1141 typed_reference_type = CoreLookupType ("System.TypedReference");
1142 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1143 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1144 decimal_constant_attribute_type = CoreLookupType ("System.Runtime.CompilerServices.DecimalConstantAttribute");
1147 // Sigh. Remove this before the release. Wonder what versions of Mono
1148 // people are running.
1150 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1152 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1154 void_ptr_type = CoreLookupType ("System.Void*");
1156 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1158 exception_type = CoreLookupType ("System.Exception");
1159 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1160 not_supported_exception_type = CoreLookupType ("System.NotSupportedException");
1163 // Attribute types
1165 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1166 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1167 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1168 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1169 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1170 security_attr_type = CoreLookupType ("System.Security.Permissions.SecurityAttribute");
1172 InitGenericCoreTypes ();
1175 // When compiling corlib, store the "real" types here.
1177 if (!RootContext.StdLib) {
1178 system_int32_type = typeof (System.Int32);
1179 system_array_type = typeof (System.Array);
1180 system_type_type = typeof (System.Type);
1181 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1183 Type [] void_arg = { };
1184 system_int_array_get_length = GetMethod (
1185 system_array_type, "get_Length", void_arg);
1186 system_int_array_get_rank = GetMethod (
1187 system_array_type, "get_Rank", void_arg);
1188 system_object_array_clone = GetMethod (
1189 system_array_type, "Clone", void_arg);
1191 Type [] system_int_arg = { system_int32_type };
1192 system_int_array_get_length_int = GetMethod (
1193 system_array_type, "GetLength", system_int_arg);
1194 system_int_array_get_upper_bound_int = GetMethod (
1195 system_array_type, "GetUpperBound", system_int_arg);
1196 system_int_array_get_lower_bound_int = GetMethod (
1197 system_array_type, "GetLowerBound", system_int_arg);
1199 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1200 system_void_array_copyto_array_int = GetMethod (
1201 system_array_type, "CopyTo", system_array_int_arg);
1203 Type [] system_3_type_arg = {
1204 system_type_type, system_type_type, system_type_type };
1205 Type [] system_4_type_arg = {
1206 system_type_type, system_type_type, system_type_type, system_type_type };
1208 MethodInfo set_corlib_type_builders = GetMethod (
1209 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1210 system_4_type_arg, true, false);
1212 if (set_corlib_type_builders != null) {
1213 object[] args = new object [4];
1214 args [0] = object_type;
1215 args [1] = value_type;
1216 args [2] = enum_type;
1217 args [3] = void_type;
1219 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1220 } else {
1221 // Compatibility for an older version of the class libs.
1222 set_corlib_type_builders = GetMethod (
1223 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1224 system_3_type_arg, true, true);
1226 if (set_corlib_type_builders == null) {
1227 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1228 return;
1231 object[] args = new object [3];
1232 args [0] = object_type;
1233 args [1] = value_type;
1234 args [2] = enum_type;
1236 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1240 system_object_expr.Type = object_type;
1241 system_string_expr.Type = string_type;
1242 system_boolean_expr.Type = bool_type;
1243 system_decimal_expr.Type = decimal_type;
1244 system_single_expr.Type = float_type;
1245 system_double_expr.Type = double_type;
1246 system_sbyte_expr.Type = sbyte_type;
1247 system_byte_expr.Type = byte_type;
1248 system_int16_expr.Type = short_type;
1249 system_uint16_expr.Type = ushort_type;
1250 system_int32_expr.Type = int32_type;
1251 system_uint32_expr.Type = uint32_type;
1252 system_int64_expr.Type = int64_type;
1253 system_uint64_expr.Type = uint64_type;
1254 system_char_expr.Type = char_type;
1255 system_void_expr.Type = void_type;
1256 system_asynccallback_expr.Type = asynccallback_type;
1257 system_iasyncresult_expr.Type = iasyncresult_type;
1258 system_valuetype_expr.Type = value_type;
1261 // These are only used for compare purposes
1263 anonymous_method_type = typeof (AnonymousMethod);
1264 null_type = typeof (NullType);
1268 // The helper methods that are used by the compiler
1270 public static void InitCodeHelpers ()
1273 // Now load the default methods that we use.
1275 Type [] string_string = { string_type, string_type };
1276 string_concat_string_string = GetMethod (
1277 string_type, "Concat", string_string);
1278 Type [] string_string_string = { string_type, string_type, string_type };
1279 string_concat_string_string_string = GetMethod (
1280 string_type, "Concat", string_string_string);
1281 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1282 string_concat_string_string_string_string = GetMethod (
1283 string_type, "Concat", string_string_string_string);
1284 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1285 string_concat_string_dot_dot_dot = GetMethod (
1286 string_type, "Concat", params_string);
1288 Type [] object_object = { object_type, object_type };
1289 string_concat_object_object = GetMethod (
1290 string_type, "Concat", object_object);
1291 Type [] object_object_object = { object_type, object_type, object_type };
1292 string_concat_object_object_object = GetMethod (
1293 string_type, "Concat", object_object_object);
1294 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1295 string_concat_object_dot_dot_dot = GetMethod (
1296 string_type, "Concat", params_object);
1298 Type [] string_ = { string_type };
1299 string_isinterneted_string = GetMethod (
1300 string_type, "IsInterned", string_);
1302 Type [] runtime_type_handle = { runtime_handle_type };
1303 system_type_get_type_from_handle = GetMethod (
1304 type_type, "GetTypeFromHandle", runtime_type_handle);
1306 Type [] delegate_delegate = { delegate_type, delegate_type };
1307 delegate_combine_delegate_delegate = GetMethod (
1308 delegate_type, "Combine", delegate_delegate);
1310 delegate_remove_delegate_delegate = GetMethod (
1311 delegate_type, "Remove", delegate_delegate);
1314 // Void arguments
1316 Type [] void_arg = { };
1317 object_getcurrent_void = GetMethod (
1318 ienumerator_type, "get_Current", void_arg);
1319 bool_movenext_void = GetMethod (
1320 ienumerator_type, "MoveNext", void_arg);
1321 void_reset_void = GetMethod (
1322 ienumerator_type, "Reset", void_arg);
1323 void_dispose_void = GetMethod (
1324 idisposable_type, "Dispose", void_arg);
1325 int_get_offset_to_string_data = GetMethod (
1326 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1327 int_array_get_length = GetMethod (
1328 array_type, "get_Length", void_arg);
1329 int_array_get_rank = GetMethod (
1330 array_type, "get_Rank", void_arg);
1331 ienumerable_getenumerator_void = GetMethod (
1332 ienumerable_type, "GetEnumerator", void_arg);
1335 // Int32 arguments
1337 Type [] int_arg = { int32_type };
1338 int_array_get_length_int = GetMethod (
1339 array_type, "GetLength", int_arg);
1340 int_array_get_upper_bound_int = GetMethod (
1341 array_type, "GetUpperBound", int_arg);
1342 int_array_get_lower_bound_int = GetMethod (
1343 array_type, "GetLowerBound", int_arg);
1346 // System.Array methods
1348 object_array_clone = GetMethod (
1349 array_type, "Clone", void_arg);
1350 Type [] array_int_arg = { array_type, int32_type };
1351 void_array_copyto_array_int = GetMethod (
1352 array_type, "CopyTo", array_int_arg);
1355 // object arguments
1357 Type [] object_arg = { object_type };
1358 void_monitor_enter_object = GetMethod (
1359 monitor_type, "Enter", object_arg);
1360 void_monitor_exit_object = GetMethod (
1361 monitor_type, "Exit", object_arg);
1363 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1365 void_initializearray_array_fieldhandle = GetMethod (
1366 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1369 // Array functions
1371 int_getlength_int = GetMethod (
1372 array_type, "GetLength", int_arg);
1375 // Decimal constructors
1377 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1378 void_decimal_ctor_five_args = GetConstructor (
1379 decimal_type, dec_arg);
1381 void_decimal_ctor_int_arg = GetConstructor (decimal_type, int_arg);
1384 // Attributes
1386 cons_param_array_attribute = GetConstructor (
1387 param_array_type, void_arg);
1389 unverifiable_code_ctor = GetConstructor (
1390 unverifiable_code_type, void_arg);
1392 decimal_constant_attribute_ctor = GetConstructor (decimal_constant_attribute_type, new Type []
1393 { byte_type, byte_type, uint32_type, uint32_type, uint32_type } );
1395 default_member_ctor = GetConstructor (default_member_type, string_);
1398 // InvalidOperationException
1400 invalid_operation_ctor = GetConstructor (
1401 invalid_operation_exception_type, void_arg);
1404 // Object
1405 object_ctor = GetConstructor (object_type, void_arg);
1407 InitGenericCodeHelpers ();
1410 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1412 /// <remarks>
1413 /// This is the "old", non-cache based FindMembers() function. We cannot use
1414 /// the cache here because there is no member name argument.
1415 /// </remarks>
1416 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1417 MemberFilter filter, object criteria)
1419 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1422 // `builder_to_declspace' contains all dynamic types.
1424 if (decl != null) {
1425 MemberList list;
1426 Timer.StartTimer (TimerType.FindMembers);
1427 list = decl.FindMembers (mt, bf, filter, criteria);
1428 Timer.StopTimer (TimerType.FindMembers);
1429 return list;
1433 // We have to take care of arrays specially, because GetType on
1434 // a TypeBuilder array will return a Type, not a TypeBuilder,
1435 // and we can not call FindMembers on this type.
1437 if (t.IsSubclassOf (TypeManager.array_type))
1438 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1440 if (t is GenericTypeParameterBuilder) {
1441 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1443 Timer.StartTimer (TimerType.FindMembers);
1444 MemberList list = tparam.FindMembers (
1445 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1446 Timer.StopTimer (TimerType.FindMembers);
1447 return list;
1451 // Since FindMembers will not lookup both static and instance
1452 // members, we emulate this behaviour here.
1454 if ((bf & instance_and_static) == instance_and_static){
1455 MemberInfo [] i_members = t.FindMembers (
1456 mt, bf & ~BindingFlags.Static, filter, criteria);
1458 int i_len = i_members.Length;
1459 if (i_len == 1){
1460 MemberInfo one = i_members [0];
1463 // If any of these are present, we are done!
1465 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1466 return new MemberList (i_members);
1469 MemberInfo [] s_members = t.FindMembers (
1470 mt, bf & ~BindingFlags.Instance, filter, criteria);
1472 int s_len = s_members.Length;
1473 if (i_len > 0 || s_len > 0)
1474 return new MemberList (i_members, s_members);
1475 else {
1476 if (i_len > 0)
1477 return new MemberList (i_members);
1478 else
1479 return new MemberList (s_members);
1483 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1487 /// <summary>
1488 /// This method is only called from within MemberLookup. It tries to use the member
1489 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1490 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1491 /// our return value will already contain all inherited members and the caller don't need
1492 /// to check base classes and interfaces anymore.
1493 /// </summary>
1494 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1495 string name, out bool used_cache)
1497 MemberCache cache;
1500 // We have to take care of arrays specially, because GetType on
1501 // a TypeBuilder array will return a Type, not a TypeBuilder,
1502 // and we can not call FindMembers on this type.
1504 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1505 used_cache = true;
1506 return TypeHandle.ArrayType.MemberCache.FindMembers (
1507 mt, bf, name, FilterWithClosure_delegate, null);
1511 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1512 // and we can ask the DeclSpace for the MemberCache.
1514 if (t is TypeBuilder) {
1515 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1516 cache = decl.MemberCache;
1519 // If this DeclSpace has a MemberCache, use it.
1522 if (cache != null) {
1523 used_cache = true;
1524 return cache.FindMembers (
1525 mt, bf, name, FilterWithClosure_delegate, null);
1528 // If there is no MemberCache, we need to use the "normal" FindMembers.
1529 // Note, this is a VERY uncommon route!
1531 MemberList list;
1532 Timer.StartTimer (TimerType.FindMembers);
1533 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1534 FilterWithClosure_delegate, name);
1535 Timer.StopTimer (TimerType.FindMembers);
1536 used_cache = false;
1537 return (MemberInfo []) list;
1540 if (t is GenericTypeParameterBuilder) {
1541 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1543 MemberList list;
1544 Timer.StartTimer (TimerType.FindMembers);
1545 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1546 FilterWithClosure_delegate, name);
1547 Timer.StopTimer (TimerType.FindMembers);
1548 used_cache = false;
1549 return (MemberInfo []) list;
1553 // This call will always succeed. There is exactly one TypeHandle instance per
1554 // type, TypeHandle.GetMemberCache() will, if necessary, create a new one, and return
1555 // the corresponding MemberCache.
1557 cache = TypeHandle.GetMemberCache (t);
1559 used_cache = true;
1560 return cache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1563 public static bool IsBuiltinType (Type t)
1565 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1566 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1567 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1568 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1569 return true;
1570 else
1571 return false;
1574 public static bool IsBuiltinType (TypeContainer tc)
1576 return IsBuiltinType (tc.TypeBuilder);
1580 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1581 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1583 public static bool IsCLRType (Type t)
1585 if (t == object_type || t == int32_type || t == uint32_type ||
1586 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1587 t == char_type || t == short_type || t == bool_type ||
1588 t == sbyte_type || t == byte_type || t == ushort_type)
1589 return true;
1590 else
1591 return false;
1594 public static bool IsDelegateType (Type t)
1596 if (t.IsGenericInstance)
1597 t = t.GetGenericTypeDefinition ();
1599 if (t.IsSubclassOf (TypeManager.delegate_type))
1600 return true;
1601 else
1602 return false;
1605 public static bool IsEnumType (Type t)
1607 if (t.IsSubclassOf (TypeManager.enum_type))
1608 return true;
1609 else
1610 return false;
1612 public static bool IsBuiltinOrEnum (Type t)
1614 if (IsBuiltinType (t))
1615 return true;
1617 if (IsEnumType (t))
1618 return true;
1620 return false;
1623 public static bool IsNullType (Type t)
1625 return t == null_type;
1629 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1631 public static bool IsUnmanagedType (Type t)
1633 if (IsBuiltinType (t) && t != TypeManager.string_type)
1634 return true;
1636 if (IsEnumType (t))
1637 return true;
1639 if (t.IsPointer)
1640 return true;
1642 if (IsValueType (t)){
1643 if (t is TypeBuilder){
1644 TypeContainer tc = LookupTypeContainer (t);
1646 if (tc.Fields != null){
1647 foreach (Field f in tc.Fields){
1648 if (f.FieldBuilder.IsStatic)
1649 continue;
1650 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1651 return false;
1653 } else
1654 return true;
1655 } else {
1656 FieldInfo [] fields = t.GetFields ();
1658 foreach (FieldInfo f in fields){
1659 if (f.IsStatic)
1660 continue;
1661 if (!IsUnmanagedType (f.FieldType))
1662 return false;
1665 return true;
1668 return false;
1671 public static bool IsValueType (Type t)
1673 return t.IsGenericParameter || t.IsValueType;
1676 public static bool IsInterfaceType (Type t)
1678 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1679 if (tc == null)
1680 return false;
1682 return tc.Kind == Kind.Interface;
1685 public static bool IsSubclassOf (Type type, Type base_type)
1687 TypeParameter tparam = LookupTypeParameter (type);
1688 TypeParameter pparam = LookupTypeParameter (base_type);
1690 if ((tparam != null) && (pparam != null)) {
1691 if (tparam == pparam)
1692 return true;
1694 return tparam.IsSubclassOf (base_type);
1697 do {
1698 if (type.Equals (base_type))
1699 return true;
1701 type = type.BaseType;
1702 } while (type != null);
1704 return false;
1707 public static bool IsPrivateAccessible (Type type, Type parent)
1709 if (type.Equals (parent))
1710 return true;
1712 if ((type is TypeBuilder) && type.IsGenericTypeDefinition && parent.IsGenericInstance) {
1714 // `a' is a generic type definition's TypeBuilder and `b' is a
1715 // generic instance of the same type.
1717 // Example:
1719 // class Stack<T>
1720 // {
1721 // void Test (Stack<T> stack) { }
1722 // }
1724 // The first argument of `Test' will be the generic instance
1725 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1728 // We hit this via Closure.Filter() for gen-82.cs.
1730 if (type != parent.GetGenericTypeDefinition ())
1731 return false;
1733 return true;
1736 if (type.IsGenericInstance && parent.IsGenericInstance) {
1737 if (type.GetGenericTypeDefinition () != parent.GetGenericTypeDefinition ())
1738 return false;
1740 return true;
1743 return false;
1746 public static bool IsFamilyAccessible (Type type, Type parent)
1748 TypeParameter tparam = LookupTypeParameter (type);
1749 TypeParameter pparam = LookupTypeParameter (parent);
1751 if ((tparam != null) && (pparam != null)) {
1752 if (tparam == pparam)
1753 return true;
1755 return tparam.IsSubclassOf (parent);
1758 do {
1759 if (IsEqualGenericInstance (type, parent))
1760 return true;
1762 type = type.BaseType;
1763 } while (type != null);
1765 return false;
1769 // Checks whether `type' is a subclass or nested child of `base_type'.
1771 public static bool IsNestedFamilyAccessible (Type type, Type base_type)
1773 do {
1774 if (IsFamilyAccessible (type, base_type))
1775 return true;
1777 // Handle nested types.
1778 type = type.DeclaringType;
1779 } while (type != null);
1781 return false;
1785 // Checks whether `type' is a nested child of `parent'.
1787 public static bool IsNestedChildOf (Type type, Type parent)
1789 if (IsEqual (type, parent))
1790 return false;
1792 type = type.DeclaringType;
1793 while (type != null) {
1794 if (IsEqual (type, parent))
1795 return true;
1797 type = type.DeclaringType;
1800 return false;
1804 // Do the right thing when returning the element type of an
1805 // array type based on whether we are compiling corlib or not
1807 public static Type GetElementType (Type t)
1809 if (RootContext.StdLib)
1810 return t.GetElementType ();
1811 else
1812 return TypeToCoreType (t.GetElementType ());
1815 /// <summary>
1816 /// Returns the User Defined Types
1817 /// </summary>
1818 public static ArrayList UserTypes {
1819 get {
1820 return user_types;
1824 public static Hashtable TypeContainers {
1825 get {
1826 return typecontainers;
1830 static Hashtable builder_to_constant;
1832 public static void RegisterConstant (FieldBuilder fb, Const c)
1834 if (builder_to_constant == null)
1835 builder_to_constant = new PtrHashtable ();
1837 if (builder_to_constant.Contains (fb))
1838 return;
1840 builder_to_constant.Add (fb, c);
1843 public static Const LookupConstant (FieldBuilder fb)
1845 if (builder_to_constant == null)
1846 return null;
1848 return (Const) builder_to_constant [fb];
1851 /// <summary>
1852 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1853 /// </summary>
1855 /// <remarks>
1856 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1857 /// for anything which is dynamic, and we need this in a number of places,
1858 /// we register this information here, and use it afterwards.
1859 /// </remarks>
1860 static public void RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1862 if (args == null)
1863 args = NoTypes;
1865 method_arguments.Add (mb, args);
1866 method_internal_params.Add (mb, ip);
1869 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1871 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1872 return null;
1874 if (method_internal_params.Contains (mb))
1875 return (InternalParameters) method_internal_params [mb];
1876 else
1877 throw new Exception ("Argument for Method not registered" + mb);
1880 /// <summary>
1881 /// Returns the argument types for a method based on its methodbase
1883 /// For dynamic methods, we use the compiler provided types, for
1884 /// methods from existing assemblies we load them from GetParameters,
1885 /// and insert them into the cache
1886 /// </summary>
1887 static public Type [] GetArgumentTypes (MethodBase mb)
1889 object t = method_arguments [mb];
1890 if (t != null)
1891 return (Type []) t;
1893 ParameterInfo [] pi = mb.GetParameters ();
1894 int c = pi.Length;
1895 Type [] types;
1897 if (c == 0) {
1898 types = NoTypes;
1899 } else {
1900 types = new Type [c];
1901 for (int i = 0; i < c; i++)
1902 types [i] = pi [i].ParameterType;
1904 method_arguments.Add (mb, types);
1905 return types;
1908 /// <summary>
1909 /// Returns the argument types for an indexer based on its PropertyInfo
1911 /// For dynamic indexers, we use the compiler provided types, for
1912 /// indexers from existing assemblies we load them from GetParameters,
1913 /// and insert them into the cache
1914 /// </summary>
1915 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1917 if (indexer_arguments.Contains (indexer))
1918 return (Type []) indexer_arguments [indexer];
1919 else if (indexer is PropertyBuilder)
1920 // If we're a PropertyBuilder and not in the
1921 // `indexer_arguments' hash, then we're a property and
1922 // not an indexer.
1923 return NoTypes;
1924 else {
1925 ParameterInfo [] pi = indexer.GetIndexParameters ();
1926 // Property, not an indexer.
1927 if (pi == null)
1928 return NoTypes;
1929 int c = pi.Length;
1930 Type [] types = new Type [c];
1932 for (int i = 0; i < c; i++)
1933 types [i] = pi [i].ParameterType;
1935 indexer_arguments.Add (indexer, types);
1936 return types;
1940 // <remarks>
1941 // This is a workaround the fact that GetValue is not
1942 // supported for dynamic types
1943 // </remarks>
1944 static Hashtable fields = new Hashtable ();
1945 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1947 if (fields.Contains (fb))
1948 return false;
1950 fields.Add (fb, value);
1952 return true;
1955 static public object GetValue (FieldBuilder fb)
1957 return fields [fb];
1960 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1961 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1963 if (fieldbuilders_to_fields.Contains (fb))
1964 return false;
1966 fieldbuilders_to_fields.Add (fb, f);
1967 return true;
1971 // The return value can be null; This will be the case for
1972 // auxiliary FieldBuilders created by the compiler that have no
1973 // real field being declared on the source code
1975 static public FieldBase GetField (FieldInfo fb)
1977 return (FieldBase) fieldbuilders_to_fields [fb];
1980 static Hashtable events;
1982 static public void RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1984 if (events == null)
1985 events = new Hashtable ();
1987 if (!events.Contains (eb)) {
1988 events.Add (eb, new Pair (add, remove));
1992 static public MethodInfo GetAddMethod (EventInfo ei)
1994 if (ei is MyEventBuilder) {
1995 Pair pair = (Pair) events [ei];
1997 return (MethodInfo) pair.First;
1999 return ei.GetAddMethod (true);
2002 static public MethodInfo GetRemoveMethod (EventInfo ei)
2004 if (ei is MyEventBuilder) {
2005 Pair pair = (Pair) events [ei];
2007 return (MethodInfo) pair.Second;
2009 return ei.GetRemoveMethod (true);
2012 static Hashtable priv_fields_events;
2014 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2016 if (priv_fields_events == null)
2017 priv_fields_events = new Hashtable ();
2019 if (priv_fields_events.Contains (einfo))
2020 return false;
2022 priv_fields_events.Add (einfo, builder);
2024 return true;
2027 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2029 if (priv_fields_events == null)
2030 return null;
2031 else
2032 return (MemberInfo) priv_fields_events [ei];
2035 static Hashtable properties;
2037 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2039 if (properties == null)
2040 properties = new Hashtable ();
2042 if (properties.Contains (pb))
2043 return false;
2045 properties.Add (pb, new Pair (get, set));
2047 return true;
2050 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2051 MethodBase set, Type[] args)
2053 if (!RegisterProperty (pb, get,set))
2054 return false;
2056 indexer_arguments.Add (pb, args);
2058 return true;
2061 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2063 Hashtable hash = new Hashtable ();
2064 return CheckStructCycles (tc, seen, hash);
2067 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2068 Hashtable hash)
2070 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc))
2071 return true;
2074 // `seen' contains all types we've already visited.
2076 if (seen.Contains (tc))
2077 return true;
2078 seen.Add (tc, null);
2080 if (tc.Fields == null)
2081 return true;
2083 foreach (Field field in tc.Fields) {
2084 if (field.FieldBuilder == null || field.FieldBuilder.IsStatic)
2085 continue;
2087 Type ftype = field.FieldBuilder.FieldType;
2088 TypeContainer ftc = LookupTypeContainer (ftype);
2089 if (ftc == null)
2090 continue;
2092 if (hash.Contains (ftc)) {
2093 Report.Error (523, tc.Location,
2094 "Struct member `{0}.{1}' of type `{2}' " +
2095 "causes a cycle in the struct layout",
2096 tc.Name, field.Name, ftc.Name);
2097 return false;
2101 // `hash' contains all types in the current path.
2103 hash.Add (tc, null);
2105 bool ok = CheckStructCycles (ftc, seen, hash);
2107 hash.Remove (tc);
2109 if (!ok)
2110 return false;
2112 if (!seen.Contains (ftc))
2113 seen.Add (ftc, null);
2116 return true;
2119 /// <summary>
2120 /// Given an array of interface types, expand and eliminate repeated ocurrences
2121 /// of an interface.
2122 /// </summary>
2124 /// <remarks>
2125 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2126 /// be IA, IB, IC.
2127 /// </remarks>
2128 public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces)
2130 ArrayList new_ifaces = new ArrayList ();
2132 foreach (TypeExpr iface in base_interfaces){
2133 TypeExpr texpr = iface.ResolveAsTypeTerminal (ec);
2134 if (texpr == null)
2135 return null;
2137 if (!new_ifaces.Contains (texpr.Type))
2138 new_ifaces.Add (texpr.Type);
2140 Type [] implementing = texpr.Type.GetInterfaces ();
2142 foreach (Type imp in implementing){
2143 if (!new_ifaces.Contains (imp))
2144 new_ifaces.Add (imp);
2147 Type [] ret = new Type [new_ifaces.Count];
2148 new_ifaces.CopyTo (ret, 0);
2149 return ret;
2152 static PtrHashtable iface_cache = new PtrHashtable ();
2154 /// <summary>
2155 /// This function returns the interfaces in the type `t'. Works with
2156 /// both types and TypeBuilders.
2157 /// </summary>
2158 public static Type [] GetInterfaces (Type t)
2161 Type [] cached = iface_cache [t] as Type [];
2162 if (cached != null)
2163 return cached;
2166 // The reason for catching the Array case is that Reflection.Emit
2167 // will not return a TypeBuilder for Array types of TypeBuilder types,
2168 // but will still throw an exception if we try to call GetInterfaces
2169 // on the type.
2171 // Since the array interfaces are always constant, we return those for
2172 // the System.Array
2175 if (t.IsArray)
2176 t = TypeManager.array_type;
2178 if (t is TypeBuilder){
2179 Type [] base_ifaces;
2181 if (t.BaseType == null)
2182 base_ifaces = NoTypes;
2183 else
2184 base_ifaces = GetInterfaces (t.BaseType);
2185 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2186 if (type_ifaces == null)
2187 type_ifaces = NoTypes;
2189 int base_count = base_ifaces.Length;
2190 Type [] result = new Type [base_count + type_ifaces.Length];
2191 base_ifaces.CopyTo (result, 0);
2192 type_ifaces.CopyTo (result, base_count);
2194 iface_cache [t] = result;
2195 return result;
2196 } else if (t is GenericTypeParameterBuilder){
2197 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2198 if (type_ifaces == null)
2199 type_ifaces = NoTypes;
2201 iface_cache [t] = type_ifaces;
2202 return type_ifaces;
2203 } else {
2204 Type[] ifaces = t.GetInterfaces ();
2205 iface_cache [t] = ifaces;
2206 return ifaces;
2211 // gets the interfaces that are declared explicitly on t
2213 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2215 return (Type []) builder_to_ifaces [t];
2218 /// <remarks>
2219 /// The following is used to check if a given type implements an interface.
2220 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2221 /// </remarks>
2222 public static bool ImplementsInterface (Type t, Type iface)
2224 Type [] interfaces;
2227 // FIXME OPTIMIZATION:
2228 // as soon as we hit a non-TypeBuiler in the interface
2229 // chain, we could return, as the `Type.GetInterfaces'
2230 // will return all the interfaces implement by the type
2231 // or its bases.
2233 do {
2234 interfaces = GetInterfaces (t);
2236 if (interfaces != null){
2237 foreach (Type i in interfaces){
2238 if (i == iface)
2239 return true;
2243 t = t.BaseType;
2244 } while (t != null);
2246 return false;
2249 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2251 // This is a custom version of Convert.ChangeType() which works
2252 // with the TypeBuilder defined types when compiling corlib.
2253 public static object ChangeType (object value, Type conversionType, out bool error)
2255 IConvertible convert_value = value as IConvertible;
2257 if (convert_value == null){
2258 error = true;
2259 return null;
2263 // We must use Type.Equals() here since `conversionType' is
2264 // the TypeBuilder created version of a system type and not
2265 // the system type itself. You cannot use Type.GetTypeCode()
2266 // on such a type - it'd always return TypeCode.Object.
2268 error = false;
2269 try {
2270 if (conversionType.Equals (typeof (Boolean)))
2271 return (object)(convert_value.ToBoolean (nf_provider));
2272 else if (conversionType.Equals (typeof (Byte)))
2273 return (object)(convert_value.ToByte (nf_provider));
2274 else if (conversionType.Equals (typeof (Char)))
2275 return (object)(convert_value.ToChar (nf_provider));
2276 else if (conversionType.Equals (typeof (DateTime)))
2277 return (object)(convert_value.ToDateTime (nf_provider));
2278 else if (conversionType.Equals (TypeManager.decimal_type)) // typeof (Decimal)))
2279 return (object)(convert_value.ToDecimal (nf_provider));
2280 else if (conversionType.Equals (typeof (Double)))
2281 return (object)(convert_value.ToDouble (nf_provider));
2282 else if (conversionType.Equals (typeof (Int16)))
2283 return (object)(convert_value.ToInt16 (nf_provider));
2284 else if (conversionType.Equals (typeof (Int32)))
2285 return (object)(convert_value.ToInt32 (nf_provider));
2286 else if (conversionType.Equals (typeof (Int64)))
2287 return (object)(convert_value.ToInt64 (nf_provider));
2288 else if (conversionType.Equals (typeof (SByte)))
2289 return (object)(convert_value.ToSByte (nf_provider));
2290 else if (conversionType.Equals (typeof (Single)))
2291 return (object)(convert_value.ToSingle (nf_provider));
2292 else if (conversionType.Equals (typeof (String)))
2293 return (object)(convert_value.ToString (nf_provider));
2294 else if (conversionType.Equals (typeof (UInt16)))
2295 return (object)(convert_value.ToUInt16 (nf_provider));
2296 else if (conversionType.Equals (typeof (UInt32)))
2297 return (object)(convert_value.ToUInt32 (nf_provider));
2298 else if (conversionType.Equals (typeof (UInt64)))
2299 return (object)(convert_value.ToUInt64 (nf_provider));
2300 else if (conversionType.Equals (typeof (Object)))
2301 return (object)(value);
2302 else
2303 error = true;
2304 } catch {
2305 error = true;
2307 return null;
2311 // This is needed, because enumerations from assemblies
2312 // do not report their underlyingtype, but they report
2313 // themselves
2315 public static Type EnumToUnderlying (Type t)
2317 if (t == TypeManager.enum_type)
2318 return t;
2320 t = t.UnderlyingSystemType;
2321 if (!TypeManager.IsEnumType (t))
2322 return t;
2324 if (t is TypeBuilder) {
2325 // slow path needed to compile corlib
2326 if (t == TypeManager.bool_type ||
2327 t == TypeManager.byte_type ||
2328 t == TypeManager.sbyte_type ||
2329 t == TypeManager.char_type ||
2330 t == TypeManager.short_type ||
2331 t == TypeManager.ushort_type ||
2332 t == TypeManager.int32_type ||
2333 t == TypeManager.uint32_type ||
2334 t == TypeManager.int64_type ||
2335 t == TypeManager.uint64_type)
2336 return t;
2337 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2339 TypeCode tc = Type.GetTypeCode (t);
2341 switch (tc){
2342 case TypeCode.Boolean:
2343 return TypeManager.bool_type;
2344 case TypeCode.Byte:
2345 return TypeManager.byte_type;
2346 case TypeCode.SByte:
2347 return TypeManager.sbyte_type;
2348 case TypeCode.Char:
2349 return TypeManager.char_type;
2350 case TypeCode.Int16:
2351 return TypeManager.short_type;
2352 case TypeCode.UInt16:
2353 return TypeManager.ushort_type;
2354 case TypeCode.Int32:
2355 return TypeManager.int32_type;
2356 case TypeCode.UInt32:
2357 return TypeManager.uint32_type;
2358 case TypeCode.Int64:
2359 return TypeManager.int64_type;
2360 case TypeCode.UInt64:
2361 return TypeManager.uint64_type;
2363 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2367 // When compiling corlib and called with one of the core types, return
2368 // the corresponding typebuilder for that type.
2370 public static Type TypeToCoreType (Type t)
2372 if (RootContext.StdLib || (t is TypeBuilder))
2373 return t;
2375 TypeCode tc = Type.GetTypeCode (t);
2377 switch (tc){
2378 case TypeCode.Boolean:
2379 return TypeManager.bool_type;
2380 case TypeCode.Byte:
2381 return TypeManager.byte_type;
2382 case TypeCode.SByte:
2383 return TypeManager.sbyte_type;
2384 case TypeCode.Char:
2385 return TypeManager.char_type;
2386 case TypeCode.Int16:
2387 return TypeManager.short_type;
2388 case TypeCode.UInt16:
2389 return TypeManager.ushort_type;
2390 case TypeCode.Int32:
2391 return TypeManager.int32_type;
2392 case TypeCode.UInt32:
2393 return TypeManager.uint32_type;
2394 case TypeCode.Int64:
2395 return TypeManager.int64_type;
2396 case TypeCode.UInt64:
2397 return TypeManager.uint64_type;
2398 case TypeCode.Single:
2399 return TypeManager.float_type;
2400 case TypeCode.Double:
2401 return TypeManager.double_type;
2402 case TypeCode.String:
2403 return TypeManager.string_type;
2404 case TypeCode.Decimal:
2405 return TypeManager.decimal_type;
2406 default:
2407 if (t == typeof (void))
2408 return TypeManager.void_type;
2409 if (t == typeof (object))
2410 return TypeManager.object_type;
2411 if (t == typeof (System.Type))
2412 return TypeManager.type_type;
2413 if (t == typeof (System.IntPtr))
2414 return TypeManager.intptr_type;
2415 return t;
2419 /// <summary>
2420 /// Utility function that can be used to probe whether a type
2421 /// is managed or not.
2422 /// </summary>
2423 public static bool VerifyUnManaged (Type t, Location loc)
2425 if (t.IsValueType || t.IsPointer){
2427 // FIXME: this is more complex, we actually need to
2428 // make sure that the type does not contain any
2429 // classes itself
2431 return true;
2434 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2435 // We need this explicit check here to make it work when
2436 // compiling corlib.
2437 return true;
2439 Report.Error (
2440 208, loc,
2441 "Cannot take the address or size of a variable of a managed type ('" +
2442 CSharpName (t) + "')");
2443 return false;
2446 /// <summary>
2447 /// Returns the name of the indexer in a given type.
2448 /// </summary>
2449 /// <remarks>
2450 /// The default is not always `Item'. The user can change this behaviour by
2451 /// using the IndexerNameAttribute in the container.
2453 /// For example, the String class indexer is named `Chars' not `Item'
2454 /// </remarks>
2455 public static string IndexerPropertyName (Type t)
2457 if (t.IsGenericInstance)
2458 t = t.GetGenericTypeDefinition ();
2460 if (t is TypeBuilder) {
2461 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2462 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2465 System.Attribute attr = System.Attribute.GetCustomAttribute (
2466 t, TypeManager.default_member_type);
2467 if (attr != null){
2468 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2469 return dma.MemberName;
2472 return TypeContainer.DefaultIndexerName;
2475 static MethodInfo declare_local_method = null;
2477 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2479 if (declare_local_method == null){
2480 declare_local_method = typeof (ILGenerator).GetMethod (
2481 "DeclareLocal",
2482 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2483 null,
2484 new Type [] { typeof (Type), typeof (bool)},
2485 null);
2486 if (declare_local_method == null){
2487 Report.Warning (-24, new Location (-1),
2488 "This version of the runtime does not support making pinned local variables. " +
2489 "This code may cause errors on a runtime with a moving GC");
2490 return ig.DeclareLocal (t);
2493 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2497 // Returns whether the array of memberinfos contains the given method
2499 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2501 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2503 foreach (MethodBase method in array) {
2504 if (method.Name != new_method.Name)
2505 continue;
2507 if (method is MethodInfo && new_method is MethodInfo)
2508 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2509 continue;
2512 Type [] old_args = TypeManager.GetArgumentTypes (method);
2513 int old_count = old_args.Length;
2514 int i;
2516 if (new_args.Length != old_count)
2517 continue;
2519 for (i = 0; i < old_count; i++){
2520 if (old_args [i] != new_args [i])
2521 break;
2523 if (i != old_count)
2524 continue;
2526 return true;
2529 return false;
2533 // We copy methods from `new_members' into `target_list' if the signature
2534 // for the method from in the new list does not exist in the target_list
2536 // The name is assumed to be the same.
2538 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2540 if (target_list == null){
2541 target_list = new ArrayList ();
2543 foreach (MemberInfo mi in new_members){
2544 if (mi is MethodBase)
2545 target_list.Add (mi);
2547 return target_list;
2550 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2551 target_list.CopyTo (target_array, 0);
2553 foreach (MemberInfo mi in new_members){
2554 MethodBase new_method = (MethodBase) mi;
2556 if (!ArrayContainsMethod (target_array, new_method))
2557 target_list.Add (new_method);
2559 return target_list;
2562 #region MemberLookup implementation
2565 // Whether we allow private members in the result (since FindMembers
2566 // uses NonPublic for both protected and private), we need to distinguish.
2569 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2571 return true;
2574 internal class Closure {
2575 internal bool private_ok;
2577 // Who is invoking us and which type is being queried currently.
2578 internal Type invocation_type;
2579 internal Type qualifier_type;
2581 // The assembly that defines the type is that is calling us
2582 internal Assembly invocation_assembly;
2583 internal IList almost_match;
2585 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2587 if (invocation_type == null)
2588 return false;
2590 Debug.Assert (IsNestedFamilyAccessible (invocation_type, m.DeclaringType));
2592 if (is_static)
2593 return true;
2595 // A nested class has access to all the protected members visible
2596 // to its parent.
2597 if (qualifier_type != null
2598 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2599 return true;
2601 if (invocation_type == m.DeclaringType
2602 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2603 // Although a derived class can access protected members of
2604 // its base class it cannot do so through an instance of the
2605 // base class (CS1540).
2606 // => Ancestry should be: declaring_type ->* invocation_type
2607 // ->* qualified_type
2608 if (qualifier_type == null
2609 || qualifier_type == invocation_type
2610 || qualifier_type.IsSubclassOf (invocation_type))
2611 return true;
2614 if (almost_match != null)
2615 almost_match.Add (m);
2616 return false;
2619 bool Filter (MethodBase mb, object filter_criteria)
2621 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2623 if (ma == MethodAttributes.Private)
2624 return private_ok ||
2625 IsPrivateAccessible (invocation_type, mb.DeclaringType) ||
2626 IsNestedChildOf (invocation_type, mb.DeclaringType);
2629 // FamAndAssem requires that we not only derivate, but we are on the
2630 // same assembly.
2632 if (ma == MethodAttributes.FamANDAssem){
2633 if (invocation_assembly != mb.DeclaringType.Assembly)
2634 return false;
2637 // Assembly and FamORAssem succeed if we're in the same assembly.
2638 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2639 if (invocation_assembly == mb.DeclaringType.Assembly)
2640 return true;
2643 // We already know that we aren't in the same assembly.
2644 if (ma == MethodAttributes.Assembly)
2645 return false;
2647 // Family and FamANDAssem require that we derive.
2648 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2649 if (invocation_type == null)
2650 return false;
2652 if (!IsNestedFamilyAccessible (invocation_type, mb.DeclaringType))
2653 return false;
2655 // Although a derived class can access protected members of its base class
2656 // it cannot do so through an instance of the base class (CS1540).
2657 if (!mb.IsStatic && (qualifier_type != null) &&
2658 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2659 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2660 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2661 return false;
2663 return true;
2666 // Public.
2667 return true;
2670 bool Filter (FieldInfo fi, object filter_criteria)
2672 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2674 if (fa == FieldAttributes.Private)
2675 return private_ok ||
2676 IsPrivateAccessible (invocation_type, fi.DeclaringType) ||
2677 IsNestedChildOf (invocation_type, fi.DeclaringType);
2680 // FamAndAssem requires that we not only derivate, but we are on the
2681 // same assembly.
2683 if (fa == FieldAttributes.FamANDAssem){
2684 if (invocation_assembly != fi.DeclaringType.Assembly)
2685 return false;
2688 // Assembly and FamORAssem succeed if we're in the same assembly.
2689 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2690 if (invocation_assembly == fi.DeclaringType.Assembly)
2691 return true;
2694 // We already know that we aren't in the same assembly.
2695 if (fa == FieldAttributes.Assembly)
2696 return false;
2698 // Family and FamANDAssem require that we derive.
2699 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2700 if (invocation_type == null)
2701 return false;
2703 if (!IsNestedFamilyAccessible (invocation_type, fi.DeclaringType))
2704 return false;
2706 // Although a derived class can access protected members of its base class
2707 // it cannot do so through an instance of the base class (CS1540).
2708 if (!fi.IsStatic && (qualifier_type != null) &&
2709 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2710 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2711 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2712 return false;
2714 return true;
2717 // Public.
2718 return true;
2722 // This filter filters by name + whether it is ok to include private
2723 // members in the search
2725 internal bool Filter (MemberInfo m, object filter_criteria)
2728 // Hack: we know that the filter criteria will always be in the
2729 // `closure' // fields.
2732 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2733 return false;
2735 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2736 (invocation_type != null) &&
2737 IsPrivateAccessible (m.DeclaringType, invocation_type))
2738 return true;
2741 // Ugly: we need to find out the type of `m', and depending
2742 // on this, tell whether we accept or not
2744 if (m is MethodBase)
2745 return Filter ((MethodBase) m, filter_criteria);
2747 if (m is FieldInfo)
2748 return Filter ((FieldInfo) m, filter_criteria);
2751 // EventInfos and PropertyInfos, return true because they lack
2752 // permission information, so we need to check later on the methods.
2754 return true;
2758 static Closure closure = new Closure ();
2759 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
2762 // Looks up a member called `name' in the `queried_type'. This lookup
2763 // is done by code that is contained in the definition for `invocation_type'
2764 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2766 // `invocation_type' is used to check whether we're allowed to access the requested
2767 // member wrt its protection level.
2769 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2770 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2771 // is B and qualifier_type is A). This is used to do the CS1540 check.
2773 // When resolving a SimpleName, `qualifier_type' is null.
2775 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2776 // the same than `queried_type' - except when we're being called from BaseAccess;
2777 // in this case, `invocation_type' is the current type and `queried_type' the base
2778 // type, so this'd normally trigger a CS1540.
2780 // The binding flags are `bf' and the kind of members being looked up are `mt'
2782 // The return value always includes private members which code in `invocation_type'
2783 // is allowed to access (using the specified `qualifier_type' if given); only use
2784 // BindingFlags.NonPublic to bypass the permission check.
2786 // The 'almost_match' argument is used for reporting error CS1540.
2788 // Returns an array of a single element for everything but Methods/Constructors
2789 // that might return multiple matches.
2791 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2792 Type queried_type, MemberTypes mt,
2793 BindingFlags original_bf, string name, IList almost_match)
2795 Timer.StartTimer (TimerType.MemberLookup);
2797 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2798 queried_type, mt, original_bf, name, almost_match);
2800 Timer.StopTimer (TimerType.MemberLookup);
2802 return retval;
2805 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2806 Type queried_type, MemberTypes mt,
2807 BindingFlags original_bf, string name, IList almost_match)
2809 BindingFlags bf = original_bf;
2811 ArrayList method_list = null;
2812 Type current_type = queried_type;
2813 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2814 bool skip_iface_check = true, used_cache = false;
2815 bool always_ok_flag = false;
2817 closure.invocation_type = invocation_type;
2818 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2819 closure.qualifier_type = qualifier_type;
2820 closure.almost_match = almost_match;
2823 // If we are a nested class, we always have access to our container
2824 // type names
2826 if (invocation_type != null){
2827 string invocation_name = invocation_type.FullName;
2828 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
2829 string container = queried_type.FullName + "+";
2830 int container_length = container.Length;
2832 if (invocation_name.Length > container_length){
2833 string shared = invocation_name.Substring (0, container_length);
2835 if (shared == container)
2836 always_ok_flag = true;
2841 // This is from the first time we find a method
2842 // in most cases, we do not actually find a method in the base class
2843 // so we can just ignore it, and save the arraylist allocation
2844 MemberInfo [] first_members_list = null;
2845 bool use_first_members_list = false;
2847 do {
2848 MemberInfo [] list;
2851 // `NonPublic' is lame, because it includes both protected and
2852 // private methods, so we need to control this behavior by
2853 // explicitly tracking if a private method is ok or not.
2855 // The possible cases are:
2856 // public, private and protected (internal does not come into the
2857 // equation)
2859 if ((invocation_type != null) &&
2860 ((invocation_type == current_type) ||
2861 IsNestedChildOf (invocation_type, current_type)) ||
2862 always_ok_flag)
2863 bf = original_bf | BindingFlags.NonPublic;
2864 else
2865 bf = original_bf;
2867 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
2869 Timer.StopTimer (TimerType.MemberLookup);
2871 list = MemberLookup_FindMembers (
2872 current_type, mt, bf, name, out used_cache);
2874 Timer.StartTimer (TimerType.MemberLookup);
2877 // When queried for an interface type, the cache will automatically check all
2878 // inherited members, so we don't need to do this here. However, this only
2879 // works if we already used the cache in the first iteration of this loop.
2881 // If we used the cache in any further iteration, we can still terminate the
2882 // loop since the cache always looks in all base classes.
2885 if (used_cache)
2886 searching = false;
2887 else
2888 skip_iface_check = false;
2890 if (current_type == TypeManager.object_type)
2891 searching = false;
2892 else {
2893 current_type = current_type.BaseType;
2896 // This happens with interfaces, they have a null
2897 // basetype. Look members up in the Object class.
2899 if (current_type == null) {
2900 current_type = TypeManager.object_type;
2901 searching = true;
2905 if (list.Length == 0)
2906 continue;
2909 // Events and types are returned by both `static' and `instance'
2910 // searches, which means that our above FindMembers will
2911 // return two copies of the same.
2913 if (list.Length == 1 && !(list [0] is MethodBase)){
2914 return list;
2918 // Multiple properties: we query those just to find out the indexer
2919 // name
2921 if (list [0] is PropertyInfo)
2922 return list;
2925 // We found an event: the cache lookup returns both the event and
2926 // its private field.
2928 if (list [0] is EventInfo) {
2929 if ((list.Length == 2) && (list [1] is FieldInfo))
2930 return new MemberInfo [] { list [0] };
2932 // Oooops
2933 return null;
2937 // We found methods, turn the search into "method scan"
2938 // mode.
2941 if (first_members_list != null) {
2942 if (use_first_members_list) {
2943 method_list = CopyNewMethods (method_list, first_members_list);
2944 use_first_members_list = false;
2947 method_list = CopyNewMethods (method_list, list);
2948 } else {
2949 first_members_list = list;
2950 use_first_members_list = true;
2952 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2954 } while (searching);
2956 if (use_first_members_list) {
2957 foreach (MemberInfo mi in first_members_list) {
2958 if (! (mi is MethodBase)) {
2959 method_list = CopyNewMethods (method_list, first_members_list);
2960 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2963 return (MemberInfo []) first_members_list;
2966 if (method_list != null && method_list.Count > 0) {
2967 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2970 // This happens if we already used the cache in the first iteration, in this case
2971 // the cache already looked in all interfaces.
2973 if (skip_iface_check)
2974 return null;
2977 // Interfaces do not list members they inherit, so we have to
2978 // scan those.
2980 if (!queried_type.IsInterface)
2981 return null;
2983 if (queried_type.IsArray)
2984 queried_type = TypeManager.array_type;
2986 Type [] ifaces = GetInterfaces (queried_type);
2987 if (ifaces == null)
2988 return null;
2990 foreach (Type itype in ifaces){
2991 MemberInfo [] x;
2993 x = MemberLookup (null, null, itype, mt, bf, name, null);
2994 if (x != null)
2995 return x;
2998 return null;
3001 // Tests whether external method is really special
3002 public static bool IsSpecialMethod (MethodBase mb)
3004 string name = mb.Name;
3005 if (name.StartsWith ("get_") || name.StartsWith ("set_"))
3006 return mb.DeclaringType.GetProperty (name.Substring (4)) != null;
3008 if (name.StartsWith ("add_"))
3009 return mb.DeclaringType.GetEvent (name.Substring (4)) != null;
3011 if (name.StartsWith ("remove_"))
3012 return mb.DeclaringType.GetEvent (name.Substring (7)) != null;
3014 if (name.StartsWith ("op_")){
3015 foreach (string oname in Unary.oper_names) {
3016 if (oname == name)
3017 return true;
3020 foreach (string oname in Binary.oper_names) {
3021 if (oname == name)
3022 return true;
3025 return false;
3028 #endregion
3032 /// <summary>
3033 /// There is exactly one instance of this class per type.
3034 /// </summary>
3035 public sealed class TypeHandle : IMemberContainer {
3036 public readonly TypeHandle BaseType;
3038 readonly int id = ++next_id;
3039 static int next_id = 0;
3041 /// <summary>
3042 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3043 /// a TypeHandle yet, a new instance of it is created. This static method
3044 /// ensures that we'll only have one TypeHandle instance per type.
3045 /// </summary>
3046 private static TypeHandle GetTypeHandle (Type t)
3048 TypeHandle handle = (TypeHandle) type_hash [t];
3049 if (handle != null)
3050 return handle;
3052 handle = new TypeHandle (t);
3053 type_hash.Add (t, handle);
3054 return handle;
3057 public static MemberCache GetMemberCache (Type t)
3059 return GetTypeHandle (t).MemberCache;
3062 public static void CleanUp ()
3064 type_hash = null;
3067 /// <summary>
3068 /// Returns the TypeHandle for TypeManager.object_type.
3069 /// </summary>
3070 public static IMemberContainer ObjectType {
3071 get {
3072 if (object_type != null)
3073 return object_type;
3075 object_type = GetTypeHandle (TypeManager.object_type);
3077 return object_type;
3081 /// <summary>
3082 /// Returns the TypeHandle for TypeManager.array_type.
3083 /// </summary>
3084 public static IMemberContainer ArrayType {
3085 get {
3086 if (array_type != null)
3087 return array_type;
3089 array_type = GetTypeHandle (TypeManager.array_type);
3091 return array_type;
3095 private static PtrHashtable type_hash = new PtrHashtable ();
3097 private static TypeHandle object_type = null;
3098 private static TypeHandle array_type = null;
3100 private Type type;
3101 private string full_name;
3102 private bool is_interface;
3103 private MemberCache member_cache;
3104 private MemberCache base_cache;
3106 private TypeHandle (Type type)
3108 this.type = type;
3109 full_name = type.FullName != null ? type.FullName : type.Name;
3110 if (type.BaseType != null) {
3111 BaseType = GetTypeHandle (type.BaseType);
3112 base_cache = BaseType.MemberCache;
3113 } else if (type.IsInterface)
3114 base_cache = TypeManager.LookupBaseInterfacesCache (type);
3115 this.is_interface = type.IsInterface || type.IsGenericParameter;
3116 this.member_cache = new MemberCache (this);
3119 // IMemberContainer methods
3121 public string Name {
3122 get {
3123 return full_name;
3127 public Type Type {
3128 get {
3129 return type;
3133 public MemberCache BaseCache {
3134 get {
3135 return base_cache;
3139 public bool IsInterface {
3140 get {
3141 return is_interface;
3145 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3147 MemberInfo [] members;
3148 if (type is GenericTypeParameterBuilder)
3149 return MemberList.Empty;
3150 if (mt == MemberTypes.Event)
3151 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3152 else
3153 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3154 null, null);
3155 Array.Reverse (members);
3157 return new MemberList (members);
3160 // IMemberFinder methods
3162 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3163 MemberFilter filter, object criteria)
3165 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3168 public MemberCache MemberCache {
3169 get {
3170 return member_cache;
3174 public override string ToString ()
3176 if (BaseType != null)
3177 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3178 else
3179 return "TypeHandle (" + id + "," + Name + ")";