mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
StreamToLoopInspection: unwrap && and || chains; copy return statement in found/not found places; do not eagerly evaluate non-trivial ternary branch
This commit is contained in:
@@ -99,6 +99,10 @@ interface ConditionalExpression {
|
||||
return new Boolean(myCondition, !myInvert);
|
||||
}
|
||||
|
||||
public boolean isInverted() {
|
||||
return myInvert;
|
||||
}
|
||||
|
||||
public Plain toPlain(String type, String trueBranch, String falseBranch) {
|
||||
return myInvert ? new Plain(type, myCondition, falseBranch, trueBranch) :
|
||||
new Plain(type, myCondition, trueBranch, falseBranch);
|
||||
|
||||
@@ -44,7 +44,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static com.intellij.codeInspection.streamToLoop.Operation.FlatMapOperation;
|
||||
|
||||
@@ -521,25 +520,33 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
|
||||
public void setFinisher(ConditionalExpression conditionalExpression) {
|
||||
if(conditionalExpression instanceof ConditionalExpression.Optional) {
|
||||
conditionalExpression = tryUnwrapOptional((ConditionalExpression.Optional)conditionalExpression, expr -> true);
|
||||
conditionalExpression = tryUnwrapOptional((ConditionalExpression.Optional)conditionalExpression, true);
|
||||
}
|
||||
setFinisher(conditionalExpression.asExpression());
|
||||
}
|
||||
|
||||
public String assignAndBreak(ConditionalExpression conditionalExpression) {
|
||||
Predicate<PsiElement> predicate = expr -> PsiUtil.skipParenthesizedExprUp(expr.getParent()) instanceof PsiReturnStatement;
|
||||
PsiStatement statement = PsiTreeUtil.getParentOfType(myPlaceholder, PsiStatement.class);
|
||||
boolean inReturn = statement instanceof PsiReturnStatement;
|
||||
if(conditionalExpression instanceof ConditionalExpression.Optional) {
|
||||
conditionalExpression = tryUnwrapOptional((ConditionalExpression.Optional)conditionalExpression, predicate);
|
||||
conditionalExpression = tryUnwrapOptional((ConditionalExpression.Optional)conditionalExpression, inReturn);
|
||||
}
|
||||
if(conditionalExpression instanceof ConditionalExpression.Boolean) {
|
||||
conditionalExpression = tryUnwrapBoolean((ConditionalExpression.Boolean)conditionalExpression);
|
||||
if (conditionalExpression instanceof ConditionalExpression.Boolean) {
|
||||
conditionalExpression = tryUnwrapBoolean((ConditionalExpression.Boolean)conditionalExpression, inReturn);
|
||||
}
|
||||
if(predicate.test(myPlaceholder)) {
|
||||
if (inReturn) {
|
||||
setFinisher(conditionalExpression.getFalseBranch());
|
||||
return "return " + conditionalExpression.getTrueBranch() + ";";
|
||||
Object mark = new Object();
|
||||
PsiTreeUtil.mark(myPlaceholder, mark);
|
||||
PsiElement returnCopy = statement.copy();
|
||||
PsiElement placeHolderCopy = PsiTreeUtil.releaseMark(returnCopy, mark);
|
||||
LOG.assertTrue(placeHolderCopy != null);
|
||||
PsiElement replacement = placeHolderCopy.replace(createExpression(conditionalExpression.getTrueBranch()));
|
||||
return (placeHolderCopy == returnCopy ? replacement : returnCopy).getText();
|
||||
}
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent());
|
||||
if(parent instanceof PsiIfStatement && conditionalExpression.getTrueBranch().equals(String.valueOf(true))) {
|
||||
if(parent instanceof PsiIfStatement && conditionalExpression instanceof ConditionalExpression.Boolean &&
|
||||
!((ConditionalExpression.Boolean)conditionalExpression).isInverted()) {
|
||||
PsiIfStatement ifStatement = (PsiIfStatement)parent;
|
||||
if(ifStatement.getElseBranch() == null) {
|
||||
PsiStatement thenStatement = ControlFlowUtils.stripBraces(ifStatement.getThenBranch());
|
||||
@@ -573,32 +580,51 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
return found + " = " + conditionalExpression.getTrueBranch() + ";\n" + getBreakStatement();
|
||||
}
|
||||
|
||||
private ConditionalExpression tryUnwrapBoolean(ConditionalExpression.Boolean condition) {
|
||||
private ConditionalExpression tryUnwrapBoolean(ConditionalExpression.Boolean condition, boolean unwrapLazilyEvaluated) {
|
||||
if (myPlaceholder instanceof PsiExpression) {
|
||||
PsiExpression negation = BoolUtils.findNegation((PsiExpression)myPlaceholder);
|
||||
if (negation != null) {
|
||||
myPlaceholder = negation;
|
||||
condition = condition.negate();
|
||||
}
|
||||
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent());
|
||||
if (parent instanceof PsiConditionalExpression) {
|
||||
ConditionalExpression candidate = null;
|
||||
if (parent instanceof PsiPolyadicExpression) {
|
||||
PsiPolyadicExpression expression = (PsiPolyadicExpression)parent;
|
||||
PsiExpression[] operands = expression.getOperands();
|
||||
if (operands.length > 1 && PsiTreeUtil.isAncestor(operands[0], myPlaceholder, false)) {
|
||||
IElementType type = expression.getOperationTokenType();
|
||||
if (type.equals(JavaTokenType.ANDAND)) {
|
||||
candidate = condition
|
||||
.toPlain("boolean", StreamEx.of(operands, 1, operands.length).map(PsiExpression::getText).joining(" && "), "false");
|
||||
} else if (type.equals(JavaTokenType.OROR)) {
|
||||
candidate = condition
|
||||
.toPlain("boolean", "true", StreamEx.of(operands, 1, operands.length).map(PsiExpression::getText).joining(" || "));
|
||||
}
|
||||
}
|
||||
} else 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());
|
||||
candidate = condition.toPlain(type.getCanonicalText(), thenExpression.getText(), elseExpression.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (candidate != null &&
|
||||
(unwrapLazilyEvaluated || ExpressionUtils.isSimpleExpression(createExpression(candidate.getFalseBranch())))) {
|
||||
myPlaceholder = parent;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ConditionalExpression tryUnwrapOptional(ConditionalExpression.Optional condition, Predicate<PsiElement> predicate) {
|
||||
private ConditionalExpression tryUnwrapOptional(ConditionalExpression.Optional condition, boolean unwrapLazilyEvaluated) {
|
||||
if (myPlaceholder instanceof PsiExpression) {
|
||||
PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myPlaceholder);
|
||||
if (call != null && !(call.getParent() instanceof PsiExpressionStatement)) {
|
||||
@@ -613,7 +639,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
if ("orElse".equals(name)) {
|
||||
absentExpression = args[0].getText();
|
||||
}
|
||||
else if ("orElseGet".equals(name) && predicate.test(call)) {
|
||||
else if (unwrapLazilyEvaluated && "orElseGet".equals(name)) {
|
||||
FunctionHelper helper = FunctionHelper.create(args[0], 0);
|
||||
if (helper != null) {
|
||||
helper.transform(this);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
for (String s : list) {
|
||||
if (s.isEmpty()) {
|
||||
return list.stream().anyMatch(Objects::isNull);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
boolean x = false;
|
||||
for (String s : list) {
|
||||
if (s.isEmpty()) {
|
||||
x = list.stream().anyMatch(Objects::isNull);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
boolean b = true;
|
||||
for (String s : list) {
|
||||
if (s.isEmpty()) {
|
||||
b = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean x = b && list.stream().anyMatch(Objects::isNull) && list.size() > 2;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
for (String s : list) {
|
||||
if (s.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return list.stream().anyMatch(Objects::isNull);
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,12 @@ import java.util.Optional;
|
||||
|
||||
public class Main {
|
||||
private static test(List<String> packages) {
|
||||
Optional<String> found = Optional.empty();
|
||||
for (String s : packages) {
|
||||
if (s.startsWith("xyz")) {
|
||||
found = Optional.of(s);
|
||||
break;
|
||||
return Optional.of(s).filter(pkg -> pkg.endsWith("abc")).isPresent();
|
||||
}
|
||||
}
|
||||
return found.filter(pkg -> pkg.endsWith("abc")).isPresent();
|
||||
return Optional.<String>empty().filter(pkg -> pkg.endsWith("abc")).isPresent();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
return list.stream().<caret>anyMatch(String::isEmpty) && list.stream().anyMatch(Objects::isNull);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
boolean x = list.stream().<caret>anyMatch(String::isEmpty) && list.stream().anyMatch(Objects::isNull);
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
boolean x = !list.stream().<caret>anyMatch(String::isEmpty) && list.stream().anyMatch(Objects::isNull) && list.size() > 2;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testCond(List<String> list) {
|
||||
return !list.stream().<caret>anyMatch(String::isEmpty) && list.stream().anyMatch(Objects::isNull);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user