foreach -> collect: simplify to addAll on collections if no filter/mapper is present (IDEA-150515)

This commit is contained in:
Anna Kozlova
2016-01-22 14:29:01 +03:00
parent ded792b1f7
commit 5d70440851
5 changed files with 55 additions and 21 deletions
@@ -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) {
@@ -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<String> foo = new ArrayList<>();
String foo(){
Sample sm = new Sample();
sm.foo.addAll(foo.stream().collect(Collectors.toList()));
sm.foo.addAll(foo);
return null;
}
}
@@ -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<Person> persons){
List<Person> names = persons.stream().collect(Collectors.toList());
List<Person> names = new ArrayList<>();
names.addAll(persons);
}
}
@@ -1,4 +1,4 @@
// "Replace with collect" "true"
// "Replace with addAll" "true"
import java.util.ArrayList;
import java.util.List;
@@ -1,4 +1,4 @@
// "Replace with collect" "true"
// "Replace with addAll" "true"
import java.util.*;
public class Collect {