2 // import.cs: System.Reflection conversions
4 // Authors: Marek Safar (marek.safar@gmail.com)
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 // Copyright 2009, 2010 Novell, Inc
12 using System.Reflection;
13 using System.Runtime.CompilerServices;
15 using System.Collections.Generic;
16 using System.Diagnostics;
17 using System.Runtime.InteropServices;
21 public class ReflectionMetaImporter
23 Dictionary<Type, TypeSpec> import_cache;
24 Dictionary<Type, PredefinedTypeSpec> type_2_predefined;
26 public ReflectionMetaImporter ()
28 import_cache = new Dictionary<Type, TypeSpec> (1024, ReferenceEquality<Type>.Default);
29 IgnorePrivateMembers = true;
34 public bool IgnorePrivateMembers { get; set; }
38 public void Initialize ()
40 // Setup mapping for predefined types
41 type_2_predefined = new Dictionary<Type, PredefinedTypeSpec> () {
42 { typeof (object), TypeManager.object_type },
43 { typeof (System.ValueType), TypeManager.value_type },
44 { typeof (System.Attribute), TypeManager.attribute_type },
46 { typeof (int), TypeManager.int32_type },
47 { typeof (long), TypeManager.int64_type },
48 { typeof (uint), TypeManager.uint32_type },
49 { typeof (ulong), TypeManager.uint64_type },
50 { typeof (byte), TypeManager.byte_type },
51 { typeof (sbyte), TypeManager.sbyte_type },
52 { typeof (short), TypeManager.short_type },
53 { typeof (ushort), TypeManager.ushort_type },
55 { typeof (System.Collections.IEnumerator), TypeManager.ienumerator_type },
56 { typeof (System.Collections.IEnumerable), TypeManager.ienumerable_type },
57 { typeof (System.IDisposable), TypeManager.idisposable_type },
59 { typeof (char), TypeManager.char_type },
60 { typeof (string), TypeManager.string_type },
61 { typeof (float), TypeManager.float_type },
62 { typeof (double), TypeManager.double_type },
63 { typeof (decimal), TypeManager.decimal_type },
64 { typeof (bool), TypeManager.bool_type },
65 { typeof (System.IntPtr), TypeManager.intptr_type },
66 { typeof (System.UIntPtr), TypeManager.uintptr_type },
68 { typeof (System.MulticastDelegate), TypeManager.multicast_delegate_type },
69 { typeof (System.Delegate), TypeManager.delegate_type },
70 { typeof (System.Enum), TypeManager.enum_type },
71 { typeof (System.Array), TypeManager.array_type },
72 { typeof (void), TypeManager.void_type },
73 { typeof (System.Type), TypeManager.type_type },
74 { typeof (System.Exception), TypeManager.exception_type },
75 { typeof (System.RuntimeFieldHandle), TypeManager.runtime_field_handle_type },
76 { typeof (System.RuntimeTypeHandle), TypeManager.runtime_handle_type }
80 public FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType)
83 var fa = fi.Attributes;
84 switch (fa & FieldAttributes.FieldAccessMask) {
85 case FieldAttributes.Public:
86 mod = Modifiers.PUBLIC;
88 case FieldAttributes.Assembly:
89 mod = Modifiers.INTERNAL;
91 case FieldAttributes.Family:
92 mod = Modifiers.PROTECTED;
94 case FieldAttributes.FamORAssem:
95 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
98 // Ignore private fields (even for error reporting) to not require extra dependencies
99 if (IgnorePrivateMembers || fi.IsDefined (typeof (CompilerGeneratedAttribute), false))
102 mod = Modifiers.PRIVATE;
106 var definition = new ImportedMemberDefinition (fi);
110 field_type = ImportType (fi.FieldType, fi, 0);
111 } catch (Exception e) {
112 // TODO: I should construct fake TypeSpec based on TypeRef signature
113 // but there is no way to do it with System.Reflection
114 throw new InternalErrorException (e, "Cannot import field `{0}.{1}' referenced in assembly `{2}'",
115 declaringType.GetSignatureForError (), fi.Name, declaringType.Assembly);
118 if ((fa & FieldAttributes.Literal) != 0) {
119 var c = Constant.CreateConstantFromValue (field_type, fi.GetValue (fi), Location.Null);
120 return new ConstSpec (declaringType, definition, field_type, fi, mod, c);
123 if ((fa & FieldAttributes.InitOnly) != 0) {
124 if (field_type == TypeManager.decimal_type) {
125 var dc = ReadDecimalConstant (fi);
127 return new ConstSpec (declaringType, definition, field_type, fi, mod, dc);
130 mod |= Modifiers.READONLY;
132 var reqs = fi.GetRequiredCustomModifiers ();
133 if (reqs.Length > 0) {
134 foreach (Type t in reqs) {
135 if (t == typeof (System.Runtime.CompilerServices.IsVolatile)) {
136 mod |= Modifiers.VOLATILE;
143 if ((fa & FieldAttributes.Static) != 0)
144 mod |= Modifiers.STATIC;
146 if (field_type.IsStruct) {
147 if (fi.IsDefined (typeof (FixedBufferAttribute), false)) {
148 var element_field = CreateField (fi.FieldType.GetField (FixedField.FixedElementName), declaringType);
149 return new FixedFieldSpec (declaringType, definition, fi, element_field, mod);
153 return new FieldSpec (declaringType, definition, field_type, fi, mod);
156 public EventSpec CreateEvent (EventInfo ei, TypeSpec declaringType, MethodSpec add, MethodSpec remove)
158 add.IsAccessor = true;
159 remove.IsAccessor = true;
161 if (add.Modifiers != remove.Modifiers)
162 throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
164 var definition = new ImportedMemberDefinition (ei);
165 return new EventSpec (declaringType, definition, ImportType (ei.EventHandlerType, ei, 0), add.Modifiers, add, remove);
168 T[] CreateGenericParameters<T> (Type type, TypeSpec declaringType) where T : TypeSpec
170 Type[] tparams = type.GetGenericArguments ();
172 int parent_owned_count;
174 parent_owned_count = type.DeclaringType.GetGenericArguments ().Length;
177 // System.Reflection duplicates parent type parameters for each
178 // nested type with slightly modified properties (eg. different owner)
179 // This just makes things more complicated (think of cloned constraints)
180 // therefore we remap any nested type owned by parent using `type_cache'
181 // to the single TypeParameterSpec
183 if (declaringType != null && parent_owned_count > 0) {
185 while (read_count != parent_owned_count) {
186 var tparams_count = declaringType.Arity;
187 if (tparams_count != 0) {
188 var parent_tp = declaringType.MemberDefinition.TypeParameters;
189 read_count += tparams_count;
190 for (int i = 0; i < tparams_count; i++) {
191 import_cache.Add (tparams[parent_owned_count - read_count + i], parent_tp[i]);
195 declaringType = declaringType.DeclaringType;
199 parent_owned_count = 0;
202 if (tparams.Length - parent_owned_count == 0)
205 return CreateGenericParameters<T> (parent_owned_count, tparams, null, 0);
208 T[] CreateGenericParameters<T> (int first, Type[] tparams, ICustomAttributeProvider ca, int dynamicCursor) where T : TypeSpec
210 var tspec = new T [tparams.Length - first];
211 for (int pos = first; pos < tparams.Length; ++pos) {
212 var type = tparams[pos];
213 int index = pos - first;
215 if (type.HasElementType) {
216 var element = type.GetElementType ();
217 var spec = ImportType (element);
220 tspec[index] = (T) (TypeSpec) ArrayContainer.MakeType (spec, type.GetArrayRank ());
224 throw new NotImplementedException ("Unknown element type " + type.ToString ());
227 tspec [index] = (T) CreateType (type, ca, dynamicCursor + index + 1);
233 public MethodSpec CreateMethod (MethodBase mb, TypeSpec declaringType)
235 Modifiers mod = ReadMethodModifiers (mb, declaringType);
236 TypeParameterSpec[] tparams;
237 ImportedMethodDefinition definition;
239 var parameters = CreateParameters (declaringType, mb.GetParameters (), mb);
241 if (mb.IsGenericMethod) {
242 if (!mb.IsGenericMethodDefinition)
243 throw new NotSupportedException ("assert");
245 tparams = CreateGenericParameters<TypeParameterSpec>(0, mb.GetGenericArguments (), null, 0);
246 definition = new ImportedGenericMethodDefinition ((MethodInfo) mb, parameters, tparams);
248 definition = new ImportedMethodDefinition (mb, parameters);
254 if (mb.MemberType == MemberTypes.Constructor) {
255 kind = MemberKind.Constructor;
256 returnType = TypeManager.void_type;
259 // Detect operators and destructors
261 string name = mb.Name;
262 kind = MemberKind.Method;
263 if (tparams == null && !mb.DeclaringType.IsInterface && name.Length > 6) {
264 if ((mod & (Modifiers.STATIC | Modifiers.PUBLIC)) == (Modifiers.STATIC | Modifiers.PUBLIC)) {
265 if (name[2] == '_' && name[1] == 'p' && name[0] == 'o') {
266 var op_type = Operator.GetType (name);
267 if (op_type.HasValue && parameters.Count > 0 && parameters.Count < 3) {
268 kind = MemberKind.Operator;
271 } else if (parameters.IsEmpty && name == Destructor.MetadataName) {
272 kind = MemberKind.Destructor;
273 if (declaringType == TypeManager.object_type) {
274 mod &= ~Modifiers.OVERRIDE;
275 mod |= Modifiers.VIRTUAL;
280 var mi = (MethodInfo) mb;
281 returnType = ImportType (mi.ReturnType, mi.ReturnTypeCustomAttributes, 0);
283 // Cannot set to OVERRIDE without full hierarchy checks
284 // this flag indicates that the method could be override
285 // but further validation is needed
286 if ((mod & Modifiers.OVERRIDE) != 0 && kind == MemberKind.Method && declaringType.BaseType != null) {
287 var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null);
288 var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None);
291 // For imported class method do additional validation to be sure that metadata
292 // override flag was correct
294 // Difference between protected internal and protected is ok
296 const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL;
297 if (candidate == null || (candidate.Modifiers & conflict_mask) != (mod & conflict_mask) || candidate.IsStatic) {
298 mod &= ~Modifiers.OVERRIDE;
303 MethodSpec ms = new MethodSpec (kind, declaringType, definition, returnType, mb, parameters, mod);
311 // Imports System.Reflection parameters
313 AParametersCollection CreateParameters (TypeSpec parent, ParameterInfo[] pi, MethodBase method)
315 int varargs = method != null && (method.CallingConvention & CallingConventions.VarArgs) != 0 ? 1 : 0;
317 if (pi.Length == 0 && varargs == 0)
318 return ParametersCompiled.EmptyReadOnlyParameters;
320 TypeSpec[] types = new TypeSpec[pi.Length + varargs];
321 IParameterData[] par = new IParameterData[pi.Length + varargs];
322 bool is_params = false;
323 for (int i = 0; i < pi.Length; i++) {
324 ParameterInfo p = pi[i];
325 Parameter.Modifier mod = 0;
326 Expression default_value = null;
327 if (p.ParameterType.IsByRef) {
328 if ((p.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
329 mod = Parameter.Modifier.OUT;
331 mod = Parameter.Modifier.REF;
334 // Strip reference wrapping
336 var el = p.ParameterType.GetElementType ();
337 types[i] = ImportType (el, p, 0); // TODO: 1 to be csc compatible
338 } else if (i == 0 && method.IsStatic && parent.IsStatic && // TODO: parent.Assembly.IsExtension &&
339 HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (method)) != null) {
340 mod = Parameter.Modifier.This;
341 types[i] = ImportType (p.ParameterType);
343 types[i] = ImportType (p.ParameterType, p, 0);
345 if (i >= pi.Length - 2 && types[i] is ArrayContainer) {
346 var cattrs = CustomAttributeData.GetCustomAttributes (p);
347 if (cattrs != null && cattrs.Any (l => l.Constructor.DeclaringType == typeof (ParamArrayAttribute))) {
348 mod = Parameter.Modifier.PARAMS;
353 if (!is_params && p.IsOptional) {
354 object value = p.DefaultValue;
355 var ptype = types[i];
356 if (((p.Attributes & ParameterAttributes.HasDefault) != 0 && ptype.Kind != MemberKind.TypeParameter) || p.IsDefined (typeof (DecimalConstantAttribute), false)) {
357 var dtype = value == null ? ptype : ImportType (value.GetType ());
358 default_value = Constant.CreateConstant (null, dtype, value, Location.Null);
359 } else if (value == Missing.Value) {
360 default_value = EmptyExpression.MissingValue;
362 default_value = new DefaultValueExpression (new TypeExpression (ptype, Location.Null), Location.Null);
367 par[i] = new ParameterData (p.Name, mod, default_value);
371 par[par.Length - 1] = new ArglistParameter (Location.Null);
372 types[types.Length - 1] = InternalType.Arglist;
375 return method != null ?
376 new ParametersImported (par, types, varargs != 0, is_params) :
377 new ParametersImported (par, types, is_params);
382 // Returns null when the property is not valid C# property
384 public PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, MethodSpec get, MethodSpec set)
387 AParametersCollection param = null;
388 TypeSpec type = null;
391 param = get.Parameters;
392 type = get.ReturnType;
395 bool is_valid_property = true;
397 if (set.ReturnType != TypeManager.void_type)
398 is_valid_property = false;
400 var set_param_count = set.Parameters.Count - 1;
402 if (set_param_count < 0) {
404 is_valid_property = false;
407 var set_type = set.Parameters.Types[set_param_count];
410 AParametersCollection set_based_param;
412 if (set_param_count == 0) {
413 set_based_param = ParametersCompiled.EmptyReadOnlyParameters;
416 // Create indexer parameters based on setter method parameters (the last parameter has to be removed)
418 var data = new IParameterData[set_param_count];
419 var types = new TypeSpec[set_param_count];
420 Array.Copy (set.Parameters.FixedParameters, data, set_param_count);
421 Array.Copy (set.Parameters.Types, types, set_param_count);
422 set_based_param = new ParametersImported (data, types, set.Parameters.HasParams);
426 param = set_based_param;
429 if (set_param_count != get.Parameters.Count)
430 is_valid_property = false;
432 if (get.ReturnType != set_type)
433 is_valid_property = false;
435 // Possible custom accessor modifiers
436 if ((mod & Modifiers.AccessibilityMask) != (set.Modifiers & Modifiers.AccessibilityMask)) {
437 var get_acc = mod & Modifiers.AccessibilityMask;
438 if (get_acc != Modifiers.PUBLIC) {
439 var set_acc = set.Modifiers & Modifiers.AccessibilityMask;
440 // If the accessor modifiers are not same, do extra restriction checks
441 if (get_acc != set_acc) {
442 var get_restr = ModifiersExtensions.IsRestrictedModifier (get_acc, set_acc);
443 var set_restr = ModifiersExtensions.IsRestrictedModifier (set_acc, get_acc);
444 if (get_restr && set_restr) {
445 is_valid_property = false; // Neither is more restrictive
449 mod &= ~Modifiers.AccessibilityMask;
458 PropertySpec spec = null;
459 if (!param.IsEmpty) {
460 var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember ();
461 if (index_name == null) {
462 is_valid_property = false;
466 is_valid_property = false;
467 if (get.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
468 is_valid_property = false;
472 is_valid_property = false;
473 if (set.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
474 is_valid_property = false;
478 if (is_valid_property)
479 spec = new IndexerSpec (declaringType, new ImportedIndexerDefinition (pi, param), type, param, pi, mod);
483 spec = new PropertySpec (MemberKind.Property, declaringType, new ImportedMemberDefinition (pi), type, pi, mod);
485 if (!is_valid_property) {
486 spec.IsNotRealProperty = true;
498 public TypeSpec CreateType (Type type)
500 return CreateType (type, null, 0);
503 TypeSpec CreateType (Type type, ICustomAttributeProvider ca, int dynamicCursor)
505 TypeSpec declaring_type;
506 if (type.IsNested && !type.IsGenericParameter)
507 declaring_type = CreateType (type.DeclaringType, type.DeclaringType, 0);
509 declaring_type = null;
511 return CreateType (type, declaring_type, ca, dynamicCursor);
514 public TypeSpec CreateType (Type type, TypeSpec declaringType, ICustomAttributeProvider ca, int dynamicCursor)
517 if (import_cache.TryGetValue (type, out spec)) {
521 if (type == typeof (object)) {
522 if (IsDynamicType (ca, dynamicCursor))
523 return InternalType.Dynamic;
532 if (!ca.IsDefined (typeof (DynamicAttribute), false))
536 // We've found same object in the cache but this one has a dynamic custom attribute
537 // and it's most likely dynamic version of same type IFoo<object> agains IFoo<dynamic>
538 // Do resolve the type process again in that case
541 if (type.IsGenericType && !type.IsGenericTypeDefinition) {
542 var type_def = type.GetGenericTypeDefinition ();
543 var targs = CreateGenericParameters<TypeSpec> (0, type.GetGenericArguments (), ca, dynamicCursor);
544 if (declaringType == null) {
545 // Simple case, no nesting
546 spec = CreateType (type_def, null, null, 0);
547 spec = spec.MakeGenericType (targs);
550 // Nested type case, converting .NET types like
551 // A`1.B`1.C`1<int, long, string> to typespec like
552 // A<int>.B<long>.C<string>
554 var nested_hierarchy = new List<TypeSpec> ();
555 while (declaringType.IsNested) {
556 nested_hierarchy.Add (declaringType);
557 declaringType = declaringType.DeclaringType;
561 if (declaringType.Arity > 0) {
562 spec = declaringType.MakeGenericType (targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ());
563 targs_pos = spec.Arity;
565 spec = declaringType;
568 for (int i = nested_hierarchy.Count; i != 0; --i) {
569 var t = nested_hierarchy [i - 1];
570 spec = MemberCache.FindNestedType (spec, t.Name, t.Arity);
572 spec = spec.MakeGenericType (targs.Skip (targs_pos).Take (spec.Arity).ToArray ());
573 targs_pos += t.Arity;
577 string name = type.Name;
578 int index = name.IndexOf ('`');
580 name = name.Substring (0, index);
582 spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos);
583 if (spec.Arity > 0) {
584 spec = spec.MakeGenericType (targs.Skip (targs_pos).ToArray ());
588 // Don't add generic type with dynamic arguments, they can interfere with same type
589 // using object type arguments
590 if (!spec.HasDynamicElement) {
592 // Add to reading cache to speed up reading
593 if (!import_cache.ContainsKey (type))
594 import_cache.Add (type, spec);
603 var ma = type.Attributes;
604 switch (ma & TypeAttributes.VisibilityMask) {
605 case TypeAttributes.Public:
606 case TypeAttributes.NestedPublic:
607 mod = Modifiers.PUBLIC;
609 case TypeAttributes.NestedPrivate:
610 mod = Modifiers.PRIVATE;
612 case TypeAttributes.NestedFamily:
613 mod = Modifiers.PROTECTED;
615 case TypeAttributes.NestedFamORAssem:
616 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
619 mod = Modifiers.INTERNAL;
623 if ((ma & TypeAttributes.Interface) != 0) {
624 kind = MemberKind.Interface;
625 } else if (type.IsGenericParameter) {
626 kind = MemberKind.TypeParameter;
627 } else if (type.IsClass || type.IsAbstract) { // System.Reflection: System.Enum returns false for IsClass
628 if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) {
629 kind = MemberKind.Delegate;
630 mod |= Modifiers.SEALED;
632 kind = MemberKind.Class;
633 if ((ma & TypeAttributes.Sealed) != 0) {
634 mod |= Modifiers.SEALED;
635 if ((ma & TypeAttributes.Abstract) != 0)
636 mod |= Modifiers.STATIC;
637 } else if ((ma & TypeAttributes.Abstract) != 0) {
638 mod |= Modifiers.ABSTRACT;
641 } else if (type.IsEnum) {
642 kind = MemberKind.Enum;
644 kind = MemberKind.Struct;
645 mod |= Modifiers.SEALED;
648 var definition = new ImportedTypeDefinition (this, type);
649 PredefinedTypeSpec pt;
651 if (kind == MemberKind.Enum) {
652 const BindingFlags underlying_member = BindingFlags.DeclaredOnly |
653 BindingFlags.Instance |
654 BindingFlags.Public | BindingFlags.NonPublic;
656 var type_members = type.GetFields (underlying_member);
657 foreach (var type_member in type_members) {
658 spec = new EnumSpec (declaringType, definition, CreateType (type_member.FieldType), type, mod);
663 kind = MemberKind.Class;
665 } else if (kind == MemberKind.TypeParameter) {
666 // Return as type_cache was updated
667 return CreateTypeParameter (type, declaringType);
668 } else if (type.IsGenericTypeDefinition) {
669 definition.TypeParameters = CreateGenericParameters<TypeParameterSpec>(type, declaringType);
671 // Constraints are not loaded on demand and can reference this type
672 if (import_cache.TryGetValue (type, out spec))
675 } else if (type_2_predefined.TryGetValue (type, out pt)) {
677 pt.SetDefinition (definition, type);
681 spec = new TypeSpec (kind, declaringType, definition, type, mod);
683 import_cache.Add (type, spec);
686 // Two stage setup as the base type can be inflated declaring type
688 if (declaringType == null || !IgnorePrivateMembers)
689 ImportTypeBase (spec, type);
694 public void ImportTypeBase (Type type)
696 TypeSpec spec = import_cache[type];
698 ImportTypeBase (spec, type);
701 void ImportTypeBase (TypeSpec spec, Type type)
703 if (spec.Kind == MemberKind.Interface)
704 spec.BaseType = TypeManager.object_type;
705 else if (type.BaseType != null) {
706 if (type.BaseType.IsGenericType)
707 spec.BaseType = CreateType (type.BaseType, type, 0);
709 spec.BaseType = CreateType (type.BaseType);
712 var ifaces = type.GetInterfaces ();
713 if (ifaces.Length > 0) {
714 foreach (Type iface in ifaces) {
715 spec.AddInterface (CreateType (iface));
720 TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType)
723 switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
724 case GenericParameterAttributes.Covariant:
725 variance = Variance.Covariant;
727 case GenericParameterAttributes.Contravariant:
728 variance = Variance.Contravariant;
731 variance = Variance.None;
735 SpecialConstraint special = SpecialConstraint.None;
736 var import_special = type.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
738 if ((import_special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) {
739 special |= SpecialConstraint.Struct;
740 } else if ((import_special & GenericParameterAttributes.DefaultConstructorConstraint) != 0) {
741 special = SpecialConstraint.Constructor;
744 if ((import_special & GenericParameterAttributes.ReferenceTypeConstraint) != 0) {
745 special |= SpecialConstraint.Class;
748 TypeParameterSpec spec;
749 var def = new ImportedTypeParameterDefinition (type);
750 if (type.DeclaringMethod != null)
751 spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type);
753 spec = new TypeParameterSpec (declaringType, type.GenericParameterPosition, def, special, variance, type);
755 // Add it now, so any constraint can reference it and get same instance
756 import_cache.Add (type, spec);
758 var constraints = type.GetGenericParameterConstraints ();
759 List<TypeSpec> tparams = null;
760 foreach (var ct in constraints) {
761 if (ct.IsGenericParameter) {
763 tparams = new List<TypeSpec> ();
765 tparams.Add (CreateType (ct));
770 if (ct == typeof (ValueType)) {
771 spec.BaseType = TypeManager.value_type;
773 spec.BaseType = CreateType (ct);
779 spec.AddInterface (CreateType (ct));
782 if (spec.BaseType == null)
783 spec.BaseType = TypeManager.object_type;
786 spec.TypeArguments = tparams.ToArray ();
791 static Type HasExtensionAttribute (IList<CustomAttributeData> attributes)
793 foreach (var attr in attributes) {
794 var dt = attr.Constructor.DeclaringType;
795 if (dt.Name == "ExtensionAttribute" && dt.Namespace == "System.Runtime.CompilerServices") {
803 public void ImportAssembly (Assembly assembly, Namespace targetNamespace)
805 Type extension_type = HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (assembly));
808 // This part tries to simulate loading of top-level
809 // types only, any missing dependencies are ignores here.
810 // Full error report is reported later when the type is
815 all_types = assembly.GetTypes ();
816 } catch (ReflectionTypeLoadException e) {
820 ImportTypes (all_types, targetNamespace, extension_type);
823 public void ImportModule (Module module, Namespace targetNamespace)
825 Type extension_type = HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (module));
829 all_types = module.GetTypes ();
830 } catch (ReflectionTypeLoadException e) {
835 ImportTypes (all_types, targetNamespace, extension_type);
838 void ImportTypes (Type[] types, Namespace targetNamespace, Type extension_type)
840 Namespace ns = targetNamespace;
841 string prev_namespace = null;
842 foreach (var t in types) {
846 // Be careful not to trigger full parent type loading
847 if (t.MemberType == MemberTypes.NestedType)
850 if (t.Name[0] == '<')
853 var it = CreateType (t, null, t, 0);
857 if (prev_namespace != t.Namespace) {
858 ns = t.Namespace == null ? targetNamespace : targetNamespace.GetNamespace (t.Namespace, true);
859 prev_namespace = t.Namespace;
864 if (it.IsStatic && extension_type != null && t.IsDefined (extension_type, false)) {
865 it.SetExtensionMethodContainer ();
870 public TypeSpec ImportType (Type type)
872 return ImportType (type, null, 0);
875 public TypeSpec ImportType (Type type, ICustomAttributeProvider ca, int dynamicCursor)
877 if (type.HasElementType) {
878 var element = type.GetElementType ();
879 var spec = ImportType (element, ca, dynamicCursor + 1);
882 return ArrayContainer.MakeType (spec, type.GetArrayRank ());
884 return ReferenceContainer.MakeType (spec);
886 return PointerContainer.MakeType (spec);
888 throw new NotImplementedException ("Unknown element type " + type.ToString ());
891 return CreateType (type, ca, dynamicCursor);
894 static bool IsDynamicType (ICustomAttributeProvider ca, int index)
897 if (ca.IsDefined (typeof (DynamicAttribute), false)) {
901 var v = (DynamicAttribute) ca.GetCustomAttributes (typeof (DynamicAttribute), false)[0];
902 return v.TransformFlags[index];
909 // Decimal constants cannot be encoded in the constant blob, and thus are marked
910 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
911 // DecimalConstantAttribute metadata.
913 static Constant ReadDecimalConstant (ICustomAttributeProvider fi)
915 object[] attrs = fi.GetCustomAttributes (typeof (DecimalConstantAttribute), false);
916 if (attrs.Length != 1)
919 return new DecimalConstant (((DecimalConstantAttribute) attrs [0]).Value, Location.Null);
922 static Modifiers ReadMethodModifiers (MethodBase mb, TypeSpec declaringType)
925 var ma = mb.Attributes;
926 switch (ma & MethodAttributes.MemberAccessMask) {
927 case MethodAttributes.Public:
928 mod = Modifiers.PUBLIC;
930 case MethodAttributes.Assembly:
931 mod = Modifiers.INTERNAL;
933 case MethodAttributes.Family:
934 mod = Modifiers.PROTECTED;
936 case MethodAttributes.FamORAssem:
937 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
940 mod = Modifiers.PRIVATE;
944 if ((ma & MethodAttributes.Static) != 0) {
945 mod |= Modifiers.STATIC;
948 if ((ma & MethodAttributes.Abstract) != 0 && declaringType.IsClass) {
949 mod |= Modifiers.ABSTRACT;
953 if ((ma & MethodAttributes.Final) != 0)
954 mod |= Modifiers.SEALED;
956 // It can be sealed and override
957 if ((ma & MethodAttributes.Virtual) != 0) {
958 if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass) {
959 // No private virtual or sealed virtual
960 if ((mod & (Modifiers.PRIVATE | Modifiers.SEALED)) == 0)
961 mod |= Modifiers.VIRTUAL;
963 mod |= Modifiers.OVERRIDE;
971 class ImportedMemberDefinition : IMemberDefinition
973 protected class AttributesBag
975 public static readonly AttributesBag Default = new AttributesBag ();
977 public AttributeUsageAttribute AttributeUsage;
978 public ObsoleteAttribute Obsolete;
979 public string[] Conditionals;
980 public string DefaultIndexerName;
981 public bool IsNotCLSCompliant;
983 public static AttributesBag Read (MemberInfo mi)
985 AttributesBag bag = null;
986 List<string> conditionals = null;
988 // It should not throw any loading exception
989 IList<CustomAttributeData> attrs = CustomAttributeData.GetCustomAttributes (mi);
991 foreach (var a in attrs) {
992 var type = a.Constructor.DeclaringType;
993 if (type == typeof (ObsoleteAttribute)) {
995 bag = new AttributesBag ();
997 var args = a.ConstructorArguments;
999 if (args.Count == 1) {
1000 bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value);
1001 } else if (args.Count == 2) {
1002 bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value, (bool) args[1].Value);
1004 bag.Obsolete = new ObsoleteAttribute ();
1010 if (type == typeof (ConditionalAttribute)) {
1012 bag = new AttributesBag ();
1014 if (conditionals == null)
1015 conditionals = new List<string> (2);
1017 conditionals.Add ((string) a.ConstructorArguments[0].Value);
1021 if (type == typeof (CLSCompliantAttribute)) {
1023 bag = new AttributesBag ();
1025 bag.IsNotCLSCompliant = !(bool) a.ConstructorArguments[0].Value;
1029 // Type only attributes
1030 if (type == typeof (DefaultMemberAttribute)) {
1032 bag = new AttributesBag ();
1034 bag.DefaultIndexerName = (string) a.ConstructorArguments[0].Value;
1038 if (type == typeof (AttributeUsageAttribute)) {
1040 bag = new AttributesBag ();
1042 bag.AttributeUsage = new AttributeUsageAttribute ((AttributeTargets) a.ConstructorArguments[0].Value);
1043 foreach (var named in a.NamedArguments) {
1044 if (named.MemberInfo.Name == "AllowMultiple")
1045 bag.AttributeUsage.AllowMultiple = (bool) named.TypedValue.Value;
1046 else if (named.MemberInfo.Name == "Inherited")
1047 bag.AttributeUsage.Inherited = (bool) named.TypedValue.Value;
1056 if (conditionals != null)
1057 bag.Conditionals = conditionals.ToArray ();
1063 protected readonly MemberInfo provider;
1064 protected AttributesBag cattrs;
1066 public ImportedMemberDefinition (MemberInfo provider)
1068 this.provider = provider;
1073 public Assembly Assembly {
1075 return provider.Module.Assembly;
1079 public bool IsImported {
1085 public virtual string Name {
1087 return provider.Name;
1093 public string[] ConditionalConditions ()
1098 return cattrs.Conditionals;
1101 public ObsoleteAttribute GetAttributeObsolete ()
1106 return cattrs.Obsolete;
1109 public bool IsNotCLSCompliant ()
1114 return cattrs.IsNotCLSCompliant;
1117 protected void ReadAttributes ()
1119 cattrs = AttributesBag.Read (provider);
1122 public void SetIsAssigned ()
1124 // Unused for imported members
1127 public void SetIsUsed ()
1129 // Unused for imported members
1133 class ImportedMethodDefinition : ImportedMemberDefinition, IParametersMember
1135 readonly AParametersCollection parameters;
1137 public ImportedMethodDefinition (MethodBase provider, AParametersCollection parameters)
1140 this.parameters = parameters;
1145 public AParametersCollection Parameters {
1151 public TypeSpec MemberType {
1153 throw new NotImplementedException ();
1160 class ImportedIndexerDefinition : ImportedMemberDefinition, IParametersMember
1162 readonly AParametersCollection parameters;
1164 public ImportedIndexerDefinition (PropertyInfo provider, AParametersCollection parameters)
1167 this.parameters = parameters;
1172 public AParametersCollection Parameters {
1178 public TypeSpec MemberType {
1180 throw new NotImplementedException ();
1187 class ImportedGenericMethodDefinition : ImportedMethodDefinition, IGenericMethodDefinition
1189 TypeParameterSpec[] tparams;
1191 public ImportedGenericMethodDefinition (MethodInfo provider, AParametersCollection parameters, TypeParameterSpec[] tparams)
1192 : base (provider, parameters)
1194 this.tparams = tparams;
1199 public TypeParameterSpec[] TypeParameters {
1205 public int TypeParametersCount {
1207 return tparams.Length;
1214 class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition
1216 TypeParameterSpec[] tparams;
1218 ReflectionMetaImporter meta_import;
1220 public ImportedTypeDefinition (ReflectionMetaImporter metaImport, Type type)
1223 this.meta_import = metaImport;
1228 public override string Name {
1232 if (tparams != null)
1233 name = name.Substring (0, name.IndexOf ('`'));
1240 public string Namespace {
1242 return ((Type) provider).Namespace;
1246 public int TypeParametersCount {
1248 return tparams == null ? 0 : tparams.Length;
1252 public TypeParameterSpec[] TypeParameters {
1263 public TypeSpec GetAttributeCoClass ()
1265 // TODO: Use ReadAttributes
1266 var attr = provider.GetCustomAttributes (typeof (CoClassAttribute), false);
1267 if (attr.Length < 1)
1270 return meta_import.CreateType (((CoClassAttribute) attr[0]).CoClass);
1273 public string GetAttributeDefaultMember ()
1278 return cattrs.DefaultIndexerName;
1281 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
1286 return cattrs.AttributeUsage;
1289 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1292 // Not interested in members of nested private types unless the importer needs them
1294 if (declaringType.IsPrivate && meta_import.IgnorePrivateMembers) {
1295 cache = MemberCache.Empty;
1299 var loading_type = (Type) provider;
1300 const BindingFlags all_members = BindingFlags.DeclaredOnly |
1301 BindingFlags.Static | BindingFlags.Instance |
1302 BindingFlags.Public | BindingFlags.NonPublic;
1304 const MethodAttributes explicit_impl = MethodAttributes.NewSlot |
1305 MethodAttributes.Virtual | MethodAttributes.HideBySig |
1306 MethodAttributes.Final;
1308 Dictionary<MethodBase, MethodSpec> possible_accessors = null;
1309 List<EventSpec> imported_events = null;
1310 EventSpec event_spec;
1311 MemberSpec imported;
1315 all = loading_type.GetMembers (all_members);
1316 } catch (Exception e) {
1317 throw new InternalErrorException (e, "Could not import type `{0}' from `{1}'",
1318 declaringType.GetSignatureForError (), declaringType.Assembly.Location);
1321 if (cache == null) {
1322 cache = new MemberCache (all.Length);
1325 // Do the types first as they can be referenced by the members before
1326 // they are found or inflated
1328 foreach (var member in all) {
1329 if (member.MemberType != MemberTypes.NestedType)
1332 Type t = (Type) member;
1334 // Ignore compiler generated types, mostly lambda containers
1335 if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false))
1338 imported = meta_import.CreateType (t, declaringType, t, 0);
1339 cache.AddMember (imported);
1342 foreach (var member in all) {
1343 if (member.MemberType != MemberTypes.NestedType)
1346 meta_import.ImportTypeBase ((Type) member);
1352 // The logic here requires methods to be returned first which seems to work for both Mono and .NET
1354 foreach (var member in all) {
1355 switch (member.MemberType) {
1356 case MemberTypes.Constructor:
1357 case MemberTypes.Method:
1358 MethodBase mb = (MethodBase) member;
1359 var attrs = mb.Attributes;
1361 if ((attrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) {
1362 if (meta_import.IgnorePrivateMembers)
1365 // Ignore explicitly implemented members
1366 if ((attrs & explicit_impl) == explicit_impl)
1369 // Ignore compiler generated methods
1370 if (mb.IsDefined (typeof (CompilerGeneratedAttribute), false))
1374 imported = meta_import.CreateMethod (mb, declaringType);
1375 if (imported.Kind == MemberKind.Method && !imported.IsGeneric) {
1376 if (possible_accessors == null)
1377 possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default);
1379 // There are no metadata rules for accessors, we have to consider any method as possible candidate
1380 possible_accessors.Add (mb, (MethodSpec) imported);
1384 case MemberTypes.Property:
1385 if (possible_accessors == null)
1388 var p = (PropertyInfo) member;
1390 // Links possible accessors with property
1392 MethodSpec get, set;
1393 m = p.GetGetMethod (true);
1394 if (m == null || !possible_accessors.TryGetValue (m, out get))
1397 m = p.GetSetMethod (true);
1398 if (m == null || !possible_accessors.TryGetValue (m, out set))
1401 // No accessors registered (e.g. explicit implementation)
1402 if (get == null && set == null)
1405 imported = meta_import.CreateProperty (p, declaringType, get, set);
1406 if (imported == null)
1410 case MemberTypes.Event:
1411 if (possible_accessors == null)
1414 var e = (EventInfo) member;
1416 // Links accessors with event
1418 MethodSpec add, remove;
1419 m = e.GetAddMethod (true);
1420 if (m == null || !possible_accessors.TryGetValue (m, out add))
1423 m = e.GetRemoveMethod (true);
1424 if (m == null || !possible_accessors.TryGetValue (m, out remove))
1427 // Both accessors are required
1428 if (add == null || remove == null)
1431 event_spec = meta_import.CreateEvent (e, declaringType, add, remove);
1432 if (!meta_import.IgnorePrivateMembers) {
1433 if (imported_events == null)
1434 imported_events = new List<EventSpec> ();
1436 imported_events.Add (event_spec);
1439 imported = event_spec;
1441 case MemberTypes.Field:
1442 var fi = (FieldInfo) member;
1444 imported = meta_import.CreateField (fi, declaringType);
1445 if (imported == null)
1449 // For dynamic binder event has to be fully restored to allow operations
1450 // within the type container to work correctly
1452 if (imported_events != null) {
1453 // The backing event field should be private but it may not
1454 int index = imported_events.FindIndex (l => l.Name == fi.Name);
1456 event_spec = imported_events[index];
1457 event_spec.BackingField = (FieldSpec) imported;
1458 imported_events.RemoveAt (index);
1464 case MemberTypes.NestedType:
1465 // Already in the cache from the first pass
1468 throw new NotImplementedException (member.ToString ());
1471 cache.AddMember (imported);
1475 if (declaringType.IsInterface && declaringType.Interfaces != null) {
1476 foreach (var iface in declaringType.Interfaces) {
1477 cache.AddInterface (iface);
1483 class ImportedTypeParameterDefinition : ImportedMemberDefinition, ITypeDefinition
1485 public ImportedTypeParameterDefinition (Type type)
1492 public string Namespace {
1498 public int TypeParametersCount {
1504 public TypeParameterSpec[] TypeParameters {
1512 public TypeSpec GetAttributeCoClass ()
1517 public string GetAttributeDefaultMember ()
1519 throw new NotSupportedException ();
1522 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
1524 throw new NotSupportedException ();
1527 public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
1529 throw new NotImplementedException ();