From 024d0f5894d3f8359a71912a2cbbcdd0c216311e Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 28 Oct 2016 14:05:09 +0200 Subject: [PATCH] IG: warn on equalsIgnoreCase(), compareTo() and compareToIgnoreCase() call to itself (IDEA-162797) --- .../ig/bugs/EqualsWithItselfInspection.java | 8 ++++++-- .../siyeh/ig/psiutils/MethodCallUtils.java | 19 +++++++++++++++++++ .../com/siyeh/ig/psiutils/MethodUtils.java | 18 ++++++++++++++++++ .../EqualsWithItself.html | 6 +++--- .../equals_with_itself/EqualsWithItself.java | 16 ++++++++++++++++ 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java index 9c8a060a9ecb..08f016c860ab 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/EqualsWithItselfInspection.java @@ -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(); diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java index c21f8817e624..85cff482b0b8 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodCallUtils.java @@ -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) { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodUtils.java index b5db5a04370d..0a95789f96fd 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/MethodUtils.java @@ -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 diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html index 3095986ff668..e14b4780d055 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/EqualsWithItself.html @@ -1,8 +1,8 @@ -Reports call to equals() 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 equals() will always return true. +Reports calls to equals() or compareTo() 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 true for equals() +or always 0 for compareTo().

diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java index 850406b12534..6ec14731c05c 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/equals_with_itself/EqualsWithItself.java @@ -24,4 +24,20 @@ class EqualsWithItself { public Object build() { return new Object(); } + + boolean string(String s) { + return s.equalsIgnoreCase(s); + } + + int compareTo(String s) { + return s.compareTo(s); + } + + int compareToIgnoreCase(String s) { + return s.compareToIgnoreCase(s); + } + + boolean safe(String a, String b) { + return a.equals(b) && a.equalsIgnoreCase(b) && a.compareTo(b) == 0; + } } \ No newline at end of file