UseCompareMethod: support boxed inputs and suggest "compareTo"

Allows to do IDEA-200365 in three steps now
This commit is contained in:
Tagir Valeev
2018-10-12 12:22:38 +07:00
parent d40546460d
commit 95f2337448
4 changed files with 93 additions and 13 deletions
@@ -4,7 +4,6 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
@@ -13,6 +12,7 @@ import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.ControlFlowUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nls;
@@ -62,7 +62,7 @@ public class UseCompareMethodInspection extends AbstractBaseJavaLocalInspectionT
private void register(CompareInfo info, PsiElement nameElement) {
holder.registerProblem(nameElement, "Can be replaced with '" + info.myClass.getClassName() + ".compare'",
new ReplaceWithPrimitiveCompareFix(info.myClass.getCanonicalText()));
new ReplaceWithPrimitiveCompareFix(info.getReplacementText()));
}
};
}
@@ -179,7 +179,8 @@ public class UseCompareMethodInspection extends AbstractBaseJavaLocalInspectionT
return null;
}
}
PsiClassType boxedType = ((PsiPrimitiveType)leftType).getBoxedType(expression);
PsiClassType boxedType = leftType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)leftType).getBoxedType(expression) :
tryCast(leftType, PsiClassType.class);
if (boxedType == null) return null;
return new CompareInfo(template, expression, canonicalPair.getFirst(), canonicalPair.getSecond(), boxedType);
}
@@ -273,9 +274,10 @@ public class UseCompareMethodInspection extends AbstractBaseJavaLocalInspectionT
@Contract("null, _ -> false")
private static boolean isTypeConvertible(PsiType type, PsiElement context) {
return type instanceof PsiPrimitiveType && (PsiType.DOUBLE.equals(type) ||
PsiType.FLOAT.equals(type) ||
PsiUtil.isLanguageLevel7OrHigher(context));
type = PsiPrimitiveType.getOptionallyUnboxedType(type);
return type != null && (PsiType.DOUBLE.equals(type) ||
PsiType.FLOAT.equals(type) ||
PsiUtil.isLanguageLevel7OrHigher(context));
}
static class CompareInfo {
@@ -298,7 +300,12 @@ public class UseCompareMethodInspection extends AbstractBaseJavaLocalInspectionT
}
private void replace(PsiElement toReplace, CommentTracker ct) {
String replacement = this.myClass.getCanonicalText() + ".compare(" + ct.text(this.myLeft) + "," + ct.text(this.myRight) + ")";
String replacement;
if (this.myLeft.getType() instanceof PsiClassType) {
replacement = ct.text(this.myLeft, ParenthesesUtils.METHOD_CALL_PRECEDENCE) + ".compareTo(" + ct.text(this.myRight) + ")";
} else {
replacement = this.myClass.getCanonicalText() + ".compare(" + ct.text(this.myLeft) + "," + ct.text(this.myRight) + ")";
}
if(toReplace == myTemplate) {
ct.replaceAndRestoreComments(myToReplace, replacement);
} else {
@@ -306,27 +313,32 @@ public class UseCompareMethodInspection extends AbstractBaseJavaLocalInspectionT
ct.replaceAndRestoreComments(toReplace, myTemplate);
}
}
public String getReplacementText() {
String methodName = this.myLeft.getType() instanceof PsiClassType ? "compareTo" : "compare";
return myClass.getName()+"."+methodName+"()";
}
}
private static class ReplaceWithPrimitiveCompareFix implements LocalQuickFix {
private final String myClassName;
private final String myReplacementText;
ReplaceWithPrimitiveCompareFix(String className) {
myClassName = className;
ReplaceWithPrimitiveCompareFix(String replacementText) {
myReplacementText = replacementText;
}
@Nls
@NotNull
@Override
public String getName() {
return "Replace with '" + StringUtil.getShortName(myClassName) + ".compare'";
return CommonQuickFixBundle.message("fix.replace.with.x", myReplacementText);
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return "Replace with static 'compare' method";
return "Replace with single comparison method";
}
@Override
@@ -2,7 +2,9 @@
<body>
<p>This inspection suggests to use <code>Integer.compare()</code>, etc. static methods where more verbose or less efficient constructs are
used. For example, <code>x &gt; y ? 1 : x &lt; y ? -1 : 0</code> or <code>Integer.valueOf(x).compareTo(y)</code> could be
replaced with <code>Integer.compare(x, y)</code>.</p>
replaced with <code>Integer.compare(x, y)</code>. If <code>x</code> and <code>y</code> are already boxed integers, then
<code>x.compareTo(y)</code> is suggested.
</p>
<p><code>Double.compare</code> and <code>Float.compare</code> methods appeared in Java 1.4, methods for other primitive types
are available since Java 1.7</p>
<!-- tooltip end -->
@@ -0,0 +1,31 @@
// "Fix all ''compare()' method can be used to compare primitives' problems in file" "true"
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
class Dto{
Long id;
Long getId() {
return id;
}
List<Long> sortIds(List<Dto> list) {
List<Long> ids = list.stream().map(Dto::getId).collect(Collectors.toList());
ids.sort(new Comparator<Long>() {
public int compare(Long o1, Long o2) {
return o1.compareTo(o2);
}
});
return ids;
}
List<Dto> sortDtos(List<Dto> list) {
list.sort(new Comparator<Dto>() {
public int compare(Dto o1, Dto o2) {
return o1.getId().compareTo(o2.getId());
}
});
return list;
}
}
@@ -0,0 +1,35 @@
// "Fix all ''compare()' method can be used to compare primitives' problems in file" "true"
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
class Dto{
Long id;
Long getId() {
return id;
}
List<Long> sortIds(List<Dto> list) {
List<Long> ids = list.stream().map(Dto::getId).collect(Collectors.toList());
ids.sort(new Comparator<Long>() {
public int compare(Long o1, Long o2) {
i<caret>f (o1 < o2) return -1;
if (o1 > o2) return 1;
return 0;
}
});
return ids;
}
List<Dto> sortDtos(List<Dto> list) {
list.sort(new Comparator<Dto>() {
public int compare(Dto o1, Dto o2) {
if (o1.getId() < o2.getId()) return -1;
if (o1.getId() > o2.getId()) return 1;
return 0;
}
});
return list;
}
}