diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterAsListSort.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterAsListSort.java new file mode 100644 index 000000000000..63f8f2499653 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterAsListSort.java @@ -0,0 +1,11 @@ +// "Replace with 'Arrays.sort()'" "true" +import java.util.Arrays; + +class Test { + void test(String[] data) { + /*array*/ + /*sort*/ + /*comparator*/ + Arrays.sort(data, String.CASE_INSENSITIVE_COMPARATOR); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterAsListSortStatic.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterAsListSortStatic.java new file mode 100644 index 000000000000..95ffe4e772c3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterAsListSortStatic.java @@ -0,0 +1,10 @@ +// "Replace with 'Arrays.sort()'" "true" +import java.util.Arrays; +import java.util.Collections; + +class Test { + void test(String[] data) { + /*array*/ + Arrays.sort(/*sort*/data/*no comparator*/); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeAsListSort.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeAsListSort.java new file mode 100644 index 000000000000..a973db47592b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeAsListSort.java @@ -0,0 +1,8 @@ +// "Replace with 'Arrays.sort()'" "true" +import java.util.Arrays; + +class Test { + void test(String[] data) { + Arrays.asList(/*array*/data)/*sort*/.sort(/*comparator*/String.CASE_INSENSITIVE_COMPARATOR); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeAsListSortStatic.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeAsListSortStatic.java new file mode 100644 index 000000000000..06e009625172 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeAsListSortStatic.java @@ -0,0 +1,9 @@ +// "Replace with 'Arrays.sort()'" "true" +import java.util.Arrays; +import java.util.Collections; + +class Test { + void test(String[] data) { + Collections.sort(/*sort*/Arrays.asList(/*array*/data)/*no comparator*/); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java index d6ca19b45523..4508f3925467 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java @@ -1,4 +1,4 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.redundancy; import com.intellij.codeInsight.PsiEquivalenceUtil; @@ -49,6 +49,9 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca instanceCall(CommonClassNames.JAVA_UTIL_LIST, "remove").parameterTypes("int"); private static final CallMatcher INDEX_OF = instanceCall(CommonClassNames.JAVA_UTIL_LIST, "indexOf").parameterTypes(CommonClassNames.JAVA_LANG_OBJECT); + private static final CallMatcher COLLECTIONS_SORT = staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "sort"); + private static final CallMatcher LIST_SORT = instanceCall(CommonClassNames.JAVA_UTIL_LIST, "sort").parameterTypes( + CommonClassNames.JAVA_UTIL_COMPARATOR); private static final CallMapper HANDLERS = new CallMapper() @@ -57,7 +60,8 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca .register(CONTAINS, SingletonContainsHandler::handler) .register(anyOf(CONTAINS, CONTAINS_KEY), ContainsBeforeAddRemoveHandler::handler) .register(REMOVE_BY_INDEX, RedundantIndexOfHandler::handler) - .register(AS_LIST, RedundantAsListForIterationHandler::handler); + .register(AS_LIST, RedundantAsListForIterationHandler::handler) + .register(AS_LIST, RedundantSortAsListHandler::handler); @NotNull @Override @@ -457,6 +461,64 @@ public class RedundantCollectionOperationInspection extends AbstractBaseJavaLoca } } + private static class RedundantSortAsListHandler implements RedundantCollectionOperationHandler { + private final boolean myCollectionsSort; + + public RedundantSortAsListHandler(boolean collectionsSort) { + myCollectionsSort = collectionsSort; + } + + @Override + public void performFix(@NotNull Project project, @NotNull PsiMethodCallExpression call) { + PsiExpression[] args = call.getArgumentList().getExpressions(); + if (args.length != 1) return; + PsiExpression array = args[0]; + String sortMethod = CommonClassNames.JAVA_UTIL_ARRAYS + ".sort"; + if (myCollectionsSort) { + PsiMethodCallExpression outerCall = PsiTreeUtil.getParentOfType(call, PsiMethodCallExpression.class); + if (outerCall == null) return; + CommentTracker ct = new CommentTracker(); + ct.replaceAndRestoreComments(call, ct.markUnchanged(array)); + ct = new CommentTracker(); + ct.replaceAndRestoreComments(outerCall, sortMethod + ct.text(outerCall.getArgumentList())); + } + else { + PsiMethodCallExpression chainedCall = ExpressionUtils.getCallForQualifier(call); + if (chainedCall == null) return; + PsiExpression[] chainedCallArgs = chainedCall.getArgumentList().getExpressions(); + if (chainedCallArgs.length != 1) return; + PsiExpression comparator = chainedCallArgs[0]; + CommentTracker ct = new CommentTracker(); + ct.replaceAndRestoreComments(chainedCall, sortMethod + "(" + ct.text(array) + "," + ct.text(comparator) + ")"); + } + } + + @NotNull + @Override + public String getReplacement() { + return "Arrays.sort()"; + } + + static RedundantSortAsListHandler handler(PsiMethodCallExpression call) { + if (MethodCallUtils.isVarArgCall(call)) return null; + PsiExpression arg = call.getArgumentList().getExpressions()[0]; + if (!(arg.getType() instanceof PsiArrayType)) return null; + PsiExpressionList parent = tryCast(PsiUtil.skipParenthesizedExprUp(call.getParent()), PsiExpressionList.class); + if (parent != null) { + PsiMethodCallExpression outerCall = tryCast(parent.getParent(), PsiMethodCallExpression.class); + if (COLLECTIONS_SORT.test(outerCall) && PsiTreeUtil.isAncestor(parent.getExpressions()[0], call, false)) { + return new RedundantSortAsListHandler(true); + } + } else { + PsiMethodCallExpression chainedCall = ExpressionUtils.getCallForQualifier(call); + if (LIST_SORT.test(chainedCall)) { + return new RedundantSortAsListHandler(false); + } + } + return null; + } + } + private static class RedundantCollectionOperationFix implements LocalQuickFix { private final RedundantCollectionOperationHandler myHandler;