IDEA-162694 Improve "Merge filter chain" intention

This commit is contained in:
Tagir Valeev
2016-10-20 11:19:25 +07:00
parent 62dc8b8241
commit 74ae9731a8
11 changed files with 150 additions and 28 deletions

View File

@@ -73,7 +73,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
final PsiExpression[] expressions = argumentList.getExpressions();
if (!name.startsWith("map") && expressions.length == 0) return true;
if (expressions.length != 1) return false;
if (!isSupportedForConversion(expressions[0], true)) return false;
if (!StreamRefactoringUtil.isRefactoringCandidate(expressions[0], true)) return false;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) return false;
@@ -81,17 +81,6 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
return InheritanceUtil.isInheritor(containingClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM);
}
private static boolean isSupportedForConversion(PsiExpression expression, boolean requireExpressionLambda) {
if(expression instanceof PsiLambdaExpression) {
PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)expression;
return lambdaExpression.getParameterList().getParametersCount() == 1 &&
(!requireExpressionLambda || LambdaUtil.extractSingleExpressionFromBody(lambdaExpression.getBody()) != null);
} else if(expression instanceof PsiMethodReferenceExpression) {
return LambdaRefactoringUtil.canConvertToLambda((PsiMethodReferenceExpression)expression);
}
return false;
}
@Nullable
private static PsiMethodCallExpression getNextExpressionToMerge(PsiMethodCallExpression methodCallExpression) {
PsiElement parent = methodCallExpression.getParent();
@@ -107,7 +96,7 @@ public class InlineStreamMapAction extends PsiElementBaseIntentionAction {
if (!nextName.equals("boxed") && !nextName.equals("asLongStream") && !nextName.equals("asDoubleStream")) return null;
return nextCall;
}
if (expressions.length != 1 || !isSupportedForConversion(expressions[0], false)) return null;
if (expressions.length != 1 || !StreamRefactoringUtil.isRefactoringCandidate(expressions[0], false)) return null;
return nextCall;
}

View File

