StreamToLoop: unwrap negation and ternary; minor refactoring

This commit is contained in:
Tagir Valeev
2016-12-12 17:27:53 +07:00
parent 38ded66633
commit 810445f21d
9 changed files with 129 additions and 12 deletions
@@ -95,6 +95,15 @@ interface Condition {
return String.valueOf(myInvert);
}
public Boolean negate() {
return new Boolean(myCondition, !myInvert);
}
public Plain toPlain(String type, String trueBranch, String falseBranch) {
return myInvert ? new Plain(type, myCondition, falseBranch, trueBranch) :
new Plain(type, myCondition, trueBranch, falseBranch);
}
@Override
public String asExpression() {
return myInvert ? myCondition : "!("+myCondition+")";
@@ -35,6 +35,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.util.RefactoringUtil;
import com.siyeh.ig.psiutils.BoolUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
import com.siyeh.ig.psiutils.StreamApiUtil;
@@ -441,11 +442,21 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
myFinisher = finisher;
}
public void setFinisher(Condition condition) {
if(condition instanceof Condition.Optional) {
condition = tryUnwrapOptional((Condition.Optional)condition, expr -> true);
}
setFinisher(condition.asExpression());
}
public String assignAndBreak(Condition condition) {
Predicate<PsiExpression> predicate = expr -> PsiUtil.skipParenthesizedExprUp(expr.getParent()) instanceof PsiReturnStatement;
if(condition instanceof Condition.Optional) {
condition = tryUnwrapOptional((Condition.Optional)condition, predicate);
}
if(condition instanceof Condition.Boolean) {
condition = tryUnwrapBoolean((Condition.Boolean)condition);
}
if(predicate.test(myPlaceholder)) {
setFinisher(condition.getFalseBranch());
return "return "+condition.getTrueBranch()+";";
@@ -454,6 +465,28 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
return found + " = " +condition.getTrueBranch()+";\n" + getBreakStatement();
}
private Condition tryUnwrapBoolean(Condition.Boolean condition) {
PsiExpression negation = BoolUtils.findNegation(myPlaceholder);
if(negation != null) {
myPlaceholder = negation;
condition = condition.negate();
}
PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent());
if(parent instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)parent;
if(PsiTreeUtil.isAncestor(ternary.getCondition(), myPlaceholder, false)) {
myPlaceholder = ternary;
PsiType type = ternary.getType();
PsiExpression thenExpression = ternary.getThenExpression();
PsiExpression elseExpression = ternary.getElseExpression();
if (type != null && thenExpression != null && elseExpression != null) {
return condition.toPlain(type.getCanonicalText(), thenExpression.getText(), elseExpression.getText());
}
}
}
return condition;
}
@NotNull
private Condition tryUnwrapOptional(Condition.Optional condition, Predicate<PsiExpression> predicate) {
PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier(myPlaceholder);
@@ -484,10 +517,6 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
return condition;
}
public void setOptionalUnwrapperFinisher(String seenCheck, String presentExpression, String type) {
setFinisher(tryUnwrapOptional(new Condition.Optional(type, seenCheck, presentExpression), expr -> true).asExpression());
}
public Project getProject() {
return myStatement.getProject();
}
@@ -333,7 +333,7 @@ abstract class TerminalOperation extends Operation {
String seen = context.declare("seen", "boolean", "false");
String accumulator = context.declareResult("acc", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null");
myUpdater.transform(context, accumulator, inVar.getName());
context.setOptionalUnwrapperFinisher(seen, accumulator, myType);
context.setFinisher(new Condition.Optional(myType, seen, accumulator));
String ifClause = "if(!" + seen + ") {\n" +
seen + "=true;\n" +
accumulator + "=" + inVar + ";\n" +
@@ -400,12 +400,10 @@ abstract class TerminalOperation extends Operation {
String count = context.declare("count", "long", "0");
String seenCheck = count + ">0";
String result = (myDoubleAccumulator ? "" : "(double)") + sum + "/" + count;
if (myUseOptional) {
context.setOptionalUnwrapperFinisher(seenCheck, result, "double");
}
else {
context.setFinisher(seenCheck + "?" + result + ":0.0");
}
Condition condition = myUseOptional ?
new Condition.Optional("double", seenCheck, result) :
new Condition.Plain("double", seenCheck, result, "0.0");
context.setFinisher(condition);
return sum + "+=" + inVar + ";\n" + count + "++;\n";
}
}
@@ -668,7 +666,7 @@ abstract class TerminalOperation extends Operation {
String seen = context.declare("seen", "boolean", "false");
String best = context.declareResult("best", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null");
String type = myType;
context.setOptionalUnwrapperFinisher(seen, best, type);
context.setFinisher(new Condition.Optional(type, seen, best));
return "if(!"+seen+" || "+myTemplate.replace("{best}", best).replace("{item}", inVar.getName()).replace("{comparator}", comparator)+") {\n" +
seen+"=true;\n"+
best+"="+inVar+";\n}\n";
@@ -0,0 +1,17 @@
// "Replace Stream API chain with loop" "true"
import java.util.Arrays;
import java.util.Objects;
public class Main {
boolean test(String[] strings) {
for (String s : strings) {
if (Objects.nonNull(s)) {
if (!s.startsWith("xyz")) {
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,17 @@
// "Replace Stream API chain with loop" "true"
import java.util.Arrays;
import java.util.Objects;
public class Main {
String test(String[] strings) {
for (String s : strings) {
if (Objects.nonNull(s)) {
if (!s.startsWith("xyz")) {
return "s";
}
}
}
return null;
}
}
@@ -0,0 +1,17 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Objects;
public class Main {
String test(List<List<String>> strings) {
for (List<String> string : strings) {
if (Objects.nonNull(string)) {
for (String s : string) {
return "abc";
}
}
}
return "xyz";
}
}
@@ -0,0 +1,10 @@
// "Replace Stream API chain with loop" "true"
import java.util.Arrays;
import java.util.Objects;
public class Main {
boolean test(String[] strings) {
return !Arrays.stream(strings).filter(Objects::nonNull).allM<caret>atch(s -> s.startsWith("xyz"));
}
}
@@ -0,0 +1,10 @@
// "Replace Stream API chain with loop" "true"
import java.util.Arrays;
import java.util.Objects;
public class Main {
String test(String[] strings) {
return Arrays.stream(strings).filter(Objects::nonNull).an<caret>yMatch(s -> !s.startsWith("xyz")) ? "s" : null;
}
}
@@ -0,0 +1,10 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Objects;
public class Main {
String test(List<List<String>> strings) {
return !strings.stream().filter(Objects::nonNull).flatMap(List::stream).fin<caret>dFirst().isPresent() ? "xyz" : "abc";
}
}