Java: Don't cause endless recursive calls of the equals() method in the inspection "Objects compared with '=='", handle qualified 'this' (IDEA-164038)

This commit is contained in:
Pavel Dolgov
2016-11-18 13:34:28 +03:00
parent b997d71de4
commit eaaccc3054
5 changed files with 56 additions and 2 deletions
@@ -32,6 +32,7 @@ import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class EqualityOperatorComparesObjectsInspection extends BaseInspection {
@@ -211,13 +212,24 @@ public class EqualityOperatorComparesObjectsInspection extends BaseInspection {
}
if (lhs instanceof PsiThisExpression || rhs instanceof PsiThisExpression) {
final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
if (method != null && "equals".equals(method.getName())) {
return;
if (method != null && "equals".equals(method.getName()) && method.getParameterList().getParametersCount() == 1) {
final PsiClass containingClass = method.getContainingClass();
if (isThisQualifier(lhs, containingClass) || isThisQualifier(rhs, containingClass)) {
return;
}
}
}
final String operationText = expression.getOperationSign().getText();
final String prefix = tokenType.equals(JavaTokenType.NE) ? "!" : "";
registerError(expression, operationText, prefix);
}
private static boolean isThisQualifier(@Nullable PsiExpression expression, @Nullable PsiClass psiClass) {
if (expression instanceof PsiThisExpression) {
final PsiJavaCodeReferenceElement qualifier = ((PsiThisExpression)expression).getQualifier();
return qualifier == null || psiClass != null && qualifier.isReferenceTo(psiClass);
}
return false;
}
}
}
@@ -0,0 +1,13 @@
class Outer {
class Inner {
private Outer outer() {
return Outer.this;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof Inner) &&
Outer.this.equals(((Inner) obj).outer());
}
}
}
@@ -0,0 +1,13 @@
class Outer {
class Inner {
private Outer outer() {
return Outer.this;
}
@Override
public boolean equals(Object obj) {
return (obj instanceof Inner) &&
Outer.this <caret>== ((Inner) obj).outer();
}
}
}
@@ -0,0 +1,14 @@
class Demo {
private Object field;
@Override
public boolean equals(Object obj) {
if (Demo.this <caret>== obj) {
return true;
}
else {
Demo other = (Demo)obj;
return field == other.field;
}
}
}
@@ -31,6 +31,8 @@ public abstract class EqualityOperatorComparesObjectsInspectionTestBase extends
public void testSimpleObjectComparison() { doTest(true, false); }
public void testNegatedObjectComparison() { doTest(false, false); }
public void testCompareThisInEqualsMethod() { assertQuickfixNotAvailable(); }
public void testCompareSameQualifiedThisInEqualsMethod() { assertQuickfixNotAvailable(); }
public void testCompareOtherQualifiedThisInEqualsMethod() { doTest(true, false); }
public void testCompareFieldInEqualsMethod() { doTest(true, false); }
@Override