diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java index cd21db66ce5e..e6851105c7ae 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java @@ -126,8 +126,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo if (ExceptionUtil.getThrownCheckedExceptions(new PsiElement[] {body}).isEmpty()) { if (!(iteratedValueType instanceof PsiClassType && ((PsiClassType)iteratedValueType).isRaw()) && isCollectCall(body, statement.getIterationParameter())) { - holder.registerProblem(iteratedValue, "Can be replaced with collect call", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new ReplaceWithCollectCallFix()); + boolean addAll = isAddAllCall(statement, body); + holder.registerProblem(iteratedValue, "Can be replaced with " + (addAll ? "addAll call" : "collect call"), + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + new ReplaceWithCollectCallFix("Replace with " + (addAll ? "addAll" : "collect"))); } else if (REPLACE_TRIVIAL_FOREACH || !isTrivial(body, statement.getIterationParameter())) { holder.registerProblem(iteratedValue, "Can be replaced with foreach call", @@ -147,6 +149,17 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo }; } + private static boolean isAddAllCall(PsiForeachStatement statement, PsiStatement body) { + final PsiIfStatement ifStatement = extractIfStatement(body); + if (ifStatement == null) { + final PsiParameter parameter = statement.getIterationParameter(); + final PsiMethodCallExpression methodCallExpression = extractAddCall(body, null); + LOG.assertTrue(methodCallExpression != null); + return isIdentityMapping(parameter, methodCallExpression.getArgumentList().getExpressions()[0]); + } + return false; + } + private static boolean isCollectCall(PsiStatement body, final PsiParameter parameter) { PsiIfStatement ifStatement = extractIfStatement(body); final PsiMethodCallExpression methodCallExpression = extractAddCall(body, ifStatement); @@ -267,6 +280,10 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo }) != null; } + private static boolean isIdentityMapping(PsiParameter parameter, PsiExpression mapperCall) { + return mapperCall instanceof PsiReferenceExpression && ((PsiReferenceExpression)mapperCall).resolve() == parameter; + } + private static class ReplaceWithForeachCallFix implements LocalQuickFix { private final String myForEachMethodName; @@ -368,6 +385,13 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } private static class ReplaceWithCollectCallFix implements LocalQuickFix { + + private final String myName; + + public ReplaceWithCollectCallFix(String name) { + myName = name; + } + @NotNull @Override public String getName() { @@ -377,7 +401,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo @NotNull @Override public String getFamilyName() { - return "Replace with collect"; + return myName; } @Override @@ -385,15 +409,27 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo final PsiForeachStatement foreachStatement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiForeachStatement.class); if (foreachStatement != null) { if (!FileModificationService.getInstance().preparePsiElementForWrite(foreachStatement)) return; + final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); PsiStatement body = foreachStatement.getBody(); final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (body != null && iteratedValue != null) { final PsiParameter parameter = foreachStatement.getIterationParameter(); - final StringBuilder builder = new StringBuilder(getIteratedValueText(iteratedValue) + ".stream()"); - final PsiIfStatement ifStatement = extractIfStatement(body); final PsiMethodCallExpression methodCallExpression = extractAddCall(body, ifStatement); + if (methodCallExpression == null) return; + + if (isAddAllCall(foreachStatement, body)) { + restoreComments(foreachStatement, body); + final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); + final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() : ""; + final String callText = StringUtil.getQualifiedName(qualifierText, "addAll(" + getIteratedValueText(iteratedValue) + ");"); + PsiElement result = foreachStatement.replace(elementFactory.createStatementFromText(callText, foreachStatement)); + reformatWhenNeeded(project, result); + return; + } + final StringBuilder builder = new StringBuilder(getIteratedValueText(iteratedValue) + ".stream()"); + builder.append(createFiltersChainText(body, parameter, ifStatement)); builder.append(createMapperFunctionalExpressionText(project, parameter, methodCallExpression.getArgumentList().getExpressions()[0])); @@ -401,7 +437,6 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo PsiElement result = null; try { final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); - final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); if (qualifierExpression instanceof PsiReferenceExpression) { final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve(); if (resolve instanceof PsiVariable) { @@ -428,14 +463,18 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo simplifyRedundantCast(result); } finally { - if (result != null) { - CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(result)); - } + reformatWhenNeeded(project, result); } } } } + private static void reformatWhenNeeded(@NotNull Project project, PsiElement result) { + if (result != null) { + CodeStyleManager.getInstance(project).reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(result)); + } + } + private static String createInitializerReplacementText(PsiType varType, PsiExpression initializer) { final PsiType initializerType = initializer.getType(); final PsiClassType rawType = initializerType instanceof PsiClassType ? ((PsiClassType)initializerType).rawType() : null; @@ -478,10 +517,6 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } return iteration; } - - private static boolean isIdentityMapping(PsiParameter parameter, PsiExpression mapperCall) { - return mapperCall instanceof PsiReferenceExpression && ((PsiReferenceExpression)mapperCall).resolve() == parameter; - } } private static void simplifyRedundantCast(PsiElement result) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAnotherInstance.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAnotherInstance.java index 13bdc5459fd3..ae642322ec02 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAnotherInstance.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAnotherInstance.java @@ -1,13 +1,12 @@ -// "Replace with collect" "true" +// "Replace with addAll" "true" import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; class Sample { List foo = new ArrayList<>(); String foo(){ Sample sm = new Sample(); - sm.foo.addAll(foo.stream().collect(Collectors.toList())); + sm.foo.addAll(foo); return null; } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectIdentityMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectIdentityMap.java index ea95020b1b09..6615b554a0cf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectIdentityMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterCollectIdentityMap.java @@ -1,11 +1,11 @@ -// "Replace with collect" "true" +// "Replace with addAll" "true" import java.util.*; -import java.util.stream.Collectors; public class Collect { class Person {} void collectNames(List persons){ - List names = persons.stream().collect(Collectors.toList()); + List names = new ArrayList<>(); + names.addAll(persons); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnotherInstance.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnotherInstance.java index e0d9d2ed91ed..4964119f8574 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnotherInstance.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnotherInstance.java @@ -1,4 +1,4 @@ -// "Replace with collect" "true" +// "Replace with addAll" "true" import java.util.ArrayList; import java.util.List; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectIdentityMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectIdentityMap.java index 9f708f63e02c..27b968a4856b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectIdentityMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeCollectIdentityMap.java @@ -1,4 +1,4 @@ -// "Replace with collect" "true" +// "Replace with addAll" "true" import java.util.*; public class Collect {