8008436: javac should not issue a warning for overriding equals without hasCode if hashCode has been overriden by a superclass

Reviewed-by: jjg, mcimadamore
This commit is contained in:
Vicente Romero 2013-02-26 09:04:19 +00:00
parent 63fe735683
commit 9f2721bfb1
6 changed files with 47 additions and 27 deletions

View File

@ -1305,7 +1305,7 @@ public abstract class Symbol implements Element {
return implementation(origin, types, checkResult, implementation_filter); return implementation(origin, types, checkResult, implementation_filter);
} }
// where // where
private static final Filter<Symbol> implementation_filter = new Filter<Symbol>() { public static final Filter<Symbol> implementation_filter = new Filter<Symbol>() {
public boolean accepts(Symbol s) { public boolean accepts(Symbol s) {
return s.kind == Kinds.MTH && return s.kind == Kinds.MTH &&
(s.flags() & SYNTHETIC) == 0; (s.flags() & SYNTHETIC) == 0;

View File

@ -3992,7 +3992,7 @@ public class Attr extends JCTree.Visitor {
attribClassBody(env, c); attribClassBody(env, c);
chk.checkDeprecatedAnnotation(env.tree.pos(), c); chk.checkDeprecatedAnnotation(env.tree.pos(), c);
chk.checkClassOverrideEqualsAndHash(c); chk.checkClassOverrideEqualsAndHash(env.tree.pos(), c);
} finally { } finally {
env.info.returnResult = prevReturnRes; env.info.returnResult = prevReturnRes;
log.useSource(prev); log.useSource(prev);

View File

@ -1964,28 +1964,29 @@ public class Check {
} }
} }
public void checkClassOverrideEqualsAndHash(ClassSymbol someClass) { private Filter<Symbol> equalsHasCodeFilter = new Filter<Symbol>() {
if (lint.isEnabled(LintCategory.OVERRIDES)) {
boolean hasEquals = false;
boolean hasHashCode = false;
Scope.Entry equalsAtObject = syms.objectType.tsym.members().lookup(names.equals);
Scope.Entry hashCodeAtObject = syms.objectType.tsym.members().lookup(names.hashCode);
for (Symbol s: someClass.members().getElements(new Filter<Symbol>() {
public boolean accepts(Symbol s) { public boolean accepts(Symbol s) {
return s.kind == Kinds.MTH && return MethodSymbol.implementation_filter.accepts(s) &&
(s.flags() & BAD_OVERRIDE) == 0; (s.flags() & BAD_OVERRIDE) == 0;
}
})) {
MethodSymbol m = (MethodSymbol)s;
hasEquals |= m.name.equals(names.equals) &&
m.overrides(equalsAtObject.sym, someClass, types, false);
hasHashCode |= m.name.equals(names.hashCode) &&
m.overrides(hashCodeAtObject.sym, someClass, types, false);
} }
if (hasEquals && !hasHashCode) { };
log.warning(LintCategory.OVERRIDES, (DiagnosticPosition) null,
public void checkClassOverrideEqualsAndHash(DiagnosticPosition pos,
ClassSymbol someClass) {
if (lint.isEnabled(LintCategory.OVERRIDES)) {
MethodSymbol equalsAtObject = (MethodSymbol)syms.objectType
.tsym.members().lookup(names.equals).sym;
MethodSymbol hashCodeAtObject = (MethodSymbol)syms.objectType
.tsym.members().lookup(names.hashCode).sym;
boolean overridesEquals = types.implementation(equalsAtObject,
someClass, false, equalsHasCodeFilter).owner == someClass;
boolean overridesHashCode = types.implementation(hashCodeAtObject,
someClass, false, equalsHasCodeFilter) != hashCodeAtObject;
if (overridesEquals && !overridesHashCode) {
log.warning(LintCategory.OVERRIDES, pos,
"override.equals.but.not.hashcode", someClass.fullname); "override.equals.but.not.hashcode", someClass.fullname);
} }
} }

View File

@ -2071,8 +2071,7 @@ compiler.warn.override.unchecked.thrown=\
# 0: class name # 0: class name
compiler.warn.override.equals.but.not.hashcode=\ compiler.warn.override.equals.but.not.hashcode=\
Class {0}\n\ Class {0} overrides equals, but neither it nor any superclass overrides hashCode method
overrides method equals but does not overrides method hashCode from Object
## The following are all possible strings for the first argument ({0}) of the ## The following are all possible strings for the first argument ({0}) of the
## above strings. ## above strings.

View File

@ -1,22 +1,42 @@
/* /*
* @test /nodynamiccopyright/ * @test /nodynamiccopyright/
* @bug 6563143 * @bug 6563143 8008436
* @summary javac should issue a warning for overriding equals without hashCode * @summary javac should issue a warning for overriding equals without hashCode
* @summary javac should not issue a warning for overriding equals without hasCode
* if hashCode has been overriden by a superclass
* @compile/ref=OverridesEqualsButNotHashCodeTest.out -Xlint:overrides -XDrawDiagnostics OverridesEqualsButNotHashCodeTest.java * @compile/ref=OverridesEqualsButNotHashCodeTest.out -Xlint:overrides -XDrawDiagnostics OverridesEqualsButNotHashCodeTest.java
*/ */
@SuppressWarnings("overrides")
public class OverridesEqualsButNotHashCodeTest { public class OverridesEqualsButNotHashCodeTest {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o == this; return o == this;
} }
@Override
public int hashCode() {
return 0;
}
} }
class Other { class SubClass extends OverridesEqualsButNotHashCodeTest {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o == this; return o == this;
} }
} }
@SuppressWarnings("overrides")
class NoWarning {
@Override
public boolean equals(Object o) {
return o == this;
}
}
class DoWarnMe {
@Override
public boolean equals(Object o) {
return o == this;
}
}

View File

@ -1,2 +1,2 @@
- compiler.warn.override.equals.but.not.hashcode: Other OverridesEqualsButNotHashCodeTest.java:37:1: compiler.warn.override.equals.but.not.hashcode: DoWarnMe
1 warning 1 warning