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