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