@@ -27,9 +27,11 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.util.LambdaRefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
@@ -49,6 +51,7 @@ public class MergeFilterChainAction extends PsiElementBaseIntentionAction {
return getFilterToMerge((PsiMethodCallExpression)gParent) != null;
}
@Nullable
private static PsiMethodCallExpression getFilterToMerge(PsiMethodCallExpression methodCallExpression) {
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
if (qualifierExpression instanceof PsiMethodCallExpression && isFilterCall((PsiMethodCallExpression)qualifierExpression)) {
@@ -67,26 +70,20 @@ public class MergeFilterChainAction extends PsiElementBaseIntentionAction {
}
public static boolean isFilterCall(PsiMethodCallExpression methodCallExpression) {
if (!"filter".equals(methodCallExpression.getMethodExpression().getReferenceName())) return false;
String name = methodCallExpression.getMethodExpression().getReferenceName();
if (!"filter".equals(name) && !"anyMatch".equals(name)) return false;
final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
final PsiExpression[] expressions = argumentList.getExpressions();
if (expressions.length != 1) return false;
if (!(expressions[0] instanceof PsiLambdaExpression)) return false;
final PsiElement lambdaBody = ((PsiLambdaExpression)expressions[0]).getBody();
if (!(lambdaBody instanceof PsiExpression)) return false;
if (!StreamRefactoringUtil.isRefactoringCandidate(expressions[0], true)) return false;
final PsiMethod method = methodCallExpression.resolveMethod();
if (method == null) return false;
final PsiClass containingClass = method.getContainingClass();
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length == 1 &&
InheritanceUtil.isInheritor(containingClass, false, CommonClassNames.JAVA_UTIL_STREAM_STREAM) &&
InheritanceUtil.isInheritor(parameters[0].getType(), CommonClassNames.JAVA_UTIL_FUNCTION_PREDICATE)) {
return true;
}
return false;
return parameters.length == 1 &&
InheritanceUtil.isInheritor(containingClass, false, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM);
}
@NotNull
@@ -101,6 +98,19 @@ public class MergeFilterChainAction extends PsiElementBaseIntentionAction {
return CodeInsightBundle.message("intention.merge.filter.family");
}
@Nullable
private static PsiLambdaExpression getLambda(PsiMethodCallExpression call) {
PsiExpression[] expressions = call.getArgumentList().getExpressions();
if(expressions.length != 1) return null;
PsiExpression expression = expressions[0];
if(expression instanceof PsiLambdaExpression) return (PsiLambdaExpression)expression;
if (expression instanceof PsiMethodReferenceExpression) {
return LambdaRefactoringUtil
.convertMethodReferenceToLambda((PsiMethodReferenceExpression)expression, false, true);
}
return null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
try {
@@ -115,11 +125,16 @@ public class MergeFilterChainAction extends PsiElementBaseIntentionAction {
final PsiMethodCallExpression callToStay = filterCall.getTextLength() < filterToMerge.getTextLength() ? filterCall : filterToMerge;
final PsiMethodCallExpression callToEliminate = callToStay == filterCall ? filterToMerge : filterCall;
final PsiLambdaExpression targetLambda = (PsiLambdaExpression)callToStay.getArgumentList().getExpressions()[0];
String resultingOperation = callToEliminate.getMethodExpression().getReferenceName();
LOG.assertTrue(resultingOperation != null);
final PsiLambdaExpression targetLambda = getLambda(callToStay);
LOG.assertTrue(targetLambda != null, callToStay);
final PsiParameter[] parameters = targetLambda.getParameterList().getParameters();
final String name = parameters.length > 0 ? parameters[0].getName() : null;
final PsiLambdaExpression sourceLambda = (PsiLambdaExpression)callToEliminate.getArgumentList().getExpressions()[0];
final PsiLambdaExpression sourceLambda = getLambda(callToEliminate);
LOG.assertTrue(sourceLambda != null, callToEliminate);
if (name != null) {
final PsiParameter[] sourceLambdaParams = sourceLambda.getParameterList().getParameters();
if (sourceLambdaParams.length > 0 && !name.equals(sourceLambdaParams[0].getName())) {
@@ -132,14 +147,20 @@ public class MergeFilterChainAction extends PsiElementBaseIntentionAction {
}
}
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
PsiElement nameElement = callToStay.getMethodExpression().getReferenceNameElement();
LOG.assertTrue(nameElement != null);
if(!resultingOperation.equals(nameElement.getText())) {
nameElement.replace(factory.createIdentifier(resultingOperation));
}
PsiElement targetBody = targetLambda.getBody();
LOG.assertTrue(targetBody instanceof PsiExpression);
final PsiElement sourceLambdaBody = sourceLambda.getBody();
LOG.assertTrue(sourceLambdaBody instanceof PsiExpression);
final PsiExpression compoundExpression = JavaPsiFacade.getElementFactory(project)
final PsiExpression compoundExpression = factory
.createExpressionFromText(
ParenthesesUtils.getText((PsiExpression)targetBody, ParenthesesUtils.OR_PRECEDENCE) + " && " +
ParenthesesUtils.getText((PsiExpression)sourceLambdaBody, ParenthesesUtils.OR_PRECEDENCE), sourceLambda);

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInsight.intention.impl;
import com.intellij.psi.LambdaUtil;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiLambdaExpression;
import com.intellij.psi.PsiMethodReferenceExpression;
import com.intellij.refactoring.util.LambdaRefactoringUtil;
/**
* @author Tagir Valeev
*/
public class StreamRefactoringUtil {
static boolean isRefactoringCandidate(PsiExpression expression, boolean requireExpressionLambda) {
if(expression instanceof PsiLambdaExpression) {
PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)expression;
return lambdaExpression.getParameterList().getParametersCount() == 1 &&
(!requireExpressionLambda || LambdaUtil.extractSingleExpressionFromBody(lambdaExpression.getBody()) != null);
} else if(expression instanceof PsiMethodReferenceExpression) {
return LambdaRefactoringUtil.canConvertToLambda((PsiMethodReferenceExpression)expression);
}
return false;
}
}

View File

@@ -0,0 +1,9 @@
// "Merge filter's chain" "true"
import java.util.stream.LongStream;
public class Main {
void test() {
System.out.println(LongStream.range(0, 100).anyMatch(x -> x > 20 && x < 50));
}
}

View File

@@ -0,0 +1,10 @@
// "Merge filter's chain" "true"
import java.util.List;
import java.util.Objects;
public class Main {
void test(List<String> list) {
list.stream().filter((o) -> Objects.nonNull(o) && o.isEmpty()).forEach(System.out::println);
}
}

View File

@@ -0,0 +1,9 @@
// "Merge filter's chain" "true"
import java.util.stream.IntStream;
public class Main {
void test() {
System.out.println(IntStream.range(0, 100).filter(x -> x > 20 && x < 50).count());
}
}

View File

@@ -0,0 +1,9 @@
// "Merge filter's chain" "true"
import java.util.List;
public class Main {
void test(List<String> list) {
list.stream().filter(s -> s.trim().isEmpty() && s.isEmpty()).forEach(System.out::println);
}
}

View File

@@ -0,0 +1,9 @@
// "Merge filter's chain" "true"
import java.util.stream.LongStream;
public class Main {
void test() {
System.out.println(LongStream.range(0, 100).filter(x -> x > 20).anyM<caret>atch(x -> x < 50));
}
}

View File

@@ -0,0 +1,10 @@
// "Merge filter's chain" "true"
import java.util.List;
import java.util.Objects;
public class Main {
void test(List<String> list) {
list.stream().filter(Objects::nonNull).filt<caret>er(String::isEmpty).forEach(System.out::println);
}
}

View File

@@ -0,0 +1,9 @@
// "Merge filter's chain" "true"
import java.util.stream.IntStream;
public class Main {
void test() {
System.out.println(IntStream.range(0, 100).filter(x -> x > 20).fil<caret>ter(x -> x < 50).count());
}
}

View File

@@ -0,0 +1,9 @@
// "Merge filter's chain" "true"
import java.util.List;
public class Main {
void test(List<String> list) {
list.stream().filte<caret>r(s -> s.trim().isEmpty()).filter(String::isEmpty).forEach(System.out::println);
}
}