--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Mar 06 15:33:39 2013 +0000
+++ b/langtools/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/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Wed Mar 06 15:33:39 2013 +0000
+++ b/langtools/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/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java Wed Mar 06 15:33:39 2013 +0000
+++ b/langtools/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/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java Wed Mar 06 15:33:39 2013 +0000
+++ b/langtools/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/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Mar 06 15:33:39 2013 +0000
+++ b/langtools/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/langtools/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/langtools/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/langtools/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/langtools/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