X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fmembercache.cs;h=a01100c25f69ffe8098f03027742bdbcc7c19fe9;hb=76ce601441e821a12585ae269d29fa34c2143864;hp=bfa57040a4b1effa10f2d5ae852aab3adeb9d09f;hpb=aa50def3260d0ef2abaa025c50809a829ca9bbdd;p=mono.git diff --git a/mcs/mcs/membercache.cs b/mcs/mcs/membercache.cs index bfa57040a4b..a01100c25f6 100644 --- a/mcs/mcs/membercache.cs +++ b/mcs/mcs/membercache.cs @@ -12,9 +12,7 @@ // using System; -using System.Text; using System.Collections.Generic; -using System.Linq; namespace Mono.CSharp { @@ -40,11 +38,12 @@ namespace Mono.CSharp { ArrayType = 1 << 19, PointerType = 1 << 20, InternalCompilerType = 1 << 21, + MissingType = 1 << 22, + Void = 1 << 23, 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] @@ -70,8 +69,7 @@ namespace Mono.CSharp { public readonly MemberKind Kind; public readonly AParametersCollection Parameters; public readonly TypeSpec MemberType; - - int arity; // -1 to ignore the check + public readonly int Arity; // -1 to ignore the check private MemberFilter (string name, MemberKind kind) { @@ -79,7 +77,7 @@ namespace Mono.CSharp { Kind = kind; Parameters = null; MemberType = null; - arity = -1; + Arity = -1; } public MemberFilter (MethodSpec m) @@ -88,7 +86,7 @@ namespace Mono.CSharp { Kind = MemberKind.Method; Parameters = m.Parameters; MemberType = m.ReturnType; - arity = m.Arity; + Arity = m.Arity; } public MemberFilter (string name, int arity, MemberKind kind, AParametersCollection param, TypeSpec type) @@ -97,12 +95,12 @@ namespace Mono.CSharp { Kind = kind; Parameters = param; MemberType = type; - this.arity = arity; + 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) @@ -130,7 +128,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) { @@ -170,6 +168,7 @@ namespace Mono.CSharp { // public class MemberCache { + [Flags] enum StateFlags { HasConversionOperator = 1 << 1, @@ -179,7 +178,7 @@ namespace Mono.CSharp { 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 = ""; @@ -209,6 +208,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 @@ -252,7 +285,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); } @@ -262,23 +295,31 @@ 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; - if (dt == TypeManager.string_type || dt == TypeManager.delegate_type || dt == TypeManager.multicast_delegate_type) { + switch (dt.BuiltinType) { + case BuiltinTypeSpec.Type.String: + case BuiltinTypeSpec.Type.Delegate: + case BuiltinTypeSpec.Type.MulticastDelegate: // Some core types have user operators but they cannot be used as 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 // TODO: Should I do this for all core types ? - } else if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) { - state |= StateFlags.HasConversionOperator; - } else { - state |= StateFlags.HasUserOperator; + break; + default: + if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) { + state |= StateFlags.HasConversionOperator; + } else { + state |= StateFlags.HasUserOperator; + } + + break; } } @@ -288,11 +329,11 @@ namespace Mono.CSharp { 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; } @@ -301,6 +342,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 @@ -328,7 +374,7 @@ namespace Mono.CSharp { } if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) { - if (existing is MemberSpec[]) { + if (existing.Count == 1) { existing = new MemberSpec[] { member }; return true; } @@ -342,7 +388,7 @@ namespace Mono.CSharp { return false; } - if (existing is MemberSpec[]) { + if (existing.Count == 1) { existing = new List () { existing[0], member }; return true; } @@ -452,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)) @@ -467,12 +513,13 @@ namespace Mono.CSharp { if (!ms.IsExtensionMethod) continue; - if (!ms.IsAccessible (invocationType)) + 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) @@ -487,7 +534,7 @@ 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; @@ -500,12 +547,14 @@ namespace Mono.CSharp { } 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)) { for (int i = 0; i < applicable.Count; ++i) { @@ -514,89 +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 same type ? + // Isn't the member of same kind ? // if ((entry.Kind & ~MemberKind.Destructor & mkind & MemberKind.MaskType) == 0) { // Destructors are ignored as they cannot be overridden by user if ((entry.Kind & MemberKind.Destructor) != 0) continue; - // Only different arity methods hide + // A method with different arity does not hide base member if (mkind != MemberKind.Method && member.MemberName.Arity != entry.Arity) continue; - - if ((member_param == null || !(entry is IParametersMember))) { - bestCandidate = entry; - return null; - } - continue; + bestCandidate = entry; + return null; } - if (entry.Kind != mkind) { - if (bestCandidate == null) - bestCandidate = entry; - + // + // Same kind of different arity is valid + // + if (member.MemberName.Arity != entry.Arity) { continue; } - if (member_param != null) { - // Check arity match - int arity = member.MemberName.Arity; - if (arity != entry.Arity) + if ((entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) { + if (entry.IsAccessor != member is AbstractPropertyEventMethod) continue; var pm = entry as IParametersMember; - AParametersCollection entry_parameters; - if (pm == null) { - if (entry.Kind != MemberKind.Delegate) - continue; - - // TODO: I don't have DelegateSpec - entry_parameters = Delegate.GetParameters (member.Compiler, (TypeSpec) entry); - } else { - entry_parameters = pm.Parameters; - } - - if (entry.IsAccessor != member is AbstractPropertyEventMethod) + if (!TypeSpecComparer.Override.IsEqual (pm.Parameters, member_param)) continue; + } - if (!TypeSpecComparer.Override.IsEqual (entry_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; } // - // Skip override members with accessors they may not fully implement the base member + // For members with parameters we can encounter an ambiguous candidates (they match exactly) + // because generic type parameters could be inflated into same types // - if (member_with_accessors) { - if ((entry.Modifiers & (Modifiers.OVERRIDE | Modifiers.SEALED)) == Modifiers.OVERRIDE) { - // - // Set candidate to member override to flag we found an implementation - // - bestCandidate = entry; - continue; - } - } else { + if (ambig_candidate == null && (entry.Kind & mkind & (MemberKind.Method | MemberKind.Indexer)) != 0) { bestCandidate = null; + ambig_candidate = entry; + continue; } + 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; } // @@ -648,7 +684,7 @@ namespace Mono.CSharp { throw new NotImplementedException (member.GetType ().ToString ()); } - public static IList GetCompletitionMembers (TypeSpec container, string name) + public static IList GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name) { var matches = new List (); foreach (var entry in container.MemberCache.member_hash) { @@ -659,7 +695,7 @@ namespace Mono.CSharp { if ((name_entry.Kind & (MemberKind.Constructor | MemberKind.Destructor | MemberKind.Operator)) != 0) continue; - if (!name_entry.IsAccessible (InternalType.FakeInternalType)) + if (!name_entry.IsAccessible (ctx)) continue; if (name == null || name_entry.Name.StartsWith (name)) { @@ -674,7 +710,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 @@ -1025,6 +1061,53 @@ namespace Mono.CSharp { } } + // + // 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 + // + public void RemoveHiddenMembers (TypeSpec container) + { + foreach (var entry in member_hash) { + var values = entry.Value; + + 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; + + for (int ii = container_members_start_at; ii < values.Count; ++ii) { + var container_entry = values[ii]; + + if (container_entry.Arity != member.Arity) + continue; + + if (container_entry is IParametersMember) { + if (!TypeSpecComparer.Override.IsEqual (((IParametersMember) container_entry).Parameters, member_param)) + continue; + } + + values.RemoveAt (i); + --container_members_start_at; + --ii; + --i; + } + } + } + } + // // Checks all appropriate container members for CLS compliance // @@ -1053,7 +1136,7 @@ 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;