IDEA-176720 Simplify Stream.of(xyz).anyMatch(predicate) to predicate.test(xyz)

This commit is contained in:
Tagir Valeev
2017-08-07 15:58:13 +07:00
parent c2461b8e6e
commit 3910c47718
3 changed files with 144 additions and 14 deletions
@@ -49,7 +49,7 @@ import java.util.*;
import java.util.stream.Stream;
import static com.intellij.util.ObjectUtils.tryCast;
import static com.siyeh.ig.callMatcher.CallMatcher.instanceCall;
import static com.siyeh.ig.callMatcher.CallMatcher.*;
import static com.siyeh.ig.psiutils.MethodCallUtils.getQualifierMethodCall;
/**
@@ -81,8 +81,10 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
instanceCall(CommonClassNames.JAVA_UTIL_OPTIONAL, "isPresent").parameterCount(0);
private static final CallMatcher BOOLEAN_EQUALS =
instanceCall(CommonClassNames.JAVA_LANG_BOOLEAN, "equals").parameterCount(1);
private static final CallMatcher STREAM_OF =
staticCall(CommonClassNames.JAVA_UTIL_STREAM_STREAM, "of").parameterTypes("T");
private static final CallMatcher STREAM_MATCH = CallMatcher.anyOf(STREAM_ANY_MATCH, STREAM_NONE_MATCH, STREAM_ALL_MATCH);
private static final CallMatcher STREAM_MATCH = anyOf(STREAM_ANY_MATCH, STREAM_NONE_MATCH, STREAM_ALL_MATCH);
private static final CallMapper<CallChainSimplification> CALL_TO_FIX_MAPPER = new CallMapper<>(
ReplaceCollectionStreamFix.handler(),
@@ -92,7 +94,8 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
ReplaceWithElementIterationFix.handler(),
ReplaceForEachMethodFix.handler(),
RemoveBooleanIdentityFix.handler(),
ReplaceWithPeekFix.handler()
ReplaceWithPeekFix.handler(),
SimpleStreamOfFix.handler()
).registerAll(SimplifyMatchNegationFix.handlers());
private static final Logger LOG = Logger.getInstance(SimplifyStreamApiCallChainsInspection.class);
@@ -205,7 +208,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
}
static CallMatcher collectorMatcher(String name, int parameterCount) {
return CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, name).parameterCount(parameterCount);
return staticCall(CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, name).parameterCount(parameterCount);
}
static boolean isParentNegated(PsiMethodCallExpression methodCall) {
@@ -279,14 +282,14 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
private static class ReplaceCollectionStreamFix implements CallChainSimplification {
private static final CallMatcher EMPTY_LIST =
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptyList").parameterCount(0);
staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptyList").parameterCount(0);
private static final CallMatcher EMPTY_SET =
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptySet").parameterCount(0);
staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "emptySet").parameterCount(0);
private static final CallMatcher SINGLETON_LIST =
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singletonList").parameterCount(1);
staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singletonList").parameterCount(1);
private static final CallMatcher SINGLETON =
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singleton").parameterCount(1);
private static final CallMatcher AS_LIST = CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_ARRAYS, "asList").parameterCount(1);
staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singleton").parameterCount(1);
private static final CallMatcher AS_LIST = staticCall(CommonClassNames.JAVA_UTIL_ARRAYS, "asList").parameterCount(1);
private static final CallMapper<ReplaceCollectionStreamFix> COLLECTION_TO_STREAM_MAPPER = new CallMapper<ReplaceCollectionStreamFix>()
.register(EMPTY_LIST,
@@ -786,6 +789,85 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
}
}
private static class SimpleStreamOfFix implements CallChainSimplification {
private static final CallMatcher LAMBDA_TERMINAL =
instanceCall(CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM, "anyMatch", "allMatch", "noneMatch", "forEach", "forEachOrdered")
.parameterCount(1);
private static final CallMatcher OPTIONAL_TERMINAL =
anyOf(instanceCall(CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM, "findFirst", "findAny").parameterCount(0),
instanceCall(CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM, "min", "max", "reduce").parameterCount(1));
private ReplacementMode myMode;
enum ReplacementMode {
OPTIONAL, FUNCTION, NEGATED_FUNCTION
}
public SimpleStreamOfFix(ReplacementMode mode) {
myMode = mode;
}
@Override
public String getName() {
switch (myMode) {
case OPTIONAL:
return "Replace with 'Optional.of'";
default:
return "Use Stream element explicitly";
}
}
@Override
public String getMessage() {
return "Unnecessary single-element Stream";
}
@Override
public PsiElement simplify(PsiMethodCallExpression streamOfCall) {
PsiExpression streamOfArg = ArrayUtil.getFirstElement(streamOfCall.getArgumentList().getExpressions());
if (streamOfArg == null) return null;
PsiMethodCallExpression nextCall = ExpressionUtils.getCallForQualifier(streamOfCall);
PsiExpression nextArg = ArrayUtil.getFirstElement(nextCall.getArgumentList().getExpressions());
String replacement;
if (myMode == ReplacementMode.OPTIONAL) {
replacement = CommonClassNames.JAVA_UTIL_OPTIONAL + ".of(" + streamOfArg.getText() + ")";
}
else {
if (nextArg == null) return null;
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(nextArg.getType());
if (method == null) return null;
String name = method.getName();
replacement =
(myMode == ReplacementMode.NEGATED_FUNCTION ? "!" : "") + nextArg.getText() + "." + name + "(" + streamOfArg.getText() + ")";
}
PsiElementFactory factory = JavaPsiFacade.getElementFactory(streamOfCall.getProject());
PsiExpression result = factory.createExpressionFromText(replacement, streamOfCall);
return nextCall.replace(result);
}
public static CallHandler<CallChainSimplification> handler() {
return CallHandler.of(STREAM_OF, call -> {
PsiMethodCallExpression nextCall = ExpressionUtils.getCallForQualifier(call);
if (nextCall == null) return null;
if (LAMBDA_TERMINAL.test(nextCall)) {
PsiExpression arg = PsiUtil.skipParenthesizedExprDown(nextCall.getArgumentList().getExpressions()[0]);
if (arg instanceof PsiReferenceExpression || arg instanceof PsiMethodCallExpression) {
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(arg.getType());
boolean negate = "noneMatch".equals(nextCall.getMethodExpression().getReferenceName());
if (method == null ||
negate && PsiUtil.skipParenthesizedExprUp(nextCall.getParent()) instanceof PsiExpressionStatement) {
return null;
}
return new SimpleStreamOfFix(negate ? ReplacementMode.NEGATED_FUNCTION : ReplacementMode.FUNCTION);
}
}
if (OPTIONAL_TERMINAL.test(nextCall)) {
return new SimpleStreamOfFix(ReplacementMode.OPTIONAL);
}
return null;
});
}
}
private static class ReplaceWithBoxedFix implements CallChainSimplification {
private static final CallMatcher MAP_TO_OBJ = instanceCall(CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM, "mapToObj").parameterCount(1);
@@ -955,11 +1037,11 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
instanceCall(CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM, "map", "mapToLong", "mapToDouble", "mapToObj")
.parameterCount(1);
private static final CallMatcher INT_STREAM_RANGE =
CallMatcher.staticCall(CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM, "range").parameterTypes("int", "int");
staticCall(CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM, "range").parameterTypes("int", "int");
private static final CallMatcher MIN_INT =
CallMatcher.anyOf(
CallMatcher.staticCall(CommonClassNames.JAVA_LANG_MATH, "min").parameterTypes("int", "int"),
CallMatcher.staticCall(CommonClassNames.JAVA_LANG_INTEGER, "min").parameterTypes("int", "int"));
anyOf(
staticCall(CommonClassNames.JAVA_LANG_MATH, "min").parameterTypes("int", "int"),
staticCall(CommonClassNames.JAVA_LANG_INTEGER, "min").parameterTypes("int", "int"));
private final String myName;
@@ -1274,7 +1356,7 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns
}
private static class ReplaceStreamSupportWithCollectionStreamFix implements CallChainSimplification {
private static final CallMatcher STREAM_SUPPORT = CallMatcher.staticCall("java.util.stream.StreamSupport", "stream")
private static final CallMatcher STREAM_SUPPORT = staticCall("java.util.stream.StreamSupport", "stream")
.parameterTypes("java.util.Spliterator", "boolean");
private static final CallMatcher SPLITERATOR =
instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "spliterator").parameterCount(0);
@@ -0,0 +1,24 @@
// "Fix all 'Simplify stream API call chains' problems in file" "true"
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
class MyClass {
void test(String someStr) {
Predicate<String> predicate = "foo"::equals;
boolean b = !predicate.test(someStr);
Stream.of(someStr).noneMatch(predicate);
boolean x = predicate.test(someStr);
boolean y = predicate.test(someStr);
boolean z = Stream.of(someStr).allMatch(unresolved);
Consumer<String> cons = System.out::println;
cons.accept(someStr);
Optional<String> first = Optional.of(someStr);
Optional<String> joined = Optional.of(someStr);
Optional<String> max = Optional.of(someStr);
}
}
@@ -0,0 +1,24 @@
// "Fix all 'Simplify stream API call chains' problems in file" "true"
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
class MyClass {
void test(String someStr) {
Predicate<String> predicate = "foo"::equals;
boolean b = Stream.o<caret>f(someStr).noneMatch(predicate);
Stream.of(someStr).noneMatch(predicate);
boolean x = Stream.of(someStr).anyMatch(predicate);
boolean y = Stream.of(someStr).allMatch(predicate);
boolean z = Stream.of(someStr).allMatch(unresolved);
Consumer<String> cons = System.out::println;
Stream.of(someStr).forEach(cons);
Optional<String> first = Stream.of(someStr).findFirst();
Optional<String> joined = Stream.of(someStr).reduce(String::concat);
Optional<String> max = Stream.of(someStr).max(String.CASE_INSENSITIVE_ORDER);
}
}