X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fimport.cs;h=7a3081c7cbbf8d660c279480fcf9446993c0a097;hb=f574f7b447e29c6f083fcad4e6dc5f89d3cb4b4d;hp=5a06e8ff3c9a8c37cd3dc274378c13021e86d852;hpb=d900315aeba415231ca22566f2c9628f4afdc2e6;p=mono.git diff --git a/mcs/mcs/import.cs b/mcs/mcs/import.cs index 5a06e8ff3c9..7a3081c7cbb 100644 --- a/mcs/mcs/import.cs +++ b/mcs/mcs/import.cs @@ -5,77 +5,150 @@ // // Dual licensed under the terms of the MIT X11 or GNU GPL // -// Copyright 2009, 2010 Novell, Inc +// Copyright 2009-2011 Novell, Inc +// Copyright 2011 Xamarin, Inc (http://www.xamarin.com) // using System; -using System.Reflection; using System.Runtime.CompilerServices; using System.Linq; using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; + +#if STATIC +using MetaType = IKVM.Reflection.Type; +using IKVM.Reflection; +using IKVM.Reflection.Emit; +#else +using MetaType = System.Type; +using System.Reflection; +using System.Reflection.Emit; +#endif namespace Mono.CSharp { - public class ReflectionMetaImporter + public abstract class MetadataImporter { - Dictionary import_cache; - Dictionary type_2_predefined; + // + // Dynamic types reader with additional logic to reconstruct a dynamic + // type using DynamicAttribute values + // + struct DynamicTypeReader + { + static readonly bool[] single_attribute = { true }; + + public int Position; + bool[] flags; + + // There is no common type for CustomAttributeData and we cannot + // use ICustomAttributeProvider + object provider; + + // + // A member provider which can be used to get CustomAttributeData + // + public DynamicTypeReader (object provider) + { + Position = 0; + flags = null; + this.provider = provider; + } + + // + // Returns true when object at local position has dynamic attribute flag + // + public bool IsDynamicObject (MetadataImporter importer) + { + if (provider != null) + ReadAttribute (importer); + + return flags != null && Position < flags.Length && flags[Position]; + } + + // + // Returns true when DynamicAttribute exists + // + public bool HasDynamicAttribute (MetadataImporter importer) + { + if (provider != null) + ReadAttribute (importer); + + return flags != null; + } + + void ReadAttribute (MetadataImporter importer) + { + IList cad; + if (provider is MemberInfo) { + cad = CustomAttributeData.GetCustomAttributes ((MemberInfo) provider); + } else if (provider is ParameterInfo) { + cad = CustomAttributeData.GetCustomAttributes ((ParameterInfo) provider); + } else { + provider = null; + return; + } + + if (cad.Count > 0) { + foreach (var ca in cad) { + var dt = ca.Constructor.DeclaringType; + if (dt.Name != "DynamicAttribute" && dt.Namespace != CompilerServicesNamespace) + continue; - public ReflectionMetaImporter () + if (ca.ConstructorArguments.Count == 0) { + flags = single_attribute; + break; + } + + var arg_type = ca.ConstructorArguments[0].ArgumentType; + + if (arg_type.IsArray && MetaType.GetTypeCode (arg_type.GetElementType ()) == TypeCode.Boolean) { + var carg = (IList) ca.ConstructorArguments[0].Value; + flags = new bool[carg.Count]; + for (int i = 0; i < flags.Length; ++i) { + if (MetaType.GetTypeCode (carg[i].ArgumentType) == TypeCode.Boolean) + flags[i] = (bool) carg[i].Value; + } + + break; + } + } + } + + provider = null; + } + } + + protected readonly Dictionary import_cache; + protected readonly Dictionary compiled_types; + protected readonly Dictionary assembly_2_definition; + readonly ModuleContainer module; + + public static readonly string CompilerServicesNamespace = "System.Runtime.CompilerServices"; + + protected MetadataImporter (ModuleContainer module) { - import_cache = new Dictionary (1024, ReferenceEquality.Default); + this.module = module; + + import_cache = new Dictionary (1024, ReferenceEquality.Default); + compiled_types = new Dictionary (40, ReferenceEquality.Default); + assembly_2_definition = new Dictionary (ReferenceEquality.Default); IgnorePrivateMembers = true; } #region Properties + public ICollection Assemblies { + get { + return assembly_2_definition.Values; + } + } + public bool IgnorePrivateMembers { get; set; } #endregion - public void Initialize () - { - // Setup mapping for predefined types - type_2_predefined = new Dictionary () { - { 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 abstract void AddCompiledType (TypeBuilder builder, TypeSpec spec); + protected abstract MemberKind DetermineKindFromBaseType (MetaType baseType); + protected abstract bool HasVolatileModifier (MetaType[] modifiers); public FieldSpec CreateField (FieldInfo fi, TypeSpec declaringType) { @@ -96,55 +169,54 @@ namespace Mono.CSharp break; default: // Ignore private fields (even for error reporting) to not require extra dependencies - if (IgnorePrivateMembers || fi.IsDefined (typeof (CompilerGeneratedAttribute), false)) + if ((IgnorePrivateMembers && !declaringType.IsStruct) || + HasAttribute (CustomAttributeData.GetCustomAttributes (fi), "CompilerGeneratedAttribute", CompilerServicesNamespace)) return null; mod = Modifiers.PRIVATE; break; } - var definition = new ImportedMemberDefinition (fi); TypeSpec field_type; try { - field_type = ImportType (fi.FieldType); + field_type = ImportType (fi.FieldType, new DynamicTypeReader (fi)); } catch (Exception e) { // TODO: I should construct fake TypeSpec based on TypeRef signature // but there is no way to do it with System.Reflection throw new InternalErrorException (e, "Cannot import field `{0}.{1}' referenced in assembly `{2}'", - declaringType.GetSignatureForError (), fi.Name, declaringType.Assembly); + declaringType.GetSignatureForError (), fi.Name, declaringType.MemberDefinition.DeclaringAssembly); } + var definition = new ImportedMemberDefinition (fi, field_type, this); + if ((fa & FieldAttributes.Literal) != 0) { - var c = Constant.CreateConstantFromValue (field_type, fi.GetValue (fi), Location.Null); + var c = Constant.CreateConstantFromValue (field_type, fi.GetRawConstantValue (), Location.Null); return new ConstSpec (declaringType, definition, field_type, fi, mod, c); } if ((fa & FieldAttributes.InitOnly) != 0) { - if (field_type == TypeManager.decimal_type) { - var dc = ReadDecimalConstant (fi); + if (field_type.BuiltinType == BuiltinTypeSpec.Type.Decimal) { + var dc = ReadDecimalConstant (CustomAttributeData.GetCustomAttributes (fi)); if (dc != null) return new ConstSpec (declaringType, definition, field_type, 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; - } - } - } + var req_mod = fi.GetRequiredCustomModifiers (); + if (req_mod.Length > 0 && HasVolatileModifier (req_mod)) + mod |= Modifiers.VOLATILE; } - if ((fa & FieldAttributes.Static) != 0) + if ((fa & FieldAttributes.Static) != 0) { mod |= Modifiers.STATIC; + } else { + // Fixed buffers cannot be static + if (declaringType.IsStruct && field_type.IsStruct && field_type.IsNested && + HasAttribute (CustomAttributeData.GetCustomAttributes (fi), "FixedBufferAttribute", CompilerServicesNamespace)) { - if (field_type.IsStruct) { - if (fi.IsDefined (typeof (FixedBufferAttribute), false)) { + // TODO: Sanity check on field_type (only few types are allowed) var element_field = CreateField (fi.FieldType.GetField (FixedField.FixedElementName), declaringType); return new FixedFieldSpec (declaringType, definition, fi, element_field, mod); } @@ -161,13 +233,14 @@ namespace Mono.CSharp 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); + var event_type = ImportType (ei.EventHandlerType, new DynamicTypeReader (ei)); + var definition = new ImportedMemberDefinition (ei, event_type, this); + return new EventSpec (declaringType, definition, event_type, add.Modifiers, add, remove); } - T[] CreateGenericParameters (Type type, TypeSpec declaringType) where T : TypeSpec + TypeParameterSpec[] CreateGenericParameters (MetaType type, TypeSpec declaringType) { - Type[] tparams = type.GetGenericArguments (); + var tparams = type.GetGenericArguments (); int parent_owned_count; if (type.IsNested) { @@ -202,27 +275,63 @@ namespace Mono.CSharp if (tparams.Length - parent_owned_count == 0) return null; - return CreateGenericParameters (parent_owned_count, tparams); + return CreateGenericParameters (parent_owned_count, tparams); + } + + TypeParameterSpec[] CreateGenericParameters (int first, MetaType[] tparams) + { + var tspec = new TypeParameterSpec[tparams.Length - first]; + for (int pos = first; pos < tparams.Length; ++pos) { + var type = tparams[pos]; + int index = pos - first; + + tspec[index] = (TypeParameterSpec) CreateType (type, new DynamicTypeReader (), false); + } + + return tspec; } - T[] CreateGenericParameters (int first, Type[] tparams) where T : TypeSpec + TypeSpec[] CreateGenericArguments (int first, MetaType[] tparams, DynamicTypeReader dtype) { - var tspec = new T [tparams.Length - first]; + ++dtype.Position; + + var tspec = new TypeSpec [tparams.Length - first]; for (int pos = first; pos < tparams.Length; ++pos) { var type = tparams[pos]; + int index = pos - first; + + TypeSpec spec; if (type.HasElementType) { var element = type.GetElementType (); - var spec = ImportType (element); + ++dtype.Position; + spec = ImportType (element, dtype); - if (type.IsArray) { - tspec[pos - first] = (T) (TypeSpec) ArrayContainer.MakeType (spec, type.GetArrayRank ()); - continue; + if (!type.IsArray) { + throw new NotImplementedException ("Unknown element type " + type.ToString ()); } - throw new NotImplementedException ("Unknown element type " + type.ToString ()); + spec = ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); + } else { + spec = CreateType (type, dtype, true); + + // + // We treat nested generic types as inflated internally where + // reflection uses type definition + // + // class A { + // IFoo> foo; // A is definition in this case + // } + // + // TODO: Is full logic from CreateType needed here as well? + // + if (!IsMissingType (type) && type.IsGenericTypeDefinition) { + var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype); + spec = spec.MakeGenericType (module, targs); + } } - tspec [pos - first] = (T) CreateType (type); + ++dtype.Position; + tspec[index] = spec; } return tspec; @@ -232,7 +341,6 @@ namespace Mono.CSharp { Modifiers mod = ReadMethodModifiers (mb, declaringType); TypeParameterSpec[] tparams; - ImportedMethodDefinition definition; var parameters = CreateParameters (declaringType, mb.GetParameters (), mb); @@ -240,10 +348,8 @@ namespace Mono.CSharp if (!mb.IsGenericMethodDefinition) throw new NotSupportedException ("assert"); - tparams = CreateGenericParameters(0, mb.GetGenericArguments ()); - definition = new ImportedGenericMethodDefinition ((MethodInfo) mb, parameters, tparams); + tparams = CreateGenericParameters (0, mb.GetGenericArguments ()); } else { - definition = new ImportedMethodDefinition (mb, parameters); tparams = null; } @@ -251,7 +357,7 @@ namespace Mono.CSharp TypeSpec returnType; if (mb.MemberType == MemberTypes.Constructor) { kind = MemberKind.Constructor; - returnType = TypeManager.void_type; + returnType = module.Compiler.BuiltinTypes.Void; } else { // // Detect operators and destructors @@ -268,35 +374,59 @@ namespace Mono.CSharp } } else if (parameters.IsEmpty && name == Destructor.MetadataName) { kind = MemberKind.Destructor; - if (declaringType == TypeManager.object_type) { + if (declaringType.BuiltinType == BuiltinTypeSpec.Type.Object) { mod &= ~Modifiers.OVERRIDE; mod |= Modifiers.VIRTUAL; } } } - returnType = ImportType (((MethodInfo)mb).ReturnType); + var mi = (MethodInfo) mb; + returnType = ImportType (mi.ReturnType, new DynamicTypeReader (mi.ReturnParameter)); // Cannot set to OVERRIDE without full hierarchy checks // this flag indicates that the method could be override // but further validation is needed - if ((mod & Modifiers.OVERRIDE) != 0 && kind == MemberKind.Method && declaringType.BaseType != null) { - var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null); - var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None); + if ((mod & Modifiers.OVERRIDE) != 0) { + bool is_real_override = false; + if (kind == MemberKind.Method && declaringType.BaseType != null) { + var filter = MemberFilter.Method (name, tparams != null ? tparams.Length : 0, parameters, null); + var candidate = MemberCache.FindMember (declaringType.BaseType, filter, BindingRestriction.None); - // - // For imported class method do additional validation to be sure that metadata - // override flag was correct - // - // Difference between protected internal and protected is ok - // - const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL; - if (candidate == null || (candidate.Modifiers & conflict_mask) != (mod & conflict_mask) || candidate.IsStatic) { + // + // For imported class method do additional validation to be sure that metadata + // override flag was correct + // + // Difference between protected internal and protected is ok + // + const Modifiers conflict_mask = Modifiers.AccessibilityMask & ~Modifiers.INTERNAL; + if (candidate != null && (candidate.Modifiers & conflict_mask) == (mod & conflict_mask) && !candidate.IsStatic) { + is_real_override = true; + } + } + + if (!is_real_override) { mod &= ~Modifiers.OVERRIDE; + if ((mod & Modifiers.SEALED) != 0) + mod &= ~Modifiers.SEALED; + else + mod |= Modifiers.VIRTUAL; } } } + IMemberDefinition definition; + if (tparams != null) { + var gmd = new ImportedGenericMethodDefinition ((MethodInfo) mb, returnType, parameters, tparams, this); + foreach (var tp in gmd.TypeParameters) { + ImportTypeParameterTypeConstraints (tp, tp.GetMetaInfo ()); + } + + definition = gmd; + } else { + definition = new ImportedParameterMemberDefinition (mb, returnType, parameters, this); + } + MethodSpec ms = new MethodSpec (kind, declaringType, definition, returnType, mb, parameters, mod); if (tparams != null) ms.IsGeneric = true; @@ -330,30 +460,41 @@ namespace Mono.CSharp // // Strip reference wrapping // - types[i] = ImportType (p.ParameterType.GetElementType ()); - } else if (i == 0 && method.IsStatic && parent.IsStatic && // TODO: parent.Assembly.IsExtension && - HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (method)) != null) { + var el = p.ParameterType.GetElementType (); + types[i] = ImportType (el, new DynamicTypeReader (p)); // TODO: 1-based positio to be csc compatible + } else if (i == 0 && method.IsStatic && parent.IsStatic && parent.MemberDefinition.DeclaringAssembly.HasExtensionMethod && + HasAttribute (CustomAttributeData.GetCustomAttributes (method), "ExtensionAttribute", CompilerServicesNamespace)) { mod = Parameter.Modifier.This; types[i] = ImportType (p.ParameterType); } else { - types[i] = ImportType (p.ParameterType); + types[i] = ImportType (p.ParameterType, new DynamicTypeReader (p)); if (i >= pi.Length - 2 && types[i] is ArrayContainer) { - var cattrs = CustomAttributeData.GetCustomAttributes (p); - if (cattrs != null && cattrs.Any (l => l.Constructor.DeclaringType == typeof (ParamArrayAttribute))) { + if (HasAttribute (CustomAttributeData.GetCustomAttributes (p), "ParamArrayAttribute", "System")) { mod = Parameter.Modifier.PARAMS; is_params = true; } } if (!is_params && p.IsOptional) { - object value = p.DefaultValue; - if (value == Missing.Value) { - default_value = EmptyExpression.Null; + object value = p.RawDefaultValue; + var ptype = types[i]; + if ((p.Attributes & ParameterAttributes.HasDefault) != 0 && ptype.Kind != MemberKind.TypeParameter && (value != null || TypeSpec.IsReferenceType (ptype))) { + if (value == null) { + default_value = Constant.CreateConstant (ptype, null, Location.Null); + } else { + default_value = ImportParameterConstant (value); + + if (ptype.IsEnum) { + default_value = new EnumConstant ((Constant) default_value, ptype); + } + } + } else if (value == Missing.Value) { + default_value = EmptyExpression.MissingValue; } else if (value == null) { - default_value = new NullLiteral (Location.Null); - } else { - default_value = Constant.CreateConstant (null, ImportType (value.GetType ()), value, Location.Null); + default_value = new DefaultValueExpression (new TypeExpression (ptype, Location.Null), Location.Null); + } else if (ptype.BuiltinType == BuiltinTypeSpec.Type.Decimal) { + default_value = ImportParameterConstant (value); } } } @@ -371,7 +512,6 @@ namespace Mono.CSharp new ParametersImported (par, types, is_params); } - // // Returns null when the property is not valid C# property // @@ -388,7 +528,7 @@ namespace Mono.CSharp bool is_valid_property = true; if (set != null) { - if (set.ReturnType != TypeManager.void_type) + if (set.ReturnType.Kind != MemberKind.Void) is_valid_property = false; var set_param_count = set.Parameters.Count - 1; @@ -470,14 +610,14 @@ namespace Mono.CSharp } if (is_valid_property) - spec = new IndexerSpec (declaringType, new ImportedIndexerDefinition (pi, param), type, param, pi, mod); + spec = new IndexerSpec (declaringType, new ImportedParameterMemberDefinition (pi, type, param, this), type, param, pi, mod); } if (spec == null) - spec = new PropertySpec (MemberKind.Property, declaringType, new ImportedMemberDefinition (pi), type, pi, mod); + spec = new PropertySpec (MemberKind.Property, declaringType, new ImportedMemberDefinition (pi, type, this), type, pi, mod); if (!is_valid_property) { - spec.IsNotRealProperty = true; + spec.IsNotCSharpCompatible = true; return spec; } @@ -489,30 +629,70 @@ namespace Mono.CSharp return spec; } - public TypeSpec CreateType (Type type) + public TypeSpec CreateType (MetaType type) + { + return CreateType (type, new DynamicTypeReader (), true); + } + + public TypeSpec CreateNestedType (MetaType type, TypeSpec declaringType) + { + return CreateType (type, declaringType, new DynamicTypeReader (type), false); + } + + TypeSpec CreateType (MetaType type, DynamicTypeReader dtype, bool canImportBaseType) { TypeSpec declaring_type; if (type.IsNested && !type.IsGenericParameter) - declaring_type = CreateType (type.DeclaringType); + declaring_type = CreateType (type.DeclaringType, new DynamicTypeReader (type.DeclaringType), true); else declaring_type = null; - return CreateType (type, declaring_type); + return CreateType (type, declaring_type, dtype, canImportBaseType); } - public TypeSpec CreateType (Type type, TypeSpec declaringType) + TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType) { TypeSpec spec; - if (import_cache.TryGetValue (type, out spec)) + if (import_cache.TryGetValue (type, out spec)) { + if (spec.BuiltinType == BuiltinTypeSpec.Type.Object) { + if (dtype.IsDynamicObject (this)) + return module.Compiler.BuiltinTypes.Dynamic; + + return spec; + } + + if (!spec.IsGeneric || type.IsGenericTypeDefinition) + return spec; + + if (!dtype.HasDynamicAttribute (this)) + return spec; + + // We've found same object in the cache but this one has a dynamic custom attribute + // and it's most likely dynamic version of same type IFoo agains IFoo + // Do type resolve process again in that case + + // TODO: Handle cases where they still unify + } + + if (IsMissingType (type)) { + spec = new TypeSpec (MemberKind.MissingType, declaringType, new ImportedTypeDefinition (type, this), type, Modifiers.PUBLIC); + spec.MemberCache = MemberCache.Empty; + import_cache.Add (type, spec); return spec; + } - if (type.IsGenericType && !type.IsGenericTypeDefinition) { + if (type.IsGenericType && !type.IsGenericTypeDefinition) { var type_def = type.GetGenericTypeDefinition (); - var targs = CreateGenericParameters (0, type.GetGenericArguments ()); + + // Generic type definition can also be forwarded + if (compiled_types.TryGetValue (type_def, out spec)) + return spec; + + var targs = CreateGenericArguments (0, type.GetGenericArguments (), dtype); if (declaringType == null) { // Simple case, no nesting - spec = CreateType (type_def, null); - spec = spec.MakeGenericType (targs); + spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType); + spec = spec.MakeGenericType (module, targs); } else { // // Nested type case, converting .NET types like @@ -527,7 +707,7 @@ namespace Mono.CSharp int targs_pos = 0; if (declaringType.Arity > 0) { - spec = declaringType.MakeGenericType (targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); + spec = declaringType.MakeGenericType (module, targs.Skip (targs_pos).Take (declaringType.Arity).ToArray ()); targs_pos = spec.Arity; } else { spec = declaringType; @@ -537,7 +717,7 @@ namespace Mono.CSharp var t = nested_hierarchy [i - 1]; spec = MemberCache.FindNestedType (spec, t.Name, t.Arity); if (t.Arity > 0) { - spec = spec.MakeGenericType (targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); + spec = spec.MakeGenericType (module, targs.Skip (targs_pos).Take (spec.Arity).ToArray ()); targs_pos += t.Arity; } } @@ -548,14 +728,22 @@ namespace Mono.CSharp name = name.Substring (0, index); spec = MemberCache.FindNestedType (spec, name, targs.Length - targs_pos); + if (spec == null) + return null; + if (spec.Arity > 0) { - spec = spec.MakeGenericType (targs.Skip (targs_pos).ToArray ()); + spec = spec.MakeGenericType (module, targs.Skip (targs_pos).ToArray ()); } } - // Add to reading cache to speed up reading - if (!import_cache.ContainsKey (type)) - import_cache.Add (type, spec); + // Don't add generic type with dynamic arguments, they can interfere with same type + // using object type arguments + if (!spec.HasDynamicElement) { + + // Add to reading cache to speed up reading + if (!import_cache.ContainsKey (type)) + import_cache.Add (type, spec); + } return spec; } @@ -587,19 +775,18 @@ namespace Mono.CSharp 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; - mod |= Modifiers.SEALED; - } else { + } else { + var base_type = type.BaseType; + if (base_type == null || (ma & TypeAttributes.Abstract) != 0) { kind = MemberKind.Class; - -#if NET_4_0 - if (type == typeof (object) && type.IsDefined (typeof (DynamicAttribute), false)) { - return InternalType.Dynamic; + } else { + kind = DetermineKindFromBaseType (base_type); + if (kind == MemberKind.Struct || kind == MemberKind.Delegate) { + mod |= Modifiers.SEALED; } -#endif + } + if (kind == MemberKind.Class) { if ((ma & TypeAttributes.Sealed) != 0) { mod |= Modifiers.SEALED; if ((ma & TypeAttributes.Abstract) != 0) @@ -608,15 +795,10 @@ namespace Mono.CSharp mod |= Modifiers.ABSTRACT; } } - } else if (type.IsEnum) { - kind = MemberKind.Enum; - } else { - kind = MemberKind.Struct; - mod |= Modifiers.SEALED; } - var definition = new ImportedTypeDefinition (this, type); - PredefinedTypeSpec pt; + var definition = new ImportedTypeDefinition (type, this); + TypeSpec pt; if (kind == MemberKind.Enum) { const BindingFlags underlying_member = BindingFlags.DeclaredOnly | @@ -633,18 +815,19 @@ namespace Mono.CSharp kind = MemberKind.Class; } else if (kind == MemberKind.TypeParameter) { - // Return as type_cache was updated - return CreateTypeParameter (type, declaringType); + spec = CreateTypeParameter (type, declaringType); } else if (type.IsGenericTypeDefinition) { - definition.TypeParameters = CreateGenericParameters(type, declaringType); - - // Constraints are not loaded on demand and can reference this type - if (import_cache.TryGetValue (type, out spec)) - return spec; - - } else if (type_2_predefined.TryGetValue (type, out pt)) { + definition.TypeParameters = CreateGenericParameters (type, declaringType); + } else if (compiled_types.TryGetValue (type, out pt)) { + // + // Same type was found in inside compiled types. It's + // either build-in type or forward referenced typed + // which point into just compiled assembly. + // spec = pt; - pt.SetDefinition (definition, type); + BuiltinTypeSpec bts = pt as BuiltinTypeSpec; + if (bts != null) + bts.SetDefinition (definition, type, mod); } if (spec == null) @@ -653,37 +836,40 @@ namespace Mono.CSharp import_cache.Add (type, spec); // - // Two stage setup as the base type can be inflated declaring type + // Two stage setup as the base type can be inflated declaring type or + // another nested type inside same declaring type which has not been + // loaded, therefore we can import a base type of nested types once + // the types have been imported // - if (declaringType == null) + if (canImportBaseType) ImportTypeBase (spec, type); return spec; } - public void ImportTypeBase (Type type) + public IAssemblyDefinition GetAssemblyDefinition (Assembly assembly) { - TypeSpec spec = import_cache[type]; - if (spec != null) - ImportTypeBase (spec, type); + IAssemblyDefinition found; + if (!assembly_2_definition.TryGetValue (assembly, out found)) { + + // This can happen in dynamic context only + var def = new ImportedAssemblyDefinition (assembly); + assembly_2_definition.Add (assembly, def); + def.ReadAttributes (); + found = def; + } + + return found; } - void ImportTypeBase (TypeSpec spec, Type type) + public void ImportTypeBase (MetaType type) { - if (spec.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 (CreateType (iface)); - } - } + TypeSpec spec = import_cache[type]; + if (spec != null) + ImportTypeBase (spec, type); } - TypeParameterSpec CreateTypeParameter (Type type, TypeSpec declaringType) + TypeParameterSpec CreateTypeParameter (MetaType type, TypeSpec declaringType) { Variance variance; switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) { @@ -712,87 +898,119 @@ namespace Mono.CSharp } TypeParameterSpec spec; - var def = new ImportedTypeParameterDefinition (type); - if (type.DeclaringMethod != null) + var def = new ImportedTypeParameterDefinition (type, this); + if (type.DeclaringMethod != null) { spec = new TypeParameterSpec (type.GenericParameterPosition, def, special, variance, type); - else + } 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); + return spec; + } - var constraints = type.GetGenericParameterConstraints (); - List tparams = null; - foreach (var ct in constraints) { - if (ct.IsGenericParameter) { - if (tparams == null) - tparams = new List (); + // + // Test for a custom attribute type match. Custom attributes are not really predefined globaly + // they can be assembly specific therefore we do check based on names only + // + public bool HasAttribute (IList attributesData, string attrName, string attrNamespace) + { + if (attributesData.Count == 0) + return false; - tparams.Add (CreateType (ct)); - continue; - } + foreach (var attr in attributesData) { + var dt = attr.Constructor.DeclaringType; + if (dt.Name == attrName && dt.Namespace == attrNamespace) + return true; + } - if (ct.IsClass) { - if (ct == typeof (ValueType)) { - spec.BaseType = TypeManager.value_type; - } else { - spec.BaseType = CreateType (ct); - } + return false; + } - continue; - } + void ImportTypeBase (TypeSpec spec, MetaType type) + { + if (spec.Kind == MemberKind.Interface) + spec.BaseType = module.Compiler.BuiltinTypes.Object; + else if (type.BaseType != null) { + TypeSpec base_type; + if (!IsMissingType (type.BaseType) && type.BaseType.IsGenericType) + base_type = CreateType (type.BaseType, new DynamicTypeReader (type), true); + else + base_type = CreateType (type.BaseType); + + spec.BaseType = base_type; + } - spec.AddInterface (CreateType (ct)); + MetaType[] ifaces; +#if STATIC + ifaces = type.__GetDeclaredInterfaces (); + if (ifaces.Length != 0) { + foreach (var iface in ifaces) { + var it = CreateType (iface); + if (it == null) + continue; + + spec.AddInterface (it); + + // Unfortunately not all languages expand inherited interfaces + var bifaces = it.Interfaces; + if (bifaces != null) { + foreach (var biface in bifaces) { + spec.AddInterface (biface); + } + } + } } - if (spec.BaseType == null) - spec.BaseType = TypeManager.object_type; + if (spec.BaseType != null) { + var bifaces = spec.BaseType.Interfaces; + if (bifaces != null) { + // + // Before adding base class interfaces close defined interfaces + // on type parameter + // + var tp = spec as TypeParameterSpec; + if (tp != null && tp.InterfacesDefined == null) { + tp.InterfacesDefined = TypeSpec.EmptyTypes; + } - if (tparams != null) - spec.TypeArguments = tparams.ToArray (); + foreach (var iface in bifaces) + spec.AddInterface (iface); + } + } +#else + ifaces = type.GetInterfaces (); - return spec; - } + if (ifaces.Length > 0) { + foreach (var iface in ifaces) { + spec.AddInterface (CreateType (iface)); + } + } +#endif - static Type HasExtensionAttribute (IList attributes) - { - foreach (var attr in attributes) { - var dt = attr.Constructor.DeclaringType; - if (dt.Name == "ExtensionAttribute" && dt.Namespace == "System.Runtime.CompilerServices") { - return dt; + if (spec.MemberDefinition.TypeParametersCount > 0) { + foreach (var tp in spec.MemberDefinition.TypeParameters) { + ImportTypeParameterTypeConstraints (tp, tp.GetMetaInfo ()); } } - return null; } - public void ImportAssembly (Assembly assembly, Namespace targetNamespace) + protected void ImportTypes (MetaType[] types, Namespace targetNamespace, bool hasExtensionTypes) { - Type extension_type = HasExtensionAttribute (CustomAttributeData.GetCustomAttributes (assembly)); - - // - // This part tries to simulate loading of top-level - // types only, any missing dependencies are ignores here. - // Full error report is reported later when the type is - // actually used - // - Type[] all_types; - try { - all_types = assembly.GetTypes (); - } catch (ReflectionTypeLoadException e) { - all_types = e.Types; - } - Namespace ns = targetNamespace; string prev_namespace = null; - foreach (var t in all_types) { - if (t == null || t.IsNested) + foreach (var t in types) { + if (t == null) + continue; + + // Be careful not to trigger full parent type loading + if (t.MemberType == MemberTypes.NestedType) continue; if (t.Name[0] == '<') continue; - var it = CreateType (t, null); + var it = CreateType (t, null, new DynamicTypeReader (t), true); if (it == null) continue; @@ -801,31 +1019,116 @@ namespace Mono.CSharp prev_namespace = t.Namespace; } - ns.AddType (it); + ns.AddType (module, it); - if (it.IsStatic && extension_type != null && t.IsDefined (extension_type, false)) { + if (it.IsStatic && hasExtensionTypes && + HasAttribute (CustomAttributeData.GetCustomAttributes (t), "ExtensionAttribute", CompilerServicesNamespace)) { it.SetExtensionMethodContainer (); } } } - public TypeSpec ImportType (Type type) + void ImportTypeParameterTypeConstraints (TypeParameterSpec spec, MetaType type) + { + var constraints = type.GetGenericParameterConstraints (); + List tparams = null; + foreach (var ct in constraints) { + if (ct.IsGenericParameter) { + if (tparams == null) + tparams = new List (); + + tparams.Add (CreateType (ct)); + continue; + } + + if (!IsMissingType (ct) && ct.IsClass) { + spec.BaseType = CreateType (ct); + continue; + } + + spec.AddInterface (CreateType (ct)); + } + + if (spec.BaseType == null) + spec.BaseType = module.Compiler.BuiltinTypes.Object; + + if (tparams != null) + spec.TypeArguments = tparams.ToArray (); + } + + Constant ImportParameterConstant (object value) + { + // + // Get type of underlying value as int constant can be used for object + // parameter type. This is not allowed in C# but other languages can do that + // + var types = module.Compiler.BuiltinTypes; + switch (System.Type.GetTypeCode (value.GetType ())) { + case TypeCode.Boolean: + return new BoolConstant (types, (bool) value, Location.Null); + case TypeCode.Byte: + return new ByteConstant (types, (byte) value, Location.Null); + case TypeCode.Char: + return new CharConstant (types, (char) value, Location.Null); + case TypeCode.Decimal: + return new DecimalConstant (types, (decimal) value, Location.Null); + case TypeCode.Double: + return new DoubleConstant (types, (double) value, Location.Null); + case TypeCode.Int16: + return new ShortConstant (types, (short) value, Location.Null); + case TypeCode.Int32: + return new IntConstant (types, (int) value, Location.Null); + case TypeCode.Int64: + return new LongConstant (types, (long) value, Location.Null); + case TypeCode.SByte: + return new SByteConstant (types, (sbyte) value, Location.Null); + case TypeCode.Single: + return new FloatConstant (types, (float) value, Location.Null); + case TypeCode.String: + return new StringConstant (types, (string) value, Location.Null); + case TypeCode.UInt16: + return new UShortConstant (types, (ushort) value, Location.Null); + case TypeCode.UInt32: + return new UIntConstant (types, (uint) value, Location.Null); + case TypeCode.UInt64: + return new ULongConstant (types, (ulong) value, Location.Null); + } + + throw new NotImplementedException (value.GetType ().ToString ()); + } + + public TypeSpec ImportType (MetaType type) + { + return ImportType (type, new DynamicTypeReader (type)); + } + + TypeSpec ImportType (MetaType type, DynamicTypeReader dtype) { if (type.HasElementType) { var element = type.GetElementType (); - var spec = ImportType (element); + ++dtype.Position; + var spec = ImportType (element, dtype); if (type.IsArray) - return ArrayContainer.MakeType (spec, type.GetArrayRank ()); + return ArrayContainer.MakeType (module, spec, type.GetArrayRank ()); if (type.IsByRef) - return ReferenceContainer.MakeType (spec); + return ReferenceContainer.MakeType (module, spec); if (type.IsPointer) - return PointerContainer.MakeType (spec); + return PointerContainer.MakeType (module, spec); throw new NotImplementedException ("Unknown element type " + type.ToString ()); } - return CreateType (type); + return CreateType (type, dtype, true); + } + + static bool IsMissingType (MetaType type) + { +#if STATIC + return type.__IsMissing; +#else + return false; +#endif } // @@ -833,13 +1136,27 @@ namespace Mono.CSharp // as IsInitOnly ('readonly' in C# parlance). We get its value from the // DecimalConstantAttribute metadata. // - static Constant ReadDecimalConstant (FieldInfo fi) + Constant ReadDecimalConstant (IList attrs) { - object[] attrs = fi.GetCustomAttributes (typeof (DecimalConstantAttribute), false); - if (attrs.Length != 1) + if (attrs.Count == 0) return null; - return new DecimalConstant (((DecimalConstantAttribute) attrs [0]).Value, Location.Null); + foreach (var ca in attrs) { + var dt = ca.Constructor.DeclaringType; + if (dt.Name != "DecimalConstantAttribute" || dt.Namespace != CompilerServicesNamespace) + continue; + + var value = new decimal ( + (int) (uint) ca.ConstructorArguments[4].Value, + (int) (uint) ca.ConstructorArguments[3].Value, + (int) (uint) ca.ConstructorArguments[2].Value, + (byte) ca.ConstructorArguments[1].Value != 0, + (byte) ca.ConstructorArguments[0].Value); + + return new DecimalConstant (module.Compiler.BuiltinTypes, value, Location.Null); + } + + return null; } static Modifiers ReadMethodModifiers (MethodBase mb, TypeSpec declaringType) @@ -873,15 +1190,21 @@ namespace Mono.CSharp return mod; } + // It can be sealed and override if ((ma & MethodAttributes.Final) != 0) mod |= Modifiers.SEALED; - // It can be sealed and override if ((ma & MethodAttributes.Virtual) != 0) { - if ((ma & MethodAttributes.NewSlot) != 0 || !declaringType.IsClass) { - // No private virtual or sealed virtual - if ((mod & (Modifiers.PRIVATE | Modifiers.SEALED)) == 0) + // Not every member can be detected based on MethodAttribute, we + // set virtual or non-virtual only when we are certain. Further checks + // to really find out what `virtual' means for this member are done + // later + if ((ma & MethodAttributes.NewSlot) != 0) { + if ((mod & Modifiers.SEALED) != 0) { + mod &= ~Modifiers.SEALED; + } else { mod |= Modifiers.VIRTUAL; + } } else { mod |= Modifiers.OVERRIDE; } @@ -891,7 +1214,7 @@ namespace Mono.CSharp } } - class ImportedMemberDefinition : IMemberDefinition + abstract class ImportedDefinition : IMemberDefinition { protected class AttributesBag { @@ -901,9 +1224,10 @@ namespace Mono.CSharp public ObsoleteAttribute Obsolete; public string[] Conditionals; public string DefaultIndexerName; - public bool IsNotCLSCompliant; - - public static AttributesBag Read (MemberInfo mi) + public bool? CLSAttributeValue; + public TypeSpec CoClass; + + public static AttributesBag Read (MemberInfo mi, MetadataImporter importer) { AttributesBag bag = null; List conditionals = null; @@ -912,8 +1236,12 @@ namespace Mono.CSharp IList attrs = CustomAttributeData.GetCustomAttributes (mi); foreach (var a in attrs) { - var type = a.Constructor.DeclaringType; - if (type == typeof (ObsoleteAttribute)) { + var dt = a.Constructor.DeclaringType; + string name = dt.Name; + if (name == "ObsoleteAttribute") { + if (dt.Namespace != "System") + continue; + if (bag == null) bag = new AttributesBag (); @@ -930,7 +1258,10 @@ namespace Mono.CSharp continue; } - if (type == typeof (ConditionalAttribute)) { + if (name == "ConditionalAttribute") { + if (dt.Namespace != "System.Diagnostics") + continue; + if (bag == null) bag = new AttributesBag (); @@ -941,35 +1272,58 @@ namespace Mono.CSharp continue; } - if (type == typeof (CLSCompliantAttribute)) { + if (name == "CLSCompliantAttribute") { + if (dt.Namespace != "System") + continue; + if (bag == null) bag = new AttributesBag (); - bag.IsNotCLSCompliant = !(bool) a.ConstructorArguments[0].Value; + bag.CLSAttributeValue = (bool) a.ConstructorArguments[0].Value; continue; } // Type only attributes - if (type == typeof (DefaultMemberAttribute)) { - if (bag == null) - bag = new AttributesBag (); + if (mi.MemberType == MemberTypes.TypeInfo || mi.MemberType == MemberTypes.NestedType) { + if (name == "DefaultMemberAttribute") { + if (dt.Namespace != "System.Reflection") + continue; - bag.DefaultIndexerName = (string) a.ConstructorArguments[0].Value; - continue; - } + if (bag == null) + bag = new AttributesBag (); - if (type == typeof (AttributeUsageAttribute)) { - if (bag == null) - bag = new AttributesBag (); + bag.DefaultIndexerName = (string) a.ConstructorArguments[0].Value; + continue; + } - 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; + if (name == "AttributeUsageAttribute") { + if (dt.Namespace != "System") + continue; + + 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; + } + + // Interface only attribute + if (name == "CoClassAttribute") { + if (dt.Namespace != "System.Runtime.InteropServices") + continue; + + if (bag == null) + bag = new AttributesBag (); + + bag.CoClass = importer.ImportType ((MetaType) a.ConstructorArguments[0].Value); + continue; } - continue; } } @@ -978,27 +1332,23 @@ namespace Mono.CSharp if (conditionals != null) bag.Conditionals = conditionals.ToArray (); - + return bag; } } protected readonly MemberInfo provider; protected AttributesBag cattrs; + protected readonly MetadataImporter importer; - public ImportedMemberDefinition (MemberInfo provider) + public ImportedDefinition (MemberInfo provider, MetadataImporter importer) { this.provider = provider; + this.importer = importer; } #region Properties - public Assembly Assembly { - get { - return provider.Module.Assembly; - } - } - public bool IsImported { get { return true; @@ -1029,17 +1379,18 @@ namespace Mono.CSharp return cattrs.Obsolete; } - public bool IsNotCLSCompliant () - { - if (cattrs == null) - ReadAttributes (); + public bool? CLSAttributeValue { + get { + if (cattrs == null) + ReadAttributes (); - return cattrs.IsNotCLSCompliant; + return cattrs.CLSAttributeValue; + } } protected void ReadAttributes () { - cattrs = AttributesBag.Read (provider); + cattrs = AttributesBag.Read (provider, importer); } public void SetIsAssigned () @@ -1053,39 +1404,286 @@ namespace Mono.CSharp } } - class ImportedMethodDefinition : ImportedMemberDefinition, IParametersMember + public class ImportedModuleDefinition { - readonly AParametersCollection parameters; + readonly Module module; + bool cls_compliant; + + public ImportedModuleDefinition (Module module) + { + this.module = module; + } + + #region Properties + + public bool IsCLSCompliant { + get { + return cls_compliant; + } + } - public ImportedMethodDefinition (MethodBase provider, AParametersCollection parameters) - : base (provider) + public string Name { + get { + return module.Name; + } + } + + #endregion + + public void ReadAttributes () { - this.parameters = parameters; + IList attrs = CustomAttributeData.GetCustomAttributes (module); + + foreach (var a in attrs) { + var dt = a.Constructor.DeclaringType; + if (dt.Name == "CLSCompliantAttribute") { + if (dt.Namespace != "System") + continue; + + cls_compliant = (bool) a.ConstructorArguments[0].Value; + continue; + } + } + } + + // + // Reads assembly attributes which where attached to a special type because + // module does have assembly manifest + // + public List ReadAssemblyAttributes () + { + var t = module.GetType (AssemblyAttributesPlaceholder.GetGeneratedName (Name)); + if (t == null) + return null; + + var field = t.GetField (AssemblyAttributesPlaceholder.AssemblyFieldName, BindingFlags.NonPublic | BindingFlags.Static); + if (field == null) + return null; + + // TODO: implement, the idea is to fabricate specil Attribute class and + // add it to OptAttributes before resolving the source code attributes + // Need to build module location as well for correct error reporting + + //var assembly_attributes = CustomAttributeData.GetCustomAttributes (field); + //var attrs = new List (assembly_attributes.Count); + //foreach (var a in assembly_attributes) + //{ + // var type = metaImporter.ImportType (a.Constructor.DeclaringType); + // var ctor = metaImporter.CreateMethod (a.Constructor, type); + + // foreach (var carg in a.ConstructorArguments) { + // carg.Value + // } + + // attrs.Add (new Attribute ("assembly", ctor, null, Location.Null, true)); + //} + + return null; + } + } + + public class ImportedAssemblyDefinition : IAssemblyDefinition + { + readonly Assembly assembly; + readonly AssemblyName aname; + bool cls_compliant; + bool contains_extension_methods; + + List internals_visible_to; + Dictionary internals_visible_to_cache; + + public ImportedAssemblyDefinition (Assembly assembly) + { + this.assembly = assembly; + this.aname = assembly.GetName (); } #region Properties - public AParametersCollection Parameters { + public Assembly Assembly { get { - return parameters; + return assembly; + } + } + + public string FullName { + get { + return aname.FullName; + } + } + + public bool HasExtensionMethod { + get { + return contains_extension_methods; + } + } + + public bool HasStrongName { + get { + return aname.GetPublicKey ().Length != 0; + } + } + + public bool IsMissing { + get { +#if STATIC + return assembly.__IsMissing; +#else + return false; +#endif + } + } + + public bool IsCLSCompliant { + get { + return cls_compliant; + } + } + + public string Location { + get { + return assembly.Location; } } + public string Name { + get { + return aname.Name; + } + } + + #endregion + + public byte[] GetPublicKeyToken () + { + return aname.GetPublicKeyToken (); + } + + public AssemblyName GetAssemblyVisibleToName (IAssemblyDefinition assembly) + { + return internals_visible_to_cache [assembly]; + } + + public bool IsFriendAssemblyTo (IAssemblyDefinition assembly) + { + if (internals_visible_to == null) + return false; + + AssemblyName is_visible = null; + if (internals_visible_to_cache == null) { + internals_visible_to_cache = new Dictionary (); + } else { + if (internals_visible_to_cache.TryGetValue (assembly, out is_visible)) + return is_visible != null; + } + + var token = assembly.GetPublicKeyToken (); + if (token != null && token.Length == 0) + token = null; + + foreach (var internals in internals_visible_to) { + if (internals.Name != assembly.Name) + continue; + + if (token == null && assembly is AssemblyDefinition) { + is_visible = internals; + break; + } + + if (!ArrayComparer.IsEqual (token, internals.GetPublicKeyToken ())) + continue; + + is_visible = internals; + break; + } + + internals_visible_to_cache.Add (assembly, is_visible); + return is_visible != null; + } + + public void ReadAttributes () + { +#if STATIC + if (assembly.__IsMissing) + return; +#endif + + IList attrs = CustomAttributeData.GetCustomAttributes (assembly); + + foreach (var a in attrs) { + var dt = a.Constructor.DeclaringType; + var name = dt.Name; + if (name == "CLSCompliantAttribute") { + if (dt.Namespace == "System") { + cls_compliant = (bool) a.ConstructorArguments[0].Value; + } + continue; + } + + if (name == "InternalsVisibleToAttribute") { + if (dt.Namespace != MetadataImporter.CompilerServicesNamespace) + continue; + + string s = a.ConstructorArguments[0].Value as string; + if (s == null) + continue; + + var an = new AssemblyName (s); + if (internals_visible_to == null) + internals_visible_to = new List (); + + internals_visible_to.Add (an); + continue; + } + + if (name == "ExtensionAttribute") { + if (dt.Namespace == MetadataImporter.CompilerServicesNamespace) + contains_extension_methods = true; + + continue; + } + } + } + + public override string ToString () + { + return FullName; + } + } + + class ImportedMemberDefinition : ImportedDefinition + { + readonly TypeSpec type; + + public ImportedMemberDefinition (MemberInfo member, TypeSpec type, MetadataImporter importer) + : base (member, importer) + { + this.type = type; + } + + #region Properties + public TypeSpec MemberType { get { - throw new NotImplementedException (); + return type; } } #endregion } - class ImportedIndexerDefinition : ImportedMemberDefinition, IParametersMember + class ImportedParameterMemberDefinition : ImportedMemberDefinition, IParametersMember { readonly AParametersCollection parameters; - public ImportedIndexerDefinition (PropertyInfo provider, AParametersCollection parameters) - : base (provider) + public ImportedParameterMemberDefinition (MethodBase provider, TypeSpec type, AParametersCollection parameters, MetadataImporter importer) + : base (provider, type, importer) + { + this.parameters = parameters; + } + + public ImportedParameterMemberDefinition (PropertyInfo provider, TypeSpec type, AParametersCollection parameters, MetadataImporter importer) + : base (provider, type, importer) { this.parameters = parameters; } @@ -1098,21 +1696,15 @@ namespace Mono.CSharp } } - public TypeSpec MemberType { - get { - throw new NotImplementedException (); - } - } - #endregion } - class ImportedGenericMethodDefinition : ImportedMethodDefinition, IGenericMethodDefinition + class ImportedGenericMethodDefinition : ImportedParameterMemberDefinition, IGenericMethodDefinition { - TypeParameterSpec[] tparams; + readonly TypeParameterSpec[] tparams; - public ImportedGenericMethodDefinition (MethodInfo provider, AParametersCollection parameters, TypeParameterSpec[] tparams) - : base (provider, parameters) + public ImportedGenericMethodDefinition (MethodInfo provider, TypeSpec type, AParametersCollection parameters, TypeParameterSpec[] tparams, MetadataImporter importer) + : base (provider, type, parameters, importer) { this.tparams = tparams; } @@ -1134,26 +1726,33 @@ namespace Mono.CSharp #endregion } - class ImportedTypeDefinition : ImportedMemberDefinition, ITypeDefinition + class ImportedTypeDefinition : ImportedDefinition, ITypeDefinition { TypeParameterSpec[] tparams; string name; - ReflectionMetaImporter meta_import; - public ImportedTypeDefinition (ReflectionMetaImporter metaImport, Type type) - : base (type) + public ImportedTypeDefinition (MetaType type, MetadataImporter importer) + : base (type, importer) { - this.meta_import = metaImport; } #region Properties + public IAssemblyDefinition DeclaringAssembly { + get { + return importer.GetAssemblyDefinition (provider.Module.Assembly); + } + } + public override string Name { get { if (name == null) { name = base.Name; - if (tparams != null) - name = name.Substring (0, name.IndexOf ('`')); + if (tparams != null) { + int arity_start = name.IndexOf ('`'); + if (arity_start > 0) + name = name.Substring (0, arity_start); + } } return name; @@ -1162,7 +1761,7 @@ namespace Mono.CSharp public string Namespace { get { - return ((Type) provider).Namespace; + return ((MetaType) provider).Namespace; } } @@ -1183,14 +1782,39 @@ namespace Mono.CSharp #endregion + public static void Error_MissingDependency (IMemberContext ctx, List types, Location loc) + { + // + // Report details about missing type and most likely cause of the problem. + // csc reports 1683, 1684 as warnings but we report them only when used + // or referenced from the user core in which case compilation error has to + // be reported because compiler cannot continue anyway + // + foreach (var t in types) { + string name = t.GetSignatureForError (); + + if (t.MemberDefinition.DeclaringAssembly == ctx.Module.DeclaringAssembly) { + ctx.Module.Compiler.Report.Error (1683, loc, + "Reference to type `{0}' claims it is defined in this assembly, but it is not defined in source or any added modules", + name); + } else if (t.MemberDefinition.DeclaringAssembly.IsMissing) { + ctx.Module.Compiler.Report.Error (12, loc, + "The type `{0}' is defined in an assembly that is not referenced. Consider adding a reference to assembly `{1}'", + name, t.MemberDefinition.DeclaringAssembly.FullName); + } else { + ctx.Module.Compiler.Report.Error (1684, loc, + "Reference to type `{0}' claims it is defined assembly `{1}', but it could not be found", + name, t.MemberDefinition.DeclaringAssembly.FullName); + } + } + } + public TypeSpec GetAttributeCoClass () { - // TODO: Use ReadAttributes - var attr = provider.GetCustomAttributes (typeof (CoClassAttribute), false); - if (attr.Length < 1) - return null; + if (cattrs == null) + ReadAttributes (); - return meta_import.CreateType (((CoClassAttribute) attr[0]).CoClass); + return cattrs.CoClass; } public string GetAttributeDefaultMember () @@ -1209,17 +1833,23 @@ namespace Mono.CSharp return cattrs.AttributeUsage; } - public void LoadMembers (TypeSpec declaringType, ref MemberCache cache) + bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly) + { + var a = importer.GetAssemblyDefinition (provider.Module.Assembly); + return a == assembly || a.IsFriendAssemblyTo (assembly); + } + + public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache) { // // Not interested in members of nested private types unless the importer needs them // - if (declaringType.IsPrivate && meta_import.IgnorePrivateMembers) { + if (declaringType.IsPrivate && importer.IgnorePrivateMembers) { cache = MemberCache.Empty; return; } - var loading_type = (Type) provider; + var loading_type = (MetaType) provider; const BindingFlags all_members = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; @@ -1238,163 +1868,206 @@ namespace Mono.CSharp all = loading_type.GetMembers (all_members); } catch (Exception e) { throw new InternalErrorException (e, "Could not import type `{0}' from `{1}'", - declaringType.GetSignatureForError (), declaringType.Assembly.Location); + declaringType.GetSignatureForError (), declaringType.MemberDefinition.DeclaringAssembly.FullName); } - cache = new MemberCache (all.Length); + if (cache == null) { + cache = new MemberCache (all.Length); - // - // Do the types first as they can be referenced by the members before - // they are found or inflated - // - foreach (var member in all) { - if (member.MemberType != MemberTypes.NestedType) - continue; + // + // Do the types first as they can be referenced by the members before + // they are found or inflated + // + foreach (var member in all) { + if (member.MemberType != MemberTypes.NestedType) + continue; - Type t = (Type) member; + var t = (MetaType) member; - // Ignore compiler generated types, mostly lambda containers - if (t.IsNotPublic && t.IsDefined (typeof (CompilerGeneratedAttribute), false)) - continue; + // Ignore compiler generated types, mostly lambda containers + if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate && importer.IgnorePrivateMembers) + continue; - imported = meta_import.CreateType (t, declaringType); - cache.AddMember (imported); - } + try { + imported = importer.CreateNestedType (t, declaringType); + } catch (Exception e) { + throw new InternalErrorException (e, "Could not import nested type `{0}' from `{1}'", + t.FullName, declaringType.MemberDefinition.DeclaringAssembly.FullName); + } - // - // The logic here requires methods to be returned first which seems to work for both Mono and .NET - // - 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 && (mb.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) - continue; + cache.AddMemberImported (imported); + } - // Ignore compiler generated methods - if (mb.IsPrivate && mb.IsDefined (typeof (CompilerGeneratedAttribute), false)) + foreach (var member in all) { + if (member.MemberType != MemberTypes.NestedType) continue; - imported = meta_import.CreateMethod (mb, declaringType); - if (imported.Kind == MemberKind.Method && !imported.IsGeneric) { - if (possible_accessors == null) - possible_accessors = new Dictionary (ReferenceEquality.Default); + var t = (MetaType) member; - // There are no metadata rules for accessors, we have to consider any method as possible candidate - possible_accessors.Add (mb, (MethodSpec) imported); - } - - break; - case MemberTypes.Property: - if (possible_accessors == null) + if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate && importer.IgnorePrivateMembers) 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; + importer.ImportTypeBase (t); + } + } - m = p.GetSetMethod (true); - if (m == null || !possible_accessors.TryGetValue (m, out set)) - set = null; + // + // Load base interfaces first to minic behaviour of compiled members + // + if (declaringType.IsInterface && declaringType.Interfaces != null) { + foreach (var iface in declaringType.Interfaces) { + cache.AddInterface (iface); + } + } - // No accessors registered (e.g. explicit implementation) - if (get == null && set == null) - continue; + if (!onlyTypes) { + // + // The logic here requires methods to be returned first which seems to work for both Mono and .NET + // + foreach (var member in all) { + switch (member.MemberType) { + case MemberTypes.Constructor: + case MemberTypes.Method: + MethodBase mb = (MethodBase) member; + var attrs = mb.Attributes; + + if ((attrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) { + if (importer.IgnorePrivateMembers) + continue; + + // Ignore explicitly implemented members + if ((attrs & explicit_impl) == explicit_impl) + continue; + + // Ignore compiler generated methods + if (importer.HasAttribute (CustomAttributeData.GetCustomAttributes (mb), "CompilerGeneratedAttribute", MetadataImporter.CompilerServicesNamespace)) + continue; + } - imported = meta_import.CreateProperty (p, declaringType, get, set); - if (imported == null) - continue; + imported = importer.CreateMethod (mb, declaringType); + if (imported.Kind == MemberKind.Method && !imported.IsGeneric) { + if (possible_accessors == null) + possible_accessors = new Dictionary (ReferenceEquality.Default); - break; - case MemberTypes.Event: - if (possible_accessors == null) - continue; + // There are no metadata rules for accessors, we have to consider any method as possible candidate + possible_accessors.Add (mb, (MethodSpec) imported); + } - 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; + break; + case MemberTypes.Property: + if (possible_accessors == null) + continue; - m = e.GetRemoveMethod (true); - if (m == null || !possible_accessors.TryGetValue (m, out remove)) - remove = null; + 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; - // Both accessors are required - if (add == null || remove == null) - continue; + m = p.GetSetMethod (true); + if (m == null || !possible_accessors.TryGetValue (m, out set)) + set = null; - event_spec = meta_import.CreateEvent (e, declaringType, add, remove); - if (!meta_import.IgnorePrivateMembers) { - if (imported_events == null) - imported_events = new List (); + // No accessors registered (e.g. explicit implementation) + if (get == null && set == null) + continue; - imported_events.Add (event_spec); - } + imported = importer.CreateProperty (p, declaringType, get, set); + if (imported == null) + continue; - imported = event_spec; - break; - case MemberTypes.Field: - var fi = (FieldInfo) member; + break; + case MemberTypes.Event: + if (possible_accessors == null) + continue; - imported = meta_import.CreateField (fi, declaringType); - if (imported == 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; - // - // For dynamic binder event has to be fully restored to allow operations - // within the type container to work correctly - // - if (imported_events != null) { - // The backing event field should be private but it may not - int index = imported_events.FindIndex (l => l.Name == fi.Name); - if (index >= 0) { - event_spec = imported_events[index]; - event_spec.BackingField = (FieldSpec) imported; - imported_events.RemoveAt (index); + 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; + + event_spec = importer.CreateEvent (e, declaringType, add, remove); + if (!importer.IgnorePrivateMembers) { + if (imported_events == null) + imported_events = new List (); + + imported_events.Add (event_spec); } - } - break; - case MemberTypes.NestedType: - meta_import.ImportTypeBase ((Type) member); - continue; - default: - throw new NotImplementedException (member.ToString ()); - } + imported = event_spec; + break; + case MemberTypes.Field: + var fi = (FieldInfo) member; - cache.AddMember (imported); - } + imported = importer.CreateField (fi, declaringType); + if (imported == null) + continue; - if (declaringType.IsInterface && declaringType.Interfaces != null) { - foreach (var iface in declaringType.Interfaces) { - cache.AddInterface (iface); + // + // For dynamic binder event has to be fully restored to allow operations + // within the type container to work correctly + // + if (imported_events != null) { + // The backing event field should be private but it may not + int i; + for (i = 0; i < imported_events.Count; ++i) { + var ev = imported_events[i]; + if (ev.Name == fi.Name) { + ev.BackingField = (FieldSpec) imported; + imported_events.RemoveAt (i); + i = -1; + break; + } + } + + if (i < 0) + continue; + } + + break; + case MemberTypes.NestedType: + // Already in the cache from the first pass + continue; + default: + throw new NotImplementedException (member.ToString ()); + } + + cache.AddMemberImported (imported); } } } } - class ImportedTypeParameterDefinition : ImportedMemberDefinition, ITypeDefinition + class ImportedTypeParameterDefinition : ImportedDefinition, ITypeDefinition { - public ImportedTypeParameterDefinition (Type type) - : base (type) + public ImportedTypeParameterDefinition (MetaType type, MetadataImporter importer) + : base (type, importer) { } #region Properties + public IAssemblyDefinition DeclaringAssembly { + get { + throw new NotImplementedException (); + } + } + public string Namespace { get { return null; @@ -1430,7 +2103,12 @@ namespace Mono.CSharp throw new NotSupportedException (); } - public void LoadMembers (TypeSpec declaringType, ref MemberCache cache) + bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly) + { + throw new NotImplementedException (); + } + + public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache) { throw new NotImplementedException (); }