Re-enable 'crlf' attributes on *.cs
[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                                                 if (declaringType == TypeManager.object_type) {
256                                                         mod &= ~Modifiers.OVERRIDE;
257                                                         mod |= Modifiers.VIRTUAL;
258                                                 }
259                                         }
260                                 }
261
262                                 returnType = ImportType (((MethodInfo)mb).ReturnType);
263
264                                 // Cannot set to OVERRIDE without full hierarchy checks
265                                 // this flag indicates that the method could be override
266                                 // but further validation is needed
267                                 if ((mod & Modifiers.OVERRIDE) != 0 && kind == MemberKind.Method && declaringType.BaseType != null) {
268                                         var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null);
269                                         var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None);
270
271                                         //
272                                         // For imported class method do additional validation to be sure that metadata
273                                         // override flag was correct
274                                         // 
275                                         // Difference between protected internal and protected is ok
276                                         //
277                                         const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL;
278                                         if (candidate == null || (candidate.Modifiers & conflict_mask) != (mod & conflict_mask) || candidate.IsStatic) {
279                                                 mod &= ~Modifiers.OVERRIDE;
280                                         }
281                                 }
282                         }
283
284                         MethodSpec ms = new MethodSpec (kind, declaringType, definition, returnType, mb, parameters, mod);
285                         if (tparams != null)
286                                 ms.IsGeneric = true;
287
288                         return ms;
289                 }
290
291                 //
292                 // Returns null when the property is not valid C# property
293                 //
294                 public static PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, MethodSpec get, MethodSpec set)
295                 {
296                         var definition = new ImportedMemberDefinition (pi);
297
298                         Modifiers mod = 0;
299                         AParametersCollection param = null;
300                         TypeSpec type = null;
301                         if (get != null) {
302                                 mod = get.Modifiers;
303                                 param = get.Parameters;
304                                 type = get.ReturnType;
305                         }
306
307                         bool is_valid_property = true;
308                         if (set != null) {
309                                 if (set.ReturnType != TypeManager.void_type)
310                                         is_valid_property = false;
311
312                                 var set_param_count = set.Parameters.Count - 1;
313
314                                 if (set_param_count < 0) {
315                                         set_param_count = 0;
316                                         is_valid_property = false;
317                                 }
318
319                                 var set_type = set.Parameters.Types[set_param_count];
320
321                                 if (mod == 0) {
322                                         AParametersCollection set_based_param;
323
324                                         if (set_param_count == 0) {
325                                                 set_based_param = ParametersCompiled.EmptyReadOnlyParameters;
326                                         } else {
327                                                 //
328                                                 // Create indexer parameters based on setter method parameters (the last parameter has to be removed)
329                                                 //
330                                                 var data = new IParameterData[set_param_count];
331                                                 var types = new TypeSpec[set_param_count];
332                                                 Array.Copy (set.Parameters.FixedParameters, data, set_param_count);
333                                                 Array.Copy (set.Parameters.Types, types, set_param_count);
334                                                 set_based_param = new ParametersImported (data, types, set.Parameters.HasParams);
335                                         }
336
337                                         mod = set.Modifiers;
338                                         param = set_based_param;
339                                         type = set_type;
340                                 } else {
341                                         if (set_param_count != get.Parameters.Count)
342                                                 is_valid_property = false;
343
344                                         if (get.ReturnType != set_type)
345                                                 is_valid_property = false;
346
347                                         // Possible custom accessor modifiers
348                                         if ((mod & Modifiers.AccessibilityMask) != (set.Modifiers & Modifiers.AccessibilityMask)) {
349                                                 var get_acc = mod & Modifiers.AccessibilityMask;
350                                                 if (get_acc != Modifiers.PUBLIC) {
351                                                         var set_acc = set.Modifiers & Modifiers.AccessibilityMask;
352                                                         // If the accessor modifiers are not same, do extra restriction checks
353                                                         if (get_acc != set_acc) {
354                                                                 var get_restr = ModifiersExtensions.IsRestrictedModifier (get_acc, set_acc);
355                                                                 var set_restr = ModifiersExtensions.IsRestrictedModifier (set_acc, get_acc);
356                                                                 if (get_restr && set_restr) {
357                                                                         is_valid_property = false; // Neither is more restrictive
358                                                                 }
359
360                                                                 if (get_restr) {
361                                                                         mod &= ~Modifiers.AccessibilityMask;
362                                                                         mod |= set_acc;
363                                                                 }
364                                                         }
365                                                 }
366                                         }
367                                 }
368                         }
369
370                         PropertySpec spec = null;
371                         if (!param.IsEmpty) {
372                                 var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember ();
373                                 if (index_name == null) {
374                                         is_valid_property = false;
375                                 } else {
376                                         if (get != null) {
377                                                 if (get.IsStatic)
378                                                         is_valid_property = false;
379                                                 if (get.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
380                                                         is_valid_property = false;
381                                         }
382                                         if (set != null) {
383                                                 if (set.IsStatic)
384                                                         is_valid_property = false;
385                                                 if (set.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
386                                                         is_valid_property = false;
387                                         }
388                                 }
389
390                                 if (is_valid_property)
391                                         spec = new IndexerSpec (declaringType, definition, type, param, pi, mod);
392                         }
393
394                         if (spec == null)
395                                 spec = new PropertySpec (MemberKind.Property, declaringType, definition, type, pi, mod);
396
397                         if (!is_valid_property) {
398                                 spec.IsNotRealProperty = true;
399                                 return spec;
400                         }
401
402                         if (set != null)
403                                 spec.Set = set;
404                         if (get != null)
405                                 spec.Get = get;
406
407                         return spec;
408                 }
409
410                 public static TypeSpec CreateType (Type type)
411                 {
412                         TypeSpec declaring_type;
413                         if (type.IsNested && !type.IsGenericParameter)
414                                 declaring_type = CreateType (type.DeclaringType);
415                         else
416                                 declaring_type = null;
417
418                         return CreateType (type, declaring_type);
419                 }
420
421                 public static TypeSpec CreateType (Type type, TypeSpec declaringType)
422                 {
423                         TypeSpec spec;
424                         if (import_cache.TryGetValue (type, out spec))
425                                 return spec;
426
427                         if (type.IsGenericType && !type.IsGenericTypeDefinition) {      
428                                 var type_def = type.GetGenericTypeDefinition ();
429                                 spec = CreateType (type_def, declaringType);
430
431                                 var targs = CreateGenericParameters<TypeSpec> (type, null);
432
433                                 InflatedTypeSpec inflated;
434                                 if (targs == null) {
435                                         // Inflating nested non-generic type, same in TypeSpec::InflateMember
436                                         inflated = new InflatedTypeSpec (spec, declaringType, TypeSpec.EmptyTypes);
437                                 } else {
438                                         // CreateGenericParameters constraint could inflate type
439                                         if (import_cache.ContainsKey (type))
440                                                 return import_cache[type];
441
442                                         inflated = spec.MakeGenericType (targs);
443
444                                         // Use of reading cache to speed up reading only
445                                         import_cache.Add (type, inflated);
446                                 }
447
448                                 return inflated;
449                         }
450
451                         Modifiers mod;
452                         MemberKind kind;
453
454                         var ma = type.Attributes;
455                         switch (ma & TypeAttributes.VisibilityMask) {
456                         case TypeAttributes.Public:
457                         case TypeAttributes.NestedPublic:
458                                 mod = Modifiers.PUBLIC;
459                                 break;
460                         case TypeAttributes.NestedPrivate:
461                                 mod = Modifiers.PRIVATE;
462                                 break;
463                         case TypeAttributes.NestedFamily:
464                                 mod = Modifiers.PROTECTED;
465                                 break;
466                         case TypeAttributes.NestedFamORAssem:
467                                 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
468                                 break;
469                         default:
470                                 mod = Modifiers.INTERNAL;
471                                 break;
472                         }
473
474                         if ((ma & TypeAttributes.Interface) != 0) {
475                                 kind = MemberKind.Interface;
476                         } else if (type.IsGenericParameter) {
477                                 kind = MemberKind.TypeParameter;
478                         } else if (type.IsClass || type.IsAbstract) {                           // SRE: System.Enum returns false for IsClass
479                                 if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) {
480                                         kind = MemberKind.Delegate;
481                                 } else {
482                                         kind = MemberKind.Class;
483
484                                         if (type == typeof (object)) {
485 #if NET_4_0
486                                                 var pa = PredefinedAttributes.Get.Dynamic.Type;
487                                                 if (pa != null && type.IsDefined (typeof (DynamicAttribute), false))
488                                                         return InternalType.Dynamic;
489 #endif
490                                         }
491
492                                         if ((ma & TypeAttributes.Sealed) != 0) {
493                                                 mod |= Modifiers.SEALED;
494                                                 if ((ma & TypeAttributes.Abstract) != 0)
495                                                         mod |= Modifiers.STATIC;
496                                         } else if ((ma & TypeAttributes.Abstract) != 0) {
497                                                 mod |= Modifiers.ABSTRACT;
498                                         }
499                                 }
500                         } else if (type.IsEnum) {
501                                 kind = MemberKind.Enum;
502                         } else {
503                                 kind = MemberKind.Struct;
504                                 mod |= Modifiers.SEALED;
505                         }
506
507                         var definition = new ImportedTypeDefinition (type);
508                         PredefinedTypeSpec pt;
509
510                         if (kind == MemberKind.Enum) {
511                                 const BindingFlags underlying_member = BindingFlags.DeclaredOnly |
512                                         BindingFlags.Instance |
513                                         BindingFlags.Public | BindingFlags.NonPublic;
514
515                                 var type_members = type.GetFields (underlying_member);
516                                 foreach (var type_member in type_members) {
517                                         spec = new EnumSpec (declaringType, definition, Import.CreateType (type_member.FieldType), type, mod);
518                                         break;
519                                 }
520
521                                 if (spec == null)
522                                         kind = MemberKind.Class;
523
524                         } else if (kind == MemberKind.TypeParameter) {
525                                 // Return as type_cache was updated
526                                 return CreateTypeParameter (type, declaringType);
527                         } else if (type.IsGenericTypeDefinition) {
528                                 definition.TypeParameters = CreateGenericParameters<TypeParameterSpec>(type, declaringType);
529
530                                 // Constraints are not loaded on demand and can reference this type
531                                 if (import_cache.TryGetValue (type, out spec))
532                                         return spec;
533
534                         } else if (type_2_predefined.TryGetValue (type, out pt)) {
535                                 spec = pt;
536                                 pt.SetDefinition (definition, type);
537                         }
538
539                         if (spec == null)
540                                 spec = new TypeSpec (kind, declaringType, definition, type, mod);
541
542                         import_cache.Add (type, spec);
543
544                         if (kind == MemberKind.Interface)
545                                 spec.BaseType = TypeManager.object_type;
546                         else if (type.BaseType != null)
547                                 spec.BaseType = CreateType (type.BaseType);
548
549                         var ifaces = type.GetInterfaces ();
550                         if (ifaces.Length > 0) {
551                                 foreach (Type iface in ifaces) {
552                                         spec.AddInterface (Import.CreateType (iface));
553                                 }
554                         }
555
556                         return spec;
557                 }
558
559                 static TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType)
560                 {
561                         Variance variance;
562                         switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
563                         case GenericParameterAttributes.Covariant:
564                                 variance = Variance.Covariant;
565                                 break;
566                         case GenericParameterAttributes.Contravariant:
567                                 variance = Variance.Contravariant;
568                                 break;
569                         default:
570                                 variance = Variance.None;
571                                 break;
572                         }
573
574                         SpecialConstraint special = SpecialConstraint.None;
575                         var import_special = type.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
576
577                         if ((import_special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) {
578                                 special |= SpecialConstraint.Struct;
579                         } else if ((import_special & GenericParameterAttributes.DefaultConstructorConstraint) != 0) {
580                                 special = SpecialConstraint.Constructor;
581                         }
582
583                         if ((import_special & GenericParameterAttributes.ReferenceTypeConstraint) != 0) {
584                                 special |= SpecialConstraint.Class;
585                         }
586
587                         TypeParameterSpec spec;
588                         var def = new ImportedTypeParameterDefinition (type);
589                         if (type.DeclaringMethod != null)
590                                 spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type);
591                         else
592                                 spec = new TypeParameterSpec (declaringType, type.GenericParameterPosition, def, special, variance, type);
593
594                         // Add it now, so any constraint can reference it and get same instance
595                         import_cache.Add (type, spec);
596
597                         var constraints = type.GetGenericParameterConstraints ();
598                         foreach (var ct in constraints) {
599                                 // TODO MemberCache: What to do ??
600                                 if (ct.IsGenericParameter) {
601                                         continue;
602                                 }
603
604                                 if (ct.IsClass) {
605                                         if (ct == typeof (ValueType)) {
606                                                 spec.BaseType = TypeManager.value_type;
607                                         } else {
608                                                 spec.BaseType = CreateType (ct);
609                                         }
610
611                                         continue;
612                                 }
613
614                                 spec.AddInterface (CreateType (ct));
615                         }
616
617                         if (spec.BaseType == null)
618                                 spec.BaseType = TypeManager.object_type;
619
620                         return spec;
621                 }
622
623                 public static TypeSpec ImportType (Type type)
624                 {
625                         if (type.HasElementType) {
626                                 var element = type.GetElementType ();
627                                 var spec = ImportType (element);
628
629                                 if (type.IsArray)
630                                         return ArrayContainer.MakeType (spec, type.GetArrayRank ());
631                                 if (type.IsByRef)
632                                         return ReferenceContainer.MakeType (spec);
633                                 if (type.IsPointer)
634                                         return PointerContainer.MakeType (spec);
635
636                                 throw new NotImplementedException ("Unknown element type " + type.ToString ());
637                         }
638
639                         TypeSpec dtype;
640                         if (type.IsNested)
641                                 dtype = ImportType (type.DeclaringType);
642                         else
643                                 dtype = null;
644
645                         return CreateType (type, dtype);
646                 }
647
648                 //
649                 // Decimal constants cannot be encoded in the constant blob, and thus are marked
650                 // as IsInitOnly ('readonly' in C# parlance).  We get its value from the 
651                 // DecimalConstantAttribute metadata.
652                 //
653                 static Constant ReadDecimalConstant (FieldInfo fi)
654                 {
655                         object[] attrs = fi.GetCustomAttributes (typeof (DecimalConstantAttribute), false);
656                         if (attrs.Length != 1)
657                                 return null;
658
659                         return new DecimalConstant (((DecimalConstantAttribute) attrs [0]).Value, Location.Null);
660                 }
661
662                 static Modifiers ReadMethodModifiers (MethodBase mb, TypeSpec declaringType)
663                 {
664                         Modifiers mod;
665                         var ma = mb.Attributes;
666                         switch (ma & MethodAttributes.MemberAccessMask) {
667                         case MethodAttributes.Public:
668                                 mod = Modifiers.PUBLIC;
669                                 break;
670                         case MethodAttributes.Assembly:
671                                 mod = Modifiers.INTERNAL;
672                                 break;
673                         case MethodAttributes.Family:
674                                 mod = Modifiers.PROTECTED;
675                                 break;
676                         case MethodAttributes.FamORAssem:
677                                 mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
678                                 break;
679                         default:
680                                 mod = Modifiers.PRIVATE;
681                                 break;
682                         }
683
684                         if ((ma & MethodAttributes.Static) != 0) {
685                                 mod |= Modifiers.STATIC;
686                                 return mod;
687                         }
688                         if ((ma & MethodAttributes.Abstract) != 0 && declaringType.IsClass) {
689                                 mod |= Modifiers.ABSTRACT;
690                                 return mod;
691                         }
692
693                         if ((ma & MethodAttributes.Final) != 0)
694                                 mod |= Modifiers.SEALED;
695
696                         // It can be sealed and override
697                         if ((ma & MethodAttributes.Virtual) != 0) {
698                                 if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass || mod == Modifiers.PRIVATE) {
699                                         mod |= Modifiers.VIRTUAL;
700                                 } else {
701                                         mod |= Modifiers.OVERRIDE;
702                                 }
703                         }
704
705                         return mod;
706                 }
707         }
708
709         class ImportedMemberDefinition : IMemberDefinition
710         {
711                 protected class AttributesBag
712                 {
713                         public static readonly AttributesBag Default = new AttributesBag ();
714
715                         public AttributeUsageAttribute AttributeUsage;
716                         public ObsoleteAttribute Obsolete;
717                         public string[] Conditionals;
718                         public string DefaultIndexerName;
719                         public bool IsNotCLSCompliant;
720
721                         public static AttributesBag Read (MemberInfo mi)
722                         {
723                                 AttributesBag bag = null;
724                                 List<string> conditionals = null;
725
726                                 var attrs = CustomAttributeData.GetCustomAttributes (mi);
727                                 foreach (var a in attrs) {
728                                         var type = a.Constructor.DeclaringType;
729                                         if (type == typeof (ObsoleteAttribute)) {
730                                                 if (bag == null)
731                                                         bag = new AttributesBag ();
732
733                                                 var args = a.ConstructorArguments;
734
735                                                 if (args.Count == 1) {
736                                                         bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value);
737                                                 } else if (args.Count == 2) {
738                                                         bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value, (bool) args[1].Value);
739                                                 } else {
740                                                         bag.Obsolete = new ObsoleteAttribute ();
741                                                 }
742
743                                                 continue;
744                                         }
745
746                                         if (type == typeof (ConditionalAttribute)) {
747                                                 if (bag == null)
748                                                         bag = new AttributesBag ();
749
750                                                 if (conditionals == null)
751                                                         conditionals = new List<string> (2);
752
753                                                 conditionals.Add ((string) a.ConstructorArguments[0].Value);
754                                                 continue;
755                                         }
756
757                                         if (type == typeof (CLSCompliantAttribute)) {
758                                                 if (bag == null)
759                                                         bag = new AttributesBag ();
760
761                                                 bag.IsNotCLSCompliant = !(bool) a.ConstructorArguments[0].Value;
762                                                 continue;
763                                         }
764
765                                         // Type only attributes
766                                         if (type == typeof (DefaultMemberAttribute)) {
767                                                 if (bag == null)
768                                                         bag = new AttributesBag ();
769
770                                                 bag.DefaultIndexerName = (string) a.ConstructorArguments[0].Value;
771                                                 continue;
772                                         }
773
774                                         if (type == typeof (AttributeUsageAttribute)) {
775                                                 if (bag == null)
776                                                         bag = new AttributesBag ();
777
778                                                 bag.AttributeUsage = new AttributeUsageAttribute ((AttributeTargets) a.ConstructorArguments[0].Value);
779                                                 foreach (var named in a.NamedArguments) {
780                                                         if (named.MemberInfo.Name == "AllowMultiple")
781                                                                 bag.AttributeUsage.AllowMultiple = (bool) named.TypedValue.Value;
782                                                         else if (named.MemberInfo.Name == "Inherited")
783                                                                 bag.AttributeUsage.Inherited = (bool) named.TypedValue.Value;
784                                                 }
785                                                 continue;
786                                         }
787                                 }
788
789                                 if (bag == null)
790                                         return Default;
791
792                                 if (conditionals != null)
793                                         bag.Conditionals = conditionals.ToArray ();
794
795                                 return bag;
796                         }
797                 }
798
799                 protected readonly MemberInfo provider;
800                 protected AttributesBag cattrs;
801
802                 public ImportedMemberDefinition (MemberInfo provider)
803                 {
804                         this.provider = provider;
805                 }
806
807                 #region Properties
808
809                 public Assembly Assembly {
810                         get { 
811                                 return provider.Module.Assembly;
812                         }
813                 }
814
815                 public bool IsImported {
816                         get {
817                                 return true;
818                         }
819                 }
820
821                 public virtual string Name {
822                         get {
823                                 return provider.Name;
824                         }
825                 }
826
827                 #endregion
828
829                 public string[] ConditionalConditions ()
830                 {
831                         if (cattrs == null)
832                                 ReadAttributes ();
833
834                         return cattrs.Conditionals;
835                 }
836
837                 public ObsoleteAttribute GetAttributeObsolete ()
838                 {
839                         if (cattrs == null)
840                                 ReadAttributes ();
841
842                         return cattrs.Obsolete;
843                 }
844
845                 public bool IsNotCLSCompliant ()
846                 {
847                         if (cattrs == null)
848                                 ReadAttributes ();
849
850                         return cattrs.IsNotCLSCompliant;
851                 }
852
853                 protected void ReadAttributes ()
854                 {
855                         cattrs = AttributesBag.Read (provider);
856                 }
857
858                 public void SetIsAssigned ()
859                 {
860                         // Unused for imported members
861                 }
862
863                 public void SetIsUsed ()
864                 {
865                         // Unused for imported members
866                 }
867         }
868
869         class ImportedMethodDefinition : ImportedMemberDefinition, IParametersMember
870         {
871                 readonly AParametersCollection parameters;
872
873                 public ImportedMethodDefinition (MethodBase provider, AParametersCollection parameters)
874                         : base (provider)
875                 {
876                         this.parameters = parameters;
877                 }
878
879                 #region Properties
880
881                 public AParametersCollection Parameters {
882                         get {
883                                 return parameters;
884                         }
885                 }
886
887                 public TypeSpec MemberType {
888                         get {
889                                 throw new NotImplementedException ();
890                         }
891                 }
892
893                 #endregion
894         }
895
896         class ImportedGenericMethodDefinition : ImportedMethodDefinition, IGenericMethodDefinition
897         {
898                 TypeParameterSpec[] tparams;
899
900                 public ImportedGenericMethodDefinition (MethodInfo provider, AParametersCollection parameters, TypeParameterSpec[] tparams)
901                         : base (provider, parameters)
902                 {
903                         this.tparams = tparams;
904                 }
905
906                 #region Properties
907
908                 public TypeParameterSpec[] TypeParameters {
909                         get {
910                                 return tparams;
911                         }
912                 }
913
914                 public int TypeParametersCount {
915                         get {
916                                 return tparams.Length;
917                         }
918                 }
919
920                 #endregion
921         }
922
923         class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition
924         {
925                 TypeParameterSpec[] tparams;
926                 string name;
927
928                 public ImportedTypeDefinition (Type type)
929                         : base (type)
930                 {
931                 }
932
933                 #region Properties
934
935                 public override string Name {
936                         get {
937                                 if (name == null) {
938                                         name = base.Name;
939                                         if (tparams != null)
940                                                 name = name.Substring (0, name.IndexOf ('`'));
941                                 }
942
943                                 return name;
944                         }
945                 }
946
947                 public string Namespace {
948                         get {
949                                 return ((Type) provider).Namespace;
950                         }
951                 }
952
953                 public int TypeParametersCount {
954                         get {
955                                 return tparams == null ? 0 : tparams.Length;
956                         }
957                 }
958
959                 public TypeParameterSpec[] TypeParameters {
960                         get {
961                                 return tparams;
962                         }
963                         set {
964                                 tparams = value;
965                         }
966                 }
967
968                 #endregion
969
970                 public TypeSpec GetAttributeCoClass ()
971                 {
972                         // TODO: Use ReadAttributes
973                         var attr =  provider.GetCustomAttributes (typeof (CoClassAttribute), false);
974                         if (attr.Length < 1)
975                                 return null;
976
977                         return Import.CreateType (((CoClassAttribute) attr[0]).CoClass);
978                 }
979
980                 public string GetAttributeDefaultMember ()
981                 {
982                         if (cattrs == null)
983                                 ReadAttributes ();
984
985                         return cattrs.DefaultIndexerName;
986                 }
987
988                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
989                 {
990                         if (cattrs == null)
991                                 ReadAttributes ();
992
993                         return cattrs.AttributeUsage;
994                 }
995
996                 public MemberCache LoadMembers (TypeSpec declaringType)
997                 {
998                         var loading_type = (Type) provider;
999                         const BindingFlags all_members = BindingFlags.DeclaredOnly |
1000                                 BindingFlags.Static | BindingFlags.Instance |
1001                                 BindingFlags.Public | BindingFlags.NonPublic;
1002
1003                         const MethodAttributes explicit_impl = MethodAttributes.NewSlot |
1004                                         MethodAttributes.Virtual | MethodAttributes.HideBySig |
1005                                         MethodAttributes.Final;
1006
1007                         Dictionary<MethodBase, MethodSpec> possible_accessors = null;
1008                         MemberSpec imported;
1009                         MethodInfo m;
1010
1011                         //
1012                         // This requires methods to be returned first which seems to work for both Mono and .NET
1013                         //
1014                         MemberInfo[] all;
1015                         try {
1016                                 all = loading_type.GetMembers (all_members);
1017                         } catch (Exception e) {
1018                                 throw new InternalErrorException (e, "Could not import type `{0}' from `{1}'",
1019                                         declaringType.GetSignatureForError (), declaringType.Assembly.Location);
1020                         }
1021
1022                         var cache = new MemberCache (all.Length);
1023                         foreach (var member in all) {
1024                                 switch (member.MemberType) {
1025                                 case MemberTypes.Constructor:
1026                                 case MemberTypes.Method:
1027                                         MethodBase mb = (MethodBase) member;
1028
1029                                         // Ignore explicitly implemented members
1030                                         if ((mb.Attributes & explicit_impl) == explicit_impl && (mb.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private)
1031                                                 continue;
1032
1033                                         // Ignore compiler generated methods
1034                                         if (mb.IsPrivate && mb.IsDefined (typeof (CompilerGeneratedAttribute), false))
1035                                                 continue;
1036
1037                                         imported = Import.CreateMethod (mb, declaringType);
1038                                         if (imported.Kind == MemberKind.Method && !imported.IsGeneric) {
1039                                                 if (possible_accessors == null)
1040                                                         possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default);
1041
1042                                                 // There are no metadata rules for accessors, we have to consider any method as possible candidate
1043                                                 possible_accessors.Add (mb, (MethodSpec) imported);
1044                                         }
1045
1046                                         break;
1047                                 case MemberTypes.Property:
1048                                         if (possible_accessors == null)
1049                                                 continue;
1050
1051                                         var p = (PropertyInfo) member;
1052                                         //
1053                                         // Links possible accessors with property
1054                                         //
1055                                         MethodSpec get, set;
1056                                         m = p.GetGetMethod (true);
1057                                         if (m == null || !possible_accessors.TryGetValue (m, out get))
1058                                                 get = null;
1059
1060                                         m = p.GetSetMethod (true);
1061                                         if (m == null || !possible_accessors.TryGetValue (m, out set))
1062                                                 set = null;
1063
1064                                         // No accessors registered (e.g. explicit implementation)
1065                                         if (get == null && set == null)
1066                                                 continue;
1067
1068                                         imported = Import.CreateProperty (p, declaringType, get, set);
1069                                         if (imported == null)
1070                                                 continue;
1071
1072                                         break;
1073                                 case MemberTypes.Event:
1074                                         if (possible_accessors == null)
1075                                                 continue;
1076
1077                                         var e = (EventInfo) member;
1078                                         //
1079                                         // Links accessors with event
1080                                         //
1081                                         MethodSpec add, remove;
1082                                         m = e.GetAddMethod (true);
1083                                         if (m == null || !possible_accessors.TryGetValue (m, out add))
1084                                                 add = null;
1085
1086                                         m = e.GetRemoveMethod (true);
1087                                         if (m == null || !possible_accessors.TryGetValue (m, out remove))
1088                                                 remove = null;
1089
1090                                         // Both accessors are required
1091                                         if (add == null || remove == null)
1092                                                 continue;
1093
1094                                         imported = Import.CreateEvent (e, declaringType, add, remove);
1095                                         break;
1096                                 case MemberTypes.Field:
1097                                         var fi = (FieldInfo) member;
1098
1099                                         // Ignore compiler generated fields
1100                                         if (fi.IsPrivate && fi.IsDefined (typeof (CompilerGeneratedAttribute), false))
1101                                                 continue;
1102
1103                                         imported = Import.CreateField (fi, declaringType);
1104                                         if (imported == null)
1105                                                 continue;
1106
1107                                         break;
1108                                 case MemberTypes.NestedType:
1109                                         Type t = (Type) member;
1110
1111                                         // Ignore compiler generated types, mostly lambda containers
1112                                         if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false))
1113                                                 continue;
1114
1115                                         imported = Import.CreateType (t, declaringType);
1116                                         break;
1117                                 default:
1118                                         throw new NotImplementedException (member.ToString ());
1119                                 }
1120
1121                                 cache.AddMember (imported);
1122                         }
1123
1124                         if (declaringType.IsInterface && declaringType.Interfaces != null) {
1125                                 foreach (var iface in declaringType.Interfaces) {
1126                                         cache.AddInterface (iface);
1127                                 }
1128                         }
1129
1130                         return cache;
1131                 }
1132         }
1133
1134         class ImportedTypeParameterDefinition : ImportedMemberDefinition, ITypeDefinition
1135         {
1136                 public ImportedTypeParameterDefinition (Type type)
1137                         : base (type)
1138                 {
1139                 }
1140
1141                 #region Properties
1142
1143                 public string Namespace {
1144                         get {
1145                                 return null;
1146                         }
1147                 }
1148
1149                 public int TypeParametersCount {
1150                         get {
1151                                 return 0;
1152                         }
1153                 }
1154
1155                 public TypeParameterSpec[] TypeParameters {
1156                         get {
1157                                 return null;
1158                         }
1159                 }
1160
1161                 #endregion
1162
1163                 public TypeSpec GetAttributeCoClass ()
1164                 {
1165                         return null;
1166                 }
1167
1168                 public string GetAttributeDefaultMember ()
1169                 {
1170                         throw new NotSupportedException ();
1171                 }
1172
1173                 public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
1174                 {
1175                         throw new NotSupportedException ();
1176                 }
1177
1178                 public MemberCache LoadMembers (TypeSpec declaringType)
1179                 {
1180                         throw new NotImplementedException ();
1181                 }
1182         }
1183 }