mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IDEA-182004 Collection.containsAll() can be simplified in certain cases
RedundantCollectionOperation: strings externalized, description fixed
This commit is contained in:
@@ -2,6 +2,6 @@
|
||||
<body>
|
||||
Reports unnecessarily complex collection operations which have simpler alternatives.
|
||||
<!-- tooltip end -->
|
||||
<small>New in 2018.1</small>
|
||||
<p><small>New in 2018.1</small></p>
|
||||
</body>
|
||||
</html>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'contains'" "true"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
void test(List<String> list) {
|
||||
list.contains("foo");
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'Objects.equals'" "true"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
void test() {
|
||||
final boolean ff = Objects.equals("foo", "bar");
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'contains'" "true"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
void test(List<String> list) {
|
||||
list.con<caret>tainsAll(Collections.singleton("foo"));
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'Objects.equals'" "true"
|
||||
import java.util.*;
|
||||
|
||||
class Test {
|
||||
void test() {
|
||||
final boolean ff = Collections.singleton("foo").contai<caret>ns("bar");
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -2030,8 +2030,8 @@
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="RedundantStringOperation" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="inspection.redundant.string.operation.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.verbose.or.redundant.code.constructs"
|
||||
enabledByDefault="true" level="WARNING" cleanupTool="true" implementationClass="com.siyeh.ig.redundancy.RedundantStringOperationInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="RedundantCollectionOperation" displayName="Redundant Collection operation"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.verbose.or.redundant.code.constructs"
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="RedundantCollectionOperation" bundle="com.siyeh.InspectionGadgetsBundle"
|
||||
key="inspection.redundant.collection.operation.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.verbose.or.redundant.code.constructs"
|
||||
enabledByDefault="true" level="WARNING" cleanupTool="true" implementationClass="com.siyeh.ig.redundancy.RedundantCollectionOperationInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="TailRecursion" bundle="com.siyeh.InspectionGadgetsBundle" key="tail.recursion.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.performance.issues" enabledByDefault="true"
|
||||
|
||||
+4
@@ -2242,3 +2242,7 @@ inspection.catch.ignores.exception.used.message='catch' parameter named <code>#r
|
||||
inspection.catch.ignores.exception.empty.message=Empty <code>#ref</code> block #loc
|
||||
inspection.catch.ignores.exception.unused.message=Unused 'catch' parameter <code>#ref</code> #loc
|
||||
inspection.catch.ignores.exception.vm.ignored.message=Some important exceptions might be ignored in a <code>#ref</code> block #loc
|
||||
|
||||
inspection.redundant.collection.operation.display.name=Redundant Collection operation
|
||||
inspection.redundant.collection.operation.fix.family.name=Simplify collection operation
|
||||
inspection.redundant.collection.operation.problem.arraycopy=Unnecessary collection created to copy an array
|
||||
|
||||
+127
-63
@@ -5,9 +5,11 @@ import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.callMatcher.CallMapper;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
@@ -17,8 +19,6 @@ import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
import static com.siyeh.ig.callMatcher.CallMatcher.*;
|
||||
|
||||
@@ -31,10 +31,21 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca
|
||||
instanceCall(CommonClassNames.JAVA_UTIL_LIST, "subList").parameterTypes("int", "int");
|
||||
private static final CallMatcher AS_LIST =
|
||||
staticCall(CommonClassNames.JAVA_UTIL_ARRAYS, "asList").parameterCount(1);
|
||||
private static final CallMatcher SINGLETON =
|
||||
anyOf(
|
||||
staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singleton", "singletonList").parameterCount(1),
|
||||
staticCall(CommonClassNames.JAVA_UTIL_LIST, "of").parameterTypes("E"),
|
||||
staticCall(CommonClassNames.JAVA_UTIL_SET, "of").parameterTypes("E"));
|
||||
private static final CallMatcher CONTAINS_ALL =
|
||||
instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "containsAll").parameterTypes(CommonClassNames.JAVA_UTIL_COLLECTION);
|
||||
private static final CallMatcher CONTAINS =
|
||||
instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "contains").parameterTypes(CommonClassNames.JAVA_LANG_OBJECT);
|
||||
|
||||
private static final CallMapper<RedundantCollectionOperationHandler> HANDLERS =
|
||||
new CallMapper<RedundantCollectionOperationHandler>()
|
||||
.register(TO_ARRAY, SimplifyToArrayHandler.handler());
|
||||
.register(TO_ARRAY, AsListToArrayHandler::handler)
|
||||
.register(CONTAINS_ALL, ContainsAllSingletonHandler::handler)
|
||||
.register(CONTAINS, SingletonContainsHandler::handler);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -55,15 +66,16 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca
|
||||
}
|
||||
|
||||
interface RedundantCollectionOperationHandler {
|
||||
default String getProblemName() {
|
||||
return InspectionGadgetsBundle.message("expression.can.be.replaced.problem.descriptor", getReplacement());
|
||||
}
|
||||
|
||||
String getProblemName();
|
||||
|
||||
String getFixName();
|
||||
String getReplacement();
|
||||
|
||||
void performFix(@NotNull Project project, @NotNull PsiMethodCallExpression call);
|
||||
}
|
||||
|
||||
private static class SimplifyToArrayHandler implements RedundantCollectionOperationHandler {
|
||||
private static class AsListToArrayHandler implements RedundantCollectionOperationHandler {
|
||||
private final String myReplacementMethod;
|
||||
@NotNull private final SmartPsiElementPointer<PsiExpression> myArrayPtr;
|
||||
private final SmartPsiElementPointer<PsiExpression> myFromPtr;
|
||||
@@ -71,11 +83,11 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca
|
||||
@NotNull private final String mySourceComponentType;
|
||||
@NotNull private final String myTargetComponentType;
|
||||
|
||||
private SimplifyToArrayHandler(PsiExpression from,
|
||||
PsiExpression to,
|
||||
@NotNull PsiExpression array,
|
||||
@NotNull String sourceComponentType,
|
||||
@NotNull String targetComponentType) {
|
||||
private AsListToArrayHandler(PsiExpression from,
|
||||
PsiExpression to,
|
||||
@NotNull PsiExpression array,
|
||||
@NotNull String sourceComponentType,
|
||||
@NotNull String targetComponentType) {
|
||||
SmartPointerManager manager = SmartPointerManager.getInstance(array.getProject());
|
||||
myArrayPtr = manager.createSmartPsiElementPointer(array);
|
||||
myFromPtr = from == null ? null : manager.createSmartPsiElementPointer(from);
|
||||
@@ -95,12 +107,12 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca
|
||||
|
||||
@Override
|
||||
public String getProblemName() {
|
||||
return "Unnecessary collection created to copy an array";
|
||||
return InspectionGadgetsBundle.message("inspection.redundant.collection.operation.problem.arraycopy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFixName() {
|
||||
return "Replace with '" + myReplacementMethod + "'";
|
||||
public String getReplacement() {
|
||||
return myReplacementMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,54 +141,106 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca
|
||||
ct.replaceAndRestoreComments(call, replacement);
|
||||
}
|
||||
|
||||
public static Function<PsiMethodCallExpression, RedundantCollectionOperationHandler> handler() {
|
||||
return call -> {
|
||||
PsiExpression arg = ArrayUtil.getFirstElement(call.getArgumentList().getExpressions());
|
||||
PsiExpression arrayLength = null;
|
||||
String targetComponentType;
|
||||
if (arg != null) {
|
||||
if (!(arg instanceof PsiNewExpression)) return null;
|
||||
PsiJavaCodeReferenceElement classRef = ((PsiNewExpression)arg).getClassReference();
|
||||
if (classRef == null) return null;
|
||||
targetComponentType = classRef.getQualifiedName();
|
||||
PsiExpression[] dimensions = ((PsiNewExpression)arg).getArrayDimensions();
|
||||
if (dimensions.length != 1) return null;
|
||||
if (!ExpressionUtils.isZero(dimensions[0])) {
|
||||
arrayLength = dimensions[0];
|
||||
}
|
||||
public static RedundantCollectionOperationHandler handler(PsiMethodCallExpression call) {
|
||||
PsiExpression arg = ArrayUtil.getFirstElement(call.getArgumentList().getExpressions());
|
||||
PsiExpression arrayLength = null;
|
||||
String targetComponentType;
|
||||
if (arg != null) {
|
||||
if (!(arg instanceof PsiNewExpression)) return null;
|
||||
PsiJavaCodeReferenceElement classRef = ((PsiNewExpression)arg).getClassReference();
|
||||
if (classRef == null) return null;
|
||||
targetComponentType = classRef.getQualifiedName();
|
||||
PsiExpression[] dimensions = ((PsiNewExpression)arg).getArrayDimensions();
|
||||
if (dimensions.length != 1) return null;
|
||||
if (!ExpressionUtils.isZero(dimensions[0])) {
|
||||
arrayLength = dimensions[0];
|
||||
}
|
||||
else {
|
||||
targetComponentType = CommonClassNames.JAVA_LANG_OBJECT;
|
||||
}
|
||||
else {
|
||||
targetComponentType = CommonClassNames.JAVA_LANG_OBJECT;
|
||||
}
|
||||
PsiExpression from = null;
|
||||
PsiExpression to = null;
|
||||
PsiMethodCallExpression qualifier = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if (SUBLIST.test(qualifier)) {
|
||||
PsiExpression[] subListArgs = qualifier.getArgumentList().getExpressions();
|
||||
from = subListArgs[0];
|
||||
to = subListArgs[1];
|
||||
qualifier = MethodCallUtils.getQualifierMethodCall(qualifier);
|
||||
}
|
||||
if (!AS_LIST.test(qualifier) || MethodCallUtils.isVarArgCall(qualifier)) return null;
|
||||
PsiExpression array = qualifier.getArgumentList().getExpressions()[0];
|
||||
PsiArrayType sourceArrayType = tryCast(array.getType(), PsiArrayType.class);
|
||||
if (sourceArrayType == null) return null;
|
||||
PsiClass componentClass = PsiUtil.resolveClassInClassTypeOnly(sourceArrayType.getComponentType());
|
||||
if (componentClass == null) return null;
|
||||
String sourceComponentType = componentClass.getQualifiedName();
|
||||
if (sourceComponentType == null) return null;
|
||||
if (from != null && to != null) {
|
||||
if (arrayLength != null && !ExpressionUtils.isDifference(from, to, arrayLength)) return null;
|
||||
}
|
||||
else {
|
||||
if (!sourceComponentType.equals(targetComponentType)) return null;
|
||||
if (arrayLength != null) {
|
||||
PsiExpression arrayFromLength = ExpressionUtils.getArrayFromLengthExpression(arrayLength);
|
||||
if (arrayFromLength == null || !PsiEquivalenceUtil.areElementsEquivalent(array, arrayFromLength)) return null;
|
||||
}
|
||||
PsiExpression from = null;
|
||||
PsiExpression to = null;
|
||||
PsiMethodCallExpression qualifier = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if (SUBLIST.test(qualifier)) {
|
||||
PsiExpression[] subListArgs = qualifier.getArgumentList().getExpressions();
|
||||
from = subListArgs[0];
|
||||
to = subListArgs[1];
|
||||
qualifier = MethodCallUtils.getQualifierMethodCall(qualifier);
|
||||
}
|
||||
if (!AS_LIST.test(qualifier) || MethodCallUtils.isVarArgCall(qualifier)) return null;
|
||||
PsiExpression array = qualifier.getArgumentList().getExpressions()[0];
|
||||
PsiArrayType sourceArrayType = tryCast(array.getType(), PsiArrayType.class);
|
||||
if (sourceArrayType == null) return null;
|
||||
PsiClass componentClass = PsiUtil.resolveClassInClassTypeOnly(sourceArrayType.getComponentType());
|
||||
if (componentClass == null) return null;
|
||||
String sourceComponentType = componentClass.getQualifiedName();
|
||||
if (sourceComponentType == null) return null;
|
||||
if (from != null && to != null) {
|
||||
if (arrayLength != null && !ExpressionUtils.isDifference(from, to, arrayLength)) return null;
|
||||
}
|
||||
else {
|
||||
if (!sourceComponentType.equals(targetComponentType)) return null;
|
||||
if (arrayLength != null) {
|
||||
PsiExpression arrayFromLength = ExpressionUtils.getArrayFromLengthExpression(arrayLength);
|
||||
if (arrayFromLength == null || !PsiEquivalenceUtil.areElementsEquivalent(array, arrayFromLength)) return null;
|
||||
}
|
||||
}
|
||||
return new SimplifyToArrayHandler(from, to, array, sourceComponentType, targetComponentType);
|
||||
};
|
||||
}
|
||||
return new AsListToArrayHandler(from, to, array, sourceComponentType, targetComponentType);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ContainsAllSingletonHandler implements RedundantCollectionOperationHandler {
|
||||
@Override
|
||||
public String getReplacement() {
|
||||
return "contains";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performFix(@NotNull Project project, @NotNull PsiMethodCallExpression call) {
|
||||
PsiExpression arg = ArrayUtil.getFirstElement(call.getArgumentList().getExpressions());
|
||||
if (arg == null) return;
|
||||
PsiMethodCallExpression singleton = tryCast(PsiUtil.skipParenthesizedExprDown(arg), PsiMethodCallExpression.class);
|
||||
if (singleton == null) return;
|
||||
PsiExpression singletonArg = ArrayUtil.getFirstElement(singleton.getArgumentList().getExpressions());
|
||||
if (singletonArg == null) return;
|
||||
ExpressionUtils.bindCallTo(call, "contains");
|
||||
CommentTracker ct = new CommentTracker();
|
||||
ct.replaceAndRestoreComments(arg, ct.markUnchanged(singletonArg));
|
||||
}
|
||||
|
||||
public static RedundantCollectionOperationHandler handler(PsiMethodCallExpression call) {
|
||||
PsiExpression containsAllArg = call.getArgumentList().getExpressions()[0];
|
||||
PsiMethodCallExpression maybeSingleton = tryCast(PsiUtil.skipParenthesizedExprDown(containsAllArg), PsiMethodCallExpression.class);
|
||||
if (!SINGLETON.test(maybeSingleton)) return null;
|
||||
return new ContainsAllSingletonHandler();
|
||||
}
|
||||
}
|
||||
|
||||
private static class SingletonContainsHandler implements RedundantCollectionOperationHandler {
|
||||
@Override
|
||||
public String getReplacement() {
|
||||
return "Objects.equals";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performFix(@NotNull Project project, @NotNull PsiMethodCallExpression call) {
|
||||
PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if (qualifierCall == null) return;
|
||||
PsiExpression left = ArrayUtil.getFirstElement(qualifierCall.getArgumentList().getExpressions());
|
||||
PsiExpression right = ArrayUtil.getFirstElement(call.getArgumentList().getExpressions());
|
||||
if (left == null || right == null) return;
|
||||
CommentTracker ct = new CommentTracker();
|
||||
PsiElement element =
|
||||
ct.replaceAndRestoreComments(call, CommonClassNames.JAVA_UTIL_OBJECTS + ".equals(" + ct.text(left) + "," + ct.text(right) + ")");
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(element);
|
||||
}
|
||||
|
||||
static RedundantCollectionOperationHandler handler(PsiMethodCallExpression call) {
|
||||
if(!PsiUtil.isLanguageLevel7OrHigher(call)) return null;
|
||||
PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
|
||||
if (!SINGLETON.test(qualifierCall)) return null;
|
||||
return new SingletonContainsHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,14 +254,14 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myHandler.getFixName();
|
||||
return InspectionGadgetsBundle.message("replace.with", myHandler.getReplacement());
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Simplify collection operation";
|
||||
return InspectionGadgetsBundle.message("inspection.redundant.collection.operation.fix.family.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user