//
// 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<Type, TypeSpec> import_cache;
- Dictionary<Type, PredefinedTypeSpec> 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<CustomAttributeData> 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<CustomAttributeTypedArgument>) 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<MetaType, TypeSpec> import_cache;
+ protected readonly Dictionary<MetaType, TypeSpec> compiled_types;
+ protected readonly Dictionary<Assembly, IAssemblyDefinition> assembly_2_definition;
+ readonly ModuleContainer module;
+
+ public static readonly string CompilerServicesNamespace = "System.Runtime.CompilerServices";
+
+ protected MetadataImporter (ModuleContainer module)
{
- import_cache = new Dictionary<Type, TypeSpec> (1024, ReferenceEquality<Type>.Default);
+ this.module = module;
+
+ import_cache = new Dictionary<MetaType, TypeSpec> (1024, ReferenceEquality<MetaType>.Default);
+ compiled_types = new Dictionary<MetaType, TypeSpec> (40, ReferenceEquality<MetaType>.Default);
+ assembly_2_definition = new Dictionary<Assembly, IAssemblyDefinition> (ReferenceEquality<Assembly>.Default);
IgnorePrivateMembers = true;
}
#region Properties
+ public ICollection<IAssemblyDefinition> 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<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 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)
{
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);
}
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<T> (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) {
if (tparams.Length - parent_owned_count == 0)
return null;
- return CreateGenericParameters<T> (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<T> (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<T> {
+ // IFoo<A<T>> foo; // A<T> 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;
{
Modifiers mod = ReadMethodModifiers (mb, declaringType);
TypeParameterSpec[] tparams;
- ImportedMethodDefinition definition;
var parameters = CreateParameters (declaringType, mb.GetParameters (), mb);
if (!mb.IsGenericMethodDefinition)
throw new NotSupportedException ("assert");
- tparams = CreateGenericParameters<TypeParameterSpec>(0, mb.GetGenericArguments ());
- definition = new ImportedGenericMethodDefinition ((MethodInfo) mb, parameters, tparams);
+ tparams = CreateGenericParameters (0, mb.GetGenericArguments ());
} else {
- definition = new ImportedMethodDefinition (mb, parameters);
tparams = null;
}
TypeSpec returnType;
if (mb.MemberType == MemberTypes.Constructor) {
kind = MemberKind.Constructor;
- returnType = TypeManager.void_type;
+ returnType = module.Compiler.BuiltinTypes.Void;
} else {
//
// Detect operators and destructors
}
} 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;
//
// 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);
}
}
}
new ParametersImported (par, types, is_params);
}
-
//
// Returns null when the property is not valid C# property
//
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;
}
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;
}
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<object> agains IFoo<dynamic>
+ // 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<TypeSpec> (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
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;
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;
}
}
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;
}
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)
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 |
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<TypeParameterSpec>(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)
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) {
}
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<TypeSpec> tparams = null;
- foreach (var ct in constraints) {
- if (ct.IsGenericParameter) {
- if (tparams == null)
- tparams = new List<TypeSpec> ();
+ //
+ // 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<CustomAttributeData> 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<CustomAttributeData> 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;
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<TypeSpec> tparams = null;
+ foreach (var ct in constraints) {
+ if (ct.IsGenericParameter) {
+ if (tparams == null)
+ tparams = new List<TypeSpec> ();
+
+ 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
}
//
// as IsInitOnly ('readonly' in C# parlance). We get its value from the
// DecimalConstantAttribute metadata.
//
- static Constant ReadDecimalConstant (FieldInfo fi)
+ Constant ReadDecimalConstant (IList<CustomAttributeData> 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)
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;
}
}
}
- class ImportedMemberDefinition : IMemberDefinition
+ abstract class ImportedDefinition : IMemberDefinition
{
protected class AttributesBag
{
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<string> conditionals = null;
IList<CustomAttributeData> 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 ();
continue;
}
- if (type == typeof (ConditionalAttribute)) {
+ if (name == "ConditionalAttribute") {
+ if (dt.Namespace != "System.Diagnostics")
+ continue;
+
if (bag == null)
bag = new AttributesBag ();
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;
}
}
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;
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 ()
}
}
- 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<CustomAttributeData> 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<Attribute> 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<Attribute> (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<AssemblyName> internals_visible_to;
+ Dictionary<IAssemblyDefinition, AssemblyName> 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<IAssemblyDefinition, AssemblyName> ();
+ } 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<CustomAttributeData> 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<AssemblyName> ();
+
+ 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;
}
}
}
- 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;
}
#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;
public string Namespace {
get {
- return ((Type) provider).Namespace;
+ return ((MetaType) provider).Namespace;
}
}
#endregion
+ public static void Error_MissingDependency (IMemberContext ctx, List<TypeSpec> 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 ()
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;
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<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.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<MethodBase, MethodSpec> (ReferenceEquality<MethodBase>.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<EventSpec> ();
+ // 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<EventSpec> ();
+
+ 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;
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 ();
}