2010-05-20 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / import.cs
index 3f333c02cc74deb7b1b7a97af07b5d0a9f7ba714..8a960c3a5e3735fc9b7f84c379e9e969d1cc646b 100644 (file)
@@ -5,29 +5,70 @@
 //
 // Dual licensed under the terms of the MIT X11 or GNU GPL
 //
-// Copyright 2009 Novell, Inc
+// Copyright 2009, 2010 Novell, Inc
 //
 
 using System;
 using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Linq;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
 
 namespace Mono.CSharp
 {
-       static class Import
+       public static class Import
        {
-               public static FieldSpec CreateField (FieldInfo fi)
+               static Dictionary<Type, TypeSpec> import_cache;
+               static Dictionary<Type, PredefinedTypeSpec> type_2_predefined;
+
+               public static void Initialize ()
                {
-                       // TODO: remove after MemberCache fix
-                       var cs = TypeManager.GetConstant (fi);
-                       if (cs != null)
-                               return cs;
-                       var fb = TypeManager.GetFieldCore (fi);
-                       if (fb != null)
-                               return fb.Spec;
-                       // End
+                       import_cache = new Dictionary<Type, TypeSpec> (1024, ReferenceEquality<Type>.Default);
+
+                       // Setup mapping for predefined types
+                       type_2_predefined = new Dictionary<Type, PredefinedTypeSpec> () {
+                               { typeof (object), TypeManager.object_type },
+                               { typeof (System.ValueType), TypeManager.value_type },
+                               { typeof (System.Attribute), TypeManager.attribute_type },
+
+                               { typeof (int), TypeManager.int32_type },
+                               { typeof (long), TypeManager.int64_type },
+                               { typeof (uint), TypeManager.uint32_type },
+                               { typeof (ulong), TypeManager.uint64_type },
+                               { typeof (byte), TypeManager.byte_type },
+                               { typeof (sbyte), TypeManager.sbyte_type },
+                               { typeof (short), TypeManager.short_type },
+                               { typeof (ushort), TypeManager.ushort_type },
+
+                               { typeof (System.Collections.IEnumerator), TypeManager.ienumerator_type },
+                               { typeof (System.Collections.IEnumerable), TypeManager.ienumerable_type },
+                               { typeof (System.IDisposable), TypeManager.idisposable_type },
+
+                               { typeof (char), TypeManager.char_type },
+                               { typeof (string), TypeManager.string_type },
+                               { typeof (float), TypeManager.float_type },
+                               { typeof (double), TypeManager.double_type },
+                               { typeof (decimal), TypeManager.decimal_type },
+                               { typeof (bool), TypeManager.bool_type },
+                               { typeof (System.IntPtr), TypeManager.intptr_type },
+                               { typeof (System.UIntPtr), TypeManager.uintptr_type },
+
+                               { typeof (System.MulticastDelegate), TypeManager.multicast_delegate_type },
+                               { typeof (System.Delegate), TypeManager.delegate_type },
+                               { typeof (System.Enum), TypeManager.enum_type },
+                               { typeof (System.Array), TypeManager.array_type },
+                               { typeof (void), TypeManager.void_type },
+                               { typeof (System.Type), TypeManager.type_type },
+                               { typeof (System.Exception), TypeManager.exception_type },
+                               { typeof (System.RuntimeFieldHandle), TypeManager.runtime_field_handle_type },
+                               { typeof (System.RuntimeTypeHandle), TypeManager.runtime_handle_type }
+                       };
+               }
 
+               public static FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType)
+               {
                        Modifiers mod = 0;
                        var fa = fi.Attributes;
                        switch (fa & FieldAttributes.FieldAccessMask) {
@@ -48,60 +89,522 @@ namespace Mono.CSharp
                                        break;
                        }
 
-                       // TODO: Remove completely
-                       IMemberDetails details;
-                       var gfd = TypeManager.GetGenericFieldDefinition (fi);
-                       fb = TypeManager.GetFieldCore (gfd);
-                       if (fb != null) {
-                               details = fb;
-                       } else {
-                               cs = TypeManager.GetConstant (gfd);
-                               if (cs != null)
-                                       details = cs.MemberDetails;
-                               else
-                                       details = new ImportedMemberDetails (fi);
-                       }
+                       // Ignore private fields (even for error reporting) to not require extra dependencies
+                       if (mod == Modifiers.PRIVATE)
+                               return null;
 
-                       if ((fa & FieldAttributes.Literal) != 0) {
-                               Expression c;
-                               if (gfd is System.Reflection.Emit.FieldBuilder) {
-                                       // TODO: Remove after MemberCache
-                                       c = TypeManager.GetConstant (gfd).Value;
-                               } else {
-                                       c = Constant.CreateConstantFromValue (fi.FieldType, gfd.GetValue (gfd), Location.Null);
-                               }
+                       var definition = new ImportedMemberDefinition (fi);
 
-                               return new ConstSpec (details, fi, mod, c);
+                       if ((fa & FieldAttributes.Literal) != 0) {
+                               var     c = Constant.CreateConstantFromValue (ImportType (fi.FieldType), fi.GetValue (fi), Location.Null);
+                               return new ConstSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod, c);
                        }
 
                        if ((fa & FieldAttributes.InitOnly) != 0) {
-                               if (fi.FieldType == TypeManager.decimal_type) {
-                                       var dc = ReadDecimalConstant (gfd);
+                               if (fi.FieldType == typeof (decimal)) {
+                                       var dc = ReadDecimalConstant (fi);
                                        if (dc != null)
-                                               return new ConstSpec (details, fi, mod, dc);
+                                               return new ConstSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod, dc);
                                }
 
                                mod |= Modifiers.READONLY;
+                       } else {
+                               var reqs = fi.GetRequiredCustomModifiers ();
+                               if (reqs.Length > 0) {
+                                       foreach (Type t in reqs) {
+                                               if (t == typeof (System.Runtime.CompilerServices.IsVolatile)) {
+                                                       mod |= Modifiers.VOLATILE;
+                                                       break;
+                                               }
+                                       }
+                               }
                        }
 
                        if ((fa & FieldAttributes.Static) != 0)
                                mod |= Modifiers.STATIC;
 
-                       if (!TypeManager.IsReferenceType (fi.FieldType)) {
-                               PredefinedAttribute pa = PredefinedAttributes.Get.FixedBuffer;
-                               if (pa.IsDefined) {
-                                       if (gfd is System.Reflection.Emit.FieldBuilder) {
-                                                // TODO: Remove this after MemberCache fix
-                                       } else if (gfd.IsDefined (pa.Type, false)) {
-                                               var element_field = fi.FieldType.GetField (FixedField.FixedElementName);
-                                               return new FixedFieldSpec (details, fi, element_field, mod);
+                       if (fi.FieldType.IsValueType) {
+                                if (fi.IsDefined (typeof (FixedBufferAttribute), false)) {
+                                       var element_field = CreateField (fi.FieldType.GetField (FixedField.FixedElementName), declaringType);
+                                       return new FixedFieldSpec (declaringType, definition, fi, element_field, mod);
+                               }
+                       }
+
+                       return new FieldSpec (declaringType, definition, ImportType (fi.FieldType), fi, mod);
+               }
+
+               public static EventSpec CreateEvent (EventInfo ei, TypeSpec declaringType, MethodSpec add, MethodSpec remove)
+               {
+                       add.IsAccessor = true;
+                       remove.IsAccessor = true;
+
+                       if (add.Modifiers != remove.Modifiers)
+                               throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
+
+                       var definition = new ImportedMemberDefinition (ei);
+                       return new EventSpec (declaringType, definition, ImportType (ei.EventHandlerType), add.Modifiers, add, remove);
+               }
+
+               static T[] CreateGenericParameters<T> (Type type, TypeSpec declaringType) where T : TypeSpec
+               {
+                       Type[] tparams = type.GetGenericArguments ();
+
+                       int parent_owned_count;
+                       if (type.IsNested) {
+                               parent_owned_count = type.DeclaringType.GetGenericArguments ().Length;
+
+                               //
+                               // System.Reflection duplicates parent type parameters for each
+                               // nested type with slightly modified properties (eg. different owner)
+                               // This just makes things more complicated (think of cloned constraints)
+                               // therefore we remap any nested type owned by parent using `type_cache'
+                               // to the single TypeParameterSpec
+                               //
+                               if (declaringType != null && parent_owned_count > 0) {
+                                       int read_count = 0;
+                                       while (read_count != parent_owned_count) {
+                                               var tparams_count = declaringType.Arity;
+                                               if (tparams_count != 0) {
+                                                       var parent_tp = declaringType.MemberDefinition.TypeParameters;
+                                                       read_count += tparams_count;
+                                                       for (int i = 0; i < tparams_count; i++) {
+                                                               import_cache.Add (tparams[parent_owned_count - read_count + i], parent_tp[i]);
+                                                       }
+                                               }
+
+                                               declaringType = declaringType.DeclaringType;
+                                       }
+                               }                       
+                       } else {
+                               parent_owned_count = 0;
+                       }
+
+                       if (tparams.Length - parent_owned_count == 0)
+                               return null;
+
+                       return CreateGenericParameters<T> (parent_owned_count, tparams);
+               }
+
+               static T[] CreateGenericParameters<T> (int first, Type[] tparams) where T : TypeSpec
+               {
+                       var tspec = new T [tparams.Length - first];
+                       for (int pos = first; pos < tparams.Length; ++pos) {
+                               var type = tparams[pos];
+                               if (type.HasElementType) {
+                                       var element = type.GetElementType ();
+                                       var spec = CreateType (element);
+
+                                       if (type.IsArray) {
+                                               tspec[pos - first] = (T) (TypeSpec) ArrayContainer.MakeType (spec, type.GetArrayRank ());
+                                               continue;
+                                       }
+
+                                       throw new NotImplementedException ("Unknown element type " + type.ToString ());
+                               }
+
+                               tspec [pos - first] = (T) CreateType (type);
+                       }
+
+                       return tspec;
+               }
+
+               public static MethodSpec CreateMethod (MethodBase mb, TypeSpec declaringType)
+               {
+                       Modifiers mod = ReadMethodModifiers (mb, declaringType);
+                       //if (declaringType.IsInterface) {
+                       //    mod = (mod & ~Modifiers.ABSTRACT) | Modifiers.VIRTUAL;
+                       //}
+
+                       bool is_generic;
+                       ImportedMethodDefinition definition;
+
+                       var parameters = ParametersImported.Create (declaringType, mb);
+
+                       if (mb.IsGenericMethod) {
+                               if (!mb.IsGenericMethodDefinition)
+                                       throw new NotSupportedException ("assert");
+
+                               var tparams = CreateGenericParameters<TypeParameterSpec>(0, mb.GetGenericArguments ());
+                               definition = new ImportedGenericMethodDefinition ((MethodInfo) mb, parameters, tparams);
+                               is_generic = true;
+                       } else {
+                               definition = new ImportedMethodDefinition (mb, parameters);
+                               is_generic = false;
+                       }
+
+                       MemberKind kind;
+                       TypeSpec returnType;
+                       if (mb.MemberType == MemberTypes.Constructor) {
+                               kind = MemberKind.Constructor;
+                               returnType = TypeManager.void_type;
+                       } else {
+                               //
+                               // Detect operators and destructors
+                               //
+                               string name = mb.Name;
+                               kind = MemberKind.Method;
+                               if (!mb.DeclaringType.IsInterface && name.Length > 6) {
+                                       if ((mod & (Modifiers.STATIC | Modifiers.PUBLIC)) == (Modifiers.STATIC | Modifiers.PUBLIC)) {
+                                               if (name[2] == '_' && name[1] == 'p' && name[0] == 'o') {
+                                                       var op_type = Operator.GetType (name);
+                                                       if (op_type.HasValue) {
+                                                               kind = MemberKind.Operator;
+                                                       }
+                                               }
+                                       } else if (parameters.IsEmpty && name == Destructor.MetadataName) {
+                                               kind = MemberKind.Destructor;
+                                       }
+                               }
+
+                               returnType = ImportType (((MethodInfo)mb).ReturnType);
+                       }
+
+                       MethodSpec ms = new MethodSpec (kind, declaringType, definition, returnType, mb, parameters, mod);
+                       if (is_generic)
+                               ms.IsGeneric = true;
+
+                       return ms;
+               }
+
+               //
+               // Returns null when the property is not valid C# property
+               //
+               public static PropertySpec CreateProperty (PropertyInfo pi, TypeSpec declaringType, MethodSpec get, MethodSpec set)
+               {
+                       var definition = new ImportedMemberDefinition (pi);
+
+                       Modifiers mod = 0;
+                       AParametersCollection param = null;
+                       TypeSpec type = null;
+                       if (get != null) {
+                               mod = get.Modifiers;
+                               param = get.Parameters;
+                               type = get.ReturnType;
+                       }
+
+                       bool is_valid_property = true;
+                       if (set != null) {
+                               if (set.ReturnType != TypeManager.void_type)
+                                       is_valid_property = false;
+
+                               var set_param_count = set.Parameters.Count - 1;
+                               if (set_param_count < 0)
+                                       is_valid_property = false;
+
+                               var data = new IParameterData [set_param_count];
+                               var types = new TypeSpec[set_param_count];
+                               for (int i = 0; i < set_param_count; ++i ) {
+                                       data[i] = set.Parameters.FixedParameters[i];
+                                       types[i] = set.Parameters.Types[i];
+                               }
+
+                               var set_param = new ParametersImported (data, types);
+                               var set_type = set.Parameters.Types[set_param_count];
+
+                               if (mod == 0) {
+                                       mod = set.Modifiers;
+                                       param = set_param;
+                                       type = set_type;
+                               } else {
+                                       if (set_param_count != get.Parameters.Count)
+                                               is_valid_property = false;
+
+                                       if (get.ReturnType != set_type)
+                                               is_valid_property = false;
+
+                                       // Possible custom accessor modifiers
+                                       if ((mod & ~Modifiers.AccessibilityMask) != (set.Modifiers & ~Modifiers.AccessibilityMask)) {
+                                               var get_acc = mod & Modifiers.AccessibilityMask;
+                                               if (get_acc != Modifiers.PUBLIC) {
+                                                       var set_acc = set.Modifiers & Modifiers.AccessibilityMask;
+                                                       // If the accessor modifiers are not same, do extra restriction checks
+                                                       if (get_acc != set_acc) {
+                                                               var get_restr = ModifiersExtensions.IsRestrictedModifier (get_acc, set_acc);
+                                                               var set_restr = ModifiersExtensions.IsRestrictedModifier (set_acc, get_acc);
+                                                               if (get_restr && set_restr) {
+                                                                       is_valid_property = false; // Neither is more restrictive
+                                                               }
+
+                                                               if (set_restr) {
+                                                                       mod &= ~Modifiers.AccessibilityMask;
+                                                                       mod |= set_acc;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       PropertySpec spec = null;
+                       if (!param.IsEmpty) {
+                               var index_name = declaringType.MemberDefinition.GetAttributeDefaultMember ();
+                               if (index_name == null) {
+                                       is_valid_property = false;
+                               } else {
+                                       if (get != null) {
+                                               if (get.IsStatic)
+                                                       is_valid_property = false;
+                                               if (get.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
+                                                       is_valid_property = false;
+                                       }
+                                       if (set != null) {
+                                               if (set.IsStatic)
+                                                       is_valid_property = false;
+                                               if (set.Name.IndexOf (index_name, StringComparison.Ordinal) != 4)
+                                                       is_valid_property = false;
+                                       }
+                               }
+
+                               if (is_valid_property)
+                                       spec = new IndexerSpec (declaringType, definition, type, param, pi, mod);
+                       }
+
+                       if (spec == null)
+                               spec = new PropertySpec (MemberKind.Property, declaringType, definition, type, pi, mod);
+
+                       if (!is_valid_property) {
+                               spec.IsNotRealProperty = true;
+                               return spec;
+                       }
+
+                       if (set != null)
+                               spec.Set = set;
+                       if (get != null)
+                               spec.Get = get;
+
+                       return spec;
+               }
+
+               public static TypeSpec CreateType (Type type)
+               {
+                       return CreateType (type, null);
+               }
+
+               public static TypeSpec CreateType (Type type, TypeSpec declaringType)
+               {
+                       TypeSpec spec;
+                       if (import_cache.TryGetValue (type, out spec))
+                               return spec;
+
+                       if (type.IsGenericType && !type.IsGenericTypeDefinition) {      
+                               var type_def = type.GetGenericTypeDefinition ();
+                               spec = CreateType (type_def, declaringType);
+
+                               var targs = CreateGenericParameters<TypeSpec> (type, null);
+
+                               InflatedTypeSpec inflated;
+                               if (targs == null) {
+                                       // Inflating nested non-generic type, same in TypeSpec::InflateMember
+                                       inflated = new InflatedTypeSpec (spec, declaringType, TypeSpec.EmptyTypes);
+                               } else {
+                                       // CreateGenericParameters constraint could inflate type
+                                       if (import_cache.ContainsKey (type))
+                                               return import_cache[type];
+
+                                       inflated = spec.MakeGenericType (targs);
+
+                                       // Use of reading cache to speed up reading only
+                                       import_cache.Add (type, inflated);
+                               }
+
+                               return inflated;
+                       }
+
+                       Modifiers mod;
+                       MemberKind kind;
+
+                       var ma = type.Attributes;
+                       switch (ma & TypeAttributes.VisibilityMask) {
+                       case TypeAttributes.Public:
+                       case TypeAttributes.NestedPublic:
+                               mod = Modifiers.PUBLIC;
+                               break;
+                       case TypeAttributes.NestedPrivate:
+                               mod = Modifiers.PRIVATE;
+                               break;
+                       case TypeAttributes.NestedFamily:
+                               mod = Modifiers.PROTECTED;
+                               break;
+                       case TypeAttributes.NestedFamORAssem:
+                               mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
+                               break;
+                       default:
+                               mod = Modifiers.INTERNAL;
+                               break;
+                       }
+
+                       if ((ma & TypeAttributes.Interface) != 0) {
+                               kind = MemberKind.Interface;
+                       } else if (type.IsGenericParameter) {
+                               kind = MemberKind.TypeParameter;
+                       } else if (type.IsClass || type.IsAbstract) {                           // SRE: System.Enum returns false for IsClass
+                               if ((ma & TypeAttributes.Sealed) != 0 && type.IsSubclassOf (typeof (MulticastDelegate))) {
+                                       kind = MemberKind.Delegate;
+                               } else {
+                                       kind = MemberKind.Class;
+
+                                       if (type == typeof (object)) {
+#if NET_4_0
+                                               var pa = PredefinedAttributes.Get.Dynamic.Type;
+                                               if (pa != null && type.IsDefined (typeof (DynamicAttribute), false))
+                                                       return InternalType.Dynamic;
+#endif
+                                       }
+
+                                       if ((ma & TypeAttributes.Sealed) != 0) {
+                                               mod |= Modifiers.SEALED;
+                                               if ((ma & TypeAttributes.Abstract) != 0)
+                                                       mod |= Modifiers.STATIC;
+                                       } else if ((ma & TypeAttributes.Abstract) != 0) {
+                                               mod |= Modifiers.ABSTRACT;
                                        }
                                }
+                       } else if (type.IsEnum) {
+                               kind = MemberKind.Enum;
+                       } else {
+                               kind = MemberKind.Struct;
+                               mod |= Modifiers.SEALED;
                        }
 
-                       // TODO: volatile
+                       var definition = new ImportedTypeDefinition (type);
+                       PredefinedTypeSpec pt;
+
+                       if (kind == MemberKind.Enum) {
+                               const BindingFlags underlying_member = BindingFlags.DeclaredOnly |
+                                       BindingFlags.Instance |
+                                       BindingFlags.Public | BindingFlags.NonPublic;
+
+                               var type_members = type.GetFields (underlying_member);
+                               foreach (var type_member in type_members) {
+                                       spec = new EnumSpec (declaringType, definition, Import.CreateType (type_member.FieldType), type, mod);
+                                       break;
+                               }
+
+                               if (spec == null)
+                                       kind = MemberKind.Class;
+
+                       } else if (kind == MemberKind.TypeParameter) {
+                               // Return as type_cache was updated
+                               return CreateTypeParameter (type, declaringType);
+                       } else if (type.IsGenericTypeDefinition) {
+                               definition.TypeParameters = CreateGenericParameters<TypeParameterSpec>(type, declaringType);
+
+                               // Constraints are not loaded on demand and can reference this type
+                               if (import_cache.TryGetValue (type, out spec))
+                                       return spec;
 
-                       return new FieldSpec (details, fi, mod);
+                       } else if (type_2_predefined.TryGetValue (type, out pt)) {
+                               spec = pt;
+                               pt.SetDefinition (definition, type);
+                       }
+
+                       if (spec == null)
+                               spec = new TypeSpec (kind, declaringType, definition, type, mod);
+
+                       import_cache.Add (type, spec);
+
+                       if (kind == MemberKind.Interface)
+                               spec.BaseType = TypeManager.object_type;
+                       else if (type.BaseType != null)
+                               spec.BaseType = CreateType (type.BaseType);
+
+                       var ifaces = type.GetInterfaces ();
+                       if (ifaces.Length > 0) {
+                               foreach (Type iface in ifaces) {
+                                       spec.AddInterface (Import.CreateType (iface));
+                               }
+                       }
+
+                       return spec;
+               }
+
+               static TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType)
+               {
+                       Variance variance;
+                       switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
+                       case GenericParameterAttributes.Covariant:
+                               variance = Variance.Covariant;
+                               break;
+                       case GenericParameterAttributes.Contravariant:
+                               variance = Variance.Contravariant;
+                               break;
+                       default:
+                               variance = Variance.None;
+                               break;
+                       }
+
+                       SpecialConstraint special = SpecialConstraint.None;
+                       var import_special = type.GenericParameterAttributes & GenericParameterAttributes.SpecialConstraintMask;
+
+                       if ((import_special & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) {
+                               special |= SpecialConstraint.Struct;
+                       } else if ((import_special & GenericParameterAttributes.DefaultConstructorConstraint) != 0) {
+                               special = SpecialConstraint.Constructor;
+                       }
+
+                       if ((import_special & GenericParameterAttributes.ReferenceTypeConstraint) != 0) {
+                               special |= SpecialConstraint.Class;
+                       }
+
+                       TypeParameterSpec spec;
+                       var def = new ImportedTypeParameterDefinition (type);
+                       if (type.DeclaringMethod != null)
+                               spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type);
+                       else
+                               spec = new TypeParameterSpec (declaringType, type.GenericParameterPosition, def, special, variance, type);
+
+                       // Add it now, so any constraint can reference it and get same instance
+                       import_cache.Add (type, spec);
+
+                       var constraints = type.GetGenericParameterConstraints ();
+                       foreach (var ct in constraints) {
+                               // TODO MemberCache: What to do ??
+                               if (ct.IsGenericParameter) {
+                                       continue;
+                               }
+
+                               if (ct.IsClass) {
+                                       if (ct == typeof (ValueType)) {
+                                               spec.BaseType = TypeManager.value_type;
+                                       } else {
+                                               spec.BaseType = CreateType (ct);
+                                       }
+
+                                       continue;
+                               }
+
+                               spec.AddInterface (CreateType (ct));
+                       }
+
+                       if (spec.BaseType == null)
+                               spec.BaseType = TypeManager.object_type;
+
+                       return spec;
+               }
+
+               public static TypeSpec ImportType (Type type)
+               {
+                       if (type.HasElementType) {
+                               var element = type.GetElementType ();
+                               var spec = ImportType (element);
+
+                               if (type.IsArray)
+                                       return ArrayContainer.MakeType (spec, type.GetArrayRank ());
+                               if (type.IsByRef)
+                                       return ReferenceContainer.MakeType (spec);
+                               if (type.IsPointer)
+                                       return PointerContainer.MakeType (spec);
+
+                               throw new NotImplementedException ("Unknown element type " + type.ToString ());
+                       }
+
+                       TypeSpec dtype;
+                       if (type.IsNested)
+                               dtype = ImportType (type.DeclaringType);
+                       else
+                               dtype = null;
+
+                       return CreateType (type, dtype);
                }
 
                //
@@ -111,34 +614,534 @@ namespace Mono.CSharp
                //
                static Constant ReadDecimalConstant (FieldInfo fi)
                {
-                       PredefinedAttribute pa = PredefinedAttributes.Get.DecimalConstant;
-                       if (!pa.IsDefined)
-                               return null;
-
-                       object[] attrs = fi.GetCustomAttributes (pa.Type, false);
+                       object[] attrs = fi.GetCustomAttributes (typeof (DecimalConstantAttribute), false);
                        if (attrs.Length != 1)
                                return null;
 
                        return new DecimalConstant (((DecimalConstantAttribute) attrs [0]).Value, Location.Null);
                }
+
+               static Modifiers ReadMethodModifiers (MethodBase mb, TypeSpec declaringType)
+               {
+                       Modifiers mod;
+                       var ma = mb.Attributes;
+                       switch (ma & MethodAttributes.MemberAccessMask) {
+                       case MethodAttributes.Public:
+                               mod = Modifiers.PUBLIC;
+                               break;
+                       case MethodAttributes.Assembly:
+                               mod = Modifiers.INTERNAL;
+                               break;
+                       case MethodAttributes.Family:
+                               mod = Modifiers.PROTECTED;
+                               break;
+                       case MethodAttributes.FamORAssem:
+                               mod = Modifiers.PROTECTED | Modifiers.INTERNAL;
+                               break;
+                       default:
+                               mod = Modifiers.PRIVATE;
+                               break;
+                       }
+
+                       if ((ma & MethodAttributes.Static) != 0) {
+                               mod |= Modifiers.STATIC;
+                       } else if ((ma & MethodAttributes.Final) != 0) {
+                               mod |= Modifiers.SEALED;
+                       } else if ((ma & MethodAttributes.Abstract) != 0 && declaringType.IsClass) {
+                               mod |= Modifiers.ABSTRACT;
+                       }
+
+                       // It can be sealed and override
+                       if ((ma & MethodAttributes.Virtual) != 0) {
+                               if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass || mod == Modifiers.PRIVATE) {
+                                       mod |= Modifiers.VIRTUAL;
+                               } else {
+                                       // Cannot set to OVERRIDE without full hierarchy checks
+                                       // this flag indicates that the method could be override
+                                       // but further validation is needed
+                                       mod |= Modifiers.OVERRIDE_UNCHECKED;
+                               }
+                       }
+
+                       return mod;
+               }
        }
 
-       class ImportedMemberDetails : IMemberDetails
+       class ImportedMemberDefinition : IMemberDefinition
        {
-               readonly ICustomAttributeProvider provider;
+               protected class AttributesBag
+               {
+                       public static readonly AttributesBag Default = new AttributesBag ();
+
+                       public AttributeUsageAttribute AttributeUsage;
+                       public ObsoleteAttribute Obsolete;
+                       public string[] Conditionals;
+                       public string DefaultIndexerName;
+                       public bool IsNotCLSCompliant;
+
+                       public static AttributesBag Read (MemberInfo mi)
+                       {
+                               AttributesBag bag = null;
+                               List<string> conditionals = null;
+
+                               var attrs = CustomAttributeData.GetCustomAttributes (mi);
+                               foreach (var a in attrs) {
+                                       var type = a.Constructor.DeclaringType;
+                                       if (type == typeof (ObsoleteAttribute)) {
+                                               if (bag == null)
+                                                       bag = new AttributesBag ();
+
+                                               var args = a.ConstructorArguments;
+
+                                               if (args.Count == 1) {
+                                                       bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value);
+                                               } else if (args.Count == 2) {
+                                                       bag.Obsolete = new ObsoleteAttribute ((string) args[0].Value, (bool) args[1].Value);
+                                               } else {
+                                                       bag.Obsolete = new ObsoleteAttribute ();
+                                               }
 
-               public ImportedMemberDetails (ICustomAttributeProvider provider)
+                                               continue;
+                                       }
+
+                                       if (type == typeof (ConditionalAttribute)) {
+                                               if (bag == null)
+                                                       bag = new AttributesBag ();
+
+                                               if (conditionals == null)
+                                                       conditionals = new List<string> (2);
+
+                                               conditionals.Add ((string) a.ConstructorArguments[0].Value);
+                                               continue;
+                                       }
+
+                                       if (type == typeof (CLSCompliantAttribute)) {
+                                               if (bag == null)
+                                                       bag = new AttributesBag ();
+
+                                               bag.IsNotCLSCompliant = !(bool) a.ConstructorArguments[0].Value;
+                                               continue;
+                                       }
+
+                                       // Type only attributes
+                                       if (type == typeof (DefaultMemberAttribute)) {
+                                               if (bag == null)
+                                                       bag = new AttributesBag ();
+
+                                               bag.DefaultIndexerName = (string) a.ConstructorArguments[0].Value;
+                                               continue;
+                                       }
+
+                                       if (type == typeof (AttributeUsageAttribute)) {
+                                               if (bag == null)
+                                                       bag = new AttributesBag ();
+
+                                               bag.AttributeUsage = new AttributeUsageAttribute ((AttributeTargets) a.ConstructorArguments[0].Value);
+                                               foreach (var named in a.NamedArguments) {
+                                                       if (named.MemberInfo.Name == "AllowMultiple")
+                                                               bag.AttributeUsage.AllowMultiple = (bool) named.TypedValue.Value;
+                                                       else if (named.MemberInfo.Name == "Inherited")
+                                                               bag.AttributeUsage.Inherited = (bool) named.TypedValue.Value;
+                                               }
+                                               continue;
+                                       }
+                               }
+
+                               if (bag == null)
+                                       return Default;
+
+                               if (conditionals != null)
+                                       bag.Conditionals = conditionals.ToArray ();
+
+                               return bag;
+                       }
+               }
+
+               protected readonly MemberInfo provider;
+               protected AttributesBag cattrs;
+
+               public ImportedMemberDefinition (MemberInfo provider)
                {
                        this.provider = provider;
                }
 
-               public ObsoleteAttribute GetObsoleteAttribute ()
+               #region Properties
+
+               public Assembly Assembly {
+                       get { 
+                               return provider.Module.Assembly;
+                       }
+               }
+
+               public bool IsImported {
+                       get {
+                               return true;
+                       }
+               }
+
+               public virtual string Name {
+                       get {
+                               return provider.Name;
+                       }
+               }
+
+               #endregion
+
+               public string[] ConditionalConditions ()
+               {
+                       if (cattrs == null)
+                               ReadAttributes ();
+
+                       return cattrs.Conditionals;
+               }
+
+               public ObsoleteAttribute GetAttributeObsolete ()
+               {
+                       if (cattrs == null)
+                               ReadAttributes ();
+
+                       return cattrs.Obsolete;
+               }
+
+               public bool IsNotCLSCompliant ()
+               {
+                       if (cattrs == null)
+                               ReadAttributes ();
+
+                       return cattrs.IsNotCLSCompliant;
+               }
+
+               protected void ReadAttributes ()
+               {
+                       cattrs = AttributesBag.Read (provider);
+               }
+
+               public void SetIsAssigned ()
+               {
+                       // Unused for imported members
+               }
+
+               public void SetIsUsed ()
+               {
+                       // Unused for imported members
+               }
+       }
+
+       class ImportedMethodDefinition : ImportedMemberDefinition, IParametersMember
+       {
+               readonly AParametersCollection parameters;
+
+               public ImportedMethodDefinition (MethodBase provider, AParametersCollection parameters)
+                       : base (provider)
+               {
+                       this.parameters = parameters;
+               }
+
+               #region Properties
+
+               public AParametersCollection Parameters {
+                       get {
+                               return parameters;
+                       }
+               }
+
+               public TypeSpec MemberType {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               #endregion
+       }
+
+       class ImportedGenericMethodDefinition : ImportedMethodDefinition, IGenericMethodDefinition
+       {
+               TypeParameterSpec[] tparams;
+
+               public ImportedGenericMethodDefinition (MethodInfo provider, AParametersCollection parameters, TypeParameterSpec[] tparams)
+                       : base (provider, parameters)
+               {
+                       this.tparams = tparams;
+               }
+
+               #region Properties
+
+               public TypeParameterSpec[] TypeParameters {
+                       get {
+                               return tparams;
+                       }
+               }
+
+               public int TypeParametersCount {
+                       get {
+                               return tparams.Length;
+                       }
+               }
+
+               #endregion
+       }
+
+       class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition
+       {
+               TypeParameterSpec[] tparams;
+               string name;
+
+               public ImportedTypeDefinition (Type type)
+                       : base (type)
+               {
+               }
+
+               #region Properties
+
+               public override string Name {
+                       get {
+                               if (name == null) {
+                                       name = base.Name;
+                                       if (tparams != null)
+                                               name = name.Substring (0, name.IndexOf ('`'));
+                               }
+
+                               return name;
+                       }
+               }
+
+               public string Namespace {
+                       get {
+                               return ((Type) provider).Namespace;
+                       }
+               }
+
+               public int TypeParametersCount {
+                       get {
+                               return tparams == null ? 0 : tparams.Length;
+                       }
+               }
+
+               public TypeParameterSpec[] TypeParameters {
+                       get {
+                               return tparams;
+                       }
+                       set {
+                               tparams = value;
+                       }
+               }
+
+               #endregion
+
+               public TypeSpec GetAttributeCoClass ()
                {
-                       var res = provider.GetCustomAttributes (typeof (ObsoleteAttribute), false);
-                       if (res == null || res.Length < 1)
+                       // TODO: Use ReadAttributes
+                       var attr =  provider.GetCustomAttributes (typeof (CoClassAttribute), false);
+                       if (attr.Length < 1)
                                return null;
 
-                       return res [0] as ObsoleteAttribute;
+                       return Import.CreateType (((CoClassAttribute) attr[0]).CoClass);
+               }
+
+               public string GetAttributeDefaultMember ()
+               {
+                       if (cattrs == null)
+                               ReadAttributes ();
+
+                       return cattrs.DefaultIndexerName;
+               }
+
+               public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
+               {
+                       if (cattrs == null)
+                               ReadAttributes ();
+
+                       return cattrs.AttributeUsage;
+               }
+
+               public MemberCache LoadMembers (TypeSpec declaringType)
+               {
+                       var loading_type = (Type) provider;
+                       const BindingFlags all_members = BindingFlags.DeclaredOnly |
+                               BindingFlags.Static | BindingFlags.Instance |
+                               BindingFlags.Public | BindingFlags.NonPublic;
+
+                       const MethodAttributes explicit_impl = MethodAttributes.NewSlot |
+                                       MethodAttributes.Virtual | MethodAttributes.HideBySig |
+                                       MethodAttributes.Final | MethodAttributes.Private;
+
+                       Dictionary<MethodBase, MethodSpec> possible_accessors = null;
+                       MemberSpec imported;
+                       MethodInfo m;
+                       List<string> fields_to_ignore = null;
+
+                       //
+                       // This requires methods to be returned first which seems to work for both Mono and .NET
+                       //
+                       var all = loading_type.GetMembers (all_members);
+
+                       var cache = new MemberCache (all.Length);
+                       foreach (var member in all) {
+                               switch (member.MemberType) {
+                               case MemberTypes.Constructor:
+                               case MemberTypes.Method:
+                                       MethodBase mb = (MethodBase) member;
+
+                                       // Ignore explicitly implemented members
+                                       if ((mb.Attributes & explicit_impl) == explicit_impl)
+                                               continue;
+
+                                       // Ignore compiler generated methods
+                                       if (mb.IsPrivate && mb.IsDefined (typeof (CompilerGeneratedAttribute), false))
+                                               continue;
+
+                                       imported = Import.CreateMethod (mb, declaringType);
+                                       if (imported.Kind == MemberKind.Method) {
+                                               if (possible_accessors == null)
+                                                       possible_accessors = new Dictionary<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.Default);
+
+                                               // There are no metadata rules for accessors, we have to any method as possible candidate
+                                               possible_accessors.Add (mb, (MethodSpec) imported);
+                                       }
+
+                                       break;
+                               case MemberTypes.Property:
+                                       if (possible_accessors == null)
+                                               continue;
+
+                                       var p = (PropertyInfo) member;
+                                       //
+                                       // Links possible accessors with property
+                                       //
+                                       MethodSpec get, set;
+                                       m = p.GetGetMethod (true);
+                                       if (m == null || !possible_accessors.TryGetValue (m, out get))
+                                               get = null;
+
+                                       m = p.GetSetMethod (true);
+                                       if (m == null || !possible_accessors.TryGetValue (m, out set))
+                                               set = null;
+
+                                       // No accessors registered (e.g. explicit implementation)
+                                       if (get == null && set == null)
+                                               continue;
+
+                                       imported = Import.CreateProperty (p, declaringType, get, set);
+                                       if (imported == null)
+                                               continue;
+
+                                       break;
+                               case MemberTypes.Event:
+                                       if (possible_accessors == null)
+                                               continue;
+
+                                       var e = (EventInfo) member;
+                                       //
+                                       // Links accessors with event
+                                       //
+                                       MethodSpec add, remove;
+                                       m = e.GetAddMethod (true);
+                                       if (m == null || !possible_accessors.TryGetValue (m, out add))
+                                               add = null;
+
+                                       m = e.GetRemoveMethod (true);
+                                       if (m == null || !possible_accessors.TryGetValue (m, out remove))
+                                               remove = null;
+
+                                       // Both accessors are required
+                                       if (add == null || remove == null)
+                                               continue;
+
+                                       if (fields_to_ignore == null)
+                                               fields_to_ignore = new List<string> ();
+
+                                       fields_to_ignore.Add (e.Name);
+
+                                       imported = Import.CreateEvent (e, declaringType, add, remove);
+                                       break;
+                               case MemberTypes.Field:
+                                       var fi = (FieldInfo) member;
+
+                                       // Ignore compiler generated fields
+                                       if (fi.IsPrivate && fi.IsDefined (typeof (CompilerGeneratedAttribute), false))
+                                               continue;
+
+                                       if (fields_to_ignore != null && fields_to_ignore.Contains (fi.Name))
+                                               continue;
+
+                                       imported = Import.CreateField (fi, declaringType);
+                                       if (imported == null)
+                                               continue;
+
+                                       break;
+                               case MemberTypes.NestedType:
+                                       Type t = (Type) member;
+
+                                       // Ignore compiler generated types, mostly lambda containers
+                                       if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false))
+                                               continue;
+
+                                       imported = Import.CreateType (t, declaringType);
+                                       break;
+                               default:
+                                       throw new NotImplementedException (member.ToString ());
+                               }
+
+                               cache.AddMember (imported);
+                       }
+
+                       if (declaringType.IsInterface && declaringType.Interfaces != null) {
+                               foreach (var iface in declaringType.Interfaces) {
+                                       cache.AddInterface (iface);
+                               }
+                       }
+
+                       return cache;
+               }
+       }
+
+       class ImportedTypeParameterDefinition : ImportedMemberDefinition, ITypeDefinition
+       {
+               public ImportedTypeParameterDefinition (Type type)
+                       : base (type)
+               {
+               }
+
+               #region Properties
+
+               public string Namespace {
+                       get {
+                               return null;
+                       }
+               }
+
+               public int TypeParametersCount {
+                       get {
+                               return 0;
+                       }
+               }
+
+               public TypeParameterSpec[] TypeParameters {
+                       get {
+                               return null;
+                       }
+               }
+
+               #endregion
+
+               public TypeSpec GetAttributeCoClass ()
+               {
+                       return null;
+               }
+
+               public string GetAttributeDefaultMember ()
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public MemberCache LoadMembers (TypeSpec declaringType)
+               {
+                       throw new NotImplementedException ();
                }
        }
-}
\ No newline at end of file
+}