8008436: javac should not issue a warning for overriding equals without hasCode if hashCode has been overriden by a superclass
authorvromero
Tue, 26 Feb 2013 09:04:19 +0000
changeset 16320 92ba27b7aaf3
parent 16319 e586bfeb39c5
child 16321 75e64bcd3ab0
8008436: javac should not issue a warning for overriding equals without hasCode if hashCode has been overriden by a superclass Reviewed-by: jjg, mcimadamore
langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
langtools/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java
langtools/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Sun Feb 24 11:36:58 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java	Tue Feb 26 09:04:19 2013 +0000
@@ -1305,7 +1305,7 @@
             return implementation(origin, types, checkResult, implementation_filter);
         }
         // 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) {
                     return s.kind == Kinds.MTH &&
                             (s.flags() & SYNTHETIC) == 0;
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Sun Feb 24 11:36:58 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Feb 26 09:04:19 2013 +0000
@@ -3992,7 +3992,7 @@
                 attribClassBody(env, c);
 
                 chk.checkDeprecatedAnnotation(env.tree.pos(), c);
-                chk.checkClassOverrideEqualsAndHash(c);
+                chk.checkClassOverrideEqualsAndHash(env.tree.pos(), c);
             } finally {
                 env.info.returnResult = prevReturnRes;
                 log.useSource(prev);
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Sun Feb 24 11:36:58 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java	Tue Feb 26 09:04:19 2013 +0000
@@ -1964,28 +1964,29 @@
         }
     }
 
-    public void checkClassOverrideEqualsAndHash(ClassSymbol someClass) {
+    private Filter<Symbol> equalsHasCodeFilter = new Filter<Symbol>() {
+        public boolean accepts(Symbol s) {
+            return MethodSymbol.implementation_filter.accepts(s) &&
+                    (s.flags() & BAD_OVERRIDE) == 0;
+
+        }
+    };
+
+    public void checkClassOverrideEqualsAndHash(DiagnosticPosition pos,
+            ClassSymbol someClass) {
         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) {
-                        return s.kind == Kinds.MTH &&
-                                (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,
+            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);
             }
         }
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Sun Feb 24 11:36:58 2013 -0800
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Feb 26 09:04:19 2013 +0000
@@ -2071,8 +2071,7 @@
 
 # 0: class name
 compiler.warn.override.equals.but.not.hashcode=\
-    Class {0}\n\
-    overrides method equals but does not overrides method hashCode from Object
+    Class {0} overrides equals, but neither it nor any superclass overrides hashCode method
 
 ## The following are all possible strings for the first argument ({0}) of the
 ## above strings.
--- a/langtools/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java	Sun Feb 24 11:36:58 2013 -0800
+++ b/langtools/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java	Tue Feb 26 09:04:19 2013 +0000
@@ -1,22 +1,42 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 6563143
+ * @bug 6563143 8008436
  * @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
  */
 
-@SuppressWarnings("overrides")
 public class OverridesEqualsButNotHashCodeTest {
     @Override
     public boolean equals(Object o) {
         return o == this;
     }
+
+    @Override
+    public int hashCode() {
+        return 0;
+    }
+}
+
+class SubClass extends OverridesEqualsButNotHashCodeTest {
+    @Override
+    public boolean equals(Object o) {
+        return o == this;
+    }
 }
 
-class Other {
+@SuppressWarnings("overrides")
+class NoWarning {
     @Override
     public boolean equals(Object o) {
         return o == this;
     }
 }
 
+class DoWarnMe {
+    @Override
+    public boolean equals(Object o) {
+        return o == this;
+    }
+}
--- a/langtools/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out	Sun Feb 24 11:36:58 2013 -0800
+++ b/langtools/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out	Tue Feb 26 09:04:19 2013 +0000
@@ -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