mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-05-06 05:10:22 +07:00
StreamToLoopInspection: support some simple StreamEx scenarios; support Java 9 takeWhile/dropWhile
This commit is contained in:
@@ -552,7 +552,7 @@ abstract class FunctionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static class InlinedFunctionHelper extends FunctionHelper {
|
||||
static class InlinedFunctionHelper extends FunctionHelper {
|
||||
private final int myArgCount;
|
||||
private final String myTemplate;
|
||||
private PsiExpression myExpression;
|
||||
|
||||
@@ -71,6 +71,17 @@ abstract class Operation {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1);
|
||||
return fn == null ? null : new FilterOperation(fn);
|
||||
}
|
||||
if(name.equals("takeWhile") && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1);
|
||||
return fn == null ? null : new TakeWhileOperation(fn);
|
||||
}
|
||||
if(name.equals("dropWhile") && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1);
|
||||
return fn == null ? null : new DropWhileOperation(fn);
|
||||
}
|
||||
if (name.equals("nonNull") && args.length == 0) { // StreamEx
|
||||
return new FilterOperation(new FunctionHelper.InlinedFunctionHelper(PsiType.BOOLEAN, 1, "{0} != null"));
|
||||
}
|
||||
if(name.equals("sorted") && !(inType instanceof PsiPrimitiveType)) {
|
||||
return new SortedOperation(args.length == 1 ? args[0] : null);
|
||||
}
|
||||
@@ -138,6 +149,33 @@ abstract class Operation {
|
||||
}
|
||||
}
|
||||
|
||||
static class TakeWhileOperation extends LambdaIntermediateOperation {
|
||||
public TakeWhileOperation(FunctionHelper fn) {
|
||||
super(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return "if(" + BoolUtils.getNegatedExpressionText(myFn.getExpression()) + ") {\n" +
|
||||
context.getBreakStatement() + "}\n" + code;
|
||||
}
|
||||
}
|
||||
|
||||
static class DropWhileOperation extends LambdaIntermediateOperation {
|
||||
public DropWhileOperation(FunctionHelper fn) {
|
||||
super(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
String dropping = context.declare("dropping", "boolean", "true");
|
||||
return "if(" + dropping + ") {\n" +
|
||||
"if(" + myFn.getText() + ") {\ncontinue;\n}\n" +
|
||||
dropping + "=false;\n" +
|
||||
"}\n" + code;
|
||||
}
|
||||
}
|
||||
|
||||
static class PeekOperation extends LambdaIntermediateOperation {
|
||||
public PeekOperation(FunctionHelper fn) {
|
||||
super(fn);
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToL
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.StreamApiUtil;
|
||||
@@ -65,30 +66,36 @@ abstract class SourceOperation extends Operation {
|
||||
String className = aClass.getQualifiedName();
|
||||
if(className == null) return null;
|
||||
if ((name.equals("range") || name.equals("rangeClosed")) && args.length == 2 && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && (className.equals(CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM) ||
|
||||
className.equals(CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM))) {
|
||||
PsiModifier.STATIC) && InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) {
|
||||
return new RangeSource(args[0], args[1], name.equals("rangeClosed"));
|
||||
}
|
||||
if (name.equals("of") && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && className.startsWith("java.util.stream.")) {
|
||||
if(args.length == 1) {
|
||||
PsiModifier.STATIC) && InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) {
|
||||
if (method.getParameterList().getParametersCount() != 1) return null;
|
||||
if (args.length == 1) {
|
||||
PsiType type = args[0].getType();
|
||||
if(type instanceof PsiArrayType) {
|
||||
PsiType componentType = ((PsiArrayType)type).getComponentType();
|
||||
if(StreamApiUtil.getStreamElementType(callType).isAssignableFrom(componentType)) {
|
||||
return new ForEachSource(args[0]);
|
||||
}
|
||||
PsiType componentType = null;
|
||||
if (type instanceof PsiArrayType) {
|
||||
componentType = ((PsiArrayType)type).getComponentType();
|
||||
}
|
||||
else if (InheritanceUtil.isInheritor(type, CommonClassNames.JAVA_LANG_ITERABLE)) {
|
||||
componentType = PsiUtil.substituteTypeParameter(type, CommonClassNames.JAVA_LANG_ITERABLE, 0, false);
|
||||
}
|
||||
PsiType elementType = StreamApiUtil.getStreamElementType(callType);
|
||||
if (componentType != null && elementType.isAssignableFrom(componentType)) {
|
||||
return new ForEachSource(args[0]);
|
||||
}
|
||||
if (type == null || !elementType.isAssignableFrom(type)) return null;
|
||||
}
|
||||
return new ExplicitSource(call);
|
||||
}
|
||||
if (name.equals("generate") && args.length == 1 && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && className.startsWith("java.util.stream.")) {
|
||||
PsiModifier.STATIC) && InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 0);
|
||||
return fn == null ? null : new GenerateSource(fn, null);
|
||||
}
|
||||
if (name.equals("iterate") && args.length == 2 && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && className.startsWith("java.util.stream.")) {
|
||||
PsiModifier.STATIC) && InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[1], 1);
|
||||
return fn == null ? null : new IterateSource(args[0], fn);
|
||||
}
|
||||
@@ -155,7 +162,7 @@ abstract class SourceOperation extends Operation {
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myCall = (PsiMethodCallExpression)replaceVarReference(myCall, oldName, newName, context);
|
||||
myCall = replaceVarReference(myCall, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -313,7 +320,7 @@ abstract class SourceOperation extends Operation {
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myCall = (PsiMethodCallExpression)replaceVarReference(myCall, oldName, newName, context);
|
||||
myCall = replaceVarReference(myCall, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -36,6 +36,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.RedundantCastUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.*;
|
||||
import one.util.streamex.IntStreamEx;
|
||||
import one.util.streamex.StreamEx;
|
||||
@@ -56,9 +57,9 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance(StreamToLoopInspection.class);
|
||||
|
||||
// To quickly filter out most of the non-interesting method calls
|
||||
private static final Set<String> SUPPORTED_TERMINALS = StreamEx.of("count", "sum", "summaryStatistics", "reduce", "collect",
|
||||
"findFirst", "findAny", "anyMatch", "allMatch", "noneMatch",
|
||||
"toArray", "average", "forEach", "forEachOrdered", "min", "max").toSet();
|
||||
private static final Set<String> SUPPORTED_TERMINALS = ContainerUtil.set(
|
||||
"count", "sum", "summaryStatistics", "reduce", "collect", "findFirst", "findAny", "anyMatch", "allMatch", "noneMatch", "toArray",
|
||||
"average", "forEach", "forEachOrdered", "min", "max", "toList", "toSet");
|
||||
|
||||
public boolean SUPPORT_UNKNOWN_SOURCES = false;
|
||||
|
||||
|
||||
@@ -94,6 +94,12 @@ abstract class TerminalOperation extends Operation {
|
||||
PsiType optionalElementType = OptionalUtil.getOptionalElementType(resultType);
|
||||
return optionalElementType == null ? null : new FindTerminalOperation(optionalElementType.getCanonicalText());
|
||||
}
|
||||
if(name.equals("toList") && args.length == 0) {
|
||||
return ToCollectionTerminalOperation.toList(resultType);
|
||||
}
|
||||
if(name.equals("toSet") && args.length == 0) {
|
||||
return ToCollectionTerminalOperation.toSet(resultType);
|
||||
}
|
||||
if((name.equals("anyMatch") || name.equals("allMatch") || name.equals("noneMatch")) && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1);
|
||||
return fn == null ? null : new MatchTerminalOperation(fn, name);
|
||||
@@ -170,8 +176,7 @@ abstract class TerminalOperation extends Operation {
|
||||
return ToCollectionTerminalOperation.toList(resultType);
|
||||
case "toSet":
|
||||
if (collectorArgs.length != 0) return null;
|
||||
return new ToCollectionTerminalOperation(resultType,
|
||||
FunctionHelper.newObjectSupplier(resultType, CommonClassNames.JAVA_UTIL_HASH_SET), "set");
|
||||
return ToCollectionTerminalOperation.toSet(resultType);
|
||||
case "toCollection":
|
||||
if (collectorArgs.length != 1) return null;
|
||||
fn = FunctionHelper.create(collectorArgs[0], 0);
|
||||
@@ -719,7 +724,14 @@ abstract class TerminalOperation extends Operation {
|
||||
|
||||
@NotNull
|
||||
private static ToCollectionTerminalOperation toList(@NotNull PsiType resultType) {
|
||||
return new ToCollectionTerminalOperation(resultType, FunctionHelper.newObjectSupplier(resultType, CommonClassNames.JAVA_UTIL_ARRAY_LIST), "list");
|
||||
return new ToCollectionTerminalOperation(resultType,
|
||||
FunctionHelper.newObjectSupplier(resultType, CommonClassNames.JAVA_UTIL_ARRAY_LIST), "list");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ToCollectionTerminalOperation toSet(@NotNull PsiType resultType) {
|
||||
return new ToCollectionTerminalOperation(resultType,
|
||||
FunctionHelper.newObjectSupplier(resultType, CommonClassNames.JAVA_UTIL_HASH_SET), "set");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Test {
|
||||
// Mock Java 9 methods with inheritor
|
||||
interface MyStream<T> extends Stream<T> {
|
||||
<R> MyStream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
|
||||
|
||||
MyStream<T> takeWhile(Predicate<? super T> predicate);
|
||||
|
||||
MyStream<T> dropWhile(Predicate<? super T> predicate);
|
||||
|
||||
static <T> MyStream<T> of(List<T> list) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void test(List<String> data) {
|
||||
List<String> xyz = new ArrayList<>();
|
||||
boolean dropping = true;
|
||||
OUTER:
|
||||
for (String s : data) {
|
||||
for (String s1 : Arrays.asList(s, s + s)) {
|
||||
if (s1.isEmpty()) {
|
||||
break OUTER;
|
||||
}
|
||||
if (dropping) {
|
||||
if (s1.length() < 3) {
|
||||
continue;
|
||||
}
|
||||
dropping = false;
|
||||
}
|
||||
xyz.add(s1);
|
||||
}
|
||||
}
|
||||
System.out.println(xyz);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Test {
|
||||
// Mock Java 9 methods with inheritor
|
||||
interface MyStream<T> extends Stream<T> {
|
||||
<R> MyStream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
|
||||
|
||||
MyStream<T> takeWhile(Predicate<? super T> predicate);
|
||||
|
||||
MyStream<T> dropWhile(Predicate<? super T> predicate);
|
||||
|
||||
static <T> MyStream<T> of(List<T> list) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void test(List<String> data) {
|
||||
List<String> xyz = MyStream.of(data)
|
||||
.flatMap(s -> Stream.of(s, s + s)).takeWhile(s -> !s.isEmpty())
|
||||
.dropWhile(s -> s.length() < 3).col<caret>lect(Collectors.toList());
|
||||
System.out.println(xyz);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user