[java] Update rule OverrideBothEqualsAndHashcode

This commit is contained in:
Andreas Dangel
2021-10-01 12:19:10 +02:00
parent 4b112e8a88
commit dc3fedd306
4 changed files with 18 additions and 37 deletions

View File

@ -240,7 +240,7 @@
<!-- <rule ref="category/java/errorprone.xml/NonCaseLabelInSwitchStatement"/> -->
<rule ref="category/java/errorprone.xml/NonStaticInitializer"/>
<!-- <rule ref="category/java/errorprone.xml/NullAssignment"/> -->
<!-- <rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/> -->
<rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/>
<!-- <rule ref="category/java/errorprone.xml/ProperCloneImplementation"/> -->
<!-- <rule ref="category/java/errorprone.xml/ProperLogger"/> -->
<!-- <rule ref="category/java/errorprone.xml/ReturnEmptyArrayRatherThanNull"/> -->

View File

@ -4,16 +4,13 @@
package net.sourceforge.pmd.lang.java.rule.errorprone;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule {
@ -46,51 +43,30 @@ public class OverrideBothEqualsAndHashcodeRule extends AbstractJavaRule {
@Override
public Object visit(ASTImplementsList node, Object data) {
for (int ix = 0; ix < node.getNumChildren(); ix++) {
if (node.getChild(ix) instanceof ASTClassOrInterfaceType) {
ASTClassOrInterfaceType cit = (ASTClassOrInterfaceType) node.getChild(ix);
Class<?> clazz = cit.getType();
if (clazz != null && node.getChild(ix).hasImageEqualTo("Comparable")) {
implementsComparable = true;
return data;
}
}
}
implementsComparable = node.children().filter(child -> TypeTestUtil.isA(Comparable.class, child)).nonEmpty();
return super.visit(node, data);
}
@Override
public Object visit(ASTMethodDeclarator node, Object data) {
public Object visit(ASTMethodDeclaration node, Object data) {
if (implementsComparable) {
return data;
}
int iFormalParams = 0;
String paramName = null;
for (int ix = 0; ix < node.getNumChildren(); ix++) {
Node sn = node.getChild(ix);
if (sn instanceof ASTFormalParameters) {
List<ASTFormalParameter> allParams = ((ASTFormalParameters) sn)
.findChildrenOfType(ASTFormalParameter.class);
for (ASTFormalParameter formalParam : allParams) {
iFormalParams++;
ASTClassOrInterfaceType param = formalParam.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
if (param != null) {
paramName = param.getImage();
}
}
}
int formalParamsCount = node.getFormalParameters().size();
ASTFormalParameter formalParam = null;
if (formalParamsCount > 0) {
formalParam = node.getFormalParameters().get(0);
}
if (iFormalParams == 0 && node.hasImageEqualTo("hashCode")) {
if (formalParamsCount == 0 && "hashCode".equals(node.getName())) {
containsHashCode = true;
nodeFound = node;
} else if (iFormalParams == 1 && node.hasImageEqualTo("equals")
&& ("Object".equals(paramName) || "java.lang.Object".equals(paramName))) {
} else if (formalParamsCount == 1 && "equals".equals(node.getName())
&& TypeTestUtil.isExactlyA(Object.class, formalParam)) {
containsEquals = true;
nodeFound = node;
}
return super.visit(node, data);
}
}

View File

@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
@org.junit.Ignore("Rule has not been updated yet")
public class OverrideBothEqualsAndHashcodeTest extends PmdRuleTst {
// no additional unit tests
}

View File

@ -7,6 +7,7 @@
<test-code>
<description>hash code only</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Foo {
public int hashCode() {}
@ -17,6 +18,7 @@ public class Foo {
<test-code>
<description>equals only</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Foo {
public boolean equals(Object other) {}
@ -46,6 +48,7 @@ public class Foo {}
<test-code>
<description>equals sig uses String, not Object</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>5</expected-linenumbers>
<code><![CDATA[
public class Foo {
public boolean equals(String o) {
@ -133,6 +136,7 @@ public class Foo {
<test-code>
<description>overloaded hashCode, should fail on equals</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Foo {
public boolean equals(Object o1) { return false; }
@ -156,6 +160,7 @@ public class Foo {
<test-code>
<description>implements interface other than Comparable, not resolvable</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Foo implements C {
public boolean equals(Object other) { return false; }
@ -167,6 +172,7 @@ public class Foo implements C {
<test-code>
<description>implements interface other than Comparable, resolvable (#1303 OverrideBothEqualsAndHashcodeRule does not work on class implements resolvable interfaces)</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>2</expected-linenumbers>
<code><![CDATA[
public class Foo implements Runnable {
public boolean equals(Object other) { return false; }