Tue, 26 Feb 2013 09:04:19 +0000
8008436: javac should not issue a warning for overriding equals without hasCode if hashCode has been overriden by a superclass
Reviewed-by: jjg, mcimadamore
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Sun Feb 24 11:36:58 2013 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Tue Feb 26 09:04:19 2013 +0000 1.3 @@ -1305,7 +1305,7 @@ 1.4 return implementation(origin, types, checkResult, implementation_filter); 1.5 } 1.6 // where 1.7 - private static final Filter<Symbol> implementation_filter = new Filter<Symbol>() { 1.8 + public static final Filter<Symbol> implementation_filter = new Filter<Symbol>() { 1.9 public boolean accepts(Symbol s) { 1.10 return s.kind == Kinds.MTH && 1.11 (s.flags() & SYNTHETIC) == 0;
2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java Sun Feb 24 11:36:58 2013 -0800 2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java Tue Feb 26 09:04:19 2013 +0000 2.3 @@ -3992,7 +3992,7 @@ 2.4 attribClassBody(env, c); 2.5 2.6 chk.checkDeprecatedAnnotation(env.tree.pos(), c); 2.7 - chk.checkClassOverrideEqualsAndHash(c); 2.8 + chk.checkClassOverrideEqualsAndHash(env.tree.pos(), c); 2.9 } finally { 2.10 env.info.returnResult = prevReturnRes; 2.11 log.useSource(prev);
3.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Sun Feb 24 11:36:58 2013 -0800 3.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Tue Feb 26 09:04:19 2013 +0000 3.3 @@ -1964,28 +1964,29 @@ 3.4 } 3.5 } 3.6 3.7 - public void checkClassOverrideEqualsAndHash(ClassSymbol someClass) { 3.8 + private Filter<Symbol> equalsHasCodeFilter = new Filter<Symbol>() { 3.9 + public boolean accepts(Symbol s) { 3.10 + return MethodSymbol.implementation_filter.accepts(s) && 3.11 + (s.flags() & BAD_OVERRIDE) == 0; 3.12 + 3.13 + } 3.14 + }; 3.15 + 3.16 + public void checkClassOverrideEqualsAndHash(DiagnosticPosition pos, 3.17 + ClassSymbol someClass) { 3.18 if (lint.isEnabled(LintCategory.OVERRIDES)) { 3.19 - boolean hasEquals = false; 3.20 - boolean hasHashCode = false; 3.21 - 3.22 - Scope.Entry equalsAtObject = syms.objectType.tsym.members().lookup(names.equals); 3.23 - Scope.Entry hashCodeAtObject = syms.objectType.tsym.members().lookup(names.hashCode); 3.24 - for (Symbol s: someClass.members().getElements(new Filter<Symbol>() { 3.25 - public boolean accepts(Symbol s) { 3.26 - return s.kind == Kinds.MTH && 3.27 - (s.flags() & BAD_OVERRIDE) == 0; 3.28 - } 3.29 - })) { 3.30 - MethodSymbol m = (MethodSymbol)s; 3.31 - hasEquals |= m.name.equals(names.equals) && 3.32 - m.overrides(equalsAtObject.sym, someClass, types, false); 3.33 - 3.34 - hasHashCode |= m.name.equals(names.hashCode) && 3.35 - m.overrides(hashCodeAtObject.sym, someClass, types, false); 3.36 - } 3.37 - if (hasEquals && !hasHashCode) { 3.38 - log.warning(LintCategory.OVERRIDES, (DiagnosticPosition) null, 3.39 + MethodSymbol equalsAtObject = (MethodSymbol)syms.objectType 3.40 + .tsym.members().lookup(names.equals).sym; 3.41 + MethodSymbol hashCodeAtObject = (MethodSymbol)syms.objectType 3.42 + .tsym.members().lookup(names.hashCode).sym; 3.43 + 3.44 + boolean overridesEquals = types.implementation(equalsAtObject, 3.45 + someClass, false, equalsHasCodeFilter).owner == someClass; 3.46 + boolean overridesHashCode = types.implementation(hashCodeAtObject, 3.47 + someClass, false, equalsHasCodeFilter) != hashCodeAtObject; 3.48 + 3.49 + if (overridesEquals && !overridesHashCode) { 3.50 + log.warning(LintCategory.OVERRIDES, pos, 3.51 "override.equals.but.not.hashcode", someClass.fullname); 3.52 } 3.53 }
4.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties Sun Feb 24 11:36:58 2013 -0800 4.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Feb 26 09:04:19 2013 +0000 4.3 @@ -2071,8 +2071,7 @@ 4.4 4.5 # 0: class name 4.6 compiler.warn.override.equals.but.not.hashcode=\ 4.7 - Class {0}\n\ 4.8 - overrides method equals but does not overrides method hashCode from Object 4.9 + Class {0} overrides equals, but neither it nor any superclass overrides hashCode method 4.10 4.11 ## The following are all possible strings for the first argument ({0}) of the 4.12 ## above strings.
5.1 --- a/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java Sun Feb 24 11:36:58 2013 -0800 5.2 +++ b/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java Tue Feb 26 09:04:19 2013 +0000 5.3 @@ -1,22 +1,42 @@ 5.4 /* 5.5 * @test /nodynamiccopyright/ 5.6 - * @bug 6563143 5.7 + * @bug 6563143 8008436 5.8 * @summary javac should issue a warning for overriding equals without hashCode 5.9 + * @summary javac should not issue a warning for overriding equals without hasCode 5.10 + * if hashCode has been overriden by a superclass 5.11 * @compile/ref=OverridesEqualsButNotHashCodeTest.out -Xlint:overrides -XDrawDiagnostics OverridesEqualsButNotHashCodeTest.java 5.12 */ 5.13 5.14 -@SuppressWarnings("overrides") 5.15 public class OverridesEqualsButNotHashCodeTest { 5.16 @Override 5.17 public boolean equals(Object o) { 5.18 return o == this; 5.19 } 5.20 + 5.21 + @Override 5.22 + public int hashCode() { 5.23 + return 0; 5.24 + } 5.25 +} 5.26 + 5.27 +class SubClass extends OverridesEqualsButNotHashCodeTest { 5.28 + @Override 5.29 + public boolean equals(Object o) { 5.30 + return o == this; 5.31 + } 5.32 } 5.33 5.34 -class Other { 5.35 +@SuppressWarnings("overrides") 5.36 +class NoWarning { 5.37 @Override 5.38 public boolean equals(Object o) { 5.39 return o == this; 5.40 } 5.41 } 5.42 5.43 +class DoWarnMe { 5.44 + @Override 5.45 + public boolean equals(Object o) { 5.46 + return o == this; 5.47 + } 5.48 +}
6.1 --- a/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out Sun Feb 24 11:36:58 2013 -0800 6.2 +++ b/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out Tue Feb 26 09:04:19 2013 +0000 6.3 @@ -1,2 +1,2 @@ 6.4 -- compiler.warn.override.equals.but.not.hashcode: Other 6.5 +OverridesEqualsButNotHashCodeTest.java:37:1: compiler.warn.override.equals.but.not.hashcode: DoWarnMe 6.6 1 warning