diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java index dccd759579f7..134705e78994 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java18api/Java8CollectionsApiInspection.java @@ -15,15 +15,21 @@ */ package com.intellij.codeInspection.java18api; +import com.intellij.codeInsight.FileModificationService; import com.intellij.codeInsight.daemon.QuickFixBundle; import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.EquivalenceChecker; +import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -52,6 +58,23 @@ public class Java8CollectionsApiInspection extends BaseJavaBatchLocalInspectionT return PsiElementVisitor.EMPTY_VISITOR; } return new JavaElementVisitor() { + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + PsiElement nameElement = expression.getMethodExpression().getReferenceNameElement(); + if(nameElement != null && expression.getArgumentList().getExpressions().length == 2 && + "sort".equals(nameElement.getText())) { + PsiMethod method = expression.resolveMethod(); + if(method != null) { + PsiClass containingClass = method.getContainingClass(); + if(containingClass != null && CommonClassNames.JAVA_UTIL_COLLECTIONS.equals(containingClass.getQualifiedName())) { + holder.registerProblem(nameElement, QuickFixBundle.message("java.8.collections.api.inspection.sort.description"), + new ReplaceWithListSortFix()); + } + } + } + } + @Override public void visitConditionalExpression(PsiConditionalExpression expression) { final ConditionInfo conditionInfo = extractConditionInfo(expression.getCondition()); @@ -296,4 +319,37 @@ public class Java8CollectionsApiInspection extends BaseJavaBatchLocalInspectionT return myInverted; } } + + private static class ReplaceWithListSortFix implements LocalQuickFix { + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return QuickFixBundle.message("java.8.collections.api.inspection.sort.fix.name"); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getStartElement(); + PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class); + if(methodCallExpression != null) { + PsiExpression[] args = methodCallExpression.getArgumentList().getExpressions(); + if(args.length == 2) { + PsiExpression list = args[0]; + PsiExpression comparator = args[1]; + String replacement = list.getText()+".sort("+comparator.getText()+")"; + if (!FileModificationService.getInstance().preparePsiElementForWrite(element.getContainingFile())) return; + methodCallExpression + .replace(JavaPsiFacade.getElementFactory(project).createExpressionFromText(replacement, methodCallExpression)); + } + } + } + } } \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java8CollectionsApi/afterSort.java b/java/java-tests/testData/inspection/java8CollectionsApi/afterSort.java new file mode 100644 index 000000000000..9755b2b17874 --- /dev/null +++ b/java/java-tests/testData/inspection/java8CollectionsApi/afterSort.java @@ -0,0 +1,9 @@ +// "Replace with List.sort" "true" +import java.util.Collections; +import java.util.List; + +public class Main { + public static void doSort(List list) { + list.sort(String.CASE_INSENSITIVE_ORDER); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java8CollectionsApi/beforeSort.java b/java/java-tests/testData/inspection/java8CollectionsApi/beforeSort.java new file mode 100644 index 000000000000..2fc0635b9c34 --- /dev/null +++ b/java/java-tests/testData/inspection/java8CollectionsApi/beforeSort.java @@ -0,0 +1,9 @@ +// "Replace with List.sort" "true" +import java.util.Collections; +import java.util.List; + +public class Main { + public static void doSort(List list) { + Collections.sort(list, String.CASE_INSENSITIVE_ORDER); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/java8CollectionsApi/beforeSortSingleArg.java b/java/java-tests/testData/inspection/java8CollectionsApi/beforeSortSingleArg.java new file mode 100644 index 000000000000..824237089fbd --- /dev/null +++ b/java/java-tests/testData/inspection/java8CollectionsApi/beforeSortSingleArg.java @@ -0,0 +1,9 @@ +// "Replace with List.sort" "false" +import java.util.Collections; +import java.util.List; + +public class Main { + public static void doSort(List list) { + Collections.sort(list); + } +} \ No newline at end of file diff --git a/resources-en/src/inspectionDescriptions/Java8CollectionsApi.html b/resources-en/src/inspectionDescriptions/Java8CollectionsApi.html index ee30be059d44..1eaeefae767e 100644 --- a/resources-en/src/inspectionDescriptions/Java8CollectionsApi.html +++ b/resources-en/src/inspectionDescriptions/Java8CollectionsApi.html @@ -1,11 +1,17 @@ -Inspection detects usages of java's Map when they can be replaced with methods putIfAbsent. For example: -
-  if (!map.containsKey(aKey)) {
-    map.put(aKey, aValue);
-  }
-
-
+Inspection detects usages of pre-Java 8 Collection API methods which can be simplified using new Java 8 API. + +The following cases are covered by this inspection: +
    +
  • Map.putIfAbsent method could be used to replace the code like this: +
    +      if (!map.containsKey(aKey)) {
    +        map.put(aKey, aValue);
    +      }
    +    
    +
  • +
  • List.sort instance method could be used to replace Collections.sort static method
  • +
\ No newline at end of file diff --git a/resources-en/src/messages/QuickFixBundle.properties b/resources-en/src/messages/QuickFixBundle.properties index e489562a2923..9760adac7187 100644 --- a/resources-en/src/messages/QuickFixBundle.properties +++ b/resources-en/src/messages/QuickFixBundle.properties @@ -286,6 +286,8 @@ add.exception.from.field.initializer.to.constructor.throws.family.text=Add excep java.8.collections.api.inspection.description=If statement could be replaced with single method java.8.collections.api.inspection.fix.family.name=Replace with single method call java.8.collections.api.inspection.fix.text=Replace with ''{0}'' method call +java.8.collections.api.inspection.sort.description=Collections.sort(list, comparator) could be replaced with list.sort(comparator) +java.8.collections.api.inspection.sort.fix.name=Replace with List.sort wrap.with.optional.parameter.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''java.util.Optional'' wrap.with.optional.single.parameter.text=Wrap using 'java.util.Optional'