X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fmembercache.cs;h=9ff3168869e9dd2f532086793c8d03a9f2755ef9;hb=67a79d55105ae66d05d31f498b0ebe63eda8b824;hp=e905e0473b9279096ec1906e8000d8380da0e173;hpb=249a4d148dc106914e74ab28edeaa75e8bd88504;p=mono.git diff --git a/mcs/mcs/membercache.cs b/mcs/mcs/membercache.cs index e905e0473b9..9ff3168869e 100644 --- a/mcs/mcs/membercache.cs +++ b/mcs/mcs/membercache.cs @@ -8,16 +8,12 @@ // // Copyright 2001 Ximian, Inc (http://www.ximian.com) // Copyright 2004-2010 Novell, Inc +// Copyright 2011 Xamarin Inc // // using System; -using System.Text; using System.Collections.Generic; -using System.Globalization; -using System.Reflection.Emit; -using System.Reflection; -using System.Linq; namespace Mono.CSharp { @@ -43,11 +39,13 @@ namespace Mono.CSharp { ArrayType = 1 << 19, PointerType = 1 << 20, InternalCompilerType = 1 << 21, + MissingType = 1 << 22, + Void = 1 << 23, + Namespace = 1 << 24, NestedMask = Class | Struct | Delegate | Enum | Interface, GenericMask = Method | Class | Struct | Delegate | Interface, - MaskType = Constructor | Event | Field | Method | Property | Indexer | Operator | Destructor | NestedMask, - All = MaskType + MaskType = Constructor | Event | Field | Method | Property | Indexer | Operator | Destructor | NestedMask } [Flags] @@ -55,23 +53,16 @@ namespace Mono.CSharp { { None = 0, - // Member has to be accessible - AccessibleOnly = 1, - // Inspect only queried type members DeclaredOnly = 1 << 1, // Exclude static InstanceOnly = 1 << 2, - // Ignore member overrides - NoOverrides = 1 << 3, - - NoAccessors = 1 << 4, + NoAccessors = 1 << 3, - StopOnFirstMatch = 1 << 5, - - DefaultMemberLookup = NoOverrides | StopOnFirstMatch + // Member has to be override + OverrideOnly = 1 << 4 } public struct MemberFilter : IEquatable @@ -80,19 +71,7 @@ namespace Mono.CSharp { public readonly MemberKind Kind; public readonly AParametersCollection Parameters; public readonly TypeSpec MemberType; - - int arity; // -1 to ignore the check - TypeSpec invocation_type; - - private MemberFilter (string name, MemberKind kind) - { - Name = name; - Kind = kind; - Parameters = null; - MemberType = null; - arity = -1; - invocation_type = null; - } + public readonly int Arity; // -1 to ignore the check public MemberFilter (MethodSpec m) { @@ -100,8 +79,7 @@ namespace Mono.CSharp { Kind = MemberKind.Method; Parameters = m.Parameters; MemberType = m.ReturnType; - arity = m.Arity; - invocation_type = null; + Arity = m.Arity; } public MemberFilter (string name, int arity, MemberKind kind, AParametersCollection param, TypeSpec type) @@ -110,22 +88,12 @@ namespace Mono.CSharp { Kind = kind; Parameters = param; MemberType = type; - this.arity = arity; - invocation_type = null; - } - - public TypeSpec InvocationType { - get { - return invocation_type; - } - set { - invocation_type = value; - } + this.Arity = arity; } public static MemberFilter Constructor (AParametersCollection param) { - return new MemberFilter (System.Reflection.ConstructorInfo.ConstructorName, 0, MemberKind.Constructor, param, null); + return new MemberFilter (Mono.CSharp.Constructor.ConstructorName, 0, MemberKind.Constructor, param, null); } public static MemberFilter Property (string name, TypeSpec type) @@ -153,7 +121,7 @@ namespace Mono.CSharp { return false; // Check arity when not disabled - if (arity >= 0 && arity != other.Arity) + if (Arity >= 0 && Arity != other.Arity) return false; if (Parameters != null) { @@ -176,18 +144,9 @@ namespace Mono.CSharp { } } - if (invocation_type != null && !IsAccessible (other)) - return false; - return true; } - bool IsAccessible (MemberSpec other) - { - bool extra; - return Expression.IsMemberAccessible (invocation_type, other, out extra); - } - #endregion } @@ -202,16 +161,17 @@ namespace Mono.CSharp { // public class MemberCache { + [Flags] enum StateFlags { - HasNoImplicitOperator = 1, - HasNoExplicitOperator = 1 << 1 + HasConversionOperator = 1 << 1, + HasUserOperator = 1 << 2 } readonly Dictionary> member_hash; Dictionary locase_members; IList missing_abstract; - StateFlags state; + StateFlags state; // TODO: Move to TypeSpec or ITypeDefinition public static readonly string IndexerNameAlias = ""; @@ -230,6 +190,7 @@ namespace Mono.CSharp { public MemberCache (MemberCache cache) : this (cache.member_hash.Count) { + this.state = cache.state; } // @@ -240,6 +201,40 @@ namespace Mono.CSharp { { } + // + // For cases where we need to union cache members + // + public void AddBaseType (TypeSpec baseType) + { + var cache = baseType.MemberCache; + + IList list; + foreach (var entry in cache.member_hash) { + if (!member_hash.TryGetValue (entry.Key, out list)) { + if (entry.Value.Count == 1) { + list = entry.Value; + } else { + list = new List (entry.Value); + } + + member_hash.Add (entry.Key, list); + continue; + } + + foreach (var ce in entry.Value) { + if (list.Contains (ce)) + continue; + + if (list is MemberSpec[]) { + list = new List () { list [0] }; + member_hash[entry.Key] = list; + } + + list.Add (ce); + } + } + } + // // Member-cache does not contain base members but it does // contain all base interface members, so the Lookup code @@ -263,9 +258,6 @@ namespace Mono.CSharp { } foreach (var ce in entry.Value) { - if (ce.DeclaringType != iface) - break; - if (list.Contains (ce)) continue; @@ -273,6 +265,12 @@ namespace Mono.CSharp { member_hash[entry.Key] = list; } } + + // Add also all base interfaces + if (iface.Interfaces != null) { + foreach (var base_iface in iface.Interfaces) + AddInterface (base_iface); + } } public void AddMember (InterfaceMemberBase imb, string exlicitName, MemberSpec ms) @@ -280,7 +278,7 @@ namespace Mono.CSharp { // Explicit names cannot be looked-up but can be used for // collision checking (no name mangling needed) if (imb.IsExplicitImpl) - AddMember (exlicitName, ms); + AddMember (exlicitName, ms, false); else AddMember (ms); } @@ -290,22 +288,49 @@ namespace Mono.CSharp { // public void AddMember (MemberSpec ms) { - AddMember (GetLookupName (ms), ms); + AddMember (GetLookupName (ms), ms, false); } - void AddMember (string name, MemberSpec member) + void AddMember (string name, MemberSpec member, bool removeHiddenMembers) { + if (member.Kind == MemberKind.Operator) { + var dt = member.DeclaringType; + + // + // Some core types have user operators but they cannot be used like normal + // user operators as they are predefined and therefore having different + // rules (e.g. binary operators) by not setting the flag we hide them for + // user conversions + // + if (!BuiltinTypeSpec.IsPrimitiveType (dt)) { + switch (dt.BuiltinType) { + case BuiltinTypeSpec.Type.String: + case BuiltinTypeSpec.Type.Delegate: + case BuiltinTypeSpec.Type.MulticastDelegate: + break; + default: + if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) { + state |= StateFlags.HasConversionOperator; + } else { + state |= StateFlags.HasUserOperator; + } + + break; + } + } + } + IList list; if (!member_hash.TryGetValue (name, out list)) { member_hash.Add (name, new MemberSpec[] { member }); return; } - if (member.DeclaringType.IsInterface) { + if (removeHiddenMembers && member.DeclaringType.IsInterface) { if (AddInterfaceMember (member, ref list)) member_hash[name] = list; } else { - if (list is MemberSpec[]) { + if (list.Count == 1) { list = new List () { list[0] }; member_hash[name] = list; } @@ -314,6 +339,11 @@ namespace Mono.CSharp { } } + public void AddMemberImported (MemberSpec ms) + { + AddMember (GetLookupName (ms), ms, true); + } + // // Ignores any base interface member which can be hidden // by this interface @@ -340,8 +370,8 @@ namespace Mono.CSharp { continue; } - if (member.DeclaringType.ImplementsInterface (entry.DeclaringType)) { - if (existing is MemberSpec[]) { + if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) { + if (existing.Count == 1) { existing = new MemberSpec[] { member }; return true; } @@ -351,11 +381,11 @@ namespace Mono.CSharp { } if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) || - entry.DeclaringType.ImplementsInterface (member.DeclaringType)) + entry.DeclaringType.ImplementsInterface (member.DeclaringType, false)) return false; } - if (existing is MemberSpec[]) { + if (existing.Count == 1) { existing = new List () { existing[0], member }; return true; } @@ -364,13 +394,6 @@ namespace Mono.CSharp { return false; } - public static IEnumerable FindIndexers (TypeSpec container, BindingRestriction restrictions) - { - var filter = new MemberFilter (IndexerNameAlias, 0, MemberKind.Indexer, null, null); - var found = FindMembers (container, filter, restrictions); - return found == null ? null : found.Cast (); - } - public static MemberSpec FindMember (TypeSpec container, MemberFilter filter, BindingRestriction restrictions) { do { @@ -386,6 +409,9 @@ namespace Mono.CSharp { if ((restrictions & BindingRestriction.NoAccessors) != 0 && entry.IsAccessor) continue; + if ((restrictions & BindingRestriction.OverrideOnly) != 0 && (entry.Modifiers & Modifiers.OVERRIDE) == 0) + continue; + if (!filter.Equals (entry)) continue; @@ -393,10 +419,6 @@ namespace Mono.CSharp { continue; return entry; - - // TODO MemberCache: - //if ((restrictions & BindingRestriction.AccessibleOnly) != 0) - // throw new NotImplementedException ("net"); } } @@ -410,110 +432,24 @@ namespace Mono.CSharp { } // - // Returns the first set of members starting from - // container, the returned list must not be modified + // A special method to work with member lookup only. It returns a list of all members named @name + // starting from @container. It's very performance sensitive // - public static IList FindMembers (TypeSpec container, MemberFilter filter, BindingRestriction restrictions) + // declaredOnlyClass cannot be used interfaces. Manual filtering is required because names are + // compacted + // + public static IList FindMembers (TypeSpec container, string name, bool declaredOnlyClass) { IList applicable; - List found = null; - int match_counter = 0; do { - int i; - if (container.MemberCache.member_hash.TryGetValue (filter.Name, out applicable)) { - for (i = 0; i < applicable.Count; ++i) { - var entry = applicable [i]; - - // Is the member of the correct type - if ((entry.Kind & filter.Kind & MemberKind.MaskType) == 0) - continue; - - // - // When using overloadable overrides filter ignore members which - // are not base members. Including properties because overrides can - // implement get or set only and we are looking for complete base member - // - const MemberKind overloadable = MemberKind.Indexer | MemberKind.Method | MemberKind.Property; - if ((restrictions & BindingRestriction.NoOverrides) != 0 && (entry.Kind & overloadable) != 0) { - if ((entry.Modifiers & Modifiers.OVERRIDE) != 0) - continue; - - if ((entry.Modifiers & Modifiers.OVERRIDE_UNCHECKED) != 0) { - bool is_override = true; - var ms = entry as MethodSpec; - if (ms != null) { - is_override = IsRealMethodOverride (ms); - } else { - var ps = (PropertySpec) entry; - if (ps.HasGet) - is_override = IsRealMethodOverride (ps.Get); - if (is_override && ps.HasSet) - is_override = IsRealMethodOverride (ps.Set); - } - - if (is_override) { - entry.Modifiers = (entry.Modifiers & ~Modifiers.OVERRIDE_UNCHECKED) | Modifiers.OVERRIDE; - continue; - } - } - } - - if ((restrictions & BindingRestriction.InstanceOnly) != 0 && entry.IsStatic) - continue; - - // Apply the filter to it. - if (!filter.Equals (entry)) - continue; - - // Try not to allocate a new list until it's necessary - if (found == null) { - if (i == match_counter) { - ++match_counter; - continue; - } - - found = new List (System.Math.Max (4, match_counter + 1)); - for (int ii = 0; ii < match_counter; ++ii) - found.Add (applicable [ii]); - } - - found.Add (entry); - } - - // Deal with allocation-less optimization - if ((restrictions & (BindingRestriction.DeclaredOnly | BindingRestriction.StopOnFirstMatch)) != 0) { - if (found != null) - return found; - - if (i == match_counter) - return applicable; - - if (match_counter > 0) { - found = new List (match_counter); - for (int ii = 0; ii < match_counter; ++ii) - found.Add (applicable[ii]); - - return found; - } - - if ((restrictions & BindingRestriction.DeclaredOnly) != 0) - return null; - } else if (found == null) { - if (i == match_counter) { - found = new List (applicable); - } else if (match_counter > 0) { - found = new List (System.Math.Max (4, match_counter)); - for (int ii = 0; ii < match_counter; ++ii) - found.Add (applicable[ii]); - } - } - } + if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnlyClass) + return applicable; container = container.BaseType; } while (container != null); - return found; + return null; } // @@ -531,7 +467,7 @@ namespace Mono.CSharp { // based on type definition var tc = container.MemberDefinition as TypeContainer; if (tc != null) - tc.DefineType (); + tc.DefineContainer (); if (container.MemberCacheTypes.member_hash.TryGetValue (name, out applicable)) { for (int i = applicable.Count - 1; i >= 0; i--) { @@ -562,7 +498,7 @@ namespace Mono.CSharp { // // Looks for extension methods with defined name and extension type // - public List FindExtensionMethods (TypeSpec invocationType, TypeSpec extensionType, string name, int arity) + public List FindExtensionMethods (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity) { IList entries; if (!member_hash.TryGetValue (name, out entries)) @@ -570,20 +506,20 @@ namespace Mono.CSharp { List candidates = null; foreach (var entry in entries) { - if (entry.Kind != MemberKind.Method || (arity >= 0 && entry.Arity != arity)) + if (entry.Kind != MemberKind.Method || (arity > 0 && entry.Arity != arity)) continue; var ms = (MethodSpec) entry; if (!ms.IsExtensionMethod) continue; - bool extra; - if (!Expression.IsMemberAccessible (invocationType, ms, out extra)) + if (!ms.IsAccessible (invocationContext)) continue; - // TODO: CodeGen.Assembly.Builder - if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && - !TypeManager.IsThisOrFriendAssembly (CodeGen.Assembly.Builder, ms.Assembly)) + // + // Extension methods cannot be nested hence checking parent is enough + // + if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && !ms.DeclaringType.MemberDefinition.IsInternalAsPublic (invocationContext.Module.DeclaringAssembly)) continue; if (candidates == null) @@ -598,18 +534,26 @@ namespace Mono.CSharp { // Returns base members of @member member if no exact match is found @bestCandidate returns // the best match // - public static MemberSpec FindBaseMember (MemberCore member, out MemberSpec bestCandidate) + public static MemberSpec FindBaseMember (MemberCore member, out MemberSpec bestCandidate, ref bool overrides) { bestCandidate = null; var container = member.Parent.PartialContainer.Definition; - if (!container.IsInterface) + if (!container.IsInterface) { container = container.BaseType; + // It can happen for a user definition of System.Object + if (container == null) + return null; + } + string name = GetLookupName (member); - IList applicable; var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : null; var mkind = GetMemberCoreKind (member); + bool member_with_accessors = mkind == MemberKind.Indexer || mkind == MemberKind.Property; + + IList applicable; + MemberSpec ambig_candidate = null; do { if (container.MemberCache.member_hash.TryGetValue (name, out applicable)) { @@ -619,57 +563,76 @@ namespace Mono.CSharp { if ((entry.Modifiers & Modifiers.PRIVATE) != 0) continue; - if ((entry.Modifiers & Modifiers.AccessibilityMask) == Modifiers.INTERNAL) { - if (!TypeManager.IsThisOrFriendAssembly (member.Assembly, entry.Assembly)) - continue; - } + if ((entry.Modifiers & Modifiers.AccessibilityMask) == Modifiers.INTERNAL && + !entry.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly)) + continue; // - // Is the member of the correct type ? - // Destructors are ignored as they cannot be overridden by user + // Isn't the member of same kind ? + // if ((entry.Kind & ~MemberKind.Destructor & mkind & MemberKind.MaskType) == 0) { - if ((entry.Kind & MemberKind.Destructor) == 0 && (member_param == null || !(entry is IParametersMember))) { - bestCandidate = entry; - return null; - } + // Destructors are ignored as they cannot be overridden by user + if ((entry.Kind & MemberKind.Destructor) != 0) + continue; - continue; - } + // A method with different arity does not hide base member + if (mkind != MemberKind.Method && member.MemberName.Arity != entry.Arity) + continue; - if (member_param == null) - return entry; + bestCandidate = entry; + return null; + } - // Check arity match - int arity = member.MemberName.Arity; - if (arity != entry.Arity) + // + // Same kind of different arity is valid + // + if (member.MemberName.Arity != entry.Arity) { continue; + } - if (entry is IParametersMember) { + if ((entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) { if (entry.IsAccessor != member is AbstractPropertyEventMethod) continue; - var entry_param = ((IParametersMember) entry).Parameters; - if (TypeSpecComparer.Override.IsEqual (entry_param, member_param)) - return entry; + var pm = entry as IParametersMember; + if (!TypeSpecComparer.Override.IsEqual (pm.Parameters, member_param)) + continue; + } + // + // Skip override for member with accessors. It may not fully implement the base member + // but keep flag we found an implementation in case the base member is abstract + // + if (member_with_accessors && ((entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.SEALED)) == Modifiers.OVERRIDE)) { + // + // Set candidate to override implementation to flag we found an implementation + // + overrides = true; continue; } - if (bestCandidate == null) - bestCandidate = entry; - } + // + // For members with parameters we can encounter an ambiguous candidates (they match exactly) + // because generic type parameters could be inflated into same types + // + if (ambig_candidate == null && (entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) { + bestCandidate = null; + ambig_candidate = entry; + continue; + } - if (member_param == null) - return null; + bestCandidate = ambig_candidate; + return entry; + } } - if (container.IsInterface) + if (container.IsInterface || ambig_candidate != null) break; container = container.BaseType; } while (container != null); - return null; + return ambig_candidate; } // @@ -713,11 +676,53 @@ namespace Mono.CSharp { return MemberKind.Interface; if (member is EventProperty) return MemberKind.Event; + if (member is Delegate) + return MemberKind.Delegate; + if (member is Enum) + return MemberKind.Enum; throw new NotImplementedException (member.GetType ().ToString ()); } - public static IList GetCompletitionMembers (TypeSpec container, string name) + public static List GetAllFieldsForDefiniteAssignment (TypeSpec container) + { + List fields = null; + foreach (var entry in container.MemberCache.member_hash) { + foreach (var name_entry in entry.Value) { + if (name_entry.Kind != MemberKind.Field) + continue; + + if ((name_entry.Modifiers & Modifiers.STATIC) != 0) + continue; + + // + // Fixed size buffers are not subject to definite assignment checking + // + if (name_entry is FixedFieldSpec || name_entry is ConstSpec) + continue; + + var fs = (FieldSpec) name_entry; + + // + // LAMESPEC: Very bizzare hack, definitive assignment is not done + // for imported non-public reference fields except array. No idea what the + // actual csc rule is + // + if (!fs.IsPublic && container.MemberDefinition.IsImported && (!fs.MemberType.IsArray && TypeSpec.IsReferenceType (fs.MemberType))) + continue; + + if (fields == null) + fields = new List (); + + fields.Add (fs); + break; + } + } + + return fields ?? new List (0); + } + + public static IList GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name) { var matches = new List (); foreach (var entry in container.MemberCache.member_hash) { @@ -728,8 +733,7 @@ namespace Mono.CSharp { if ((name_entry.Kind & (MemberKind.Constructor | MemberKind.Destructor | MemberKind.Operator)) != 0) continue; - bool extra; - if (!Expression.IsMemberAccessible (InternalType.FakeInternalType, name_entry, out extra)) + if (!name_entry.IsAccessible (ctx)) continue; if (name == null || name_entry.Name.StartsWith (name)) { @@ -744,7 +748,7 @@ namespace Mono.CSharp { // // Returns members of @iface only, base members are ignored // - public static IList GetInterfaceMethods (TypeSpec iface) + public static List GetInterfaceMethods (TypeSpec iface) { // // MemberCache flatten interfaces, therefore in cases like this one @@ -787,7 +791,7 @@ namespace Mono.CSharp { while (true) { foreach (var entry in abstract_type.MemberCache.member_hash) { foreach (var name_entry in entry.Value) { - if ((name_entry.Modifiers & Modifiers.ABSTRACT) == 0) + if ((name_entry.Modifiers & (Modifiers.ABSTRACT | Modifiers.OVERRIDE)) != Modifiers.ABSTRACT) continue; if (name_entry.Kind != MemberKind.Method) @@ -833,8 +837,13 @@ namespace Mono.CSharp { var filter = new MemberFilter (candidate); foreach (var item in applicable) { - // TODO: Need to test what should happen for OVERRIDE_UNCHECKED - if ((item.Modifiers & (Modifiers.OVERRIDE | Modifiers.OVERRIDE_UNCHECKED | Modifiers.VIRTUAL)) == 0) + if ((item.Modifiers & (Modifiers.OVERRIDE | Modifiers.VIRTUAL)) == 0) + continue; + + // + // Abstract override does not override anything + // + if ((item.Modifiers & Modifiers.ABSTRACT) != 0) continue; if (filter.Equals (item)) { @@ -871,9 +880,9 @@ namespace Mono.CSharp { if (ms.Kind == MemberKind.Constructor) { if (ms.IsStatic) - return ConstructorInfo.TypeConstructorName; + return Constructor.TypeConstructorName; - return ConstructorInfo.ConstructorName; + return Constructor.ConstructorName; } return ms.Name; @@ -885,42 +894,70 @@ namespace Mono.CSharp { return IndexerNameAlias; if (mc is Constructor) - return ConstructorInfo.ConstructorName; + return mc.IsStatic ? Constructor.TypeConstructorName : Constructor.ConstructorName; return mc.MemberName.Name; } // - // Returns all operators declared on container and its base types + // Returns all operators declared on container and its base types (until declaredOnly is used) // - public static MethodSpec[] GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly) + public static IList GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly) { - MethodSpec[] found = null; + IList found = null; IList applicable; do { var mc = container.MemberCache; - if (op == Operator.OpType.Implicit && (mc.state & StateFlags.HasNoImplicitOperator) == 0 || - op == Operator.OpType.Explicit && (mc.state & StateFlags.HasNoExplicitOperator) == 0) { + + if (((op == Operator.OpType.Implicit || op == Operator.OpType.Explicit) && (mc.state & StateFlags.HasConversionOperator) != 0) || + (mc.state & StateFlags.HasUserOperator) != 0) { if (mc.member_hash.TryGetValue (Operator.GetMetadataName (op), out applicable)) { - int start_index; - if (found == null) { - start_index = 0; - found = new MethodSpec[applicable.Count]; - } else { - start_index = found.Length; - Array.Resize (ref found, found.Length + applicable.Count); + int i; + for (i = 0; i < applicable.Count; ++i) { + if (applicable[i].Kind != MemberKind.Operator) { + break; + } } - for (int i = 0; i < applicable.Count; ++i) { - if (applicable[i].Kind == MemberKind.Operator) - found[i + start_index] = (MethodSpec) applicable[i]; + // + // Handles very rare case where a method with same name as operator (op_xxxx) exists + // and we have to resize the applicable list + // + if (i != applicable.Count) { + for (i = 0; i < applicable.Count; ++i) { + if (applicable[i].Kind != MemberKind.Operator) { + continue; + } + + if (found == null) { + found = new List (); + found.Add (applicable[i]); + } else { + var prev = found as List; + if (prev == null) { + prev = new List (found.Count + 1); + prev.AddRange (found); + } + + prev.Add (applicable[i]); + } + } + } else { + if (found == null) { + found = applicable; + } else { + var merged = found as List; + if (merged == null) { + merged = new List (found.Count + applicable.Count); + merged.AddRange (found); + found = merged; + } + + merged.AddRange (applicable); + } } - } else if (op == Operator.OpType.Implicit) { - mc.state |= StateFlags.HasNoImplicitOperator; - } else if (op == Operator.OpType.Explicit) { - mc.state |= StateFlags.HasNoExplicitOperator; } } @@ -929,7 +966,7 @@ namespace Mono.CSharp { break; container = container.BaseType; - } while (container != null && container.BaseType != null); + } while (container != null); return found; } @@ -967,9 +1004,12 @@ namespace Mono.CSharp { public void InflateMembers (MemberCache cacheToInflate, TypeSpec inflatedType, TypeParameterInflator inflator) { var inflated_member_hash = cacheToInflate.member_hash; - Dictionary accessor_relation = null; + Dictionary accessor_relation = null; List accessor_members = null; + // Copy member specific flags when all members were added + cacheToInflate.state = state; + foreach (var item in member_hash) { var members = item.Value; IList inflated_members = null; @@ -1000,10 +1040,10 @@ namespace Mono.CSharp { if (member.DeclaringType != inflatedType) { // - // Don't inflate non generic interface members + // Don't inflate top-level non-generic interface members // merged into generic interface // - if (!member.DeclaringType.IsGeneric) { + if (!member.DeclaringType.IsGeneric && !member.DeclaringType.IsNested) { inflated_members [i] = member; continue; } @@ -1040,8 +1080,8 @@ namespace Mono.CSharp { if (member.IsAccessor) { if (accessor_relation == null) - accessor_relation = new Dictionary (); - accessor_relation.Add ((MethodSpec) member, (MethodSpec) inflated); + accessor_relation = new Dictionary (); + accessor_relation.Add (member, (MethodSpec) inflated); } } } @@ -1066,38 +1106,50 @@ namespace Mono.CSharp { } // - // For imported class method do additional validation to be sure that metadata - // override flag was correct + // Removes hidden base members of an interface. For compiled interfaces we cannot + // do name filtering during Add (as we do for import) because we need all base + // names to be valid during type definition. + // Add replaces hidden base member with current one which means any name collision + // (CS0108) of non-first name would be unnoticed because the name was replaced + // with the one from compiled type // - static bool IsRealMethodOverride (MethodSpec ms) + public void RemoveHiddenMembers (TypeSpec container) { - IList candidates; - var dt = ms.DeclaringType; - while (dt.BaseType != null) { - var base_cache = dt.BaseType.MemberCache; - if (base_cache.member_hash.TryGetValue (ms.Name, out candidates)) { - foreach (var candidate in candidates) { - if (candidate.Kind != ms.Kind) - continue; + foreach (var entry in member_hash) { + var values = entry.Value; - if (candidate.Arity != ms.Arity) - continue; + int container_members_start_at = 0; + while (values[container_members_start_at].DeclaringType != container && ++container_members_start_at < entry.Value.Count); + + if (container_members_start_at == 0 || container_members_start_at == values.Count) + continue; + + for (int i = 0; i < container_members_start_at; ++i) { + var member = values[i]; + + if (!container.ImplementsInterface (member.DeclaringType, false)) + continue; + + var member_param = member is IParametersMember ? ((IParametersMember) member).Parameters : ParametersCompiled.EmptyReadOnlyParameters; - if (!TypeSpecComparer.Override.IsEqual (((MethodSpec) candidate).Parameters, ms.Parameters)) + for (int ii = container_members_start_at; ii < values.Count; ++ii) { + var container_entry = values[ii]; + + if (container_entry.Arity != member.Arity) continue; - // Everything matches except modifiers, it's not correct soverride - if ((candidate.Modifiers & Modifiers.AccessibilityMask) != (ms.Modifiers & Modifiers.AccessibilityMask)) - return false; + if (container_entry is IParametersMember) { + if (!TypeSpecComparer.Override.IsEqual (((IParametersMember) container_entry).Parameters, member_param)) + continue; + } - return true; + values.RemoveAt (i); + --container_members_start_at; + --ii; + --i; } } - - dt = dt.BaseType; } - - return false; } // @@ -1111,8 +1163,9 @@ namespace Mono.CSharp { if (container.BaseType == null) { locase_members = new Dictionary (member_hash.Count); // StringComparer.OrdinalIgnoreCase); } else { - container.BaseType.MemberCache.VerifyClsCompliance (container.BaseType, report); - locase_members = new Dictionary (container.BaseType.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase); + var btype = container.BaseType.GetDefinition (); + btype.MemberCache.VerifyClsCompliance (btype, report); + locase_members = new Dictionary (btype.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase); } var is_imported_type = container.MemberDefinition.IsImported; @@ -1128,13 +1181,17 @@ namespace Mono.CSharp { if ((name_entry.Kind & MemberKind.MaskType) == 0) continue; - if (name_entry.MemberDefinition.IsNotCLSCompliant ()) + if (name_entry.MemberDefinition.CLSAttributeValue == false) continue; - IParametersMember p_a = name_entry as IParametersMember; - if (p_a != null && !name_entry.IsAccessor) { - if (!is_imported_type) { + IParametersMember p_a = null; + if (!is_imported_type) { + p_a = name_entry as IParametersMember; + if (p_a != null && !name_entry.IsAccessor) { var p_a_pd = p_a.Parameters; + // + // Check differing overloads in @container + // for (int ii = i + 1; ii < entry.Value.Count; ++ii) { var checked_entry = entry.Value[ii]; IParametersMember p_b = checked_entry as IParametersMember; @@ -1149,24 +1206,7 @@ namespace Mono.CSharp { var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters); if (res != 0) { - var last = GetLaterDefinedMember (checked_entry, name_entry); - if (last == checked_entry.MemberDefinition) { - report.SymbolRelatedToPreviousError (name_entry); - } else { - report.SymbolRelatedToPreviousError (checked_entry); - } - - if ((res & 1) != 0) { - report.Warning (3006, 1, last.Location, - "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant", - name_entry.GetSignatureForError ()); - } - - if ((res & 2) != 0) { - report.Warning (3007, 1, last.Location, - "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant", - name_entry.GetSignatureForError ()); - } + ReportOverloadedMethodClsDifference (name_entry, checked_entry, res, report); } } } @@ -1184,11 +1224,26 @@ namespace Mono.CSharp { } else { bool same_names_only = true; foreach (var f in found) { - if (f.Name == name_entry.Name) - continue; + if (f.Name == name_entry.Name) { + if (p_a != null) { + IParametersMember p_b = f as IParametersMember; + if (p_b == null) + continue; + + if (p_a.Parameters.Count != p_b.Parameters.Count) + continue; + + if (f.IsAccessor) + continue; + + var res = ParametersCompiled.IsSameClsSignature (p_a.Parameters, p_b.Parameters); + if (res != 0) { + ReportOverloadedMethodClsDifference (f, name_entry, res, report); + } + } -// if (f.IsAccessor && name_entry.IsAccessor) -// continue; + continue; + } same_names_only = false; if (!is_imported_type) { @@ -1227,12 +1282,37 @@ namespace Mono.CSharp { if (mc_b == null) return mc_a; + if (a.DeclaringType.MemberDefinition != b.DeclaringType.MemberDefinition) + return mc_b; + if (mc_a.Location.File != mc_a.Location.File) return mc_b; return mc_b.Location.Row > mc_a.Location.Row ? mc_b : mc_a; } + static void ReportOverloadedMethodClsDifference (MemberSpec a, MemberSpec b, int res, Report report) + { + var last = GetLaterDefinedMember (a, b); + if (last == a.MemberDefinition) { + report.SymbolRelatedToPreviousError (b); + } else { + report.SymbolRelatedToPreviousError (a); + } + + if ((res & 1) != 0) { + report.Warning (3006, 1, last.Location, + "Overloaded method `{0}' differing only in ref or out, or in array rank, is not CLS-compliant", + last.GetSignatureForError ()); + } + + if ((res & 2) != 0) { + report.Warning (3007, 1, last.Location, + "Overloaded method `{0}' differing only by unnamed array types is not CLS-compliant", + last.GetSignatureForError ()); + } + } + public bool CheckExistingMembersOverloads (MemberCore member, AParametersCollection parameters) { var name = GetLookupName (member); @@ -1275,8 +1355,10 @@ namespace Mono.CSharp { type_a = parameters.Types [ii]; type_b = p_types [ii]; - if ((pd.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF) != - (parameters.FixedParameters [ii].ModFlags & Parameter.Modifier.ISBYREF)) + var a_byref = (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0; + var b_byref = (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.RefOutMask) != 0; + + if (a_byref != b_byref) break; } while (TypeSpecComparer.Override.IsEqual (type_a, type_b) && ii-- != 0); @@ -1295,7 +1377,9 @@ namespace Mono.CSharp { // if (pd != null && member is MethodCore) { ii = method_param_count; - while (ii-- != 0 && parameters.FixedParameters[ii].ModFlags == pd.FixedParameters[ii].ModFlags && + while (ii-- != 0 && + (parameters.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) == + (pd.FixedParameters[ii].ModFlags & Parameter.Modifier.ModifierMask) && parameters.ExtensionMethodType == pd.ExtensionMethodType) ; if (ii >= 0) {