Negative header ids should be valid
[mono.git] / mcs / mcs / membercache.cs
index e22e30d36adf6a8f767e16acdfd5ee9b550952f4..9ff3168869e9dd2f532086793c8d03a9f2755ef9 100644 (file)
@@ -8,6 +8,7 @@
 //
 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
 // Copyright 2004-2010 Novell, Inc
+// Copyright 2011 Xamarin Inc
 //
 //
 
@@ -40,6 +41,7 @@ namespace Mono.CSharp {
                InternalCompilerType = 1 << 21,
                MissingType = 1 << 22,
                Void = 1 << 23,
+               Namespace = 1 << 24,
 
                NestedMask = Class | Struct | Delegate | Enum | Interface,
                GenericMask = Method | Class | Struct | Delegate | Interface,
@@ -71,15 +73,6 @@ namespace Mono.CSharp {
                public readonly TypeSpec MemberType;
                public readonly int Arity; // -1 to ignore the check
 
-               private MemberFilter (string name, MemberKind kind)
-               {
-                       Name = name;
-                       Kind = kind;
-                       Parameters = null;
-                       MemberType = null;
-                       Arity = -1;
-               }
-
                public MemberFilter (MethodSpec m)
                {
                        Name = m.Name;
@@ -302,24 +295,28 @@ namespace Mono.CSharp {
                {
                        if (member.Kind == MemberKind.Operator) {
                                var dt = member.DeclaringType;
-                               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 ?
-                                       break;
-                               default:
-                                       if (name == Operator.GetMetadataName (Operator.OpType.Implicit) || name == Operator.GetMetadataName (Operator.OpType.Explicit)) {
-                                               state |= StateFlags.HasConversionOperator;
-                                       } else {
-                                               state |= StateFlags.HasUserOperator;
-                                       }
 
-                                       break;
+                               //
+                               // 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;
+                                       }
                                }
                        }
 
@@ -438,12 +435,15 @@ namespace Mono.CSharp {
                // 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<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnly)
+               // declaredOnlyClass cannot be used interfaces. Manual filtering is required because names are
+               // compacted
+               //
+               public static IList<MemberSpec> FindMembers (TypeSpec container, string name, bool declaredOnlyClass)
                {
                        IList<MemberSpec> applicable;
 
                        do {
-                               if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnly)
+                               if (container.MemberCache.member_hash.TryGetValue (name, out applicable) || declaredOnlyClass)
                                        return applicable;
 
                                container = container.BaseType;
@@ -467,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--) {
@@ -498,7 +498,7 @@ namespace Mono.CSharp {
                //
                // Looks for extension methods with defined name and extension type
                //
-               public List<MethodSpec> FindExtensionMethods (TypeContainer invocationType, TypeSpec extensionType, string name, int arity)
+               public List<MethodSpec> FindExtensionMethods (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
                {
                        IList<MemberSpec> entries;
                        if (!member_hash.TryGetValue (name, out entries))
@@ -513,10 +513,13 @@ namespace Mono.CSharp {
                                if (!ms.IsExtensionMethod)
                                        continue;
 
-                               if (!ms.IsAccessible (invocationType))
+                               if (!ms.IsAccessible (invocationContext))
                                        continue;
 
-                               if ((ms.DeclaringType.Modifiers & Modifiers.INTERNAL) != 0 && !ms.DeclaringType.MemberDefinition.IsInternalAsPublic (invocationType.DeclaringAssembly))
+                               //
+                               // 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)
@@ -531,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;
@@ -544,12 +547,14 @@ namespace Mono.CSharp {
                        }
 
                        string name = GetLookupName (member);
-                       IList<MemberSpec> 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<MemberSpec> applicable;
+                       MemberSpec ambig_candidate = null;
+
                        do {
                                if (container.MemberCache.member_hash.TryGetValue (name, out applicable)) {
                                        for (int i = 0; i < applicable.Count; ++i) {
@@ -595,31 +600,39 @@ namespace Mono.CSharp {
                                                }
 
                                                //
-                                               // Skip override members with accessors they may not fully implement the base member
+                                               // 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) {
-                                                       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 (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;
+                                               }
+
+                                               //
+                                               // 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;
                                                }
 
+                                               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;
                }
 
                //
@@ -671,6 +684,44 @@ namespace Mono.CSharp {
                        throw new NotImplementedException (member.GetType ().ToString ());
                }
 
+               public static List<FieldSpec> GetAllFieldsForDefiniteAssignment (TypeSpec container)
+               {
+                       List<FieldSpec> 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<FieldSpec> ();
+
+                                       fields.Add (fs);
+                                       break;
+                               }
+                       }
+
+                       return fields ?? new List<FieldSpec> (0);
+               }
+
                public static IList<MemberSpec> GetCompletitionMembers (IMemberContext ctx, TypeSpec container, string name)
                {
                        var matches = new List<MemberSpec> ();
@@ -697,7 +748,7 @@ namespace Mono.CSharp {
                //
                // Returns members of @iface only, base members are ignored
                //
-               public static IList<MethodSpec> GetInterfaceMethods (TypeSpec iface)
+               public static List<MethodSpec> GetInterfaceMethods (TypeSpec iface)
                {
                        //
                        // MemberCache flatten interfaces, therefore in cases like this one
@@ -740,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)
@@ -789,6 +840,12 @@ namespace Mono.CSharp {
                                                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)) {
                                                        --not_implemented_count;
                                                        abstract_methods [i] = null;
@@ -837,7 +894,7 @@ namespace Mono.CSharp {
                                return IndexerNameAlias;
 
                        if (mc is Constructor)
-                               return Constructor.ConstructorName;
+                               return mc.IsStatic ? Constructor.TypeConstructorName : Constructor.ConstructorName;
 
                        return mc.MemberName.Name;
                }
@@ -1106,8 +1163,9 @@ namespace Mono.CSharp {
                        if (container.BaseType == null) {
                                locase_members = new Dictionary<string, MemberSpec[]> (member_hash.Count); // StringComparer.OrdinalIgnoreCase);
                        } else {
-                               container.BaseType.MemberCache.VerifyClsCompliance (container.BaseType, report);
-                               locase_members = new Dictionary<string, MemberSpec[]> (container.BaseType.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase);
+                               var btype = container.BaseType.GetDefinition ();
+                               btype.MemberCache.VerifyClsCompliance (btype, report);
+                               locase_members = new Dictionary<string, MemberSpec[]> (btype.MemberCache.locase_members); //, StringComparer.OrdinalIgnoreCase);
                        }
 
                        var is_imported_type = container.MemberDefinition.IsImported;
@@ -1126,10 +1184,14 @@ namespace Mono.CSharp {
                                        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;
@@ -1144,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);
                                                                }
                                                        }
                                                }
@@ -1179,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) {
@@ -1222,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);
@@ -1270,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);
@@ -1290,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) {