StreamToLoop: special handling of max().orElse(MIN_VALUE), etc.

This commit is contained in:
Tagir Valeev
2018-03-12 15:22:15 +07:00
parent ebbdbbe432
commit c1f2c5c380
4 changed files with 76 additions and 4 deletions

View File

@@ -502,6 +502,22 @@ public class StreamToLoopInspection extends AbstractBaseJavaLocalInspectionTool
return name;
}
public boolean tryUnwrapOrElse(@NotNull Number wantedValue) {
if (!(myStreamExpression instanceof PsiExpression)) return false;
PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myStreamExpression);
if (call == null ||
call.getParent() instanceof PsiExpressionStatement ||
!"orElse".equals(call.getMethodExpression().getReferenceName())) {
return false;
}
PsiExpression[] args = call.getArgumentList().getExpressions();
if (args.length == 1 && wantedValue.equals(ExpressionUtils.computeConstantExpression(args[0]))) {
myStreamExpression = call;
return true;
}
return false;
}
private static boolean isCompatibleType(@NotNull PsiVariable var, @NotNull PsiType type, @Nullable String mostAbstractAllowedType) {
if (EquivalenceChecker.getCanonicalPsiEquivalence().typesAreEquivalent(var.getType(), type)) return true;
if (mostAbstractAllowedType == null) return false;

View File

@@ -798,11 +798,13 @@ abstract class TerminalOperation extends Operation {
private final PsiType myType;
private final String myTemplate;
private @Nullable final FunctionHelper myComparator;
private final boolean myMax;
public MinMaxTerminalOperation(PsiType type, String template, @Nullable FunctionHelper comparator) {
public MinMaxTerminalOperation(PsiType type, String template, @Nullable FunctionHelper comparator, boolean max) {
myType = type;
myTemplate = template;
myComparator = comparator;
myMax = max;
}
@Override
@@ -812,8 +814,33 @@ abstract class TerminalOperation extends Operation {
}
}
Number getExtremeValue() {
if (PsiType.INT.equals(myType)) {
return myMax ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
if (PsiType.LONG.equals(myType)) {
return myMax ? Long.MIN_VALUE : Long.MAX_VALUE;
}
return null;
}
String getExtremeValueExpression() {
if (PsiType.INT.equals(myType)) {
return CommonClassNames.JAVA_LANG_INTEGER + (myMax ? ".MIN_VALUE" : ".MAX_VALUE");
}
if (PsiType.LONG.equals(myType)) {
return CommonClassNames.JAVA_LANG_LONG + (myMax ? ".MIN_VALUE" : ".MAX_VALUE");
}
return null;
}
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
if (getExtremeValue() != null && context.tryUnwrapOrElse(getExtremeValue())) {
String best = context.declareResult("best", myType, getExtremeValueExpression(), ResultKind.NON_FINAL);
String comparePredicate = myTemplate.replace("{best}", best).replace("{item}", inVar.getName());
return "if(" + comparePredicate + ")\n" + best + "=" + inVar + ";\n";
}
String seen = context.declare("seen", "boolean", "false");
String best = context.declareResult("best", myType, myType instanceof PsiPrimitiveType ? "0" : "null", ResultKind.UNKNOWN);
context.setFinisher(new ConditionalExpression.Optional(myType, seen, best));
@@ -837,16 +864,16 @@ abstract class TerminalOperation extends Operation {
String sign = max ? ">" : "<";
if(comparator == null) {
if (PsiType.INT.equals(elementType) || PsiType.LONG.equals(elementType)) {
return new MinMaxTerminalOperation(elementType, "{item}" + sign + "{best}", null);
return new MinMaxTerminalOperation(elementType, "{item}" + sign + "{best}", null, max);
}
if (PsiType.DOUBLE.equals(elementType)) {
return new MinMaxTerminalOperation(elementType, "java.lang.Double.compare({item},{best})" + sign + "0", null);
return new MinMaxTerminalOperation(elementType, "java.lang.Double.compare({item},{best})" + sign + "0", null, max);
}
}
else {
FunctionHelper fn = FunctionHelper.create(comparator, 2);
if(fn != null) {
return new MinMaxTerminalOperation(elementType, "{comparator}"+sign+"0", fn);
return new MinMaxTerminalOperation(elementType, "{comparator}" + sign + "0", fn, max);
}
}
return null;

View File

@@ -104,6 +104,26 @@ public class Main {
return seen ? best : supplier.getAsInt();
}
public static int testMinMaxValue(List<String> strings) {
int best = Integer.MAX_VALUE;
for (String string : strings) {
int length = string.length();
if (length < best)
best = length;
}
return best;
}
public static long testMaxMinValue(List<String> strings) {
long max = Long.MIN_VALUE;
for (String string : strings) {
long length = string.length();
if (length > max)
max = length;
}
return max;
}
public static void main(String[] args) {
System.out.println(testMaxComparator(Arrays.asList()));
System.out.println(testMaxComparator(Arrays.asList("a", "bbb", "cc", "d", "eee")));

View File

@@ -36,6 +36,15 @@ public class Main {
return strings.stream().mapToInt(String::length).min().orElseGet(supplier);
}
public static int testMinMaxValue(List<String> strings) {
return strings.stream().mapToInt(String::length).min().orElse(Integer.MAX_VALUE);
}
public static long testMaxMinValue(List<String> strings) {
long max = strings.stream().mapToLong(String::length).max().orElse(Long.MIN_VALUE);
return max;
}
public static void main(String[] args) {
System.out.println(testMaxComparator(Arrays.asList()));
System.out.println(testMaxComparator(Arrays.asList("a", "bbb", "cc", "d", "eee")));