mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-161194 Add inspection to optimize Stream.filter(...).findAny().isPresent() to anyMatch(...)
This commit is contained in:
+163
-78
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
@@ -36,6 +37,8 @@ import java.util.Arrays;
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance("#" + SimplifyStreamApiCallChainsInspection.class.getName());
|
||||
|
||||
private static final String FOR_EACH_METHOD = "forEach";
|
||||
private static final String FOR_EACH_ORDERED_METHOD = "forEachOrdered";
|
||||
private static final String STREAM_METHOD = "stream";
|
||||
@@ -47,6 +50,11 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
private static final String SINGLETON_LIST_METHOD = "singletonList";
|
||||
private static final String SINGLETON_METHOD = "singleton";
|
||||
private static final String COLLECT_METHOD = "collect";
|
||||
private static final String IS_PRESENT_METHOD = "isPresent";
|
||||
private static final String FIND_ANY_METHOD = "findAny";
|
||||
private static final String FIND_FIRST_METHOD = "findFirst";
|
||||
private static final String FILTER_METHOD = "filter";
|
||||
private static final String ANY_MATCH_METHOD = "anyMatch";
|
||||
|
||||
private static final String COUNTING_COLLECTOR = "counting";
|
||||
private static final String MIN_BY_COLLECTOR = "minBy";
|
||||
@@ -74,97 +82,132 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression methodCall) {
|
||||
final PsiMethod method = methodCall.resolveMethod();
|
||||
if (isCallOf(method, CommonClassNames.JAVA_UTIL_COLLECTION, STREAM_METHOD, 0)) {
|
||||
final PsiMethodCallExpression qualifierCall = getQualifierMethodCall(methodCall);
|
||||
if (qualifierCall == null) return;
|
||||
final PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
ReplaceCollectionStreamFix fix = null;
|
||||
if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_ARRAYS, AS_LIST_METHOD, 1)) {
|
||||
if (hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ArraysAsListSingleArrayFix();
|
||||
}
|
||||
else {
|
||||
fix = new ReplaceWithStreamOfFix("Arrays.asList()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_LIST_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ReplaceSingletonWithStreamOfFix("Collections.singletonList()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ReplaceSingletonWithStreamOfFix("Collections.singleton()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_LIST_METHOD, 0)) {
|
||||
fix = new ReplaceWithStreamEmptyFix(EMPTY_LIST_METHOD);
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_SET_METHOD, 0)) {
|
||||
fix = new ReplaceWithStreamEmptyFix(EMPTY_SET_METHOD);
|
||||
}
|
||||
if (fix != null) {
|
||||
holder.registerProblem(methodCall, null, fix.getMessage(), new SimplifyCallChainFix(fix));
|
||||
}
|
||||
handleCollectionStream(methodCall);
|
||||
}
|
||||
else if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, COLLECT_METHOD, 1)) {
|
||||
PsiElement parameter = methodCall.getArgumentList().getExpressions()[0];
|
||||
if(parameter instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)parameter;
|
||||
PsiMethod collectorMethod = collectorCall.resolveMethod();
|
||||
ReplaceCollectorFix fix = null;
|
||||
if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, COUNTING_COLLECTOR, 0)) {
|
||||
fix = new ReplaceCollectorFix(COUNTING_COLLECTOR, "count()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MIN_BY_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(MIN_BY_COLLECTOR, "min({0})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAX_BY_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(MAX_BY_COLLECTOR, "max({0})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAPPING_COLLECTOR, 2)) {
|
||||
fix = new ReplaceCollectorFix(MAPPING_COLLECTOR, "map({0}).collect({1})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({0})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 2)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({0}, {1})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 3)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "map({1}).reduce({0}, {2})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_INT_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_INT_COLLECTOR, "mapToInt({0}).sum()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_LONG_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_LONG_COLLECTOR, "mapToLong({0}).sum()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_DOUBLE_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_DOUBLE_COLLECTOR, "mapToDouble({0}).sum()", false);
|
||||
}
|
||||
if (fix != null &&
|
||||
collectorCall.getArgumentList().getExpressions().length == collectorMethod.getParameterList().getParametersCount()) {
|
||||
TextRange range = methodCall.getTextRange();
|
||||
PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement();
|
||||
if(nameElement != null) {
|
||||
range = new TextRange(nameElement.getTextOffset(), range.getEndOffset());
|
||||
handleStreamCollect(methodCall);
|
||||
}
|
||||
else if (isCallOf(method, CommonClassNames.JAVA_UTIL_OPTIONAL, IS_PRESENT_METHOD, 0)) {
|
||||
handleOptionalIsPresent(methodCall);
|
||||
}
|
||||
else {
|
||||
handleStreamForEach(methodCall, method);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOptionalIsPresent(PsiMethodCallExpression methodCall) {
|
||||
PsiExpression optionalQualifier = methodCall.getMethodExpression().getQualifierExpression();
|
||||
if(optionalQualifier instanceof PsiMethodCallExpression) {
|
||||
PsiMethod optionalProducer = ((PsiMethodCallExpression)optionalQualifier).resolveMethod();
|
||||
if (isCallOf(optionalProducer, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FIND_FIRST_METHOD, 0) ||
|
||||
isCallOf(optionalProducer, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FIND_ANY_METHOD, 0)) {
|
||||
PsiExpression streamQualifier = ((PsiMethodCallExpression)optionalQualifier).getMethodExpression().getQualifierExpression();
|
||||
if(streamQualifier instanceof PsiMethodCallExpression) {
|
||||
PsiMethod streamMethod = ((PsiMethodCallExpression)streamQualifier).resolveMethod();
|
||||
if(isCallOf(streamMethod, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FILTER_METHOD, 1)) {
|
||||
ReplaceOptionalIsPresentChainFix fix = new ReplaceOptionalIsPresentChainFix(optionalProducer.getName());
|
||||
holder
|
||||
.registerProblem(methodCall, getCallChainRange(methodCall, (PsiMethodCallExpression)streamQualifier), fix.getMessage(),
|
||||
new SimplifyCallChainFix(fix));
|
||||
}
|
||||
holder.registerProblem(methodCall, range.shiftRight(-methodCall.getTextOffset()), fix.getMessage(),
|
||||
new SimplifyCallChainFix(fix));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStreamForEach(PsiMethodCallExpression methodCall, PsiMethod method) {
|
||||
final String name;
|
||||
if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_METHOD, 1)) {
|
||||
name = FOR_EACH_METHOD;
|
||||
}
|
||||
else if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_ORDERED_METHOD, 1)) {
|
||||
name = FOR_EACH_ORDERED_METHOD;
|
||||
}
|
||||
else {
|
||||
final String name;
|
||||
if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_METHOD, 1)) {
|
||||
name = FOR_EACH_METHOD;
|
||||
return;
|
||||
}
|
||||
final PsiMethodCallExpression qualifierCall = getQualifierMethodCall(methodCall);
|
||||
if (qualifierCall == null) return;
|
||||
final PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTION, STREAM_METHOD, 0)) {
|
||||
final ReplaceStreamMethodFix fix = new ReplaceStreamMethodFix(name, FOR_EACH_METHOD, true);
|
||||
holder
|
||||
.registerProblem(methodCall, getCallChainRange(methodCall, qualifierCall), fix.getMessage(), new SimplifyCallChainFix(fix));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStreamCollect(PsiMethodCallExpression methodCall) {
|
||||
PsiElement parameter = methodCall.getArgumentList().getExpressions()[0];
|
||||
if(parameter instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)parameter;
|
||||
PsiMethod collectorMethod = collectorCall.resolveMethod();
|
||||
ReplaceCollectorFix fix = null;
|
||||
if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, COUNTING_COLLECTOR, 0)) {
|
||||
fix = new ReplaceCollectorFix(COUNTING_COLLECTOR, "count()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MIN_BY_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(MIN_BY_COLLECTOR, "min({0})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAX_BY_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(MAX_BY_COLLECTOR, "max({0})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAPPING_COLLECTOR, 2)) {
|
||||
fix = new ReplaceCollectorFix(MAPPING_COLLECTOR, "map({0}).collect({1})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({0})", true);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 2)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({0}, {1})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 3)) {
|
||||
fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "map({1}).reduce({0}, {2})", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_INT_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_INT_COLLECTOR, "mapToInt({0}).sum()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_LONG_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_LONG_COLLECTOR, "mapToLong({0}).sum()", false);
|
||||
} else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_DOUBLE_COLLECTOR, 1)) {
|
||||
fix = new ReplaceCollectorFix(SUMMING_DOUBLE_COLLECTOR, "mapToDouble({0}).sum()", false);
|
||||
}
|
||||
else if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_ORDERED_METHOD, 1)) {
|
||||
name = FOR_EACH_ORDERED_METHOD;
|
||||
if (fix != null &&
|
||||
collectorCall.getArgumentList().getExpressions().length == collectorMethod.getParameterList().getParametersCount()) {
|
||||
TextRange range = methodCall.getTextRange();
|
||||
PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement();
|
||||
if(nameElement != null) {
|
||||
range = new TextRange(nameElement.getTextOffset(), range.getEndOffset());
|
||||
}
|
||||
holder.registerProblem(methodCall, range.shiftRight(-methodCall.getTextOffset()), fix.getMessage(),
|
||||
new SimplifyCallChainFix(fix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCollectionStream(PsiMethodCallExpression methodCall) {
|
||||
final PsiMethodCallExpression qualifierCall = getQualifierMethodCall(methodCall);
|
||||
if (qualifierCall == null) return;
|
||||
final PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
ReplaceCollectionStreamFix fix = null;
|
||||
if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_ARRAYS, AS_LIST_METHOD, 1)) {
|
||||
if (hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ArraysAsListSingleArrayFix();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
fix = new ReplaceWithStreamOfFix("Arrays.asList()");
|
||||
}
|
||||
final PsiMethodCallExpression qualifierCall = getQualifierMethodCall(methodCall);
|
||||
if (qualifierCall == null) return;
|
||||
final PsiMethod qualifier = qualifierCall.resolveMethod();
|
||||
if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTION, STREAM_METHOD, 0)) {
|
||||
final ReplaceStreamMethodFix fix = new ReplaceStreamMethodFix(name, FOR_EACH_METHOD, true);
|
||||
holder
|
||||
.registerProblem(methodCall, getCallChainRange(methodCall, qualifierCall), fix.getMessage(), new SimplifyCallChainFix(fix));
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_LIST_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ReplaceSingletonWithStreamOfFix("Collections.singletonList()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, SINGLETON_METHOD, 1)) {
|
||||
if (!hasSingleArrayArgument(qualifierCall)) {
|
||||
fix = new ReplaceSingletonWithStreamOfFix("Collections.singleton()");
|
||||
}
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_LIST_METHOD, 0)) {
|
||||
fix = new ReplaceWithStreamEmptyFix(EMPTY_LIST_METHOD);
|
||||
}
|
||||
else if (isCallOf(qualifier, CommonClassNames.JAVA_UTIL_COLLECTIONS, EMPTY_SET_METHOD, 0)) {
|
||||
fix = new ReplaceWithStreamEmptyFix(EMPTY_SET_METHOD);
|
||||
}
|
||||
if (fix != null) {
|
||||
holder.registerProblem(methodCall, null, fix.getMessage(), new SimplifyCallChainFix(fix));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -486,4 +529,46 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
|
||||
(myChangeSemantics ? " (may change semantics when result is null)" : "");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReplaceOptionalIsPresentChainFix implements CallChainFix {
|
||||
private final String myFindMethodName;
|
||||
|
||||
ReplaceOptionalIsPresentChainFix(String findMethodName) {
|
||||
myFindMethodName = findMethodName;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace Stream.filter()." + myFindMethodName + "().isPresent() with Stream.anyMatch()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression isPresentCall = (PsiMethodCallExpression)element;
|
||||
PsiExpression isPresentQualifier = isPresentCall.getMethodExpression().getQualifierExpression();
|
||||
if(isPresentQualifier instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression findCall = (PsiMethodCallExpression)isPresentQualifier;
|
||||
PsiExpression findQualifier = findCall.getMethodExpression().getQualifierExpression();
|
||||
if(findQualifier instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression filterCall = (PsiMethodCallExpression)findQualifier;
|
||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(element.getContainingFile())) return;
|
||||
PsiElement replacement = element.replace(filterCall);
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
PsiElement filterName = ((PsiMethodCallExpression)replacement).getMethodExpression().getReferenceNameElement();
|
||||
LOG.assertTrue(filterName != null);
|
||||
filterName.replace(factory.createIdentifier(ANY_MATCH_METHOD));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getMessage() {
|
||||
return "Stream.filter()." + myFindMethodName + "().isPresent() can be replaced with Stream.anyMatch()";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace Stream.filter().findAny().isPresent() with Stream.anyMatch()" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class FilterFindIsPresent {
|
||||
public static void test(List<String> list) {
|
||||
if(list.stream().anyMatch(l -> !l.isEmpty())) {
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace Stream.filter().findFirst().isPresent() with Stream.anyMatch()" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class FilterFindIsPresent {
|
||||
public static void test(List<String> list) {
|
||||
if(list.stream().anyMatch(l -> !l.isEmpty())) {
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace Stream.filter().findAny().isPresent() with Stream.anyMatch()" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class FilterFindIsPresent {
|
||||
public static void test(List<String> list) {
|
||||
if(list.stream().fi<caret>lter(l -> !l.isEmpty()).findAny().isPresent()) {
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace Stream.filter().findFirst().isPresent() with Stream.anyMatch()" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
class FilterFindIsPresent {
|
||||
public static void test(List<String> list) {
|
||||
if(list.stream().filter(l -> !l.isEmpty()).findFirst().isPre<caret>sent()) {
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user