changeset 1759:3806171b52d8

8009138: javac, equals-hashCode warning tuning Reviewed-by: mcimadamore
author vromero
date Thu, 07 Mar 2013 10:04:28 +0000
parents c98b3e96c726
children 823fb9229724
files src/share/classes/com/sun/tools/javac/code/Symbol.java src/share/classes/com/sun/tools/javac/code/Symtab.java src/share/classes/com/sun/tools/javac/comp/Attr.java src/share/classes/com/sun/tools/javac/comp/Check.java src/share/classes/com/sun/tools/javac/resources/compiler.properties test/tools/javac/6563143/EqualsHashCodeWarningTest.java test/tools/javac/6563143/EqualsHashCodeWarningTest.out test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out
diffstat 9 files changed, 99 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Mar 06 15:33:39 2013 +0000
+++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Mar 07 10:04:28 2013 +0000
@@ -237,7 +237,7 @@
     }
 
     /** Has this symbol an empty name? This includes anonymous
-     *  inner classses.
+     *  inner classes.
      */
     public boolean isAnonymous() {
         return name.isEmpty();
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Mar 06 15:33:39 2013 +0000
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Mar 07 10:04:28 2013 +0000
@@ -148,6 +148,7 @@
     public final Type listType;
     public final Type collectionsType;
     public final Type comparableType;
+    public final Type comparatorType;
     public final Type arraysType;
     public final Type iterableType;
     public final Type iteratorType;
@@ -502,6 +503,7 @@
         listType = enterClass("java.util.List");
         collectionsType = enterClass("java.util.Collections");
         comparableType = enterClass("java.lang.Comparable");
+        comparatorType = enterClass("java.util.Comparator");
         arraysType = enterClass("java.util.Arrays");
         iterableType = target.hasIterable()
             ? enterClass("java.lang.Iterable")
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Mar 06 15:33:39 2013 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Mar 07 10:04:28 2013 +0000
@@ -4016,7 +4016,7 @@
                 attribClassBody(env, c);
 
                 chk.checkDeprecatedAnnotation(env.tree.pos(), c);
-                chk.checkClassOverrideEqualsAndHash(env.tree.pos(), c);
+                chk.checkClassOverrideEqualsAndHashIfNeeded(env.tree.pos(), c);
             } finally {
                 env.info.returnResult = prevReturnRes;
                 log.useSource(prev);
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Wed Mar 06 15:33:39 2013 +0000
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Mar 07 10:04:28 2013 +0000
@@ -1972,14 +1972,32 @@
         }
     };
 
-    public void checkClassOverrideEqualsAndHash(DiagnosticPosition pos,
+    public void checkClassOverrideEqualsAndHashIfNeeded(DiagnosticPosition pos,
+            ClassSymbol someClass) {
+        /* At present, annotations cannot possibly have a method that is override
+         * equivalent with Object.equals(Object) but in any case the condition is
+         * fine for completeness.
+         */
+        if (someClass == (ClassSymbol)syms.objectType.tsym ||
+            someClass.isInterface() || someClass.isEnum() ||
+            (someClass.flags() & ANNOTATION) != 0 ||
+            (someClass.flags() & ABSTRACT) != 0) return;
+        //anonymous inner classes implementing interfaces need especial treatment
+        if (someClass.isAnonymous()) {
+            List<Type> interfaces =  types.interfaces(someClass.type);
+            if (interfaces != null && !interfaces.isEmpty() &&
+                interfaces.head.tsym == syms.comparatorType.tsym) return;
+        }
+        checkClassOverrideEqualsAndHash(pos, someClass);
+    }
+
+    private 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,
@@ -1987,7 +2005,7 @@
 
             if (overridesEquals && !overridesHashCode) {
                 log.warning(LintCategory.OVERRIDES, pos,
-                        "override.equals.but.not.hashcode", someClass.fullname);
+                        "override.equals.but.not.hashcode", someClass);
             }
         }
     }
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Mar 06 15:33:39 2013 +0000
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Mar 07 10:04:28 2013 +0000
@@ -2077,7 +2077,7 @@
     {0}\n\
     overridden method does not throw {1}
 
-# 0: class name
+# 0: symbol
 compiler.warn.override.equals.but.not.hashcode=\
     Class {0} overrides equals, but neither it nor any superclass overrides hashCode method
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/6563143/EqualsHashCodeWarningTest.java	Thu Mar 07 10:04:28 2013 +0000
@@ -0,0 +1,71 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 6563143 8008436 8009138
+ * @summary javac should issue a warning for overriding equals without hashCode
+ * @summary javac should not issue a warning for overriding equals without hasCode
+ * @summary javac, equals-hashCode warning tuning
+ * if hashCode has been overriden by a superclass
+ * @compile/ref=EqualsHashCodeWarningTest.out -Xlint:overrides -XDrawDiagnostics EqualsHashCodeWarningTest.java
+ */
+
+import java.util.Comparator;
+
+public class EqualsHashCodeWarningTest {
+    @Override
+    public boolean equals(Object o) {
+        return o == this;
+    }
+
+    @Override
+    public int hashCode() {
+        return 0;
+    }
+
+    public Comparator m() {
+        return new Comparator() {
+            @Override
+            public boolean equals(Object o) {return true;}
+
+            @Override
+            public int compare(Object o1, Object o2) {
+                return 0;
+            }
+        };
+    }
+}
+
+class SubClass extends EqualsHashCodeWarningTest {
+    @Override
+    public boolean equals(Object o) {
+        return true;
+    }
+}
+
+@SuppressWarnings("overrides")
+class DontWarnMe {
+    @Override
+    public boolean equals(Object o) {
+        return true;
+    }
+}
+
+class DoWarnMe {
+    @Override
+    public boolean equals(Object o) {
+        return o == this;
+    }
+}
+
+abstract class IamAbstractGetMeOutOfHere {
+    public boolean equals(Object o){return true;}
+}
+
+interface I {
+    public boolean equals(Object o);
+}
+
+enum E {
+    A, B
+}
+
+@interface anno {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/6563143/EqualsHashCodeWarningTest.out	Thu Mar 07 10:04:28 2013 +0000
@@ -0,0 +1,2 @@
+EqualsHashCodeWarningTest.java:52:1: compiler.warn.override.equals.but.not.hashcode: DoWarnMe
+1 warning
--- a/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.java	Wed Mar 06 15:33:39 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * @test /nodynamiccopyright/
- * @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
- */
-
-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;
-    }
-}
-
-@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/test/tools/javac/6563143/OverridesEqualsButNotHashCodeTest.out	Wed Mar 06 15:33:39 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-OverridesEqualsButNotHashCodeTest.java:37:1: compiler.warn.override.equals.but.not.hashcode: DoWarnMe
-1 warning