diff options
author | Marek Safar <marek.safar@gmail.com> | 2004-08-04 23:37:26 +0400 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2004-08-04 23:37:26 +0400 |
commit | 7778ab8a68ccf30716e7722f65a0650d27763f5d (patch) | |
tree | a1f43c7f0224179a5e5264de2af8f73e4c3ed509 /mcs | |
parent | 59b9c82b33b00e1a330ee77c602f8ee272f958ad (diff) |
2004-08-04 Marek Safar <marek.safar@seznam.cz>
Fix bug #59760
* class.cs (TypeContainer ): New inner classes MethodArrayList,
OperatorArrayList, MethodCoreArrayList for typecontainer
containers. Changed class member types to these new types.
(MethodArrayList.DefineMembers): Added test for CS0659.
svn path=/trunk/mcs/; revision=31883
Diffstat (limited to 'mcs')
-rwxr-xr-x | mcs/mcs/ChangeLog | 8 | ||||
-rwxr-xr-x | mcs/mcs/class.cs | 496 | ||||
-rw-r--r-- | mcs/mcs/report.cs | 6 |
3 files changed, 287 insertions, 223 deletions
diff --git a/mcs/mcs/ChangeLog b/mcs/mcs/ChangeLog index 5db5bf75940..bbc0ab66509 100755 --- a/mcs/mcs/ChangeLog +++ b/mcs/mcs/ChangeLog @@ -1,3 +1,11 @@ +2004-08-04 Marek Safar <marek.safar@seznam.cz> + + Fix bug #59760 + * class.cs (TypeContainer ): New inner classes MethodArrayList, + OperatorArrayList, MethodCoreArrayList for typecontainer + containers. Changed class member types to these new types. + (MethodArrayList.DefineMembers): Added test for CS0659. + 2004-08-04 Miguel de Icaza <miguel@ximian.com> * attribute.cs: Revert patch from Raja, it introduced a regression diff --git a/mcs/mcs/class.cs b/mcs/mcs/class.cs index 9ee0dd995ed..079f92f575b 100755 --- a/mcs/mcs/class.cs +++ b/mcs/mcs/class.cs @@ -53,6 +53,241 @@ namespace Mono.CSharp { /// </summary> public abstract class TypeContainer : DeclSpace, IMemberContainer { + public class MemberCoreArrayList: ArrayList + { + /// <summary> + /// Defines the MemberCore objects that are in this array + /// </summary> + public virtual void DefineContainerMembers () + { + foreach (MemberCore mc in this) { + mc.Define (); + } + } + } + + public class MethodArrayList: MemberCoreArrayList + { + [Flags] + enum CachedMethods { + Equals = 1, + GetHashCode = 1 << 1 + } + + CachedMethods cached_method; + TypeContainer container; + + public MethodArrayList (TypeContainer container) + { + this.container = container; + } + + /// <summary> + /// Method container contains Equals method + /// </summary> + public bool HasEquals { + set { + cached_method |= CachedMethods.Equals; + } + + get { + return (cached_method & CachedMethods.Equals) != 0; + } + } + + /// <summary> + /// Method container contains GetHashCode method + /// </summary> + public bool HasGetHashCode { + set { + cached_method |= CachedMethods.GetHashCode; + } + + get { + return (cached_method & CachedMethods.GetHashCode) != 0; + } + } + + public override void DefineContainerMembers () + { + base.DefineContainerMembers (); + + if (HasEquals && !HasGetHashCode) { + Report.Warning (Message.CS0659_overrides_Equals_but_does_not_override_GetHashCode, container.Location, container.GetSignatureForError ()); + } + } + + } + + public class OperatorArrayList: MemberCoreArrayList + { + TypeContainer container; + + public OperatorArrayList (TypeContainer container) + { + this.container = container; + } + + // + // Operator pair checking + // + class OperatorEntry + { + public int flags; + public Type ret_type; + public Type type1, type2; + public Operator op; + public Operator.OpType ot; + + public OperatorEntry (int f, Operator o) + { + flags = f; + + ret_type = o.OperatorMethod.GetReturnType (); + Type [] pt = o.OperatorMethod.ParameterTypes; + type1 = pt [0]; + type2 = pt [1]; + op = o; + ot = o.OperatorType; + } + + public override int GetHashCode () + { + return ret_type.GetHashCode (); + } + + public override bool Equals (object o) + { + OperatorEntry other = (OperatorEntry) o; + + if (other.ret_type != ret_type) + return false; + if (other.type1 != type1) + return false; + if (other.type2 != type2) + return false; + return true; + } + } + + // + // Checks that some operators come in pairs: + // == and != + // > and < + // >= and <= + // true and false + // + // They are matched based on the return type and the argument types + // + void CheckPairedOperators () + { + Hashtable pairs = new Hashtable (null, null); + Operator true_op = null; + Operator false_op = null; + bool has_equality_or_inequality = false; + + // Register all the operators we care about. + foreach (Operator op in this){ + int reg = 0; + + switch (op.OperatorType){ + case Operator.OpType.Equality: + reg = 1; + has_equality_or_inequality = true; + break; + case Operator.OpType.Inequality: + reg = 2; + has_equality_or_inequality = true; + break; + + case Operator.OpType.True: + true_op = op; + break; + case Operator.OpType.False: + false_op = op; + break; + + case Operator.OpType.GreaterThan: + reg = 1; break; + case Operator.OpType.LessThan: + reg = 2; break; + + case Operator.OpType.GreaterThanOrEqual: + reg = 1; break; + case Operator.OpType.LessThanOrEqual: + reg = 2; break; + } + if (reg == 0) + continue; + + OperatorEntry oe = new OperatorEntry (reg, op); + + object o = pairs [oe]; + if (o == null) + pairs [oe] = oe; + else { + oe = (OperatorEntry) o; + oe.flags |= reg; + } + } + + if (true_op != null){ + if (false_op == null) + Report.Error (216, true_op.Location, "operator true requires a matching operator false"); + } else if (false_op != null) + Report.Error (216, false_op.Location, "operator false requires a matching operator true"); + + // + // Look for the mistakes. + // + foreach (DictionaryEntry de in pairs){ + OperatorEntry oe = (OperatorEntry) de.Key; + + if (oe.flags == 3) + continue; + + string s = ""; + switch (oe.ot){ + case Operator.OpType.Equality: + s = "!="; + break; + case Operator.OpType.Inequality: + s = "=="; + break; + case Operator.OpType.GreaterThan: + s = "<"; + break; + case Operator.OpType.LessThan: + s = ">"; + break; + case Operator.OpType.GreaterThanOrEqual: + s = "<="; + break; + case Operator.OpType.LessThanOrEqual: + s = ">="; + break; + } + Report.Error (216, oe.op.Location, + "The operator `" + oe.op + "' requires a matching operator `" + s + "' to also be defined"); + } + + if (has_equality_or_inequality && container.Methods == null && (RootContext.WarningLevel > 2)) { + if (!container.Methods.HasEquals) + Report.Warning (Message.CS0660_defines_operator_but_does_not_override_Equals, container.Location, container.GetSignatureForError ()); + + if (!container.Methods.HasGetHashCode) + Report.Warning (Message.CS0661_defines_operator_but_does_not_override_GetHashCode, container.Location, container.GetSignatureForError ()); + } + } + + public override void DefineContainerMembers () + { + base.DefineContainerMembers (); + CheckPairedOperators (); + } + } + + // Whether this is a struct, class or interface public readonly Kind Kind; @@ -60,19 +295,19 @@ namespace Mono.CSharp { ArrayList types; // Holds the list of properties - ArrayList properties; + MemberCoreArrayList properties; // Holds the list of enumerations - ArrayList enums; + MemberCoreArrayList enums; // Holds the list of delegates - ArrayList delegates; + MemberCoreArrayList delegates; // Holds the list of constructors - ArrayList instance_constructors; + MemberCoreArrayList instance_constructors; // Holds the list of fields - ArrayList fields; + MemberCoreArrayList fields; // Holds a list of fields that have initializers ArrayList initialized_fields; @@ -81,22 +316,22 @@ namespace Mono.CSharp { ArrayList initialized_static_fields; // Holds the list of constants - ArrayList constants; + MemberCoreArrayList constants; // Holds the list of - ArrayList interfaces; + MemberCoreArrayList interfaces; // Holds the methods. - ArrayList methods; + MethodArrayList methods; // Holds the events - ArrayList events; + MemberCoreArrayList events; // Holds the indexers ArrayList indexers; // Holds the operators - ArrayList operators; + MemberCoreArrayList operators; // Holds the iterators ArrayList iterators; @@ -212,7 +447,7 @@ namespace Mono.CSharp { return res; if (constants == null) - constants = new ArrayList (); + constants = new MemberCoreArrayList (); constants.Add (constant); DefineName (fullname, constant); @@ -228,7 +463,7 @@ namespace Mono.CSharp { return res; if (enums == null) - enums = new ArrayList (); + enums = new MemberCoreArrayList (); enums.Add (e); DefineName (e.Name, e); @@ -273,7 +508,7 @@ namespace Mono.CSharp { return res; if (delegates == null) - delegates = new ArrayList (); + delegates = new MemberCoreArrayList (); DefineName (d.Name, d); delegates.Add (d); @@ -295,7 +530,7 @@ namespace Mono.CSharp { return AdditionResult.EnclosingClash; if (methods == null) - methods = new ArrayList (); + methods = new MethodArrayList (this); if (method.Name.IndexOf ('.') != -1) methods.Insert (0, method); @@ -329,7 +564,7 @@ namespace Mono.CSharp { } if (instance_constructors == null) - instance_constructors = new ArrayList (); + instance_constructors = new MemberCoreArrayList (); instance_constructors.Add (c); } @@ -346,7 +581,7 @@ namespace Mono.CSharp { return res; if (interfaces == null) - interfaces = new ArrayList (); + interfaces = new MemberCoreArrayList (); interfaces.Add (iface); DefineName (iface.Name, iface); @@ -363,7 +598,7 @@ namespace Mono.CSharp { return res; if (fields == null) - fields = new ArrayList (); + fields = new MemberCoreArrayList (); fields.Add (field); @@ -407,7 +642,7 @@ namespace Mono.CSharp { } if (properties == null) - properties = new ArrayList (); + properties = new MemberCoreArrayList (); if (prop.Name.IndexOf ('.') != -1) properties.Insert (0, prop); @@ -440,7 +675,7 @@ namespace Mono.CSharp { return res; if (events == null) - events = new ArrayList (); + events = new MemberCoreArrayList (); events.Add (e); DefineName (fullname, e); @@ -462,7 +697,7 @@ namespace Mono.CSharp { public AdditionResult AddOperator (Operator op) { if (operators == null) - operators = new ArrayList (); + operators = new OperatorArrayList (this); operators.Add (op); @@ -522,7 +757,7 @@ namespace Mono.CSharp { } } - public ArrayList Methods { + public MethodArrayList Methods { get { return methods; } @@ -566,10 +801,6 @@ namespace Mono.CSharp { get { return fields; } - - set { - fields = value; - } } public ArrayList InstanceConstructors { @@ -1084,21 +1315,6 @@ namespace Mono.CSharp { return true; } - /// <summary> - /// Defines the MemberCore objects that are in the `list' Arraylist - /// </summary> - static ArrayList remove_list = new ArrayList (); - void DefineContainerMembers (ArrayList list) - { - remove_list.Clear (); - - foreach (MemberCore mc in list){ - if (!mc.Define ()){ - remove_list.Add (mc); - } - } - } - // // Defines the indexers, and also verifies that the IndexerNameAttribute in the // class is consistent. Either it is `Item' or it is the name defined by all the @@ -1205,10 +1421,10 @@ namespace Mono.CSharp { } if (constants != null) - DefineContainerMembers (constants); + constants.DefineContainerMembers (); if (fields != null) - DefineContainerMembers (fields); + fields.DefineContainerMembers (); if ((Kind == Kind.Class) && !(this is ClassPart)){ if (instance_constructors == null){ @@ -1247,34 +1463,31 @@ namespace Mono.CSharp { // Constructors are not in the defined_names array // if (instance_constructors != null) - DefineContainerMembers (instance_constructors); + instance_constructors.DefineContainerMembers (); if (default_static_constructor != null) default_static_constructor.Define (); if (methods != null) - DefineContainerMembers (methods); + methods.DefineContainerMembers (); if (properties != null) - DefineContainerMembers (properties); + properties.DefineContainerMembers (); if (events != null) - DefineContainerMembers (events); + events.DefineContainerMembers (); if (indexers != null) DefineIndexers (); - if (operators != null){ - DefineContainerMembers (operators); - - CheckPairedOperators (); - } + if (operators != null) + operators.DefineContainerMembers (); if (enums != null) - DefineContainerMembers (enums); + enums.DefineContainerMembers (); if (delegates != null) - DefineContainerMembers (delegates); + delegates.DefineContainerMembers (); #if CACHE if (!(this is ClassPart)) @@ -2255,177 +2468,7 @@ namespace Mono.CSharp { return FindMembers (mt, bf | BindingFlags.DeclaredOnly, null, null); } - // - // Operator pair checking - // - - class OperatorEntry { - public int flags; - public Type ret_type; - public Type type1, type2; - public Operator op; - public Operator.OpType ot; - - public OperatorEntry (int f, Operator o) - { - flags = f; - - ret_type = o.OperatorMethod.GetReturnType (); - Type [] pt = o.OperatorMethod.ParameterTypes; - type1 = pt [0]; - type2 = pt [1]; - op = o; - ot = o.OperatorType; - } - - public override int GetHashCode () - { - return ret_type.GetHashCode (); - } - - public override bool Equals (object o) - { - OperatorEntry other = (OperatorEntry) o; - - if (other.ret_type != ret_type) - return false; - if (other.type1 != type1) - return false; - if (other.type2 != type2) - return false; - return true; - } - } - - // - // Checks that some operators come in pairs: - // == and != - // > and < - // >= and <= - // true and false - // - // They are matched based on the return type and the argument types - // - void CheckPairedOperators () - { - Hashtable pairs = new Hashtable (null, null); - Operator true_op = null; - Operator false_op = null; - bool has_equality_or_inequality = false; - - // Register all the operators we care about. - foreach (Operator op in operators){ - int reg = 0; - - switch (op.OperatorType){ - case Operator.OpType.Equality: - reg = 1; - has_equality_or_inequality = true; - break; - case Operator.OpType.Inequality: - reg = 2; - has_equality_or_inequality = true; - break; - - case Operator.OpType.True: - true_op = op; - break; - case Operator.OpType.False: - false_op = op; - break; - - case Operator.OpType.GreaterThan: - reg = 1; break; - case Operator.OpType.LessThan: - reg = 2; break; - - case Operator.OpType.GreaterThanOrEqual: - reg = 1; break; - case Operator.OpType.LessThanOrEqual: - reg = 2; break; - } - if (reg == 0) - continue; - - OperatorEntry oe = new OperatorEntry (reg, op); - object o = pairs [oe]; - if (o == null) - pairs [oe] = oe; - else { - oe = (OperatorEntry) o; - oe.flags |= reg; - } - } - - if (true_op != null){ - if (false_op == null) - Report.Error (216, true_op.Location, "operator true requires a matching operator false"); - } else if (false_op != null) - Report.Error (216, false_op.Location, "operator false requires a matching operator true"); - - // - // Look for the mistakes. - // - foreach (DictionaryEntry de in pairs){ - OperatorEntry oe = (OperatorEntry) de.Key; - - if (oe.flags == 3) - continue; - - string s = ""; - switch (oe.ot){ - case Operator.OpType.Equality: - s = "!="; - break; - case Operator.OpType.Inequality: - s = "=="; - break; - case Operator.OpType.GreaterThan: - s = "<"; - break; - case Operator.OpType.LessThan: - s = ">"; - break; - case Operator.OpType.GreaterThanOrEqual: - s = "<="; - break; - case Operator.OpType.LessThanOrEqual: - s = ">="; - break; - } - Report.Error (216, oe.op.Location, - "The operator `" + oe.op + "' requires a matching operator `" + s + "' to also be defined"); - } - - if ((has_equality_or_inequality) && (RootContext.WarningLevel >= 2)) { - MethodSignature equals_ms = new MethodSignature ( - "Equals", TypeManager.bool_type, new Type [] { TypeManager.object_type }); - MethodSignature hash_ms = new MethodSignature ( - "GetHashCode", TypeManager.int32_type, new Type [0]); - - MemberList equals_ml = FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance | - BindingFlags.DeclaredOnly, MethodSignature.method_signature_filter, - equals_ms); - MemberList hash_ml = FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance | - BindingFlags.DeclaredOnly, MethodSignature.method_signature_filter, - hash_ms); - - bool equals_ok = false; - if ((equals_ml != null) && (equals_ml.Count == 1)) - equals_ok = equals_ml [0].DeclaringType == TypeBuilder; - bool hash_ok = false; - if ((hash_ml != null) && (hash_ml.Count == 1)) - hash_ok = hash_ml [0].DeclaringType == TypeBuilder; - - if (!equals_ok) - Report.Warning (660, Location, "`" + Name + "' defines operator == or operator != but does " + - "not override Object.Equals (object o)"); - if (!hash_ok) - Report.Warning (661, Location, "`" + Name + "' defines operator == or operator != but does " + - "not override Object.GetHashCode ()"); - } - } } public class PartialContainer : TypeContainer { @@ -2944,6 +2987,13 @@ namespace Mono.CSharp { } } + if (RootContext.WarningLevel > 2) { + if (Name == "Equals" && parameter_types.Length == 1 && parameter_types [0] == TypeManager.object_type) + Parent.Methods.HasEquals = true; + else if (Name == "GetHashCode" && parameter_types.Length == 0) + Parent.Methods.HasGetHashCode = true; + } + ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (parent_method); if (oa != null) { Report.SymbolRelatedToPreviousError (parent_method); diff --git a/mcs/mcs/report.cs b/mcs/mcs/report.cs index 6f57ff7da39..19c0e05ef83 100644 --- a/mcs/mcs/report.cs +++ b/mcs/mcs/report.cs @@ -65,6 +65,9 @@ namespace Mono.CSharp { CS0642_Possible_mistaken_empty_statement = 642, CS0649_Field_is_never_assigned_to_and_will_always_have_its_default_value = 649, CS0657_is_not_a_valid_attribute_location_for_this_declaration = 657, + CS0659_overrides_Equals_but_does_not_override_GetHashCode = 659, + CS0660_defines_operator_but_does_not_override_Equals = 660, + CS0661_defines_operator_but_does_not_override_GetHashCode = 661, CS0672_Member_overrides_obsolete_member = 672, CS1030_warning = 1030, CS1555_Could_not_find_specified_for_Main_method = 1555, @@ -301,6 +304,9 @@ namespace Mono.CSharp { case 0642: return new WarningData (3, "Possible mistaken empty statement"); case 0649: return new WarningData (4, "Field '{0}' is never assigned to, and will always have its default value '{1}'"); case 0657: return new ErrorData ("'{0}' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are '{1}'"); + case 0659: return new WarningData (3, "'{0}' overrides Object.Equals(object) but does not override Object.GetHashCode()"); + case 0660: return new WarningData (3, "'{0}' defines operator == or operator != but does not override Object.Equals(object o)"); + case 0661: return new WarningData (3, "'{0}' defines operator == or operator != but does not override Object.GetHashCode()"); case 0672: return new WarningData (1, "Member '{0}' overrides obsolete member. Add the Obsolete attribute to '{0}'"); case 1030: return new WarningData (1, "#warning: '{0}'"); case 1555: return new ErrorData ("Could not find '{0}' specified for Main method"); |