IG: warn on equalsIgnoreCase(), compareTo() and compareToIgnoreCase() call to itself (IDEA-162797)

This commit is contained in:
Bas Leijdekkers
2016-10-29 20:50:05 +02:00
parent 50d645e256
commit 024d0f5894
5 changed files with 62 additions and 5 deletions
@@ -16,7 +16,8 @@
package com.siyeh.ig.bugs;
import com.intellij.psi.*;
import com.siyeh.InspectionGadgetsBundle;import com.siyeh.ig.BaseInspection;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.EquivalenceChecker;
import com.siyeh.ig.psiutils.MethodCallUtils;
@@ -52,7 +53,10 @@ public class EqualsWithItselfInspection extends BaseInspection {
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
super.visitMethodCallExpression(expression);
if (!MethodCallUtils.isEqualsCall(expression)) {
if (!MethodCallUtils.isEqualsCall(expression) &&
!MethodCallUtils.isEqualsIgnoreCaseCall(expression) &&
!MethodCallUtils.isCompareToCall(expression) &&
!MethodCallUtils.isCompareToIgnoreCaseCall(expression)) {
return;
}
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
@@ -72,6 +72,15 @@ public class MethodCallUtils {
return MethodUtils.isCompareTo(method);
}
public static boolean isCompareToIgnoreCaseCall(@NotNull PsiMethodCallExpression expression) {
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
if (!"compareToIgnoreCase".equals(methodExpression.getReferenceName())) {
return false;
}
final PsiMethod method = expression.resolveMethod();
return MethodUtils.isCompareToIgnoreCase(method);
}
public static boolean isEqualsCall(PsiMethodCallExpression expression) {
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final String name = methodExpression.getReferenceName();
@@ -82,6 +91,16 @@ public class MethodCallUtils {
return MethodUtils.isEquals(method);
}
public static boolean isEqualsIgnoreCaseCall(PsiMethodCallExpression expression) {
final PsiReferenceExpression methodExpression = expression.getMethodExpression();
final String name = methodExpression.getReferenceName();
if (!HardcodedMethodConstants.EQUALS_IGNORE_CASE.equals(name)) {
return false;
}
final PsiMethod method = expression.resolveMethod();
return MethodUtils.isEqualsIgnoreCase(method);
}
public static boolean isSimpleCallToMethod(@NotNull PsiMethodCallExpression expression, @NonNls @Nullable String calledOnClassName,
@Nullable PsiType returnType, @NonNls @Nullable String methodName, @NonNls @Nullable String... parameterTypeStrings) {
if (parameterTypeStrings == null) {
@@ -49,6 +49,15 @@ public class MethodUtils {
&& InheritanceUtil.isInheritor(method.getContainingClass(), CommonClassNames.JAVA_LANG_COMPARABLE);
}
@Contract("null -> false")
public static boolean isCompareToIgnoreCase(@Nullable PsiMethod method) {
if (method == null) {
return false;
}
final PsiClassType stringType = TypeUtils.getStringType(method);
return methodMatches(method, "java.lang.String", PsiType.INT, "compareToIgnoreCase", stringType);
}
@Contract("null -> false")
public static boolean isHashCode(@Nullable PsiMethod method) {
return method != null && methodMatches(method, null, PsiType.INT, HardcodedMethodConstants.HASH_CODE);
@@ -77,6 +86,15 @@ public class MethodUtils {
return methodMatches(method, null, PsiType.BOOLEAN, HardcodedMethodConstants.EQUALS, objectType);
}
@Contract("null -> false")
public static boolean isEqualsIgnoreCase(@Nullable PsiMethod method) {
if (method == null) {
return false;
}
final PsiClassType stringType = TypeUtils.getStringType(method);
return methodMatches(method, "java.lang.String", PsiType.BOOLEAN, HardcodedMethodConstants.EQUALS_IGNORE_CASE, stringType);
}
/**
* @param method the method to compare to.
* @param containingClassName the name of the class which contiains the
@@ -1,8 +1,8 @@
<html>
<body>
Reports call to <b>equals()</b> were an object is compared for equality with itself.
This means that the argument and the qualifier to the call are identical.
In this case <b>equals()</b> will always return <b>true</b>.
Reports calls to <b>equals()</b> or <b>compareTo()</b> were an object is compared for equality with itself.
This means the argument and the qualifier to the call are identical, and it will always return <b>true</b> for <b>equals()</b>
or always <b>0</b> for <b>compareTo()</b>.
<!-- tooltip end -->
<p>
</body>
@@ -24,4 +24,20 @@ class EqualsWithItself {
public Object build() {
return new Object();
}
boolean string(String s) {
return s.<warning descr="'equalsIgnoreCase()' called on itself">equalsIgnoreCase</warning>(s);
}
int compareTo(String s) {
return s.<warning descr="'compareTo()' called on itself">compareTo</warning>(s);
}
int compareToIgnoreCase(String s) {
return s.<warning descr="'compareToIgnoreCase()' called on itself">compareToIgnoreCase</warning>(s);
}
boolean safe(String a, String b) {
return a.equals(b) && a.equalsIgnoreCase(b) && a.compareTo(b) == 0;
}
}