move old code to temporary dir (keep them for a while for reference.)
[mono.git] / mcs / mcs / import.cs
1 //
2 // import.cs: System.Reflection conversions
3 //
4 // Authors: Marek Safar (marek.safar@gmail.com)
5 //
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
7 //
8 // Copyright 2009, 2010 Novell, Inc
9 //
10
11 using System;
12 using System.Reflection;
13 using System.Runtime.CompilerServices;
14 using System.Linq;
15 using System.Collections.Generic;
16 using System.Diagnostics;
17 using System.Runtime.InteropServices;
18
19 namespace Mono.CSharp
20 {
21         public static class Import
22         {
23                 static Dictionary<Type, TypeSpec> import_cache;
24                 static Dictionary<Type, PredefinedTypeSpec> type_2_predefined;
25
26                 public static void Initialize ()
27                 {
28                         import_cache = new Dictionary<Type, TypeSpec> (1024, ReferenceEquality<Type>.Default);
29
30                         // Setup mapping for predefined types
31                         type_2_predefined = new Dictionary<Type, PredefinedTypeSpec> () {
32                                 { typeof (object), TypeManager.object_type },
33                                 { typeof (System.ValueType), TypeManager.value_type },
34                                 { typeof (System.Attribute), TypeManager.attribute_type },
35
36                                 { typeof (int), TypeManager.int32_type },
37                                 { typeof (long), TypeManager.int64_type },
38                                 { typeof (uint), TypeManager.uint32_type },
39                                 { typeof (ulong), TypeManager.uint64_type },
40                                 { typeof (byte), TypeManager.byte_type },
41                                 { typeof (sbyte), TypeManager.sbyte_type },
42                                 { typeof (short), TypeManager.short_type },
43                                 { typeof (ushort), TypeManager.ushort_type },
44
45                                 { typeof (System.Collections.IEnumerator), TypeManager.ienumerator_type },
46                                 { typeof (System.Collections.IEnumerable), TypeManager.ienumerable_type },
47                                 { typeof (System.IDisposable), TypeManager.idisposable_type },
48
49                                 { typeof (char), TypeManager.char_type },
50                                 { typeof (string), TypeManager.string_type },
51                                 { typeof (float), TypeManager.float_type },
52                                 { typeof (double), TypeManager.double_type },
53                                 { typeof (decimal), TypeManager.decimal_type },
54                                 { typeof (bool), TypeManager.bool_type },
55                                 { typeof (System.IntPtr), TypeManager.intptr_type },
56                                 { typeof (System.UIntPtr), TypeManager.uintptr_type },
57
58                                 { typeof (System.MulticastDelegate), TypeManager.multicast_delegate_type },
59                                 { typeof (System.Delegate), TypeManager.delegate_type },
60                                 { typeof (System.Enum), TypeManager.enum_type },
61                                 { typeof (System.Array), TypeManager.array_type },
62                                 { typeof (void), TypeManager.void_type },
63                                 { typeof (System.Type), TypeManager.type_type },
64                                 { typeof (System.Exception), TypeManager.exception_type },
65                                 { typeof (System.RuntimeFieldHandle), TypeManager.runtime_field_handle_type },
66                                 { typeof (System.RuntimeTypeHandle), TypeManager.runtime_handle_type }
67                         };
68                 }
69
70                 public static FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType)
71                 {
72                         Modifiers mod = 0;
73                         var fa = fi.Attributes;
74                         switch (fa & FieldAttributes.FieldAccessMask) {
75                                 case FieldAttributes.Public:
76                                         mod = Modifiers.PUBLIC;
77                                         break;
78                                 case FieldAttributes.Assembly:
79                                         mod = Modifiers.INTERNAL;
80                                         break;
81                                 case FieldAttributes.Family:
82                                         mod = Modifiers.PROTECTED;
83                                         break;
84                                 case FieldAttributes.FamORAssem:
85                                         mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
86                                         break;
87                                 default:
88                                         mod = Modifiers.PRIVATE;
89                                         break;
90                         }
91
92                         // Ignore private fields (even for error reporting) to not require extra dependencies
93                         if (mod == Modifiers.PRIVATE)
94                                 return null;
95
96                         var definition = new ImportedMemberDefinition (fi);
97
98                         if ((fa & FieldAttributes.Literal) != 0) {
99                                 var     c = Constant.CreateConstantFromValue (ImportType (fi.FieldType), fi.GetValue (fi), Location.Null);
100                                 return new ConstSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod, c);
101                         }
102
103                         if ((fa & FieldAttributes.InitOnly) != 0) {
104                                 if (fi.FieldType == typeof (decimal)) {
105                                         var dc = ReadDecimalConstant (fi);
106                                         if (dc != null)
107                                                 return new ConstSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod, dc);
108                                 }
109
110                                 mod |= Modifiers.READONLY;
111                         } else {
112                                 var reqs = fi.GetRequiredCustomModifiers ();
113                                 if (reqs.Length > 0) {
114                                         foreach (Type t in reqs) {
115                                                 if (t == typeof (System.Runtime.CompilerServices.IsVolatile)) {
116                                                         mod |= Modifiers.VOLATILE;
117                                                         break;
118                                                 }
119                                         }
120                                 }
121                         }
122
123                         if ((fa & FieldAttributes.Static) != 0)
124                                 mod |= Modifiers.STATIC;
125
126                         if (fi.FieldType.IsValueType) {
127                                  if (fi.IsDefined (typeof (FixedBufferAttribute), false)) {
128                                         var element_field = CreateField (fi.FieldType.GetField (FixedField.FixedElementName), declaringType);
129                                         return new FixedFieldSpec (declaringType, definition, fi, element_field, mod);
130                                 }
131                         }
132
133                         return new FieldSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod);
134                 }
135
136                 public static EventSpec CreateEvent (EventInfo ei, TypeSpec declaringType, MethodSpec add, MethodSpec remove)
137                 {
138                         add.IsAccessor = true;
139                         remove.IsAccessor = true;
140
141                         if (add.Modifiers != remove.Modifiers)
142                                 throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
143
144                         var definition = new ImportedMemberDefinition (ei);
145                         return new EventSpec (declaringType, definition, ImportType (ei.EventHandlerType), add.Modifiers, add, remove);
146                 }
147
148                 static T[] CreateGenericParameters<T> (Type type, TypeSpec declaringType) where T : TypeSpec
149                 {
150                         Type[] tparams = type.GetGenericArguments ();
151
152                         int parent_owned_count;
153                         if (type.IsNested) {
154                                 parent_owned_count = type.DeclaringType.GetGenericArguments ().Length;
155
156                                 //
157                                 // System.Reflection duplicates parent type parameters for each
158                                 // nested type with slightly modified properties (eg. different owner)
159                                 // This just makes things more complicated (think of cloned constraints)
160                                 // therefore we remap any nested type owned by parent using `type_cache'
161                                 // to the single TypeParameterSpec
162                                 //
163                                 if (declaringType != null && parent_owned_count > 0) {
164                                         int read_count = 0;
165                                         while (read_count != parent_owned_count) {
166                                                 var tparams_count = declaringType.Arity;
167                                                 if (tparams_count != 0) {
168                                                         var parent_tp = declaringType.MemberDefinition.TypeParameters;
169                                                         read_count += tparams_count;
170                                                         for (int i = 0; i < tparams_count; i++) {
171                                                                 import_cache.Add (tparams[parent_owned_count - read_count + i], parent_tp[i]);
172                                                         }
173                                                 }
174
175                                                 declaringType = declaringType.DeclaringType;
176                                         }
177                                 }                       
178                         } else {
179                                 parent_owned_count = 0;
180                         }
181
182                         if (tparams.Length - parent_owned_count == 0)
183                                 return null;
184
185                         return CreateGenericParameters<T> (parent_owned_count, tparams);
186                 }
187
188                 static T[] CreateGenericParameters<T> (int first, Type[] tparams) where T : TypeSpec
189                 {
190                         var tspec = new T [tparams.Length - first];
191                         for (int pos = first; pos < tparams.Length; ++pos) {
192                                 var type = tparams[pos];
193                                 if (type.HasElementType) {
194                                         var element = type.GetElementType ();
195                                         var spec = CreateType (element);
196
197                                         if (type.IsArray) {
198                                                 tspec[pos - first] = (T) (TypeSpec) ArrayContainer.MakeType (spec, type.GetArrayRank ());
199                                                 continue;
200                                         }
201
202                                         throw new NotImplementedException ("Unknown element type " + type.ToString ());
203                                 }
204
205                                 tspec [pos - first] = (T) CreateType (type);
206                         }
207
208                         return tspec;
209                 }
210
211                 public static MethodSpec CreateMethod (MethodBase mb, TypeSpec declaringType)
212                 {
213                         Modifiers mod = ReadMethodModifiers (mb, declaringType);
214                         //if (declaringType.IsInterface) {
215                         //    mod = (mod & ~Modifiers.ABSTRACT) | Modifiers.VIRTUAL;
216                         //}
217
218                         TypeParameterSpec[] tparams;
219                         ImportedMethodDefinition definition;
220
221                         var parameters = ParametersImported.Create (declaringType, mb);
222
223                         if (mb.IsGenericMethod) {
224                                 if (!mb.IsGenericMethodDefinition)
225                                         throw new NotSupportedException ("assert");
226
227                                 tparams = CreateGenericParameters<TypeParameterSpec>(0, mb.GetGenericArguments ());
228                                 definition = new ImportedGenericMethodDefinition ((MethodInfo) mb, parameters, tparams);
229                         } else {
230                                 definition = new ImportedMethodDefinition (mb, parameters);
231                                 tparams = null;
232                         }
233
234                         MemberKind kind;
235                         TypeSpec returnType;
236                         if (mb.MemberType == MemberTypes.Constructor) {
237                                 kind = MemberKind.Constructor;
238                                 returnType = TypeManager.void_type;
239                         } else {
240                                 //
241                                 // Detect operators and destructors
242                                 //
243                                 string name = mb.Name;
244                                 kind = MemberKind.Method;
245                                 if (tparams == null && !mb.DeclaringType.IsInterface && name.Length > 6) {
246                                         if ((mod & (Modifiers.STATIC | Modifiers.PUBLIC)) == (Modifiers.STATIC | Modifiers.PUBLIC)) {
247                                                 if (name[2] == '_' && name[1] == 'p' && name[0] == 'o') {
248                                                         var op_type = Operator.GetType (name);
249                                                         if (op_type.HasValue && parameters.Count > 0 && parameters.Count < 3) {
250                                                                 kind = MemberKind.Operator;
251                                                         }
252                                                 }
253                                         } else if (parameters.IsEmpty && name == Destructor.MetadataName) {
254                                                 kind = MemberKind.Destructor;
255                                         }
256                                 }
257
258                                 returnType = ImportType (((MethodInfo)mb).ReturnType);
259
260                                 // Cannot set to OVERRIDE without full hierarchy checks
261                                 // this flag indicates that the method could be override
262                                 // but further validation is needed
263                                 if ((mod & Modifiers.OVERRIDE) != 0 && kind == MemberKind.Method && declaringType.BaseType != null) {
264                                         var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null);
265                                         var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None);
266
267                                         //
268                                         // For imported class method do additional validation to be sure that metadata
269                                         // override flag was correct
270                                         // 
271                                         // Difference between protected internal and protected is ok
272                                         //
273                                         const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL;
274                                         if (candidate == null || (candidate.Modifiers & conflict_mask) != (mod & conflict_mask) || candidate.IsStatic) {
275                                                 mod &= ~Modifiers.OVERRIDE;
276                                         }
277                                 }
278                         }
279
280                         MethodSpec ms = new MethodSpec (kind, declaringType, definition, returnType, mb, parameters, mod);
281                         if (tparams != null)
282                                 ms.IsGeneric = true;
283
284                         return ms;
285                 }
286
287                 //
288                 // Returns null when the property is not valid C# property
289                 //
290                 public static PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, MethodSpec get, MethodSpec set)
291                 {
292                         var definition = new ImportedMemberDefinition (pi);
293
294                         Modifiers mod = 0;
295                         AParametersCollection param = null;
296                         TypeSpec type = null;
297                         if (get != null) {
298                                 mod = get.Modifiers;
299                                 param = get.Parameters;
300                                 type = get.ReturnType;
301                         }
302
303                         bool is_valid_property = true;
304                         if (set != null) {
305                                 if (set.ReturnType != TypeManager.void_type)
306                                         is_valid_property = false;
307
308                                 var set_param_count = set.Parameters.Count - 1;
309                                 if (set_param_count < 0)
310                                         is_valid_property = false;
311
312                                 var data = new IParameterData [set_param_count];
313                                 var types = new TypeSpec[set_param_count];
314                                 for (int i = 0; i < set_param_count; ++i ) {
315                                         data[i] = set.Parameters.FixedParameters[i];
316                                         types[i] = set.Parameters.Types[i];
317                                 }
318
319                                 var set_param = new ParametersImported (data, types);
320                                 var set_type = set.Parameters.Types[set_param_count];
321
322                                 if (mod == 0) {
323                                         mod = set.Modifiers;
324                                         param = set_param;
325                                         type = set_type;
326                                 } else {
327                                         if (set_param_count != get.Parameters.Count)
328                                                 is_valid_property = false;
329
330                                         if (get.ReturnType != set_type)
331                                                 is_valid_property = false;
332
333                                         // Possible custom accessor modifiers
334                                         if ((mod & Modifiers.AccessibilityMask) != (set.Modifiers & Modifiers.AccessibilityMask)) {
335                                                 var get_acc = mod & Modifiers.AccessibilityMask;
336                                                 if (get_acc != Modifiers.PUBLIC) {
337                                                         var set_acc = set.Modifiers & Modifiers.AccessibilityMask;
338                                                         // If the accessor modifiers are not same, do extra restriction checks
339                                                         if (get_acc != set_acc) {
340                                                                 var get_restr = ModifiersExtensions.IsRestrictedModifier (get_acc, set_acc);
341                                                                 var set_restr = ModifiersExtensions.IsRestrictedModifier (set_acc, get_acc);
342                                                                 if (get_restr && set_restr) {
343                                                                         is_valid_property = false; // Neither is more restrictive
344                                                                 }
345
346                                                                 if (get_restr) {
347                                                                         mod &= ~Modifiers.AccessibilityMask;
348                                                                         mod |= set_acc;
349                                                                 }
350                                                         }
351                                                 }
352                                         }
353                                 }
354                         }
355
356                         PropertySpec spec = null;
357                         if (!param.IsEmpty) {
358                                 var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember ();
359                                 if (index_name == null) {
360                                         is_valid_property = false;
361                                 } else {
362                                         if (get != null) {
363                                                 if (get.IsStatic)
364                                                         is_valid_property = false;
365                                                 if (get.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
366                                                         is_valid_property = false;
367                                         }
368                                         if (set != null) {
369                                                 if (set.IsStatic)
370                                                         is_valid_property = false;
371                                                 if (set.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
372                                                         is_valid_property = false;
373                                         }
374                                 }
375
376                                 if (is_valid_property)
377                                         spec = new IndexerSpec (declaringType, definition, type, param, pi, mod);
378                         }
379
380                         if (spec == null)
381                                 spec = new PropertySpec (MemberKind.Property, declaringType, definition, type, pi, mod);
382
383                         if (!is_valid_property) {
384                                 spec.IsNotRealProperty = true;
385                                 return spec;
386                         }
387
388                         if (set != null)
389                                 spec.Set = set;
390                         if (get != null)
391                                 spec.Get = get;
392
393                         return spec;
394                 }
395
396                 public static TypeSpec CreateType (Type type)
397                 {
398                         return CreateType (type, null);
399                 }
400
401                 public static TypeSpec CreateType (Type type, TypeSpec declaringType)
402                 {
403                         TypeSpec spec;
404                         if (import_cache.TryGetValue (type, out spec))
405                                 return spec;
406
407                         if (type.IsGenericType && !type.IsGenericTypeDefinition) {      
408                                 var type_def = type.GetGenericTypeDefinition ();
409                                 spec = CreateType (type_def, declaringType);
410
411                                 var targs = CreateGenericParameters<TypeSpec> (type, null);
412
413                                 InflatedTypeSpec inflated;
414                                 if (targs == null) {
415                                         // Inflating nested non-generic type, same in TypeSpec::InflateMember
416                                         inflated = new InflatedTypeSpec (spec, declaringType, TypeSpec.EmptyTypes);
417                                 } else {
418                                         // CreateGenericParameters constraint could inflate type
419                                         if (import_cache.ContainsKey (type))
420                                                 return import_cache[type];
421
422                                         inflated = spec.MakeGenericType (targs);
423
424                                         // Use of reading cache to speed up reading only
425                                         import_cache.Add (type, inflated);
426                                 }
427
428                                 return inflated;
429                         }
430
431                         Modifiers mod;
432                         MemberKind kind;
433
434                         var ma = type.Attributes;
435                         switch (ma & TypeAttributes.VisibilityMask) {
436                         case TypeAttributes.Public:
437                         case TypeAttributes.NestedPublic:
438                                 mod = Modifiers.PUBLIC;
439                                 break;
440                         case TypeAttributes.NestedPrivate:
441                                 mod = Modifiers.PRIVATE;
442                                 break;
443                         case TypeAttributes.NestedFamily:
444                                 mod = Modifiers.PROTECTED;
445                                 break;
446                         case TypeAttributes.NestedFamORAssem:
447                                 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
448                                 break;
449                         default:
450                                 mod = Modifiers.INTERNAL;
451                                 break;
452                         }
453
454                         if ((ma & TypeAttributes.Interface) != 0) {
455                                 kind = MemberKind.Interface;
456                         } else if (type.IsGenericParameter) {
457                                 kind = MemberKind.TypeParameter;
458                         } else if (type.IsClass || type.IsAbstract) {                           // SRE: System.Enum returns false for IsClass
459                                 if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) {
460                                         kind = MemberKind.Delegate;
461                                 } else {
462                                         kind = MemberKind.Class;
463
464                                         if (type == typeof (object)) {
465 #if NET_4_0
466                                                 var pa = PredefinedAttributes.Get.Dynamic.Type;
467                                                 if (pa != null && type.IsDefined (typeof (DynamicAttribute), false))
468                                                         return InternalType.Dynamic;
469 #endif
470                                         }
471
472                                         if ((ma & TypeAttributes.Sealed) != 0) {
473                                                 mod |= Modifiers.SEALED;
474                                                 if ((ma & TypeAttributes.Abstract) != 0)
475                                                         mod |= Modifiers.STATIC;
476                                         } else if ((ma & TypeAttributes.Abstract) != 0) {
477                                                 mod |= Modifiers.ABSTRACT;
478                                         }
479                                 }
480                         } else if (type.IsEnum) {
481                                 kind = MemberKind.Enum;
482                         } else {
483                                 kind = MemberKind.Struct;
484                                 mod |= Modifiers.SEALED;
485                         }
486
487                         var definition = new ImportedTypeDefinition (type);
488                         PredefinedTypeSpec pt;
489
490                         if (kind == MemberKind.Enum) {
491                                 const BindingFlags underlying_member = BindingFlags.DeclaredOnly |
492                                         BindingFlags.Instance |
493                                         BindingFlags.Public | BindingFlags.NonPublic;
494
495                                 var type_members = type.GetFields (underlying_member);
496                                 foreach (var type_member in type_members) {
497                                         spec = new EnumSpec (declaringType, definition, Import.CreateType (type_member.FieldType), type, mod);
498                                         break;
499                                 }
500
501                                 if (spec == null)
502                                         kind = MemberKind.Class;
503
504                         } else if (kind == MemberKind.TypeParameter) {
505                                 // Return as type_cache was updated
506                                 return CreateTypeParameter (type, declaringType);
507                         } else if (type.IsGenericTypeDefinition) {
508                                 definition.TypeParameters = CreateGenericParameters<TypeParameterSpec>(type, declaringType);
509
510                                 // Constraints are not loaded on demand and can reference this type
511                                 if (import_cache.TryGetValue (type, out spec))
512                                         return spec;
513
514                         } else if (type_2_predefined.TryGetValue (type, out pt)) {
515                                 spec = pt;
516                                 pt.SetDefinition (definition, type);
517                         }
518
519                         if (spec == null)
520                                 spec = new TypeSpec (kind, declaringType, definition, type, mod);
521
522                         import_cache.Add (type, spec);
523
524                         if (kind == MemberKind.Interface)
525                                 spec.BaseType = TypeManager.object_type;
526                         else if (type.BaseType != null)
527                                 spec.BaseType = CreateType (type.BaseType);
528
529                         var ifaces = type.GetInterfaces ();
530                         if (ifaces.Length > 0) {
531                                 foreach (Type iface in ifaces) {
532                                         spec.AddInterface (Import.CreateType (iface));
533                                 }
534                         }
535
536                         return spec;
537                 }
538
539                 static TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType)
540                 {
541                         Variance variance;
542                         switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
543                         case GenericParameterAttributes.Covariant:
544                                 variance = Variance.Covariant;
545                                 break;
546                         case GenericParameterAttributes.Contravariant:
547                                 variance = Variance.Contravariant;
548                                 break;
549                         default:
550                                 variance = Variance.None;
551                                 break;
552                         }
553
554                         SpecialConstraint special = SpecialConstraint.None;
555                         var import_special = type.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
556
557                         if ((import_special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) {
558                                 special |= SpecialConstraint.Struct;
559                         } else if ((import_special & GenericParameterAttributes.DefaultConstructorConstraint) != 0) {
560                                 special = SpecialConstraint.Constructor;
561                         }
562
563                         if ((import_special & GenericParameterAttributes.ReferenceTypeConstraint) != 0) {
564                                 special |= SpecialConstraint.Class;
565                         }
566
567                         TypeParameterSpec spec;
568                         var def = new ImportedTypeParameterDefinition (type);
569                         if (type.DeclaringMethod != null)
570                                 spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type);
571                         else
572                                 spec = new TypeParameterSpec (declaringType, type.GenericParameterPosition, def, special, variance, type);
573
574                         // Add it now, so any constraint can reference it and get same instance
575                         import_cache.Add (type, spec);
576
577                         var constraints = type.GetGenericParameterConstraints ();
578                         foreach (var ct in constraints) {
579                                 // TODO MemberCache: What to do ??
580                                 if (ct.IsGenericParameter) {
581                                         continue;
582                                 }
583
584                                 if (ct.IsClass) {
585                                         if (ct == typeof (ValueType)) {
586                                                 spec.BaseType = TypeManager.value_type;
587                                         } else {
588                                                 spec.BaseType = CreateType (ct);
589                                         }
590
591                                         continue;
592                                 }
593
594                                 spec.AddInterface (CreateType (ct));
595                         }
596
597                         if (spec.BaseType == null)
598                                 spec.BaseType = TypeManager.object_type;
599
600                         return spec;
601                 }
602
603                 public static TypeSpec ImportType (Type type)
604                 {
605                         if (type.HasElementType) {
606                                 var element = type.GetElementType ();
607                                 var spec = ImportType (element);
608
609                                 if (type.IsArray)
610                                         return ArrayContainer.MakeType (spec, type.GetArrayRank ());
611                                 if (type.IsByRef)
612                                         return ReferenceContainer.MakeType (spec);
613                                 if (type.IsPointer)
614                                         return PointerContainer.MakeType (spec);
615
616                                 throw new NotImplementedException ("Unknown element type " + type.ToString ());
617                         }
618
619                         TypeSpec dtype;
620                         if (type.IsNested)
621                                 dtype = ImportType (type.DeclaringType);
622                         else
623                                 dtype = null;
624
625                         return CreateType (type, dtype);
626                 }
627
628                 //
629                 // Decimal constants cannot be encoded in the constant blob, and thus are marked
630                 // as IsInitOnly ('readonly' in C# parlance).  We get its value from the 
631                 // DecimalConstantAttribute metadata.
632                 //
633                 static Constant ReadDecimalConstant (FieldInfo fi)
634                 {
635                         object[] attrs = fi.GetCustomAttributes (typeof (DecimalConstantAttribute), false);
636                         if (attrs.Length != 1)
637                                 return null;
638
639                         return new DecimalConstant (((DecimalConstantAttribute) attrs [0]).Value, Location.Null);
640                 }
641
642                 static Modifiers ReadMethodModifiers (MethodBase mb, TypeSpec declaringType)
643                 {
644                         Modifiers mod;
645                         var ma = mb.Attributes;
646                         switch (ma & MethodAttributes.MemberAccessMask) {
647                         case MethodAttributes.Public:
648                                 mod = Modifiers.PUBLIC;
649                                 break;
650                         case MethodAttributes.Assembly:
651                                 mod = Modifiers.INTERNAL;
652                                 break;
653                         case MethodAttributes.Family:
654                                 mod = Modifiers.PROTECTED;
655                                 break;
656                         case MethodAttributes.FamORAssem:
657                                 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
658                                 break;
659                         default:
660                                 mod = Modifiers.PRIVATE;
661                                 break;
662                         }
663
664                         if ((ma & MethodAttributes.Static) != 0) {
665                                 mod |= Modifiers.STATIC;
666                         } else if ((ma & MethodAttributes.Final) != 0) {
667                                 mod |= Modifiers.SEALED;
668                         } else if ((ma & MethodAttributes.Abstract) != 0 && declaringType.IsClass) {
669                                 mod |= Modifiers.ABSTRACT;
670                         }
671
672                         // It can be sealed and override
673                         if ((ma & MethodAttributes.Virtual) != 0) {
674                                 if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass || mod == Modifiers.PRIVATE) {
675                                         mod |= Modifiers.VIRTUAL;
676                                 } else {
677                                         mod |= Modifiers.OVERRIDE;
678                                 }
679                         }
680
681                         return mod;
682                 }
683         }
684
685         class ImportedMemberDefinition : IMemberDefinition
686         {
687                 protected class AttributesBag
688                 {
689                         public static readonly AttributesBag Default = new AttributesBag ();
690
691                         public AttributeUsageAttribute AttributeUsage;
692                         public ObsoleteAttribute Obsolete;
693                         public string[] Conditionals;
694                         public string DefaultIndexerName;
695                         public bool IsNotCLSCompliant;
696
697                         public static AttributesBag Read (MemberInfo mi)
698                         {
699                                 AttributesBag bag = null;
700                                 List<string> conditionals = null;
701
702                                 var attrs = CustomAttributeData.GetCustomAttributes (mi);
703                                 foreach (var a in attrs) {
704                                         var type = a.Constructor.DeclaringType;
705                                         if (type == typeof (ObsoleteAttribute)) {
706                                                 if (bag == null)
707                                                         bag = new AttributesBag ();
708
709                                                 var args = a.ConstructorArguments;
710
711                                                 if (args.Count == 1) {
712                                                         bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value);
713                                                 } else if (args.Count == 2) {
714                                                         bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value, (bool) args[1].Value);
715                                                 } else {
716                                                         bag.Obsolete = new ObsoleteAttribute ();
717                                                 }
718
719                                                 continue;
720                                         }
721
722                                         if (type == typeof (ConditionalAttribute)) {
723                                                 if (bag == null)
724                                                         bag = new AttributesBag ();
725
726                                                 if (conditionals == null)
727                                                         conditionals = new List<string> (2);
728
729                                                 conditionals.Add ((string) a.ConstructorArguments[0].Value);
730                                                 continue;
731                                         }
732
733                                         if (type == typeof (CLSCompliantAttribute)) {
734                                                 if (bag == null)
735                                                         bag = new AttributesBag ();
736
737                                                 bag.IsNotCLSCompliant = !(bool) a.ConstructorArguments[0].Value;
738                                                 continue;
739                                         }
740
741                                         // Type only attributes
742                                         if (type == typeof (DefaultMemberAttribute)) {
743                                                 if (bag == null)
744                                                         bag = new AttributesBag ();
745
746                                                 bag.DefaultIndexerName = (string) a.ConstructorArguments[0].Value;
747                                                 continue;
748                                         }
749
750                                         if (type == typeof (AttributeUsageAttribute)) {
751                                                 if (bag == null)
752                                                         bag = new AttributesBag ();
753
754                                                 bag.AttributeUsage = new AttributeUsageAttribute ((AttributeTargets) a.ConstructorArguments[0].Value);
755                                                 foreach (var named in a.NamedArguments) {
756                                                         if (named.MemberInfo.Name == "AllowMultiple")
757                                                                 bag.AttributeUsage.AllowMultiple = (bool) named.TypedValue.Value;
758                                                         else if (named.MemberInfo.Name == "Inherited")
759                                                                 bag.AttributeUsage.Inherited = (bool) named.TypedValue.Value;
760                                                 }
761                                                 continue;
762                                         }
763                                 }
764
765                                 if (bag == null)
766                                         return Default;
767
768                                 if (conditionals != null)
769                                         bag.Conditionals = conditionals.ToArray ();
770
771                                 return bag;
772                         }
773                 }
774
775                 protected readonly MemberInfo provider;
776                 protected AttributesBag cattrs;
777
778                 public ImportedMemberDefinition (MemberInfo provider)
779                 {
780                         this.provider = provider;
781                 }
782
783                 #region Properties
784
785                 public Assembly Assembly {
786                         get { 
787                                 return provider.Module.Assembly;
788                         }
789                 }
790
791                 public bool IsImported {
792                         get {
793                                 return true;
794                         }
795                 }
796
797                 public virtual string Name {
798                         get {
799                                 return provider.Name;
800                         }
801                 }
802
803                 #endregion
804
805                 public string[] ConditionalConditions ()
806                 {
807                         if (cattrs == null)
808                                 ReadAttributes ();
809
810                         return cattrs.Conditionals;
811                 }
812
813                 public ObsoleteAttribute GetAttributeObsolete ()
814                 {
815                         if (cattrs == null)
816                                 ReadAttributes ();
817
818                         return cattrs.Obsolete;
819                 }
820
821                 public bool IsNotCLSCompliant ()
822                 {
823                         if (cattrs == null)
824                                 ReadAttributes ();
825
826                         return cattrs.IsNotCLSCompliant;
827                 }
828
829                 protected void ReadAttributes ()
830                 {
831                         cattrs = AttributesBag.Read (provider);
832                 }
833
834                 public void SetIsAssigned ()
835                 {
836                         // Unused for imported members
837                 }
838
839                 public void SetIsUsed ()
840                 {
841                         // Unused for imported members
842                 }
843         }
844
845         class ImportedMethodDefinition : ImportedMemberDefinition, IParametersMember
846         {
847                 readonly AParametersCollection parameters;
848
849                 public ImportedMethodDefinition (MethodBase provider, AParametersCollection parameters)
850                         : base (provider)
851                 {
852                         this.parameters = parameters;
853                 }
854
855                 #region Properties
856
857                 public AParametersCollection Parameters {
858                         get {
859                                 return parameters;
860                         }
861                 }
862
863                 public TypeSpec MemberType {
864                         get {
865                                 throw new NotImplementedException ();
866                         }
867                 }
868
869                 #endregion
870         }
871
872         class ImportedGenericMethodDefinition : ImportedMethodDefinition, IGenericMethodDefinition
873         {
874                 TypeParameterSpec[] tparams;
875
876                 public ImportedGenericMethodDefinition (MethodInfo provider, AParametersCollection parameters, TypeParameterSpec[] tparams)
877                         : base (provider, parameters)
878                 {
879                         this.tparams = tparams;
880                 }
881
882                 #region Properties
883
884                 public TypeParameterSpec[] TypeParameters {
885                         get {
886                                 return tparams;
887                         }
888                 }
889
890                 public int TypeParametersCount {
891                         get {
892                                 return tparams.Length;
893                         }
894                 }
895
896                 #endregion
897         }
898
899         class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition
900         {
901                 TypeParameterSpec[] tparams;
902                 string name;
903
904                 public ImportedTypeDefinition (Type type)
905                         : base (type)
906                 {
907                 }
908
909                 #region Properties
910
911                 public override string Name {
912                         get {
913                                 if (name == null) {
914                                         name = base.Name;
915                                         if (tparams != null)
916                                                 name = name.Substring (0, name.IndexOf ('`'));
917                                 }
918
919                                 return name;
920                         }
921                 }
922
923                 public string Namespace {
924                         get {
925                                 return ((Type) provider).Namespace;
926                         }
927                 }
928
929                 public int TypeParametersCount {
930                         get {
931                                 return tparams == null ? 0 : tparams.Length;
932                         }
933                 }
934
935                 public TypeParameterSpec[] TypeParameters {
936                         get {
937                                 return tparams;
938                         }
939                         set {
940                                 tparams = value;
941                         }
942                 }
943
944                 #endregion
945
946                 public TypeSpec GetAttributeCoClass ()
947                 {
948                         // TODO: Use ReadAttributes
949                         var attr =  provider.GetCustomAttributes (typeof (CoClassAttribute), false);
950                         if (attr.Length < 1)
951                                 return null;
952
953                         return Import.CreateType (((CoClassAttribute) attr[0]).CoClass);
954                 }
955
956                 public string GetAttributeDefaultMember ()
957                 {
958                         if (cattrs == null)
959                                 ReadAttributes ();
960
961                         return cattrs.DefaultIndexerName;
962                 }
963
964                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
965                 {
966                         if (cattrs == null)
967                                 ReadAttributes ();
968
969                         return cattrs.AttributeUsage;
970                 }
971
972                 public MemberCache LoadMembers (TypeSpec declaringType)
973                 {
974                         var loading_type = (Type) provider;
975                         const BindingFlags all_members = BindingFlags.DeclaredOnly |
976                                 BindingFlags.Static | BindingFlags.Instance |
977                                 BindingFlags.Public | BindingFlags.NonPublic;
978
979                         const MethodAttributes explicit_impl = MethodAttributes.NewSlot |
980                                         MethodAttributes.Virtual | MethodAttributes.HideBySig |
981                                         MethodAttributes.Final;
982
983                         Dictionary<MethodBase, MethodSpec> possible_accessors = null;
984                         MemberSpec imported;
985                         MethodInfo m;
986
987                         //
988                         // This requires methods to be returned first which seems to work for both Mono and .NET
989                         //
990                         MemberInfo[] all;
991                         try {
992                                 all = loading_type.GetMembers (all_members);
993                         } catch (Exception e) {
994                                 throw new InternalErrorException (e, "Could not import type `{0}' from `{1}'",
995                                         declaringType.GetSignatureForError (), declaringType.Assembly.Location);
996                         }
997
998                         var cache = new MemberCache (all.Length);
999                         foreach (var member in all) {
1000                                 switch (member.MemberType) {
1001                                 case MemberTypes.Constructor:
1002                                 case MemberTypes.Method:
1003                                         MethodBase mb = (MethodBase) member;
1004
1005                                         // Ignore explicitly implemented members
1006                                         if ((mb.Attributes & explicit_impl) == explicit_impl && (mb.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
1007                                                 continue;
1008
1009                                         // Ignore compiler generated methods
1010                                         if (mb.IsPrivate && mb.IsDefined (typeof (CompilerGeneratedAttribute), false))
1011                                                 continue;
1012
1013                                         imported = Import.CreateMethod (mb, declaringType);
1014                                         if (imported.Kind == MemberKind.Method && !imported.IsGeneric) {
1015                                                 if (possible_accessors == null)
1016                                                         possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default);
1017
1018                                                 // There are no metadata rules for accessors, we have to consider any method as possible candidate
1019                                                 possible_accessors.Add (mb, (MethodSpec) imported);
1020                                         }
1021
1022                                         break;
1023                                 case MemberTypes.Property:
1024                                         if (possible_accessors == null)
1025                                                 continue;
1026
1027                                         var p = (PropertyInfo) member;
1028                                         //
1029                                         // Links possible accessors with property
1030                                         //
1031                                         MethodSpec get, set;
1032                                         m = p.GetGetMethod (true);
1033                                         if (m == null || !possible_accessors.TryGetValue (m, out get))
1034                                                 get = null;
1035
1036                                         m = p.GetSetMethod (true);
1037                                         if (m == null || !possible_accessors.TryGetValue (m, out set))
1038                                                 set = null;
1039
1040                                         // No accessors registered (e.g. explicit implementation)
1041                                         if (get == null && set == null)
1042                                                 continue;
1043
1044                                         imported = Import.CreateProperty (p, declaringType, get, set);
1045                                         if (imported == null)
1046                                                 continue;
1047
1048                                         break;
1049                                 case MemberTypes.Event:
1050                                         if (possible_accessors == null)
1051                                                 continue;
1052
1053                                         var e = (EventInfo) member;
1054                                         //
1055                                         // Links accessors with event
1056                                         //
1057                                         MethodSpec add, remove;
1058                                         m = e.GetAddMethod (true);
1059                                         if (m == null || !possible_accessors.TryGetValue (m, out add))
1060                                                 add = null;
1061
1062                                         m = e.GetRemoveMethod (true);
1063                                         if (m == null || !possible_accessors.TryGetValue (m, out remove))
1064                                                 remove = null;
1065
1066                                         // Both accessors are required
1067                                         if (add == null || remove == null)
1068                                                 continue;
1069
1070                                         imported = Import.CreateEvent (e, declaringType, add, remove);
1071                                         break;
1072                                 case MemberTypes.Field:
1073                                         var fi = (FieldInfo) member;
1074
1075                                         // Ignore compiler generated fields
1076                                         if (fi.IsPrivate && fi.IsDefined (typeof (CompilerGeneratedAttribute), false))
1077                                                 continue;
1078
1079                                         imported = Import.CreateField (fi, declaringType);
1080                                         if (imported == null)
1081                                                 continue;
1082
1083                                         break;
1084                                 case MemberTypes.NestedType:
1085                                         Type t = (Type) member;
1086
1087                                         // Ignore compiler generated types, mostly lambda containers
1088                                         if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false))
1089                                                 continue;
1090
1091                                         imported = Import.CreateType (t, declaringType);
1092                                         break;
1093                                 default:
1094                                         throw new NotImplementedException (member.ToString ());
1095                                 }
1096
1097                                 cache.AddMember (imported);
1098                         }
1099
1100                         if (declaringType.IsInterface && declaringType.Interfaces != null) {
1101                                 foreach (var iface in declaringType.Interfaces) {
1102                                         cache.AddInterface (iface);
1103                                 }
1104                         }
1105
1106                         return cache;
1107                 }
1108         }
1109
1110         class ImportedTypeParameterDefinition : ImportedMemberDefinition, ITypeDefinition
1111         {
1112                 public ImportedTypeParameterDefinition (Type type)
1113                         : base (type)
1114                 {
1115                 }
1116
1117                 #region Properties
1118
1119                 public string Namespace {
1120                         get {
1121                                 return null;
1122                         }
1123                 }
1124
1125                 public int TypeParametersCount {
1126                         get {
1127                                 return 0;
1128                         }
1129                 }
1130
1131                 public TypeParameterSpec[] TypeParameters {
1132                         get {
1133                                 return null;
1134                         }
1135                 }
1136
1137                 #endregion
1138
1139                 public TypeSpec GetAttributeCoClass ()
1140                 {
1141                         return null;
1142                 }
1143
1144                 public string GetAttributeDefaultMember ()
1145                 {
1146                         throw new NotSupportedException ();
1147                 }
1148
1149                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
1150                 {
1151                         throw new NotSupportedException ();
1152                 }
1153
1154                 public MemberCache LoadMembers (TypeSpec declaringType)
1155                 {
1156                         throw new NotImplementedException ();
1157                 }
1158         }
1159 }