mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
add support for binary operation reduction in stream migration
This commit is contained in:
+15
-12
@@ -21,7 +21,6 @@ import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils.InitializerUsageStatus;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -46,22 +45,25 @@ abstract class BaseStreamApiMigration {
|
||||
return myShouldWarn;
|
||||
}
|
||||
|
||||
static PsiElement replaceWithNumericAddition(PsiLoopStatement loopStatement,
|
||||
PsiVariable var,
|
||||
String streamText,
|
||||
PsiType expressionType) {
|
||||
static PsiElement replaceWithOperation(PsiLoopStatement loopStatement,
|
||||
PsiVariable var,
|
||||
String streamText,
|
||||
PsiType expressionType,
|
||||
OperationReductionMigration.ReductionOperation reductionOperation) {
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(loopStatement.getProject());
|
||||
restoreComments(loopStatement, loopStatement.getBody());
|
||||
InitializerUsageStatus status = ControlFlowUtils.getInitializerUsageStatus(var, loopStatement);
|
||||
if (status != ControlFlowUtils.InitializerUsageStatus.UNKNOWN) {
|
||||
if (status != InitializerUsageStatus.UNKNOWN) {
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if (ExpressionUtils.isZero(initializer)) {
|
||||
if (initializer != null && reductionOperation.getInitializerExpressionRestriction().test(initializer)) {
|
||||
PsiType type = var.getType();
|
||||
String replacement = (type.equals(expressionType) ? "" : "(" + type.getCanonicalText() + ") ") + streamText;
|
||||
String replacement = (type.isAssignableFrom(expressionType) ? "" : "(" + type.getCanonicalText() + ") ") + streamText;
|
||||
return replaceInitializer(loopStatement, var, initializer, replacement, status);
|
||||
}
|
||||
}
|
||||
return loopStatement.replace(elementFactory.createStatementFromText(var.getName() + "+=" + streamText + ";", loopStatement));
|
||||
return loopStatement
|
||||
.replace(elementFactory.createStatementFromText(var.getName() + reductionOperation.getOperation() + "=" + streamText + ";",
|
||||
loopStatement));
|
||||
}
|
||||
|
||||
static PsiElement replaceInitializer(PsiLoopStatement loopStatement,
|
||||
@@ -71,12 +73,13 @@ abstract class BaseStreamApiMigration {
|
||||
InitializerUsageStatus status) {
|
||||
Project project = loopStatement.getProject();
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
|
||||
if(status == ControlFlowUtils.InitializerUsageStatus.DECLARED_JUST_BEFORE) {
|
||||
if (status == ControlFlowUtils.InitializerUsageStatus.DECLARED_JUST_BEFORE) {
|
||||
initializer.replace(elementFactory.createExpressionFromText(replacement, loopStatement));
|
||||
removeLoop(loopStatement);
|
||||
return var;
|
||||
} else {
|
||||
if(status == ControlFlowUtils.InitializerUsageStatus.AT_WANTED_PLACE_ONLY) {
|
||||
}
|
||||
else {
|
||||
if (status == ControlFlowUtils.InitializerUsageStatus.AT_WANTED_PLACE_ONLY) {
|
||||
initializer.delete();
|
||||
}
|
||||
return
|
||||
|
||||
@@ -19,6 +19,8 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.codeInspection.streamMigration.OperationReductionMigration.SUM_OPERATION;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
@@ -39,6 +41,6 @@ class CountMigration extends BaseStreamApiMigration {
|
||||
PsiElement element = ((PsiReferenceExpression)operand).resolve();
|
||||
if (!(element instanceof PsiLocalVariable)) return null;
|
||||
PsiLocalVariable var = (PsiLocalVariable)element;
|
||||
return replaceWithNumericAddition(tb.getMainLoop(), var, tb.generate() + ".count()", PsiType.LONG);
|
||||
return replaceWithOperation(tb.getMainLoop(), var, tb.generate() + ".count()", PsiType.LONG, SUM_OPERATION);
|
||||
}
|
||||
}
|
||||
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamMigration;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Created by Roman Ivanov.
|
||||
*/
|
||||
public class OperationReductionMigration extends BaseStreamApiMigration {
|
||||
private final ReductionOperation myReductionOperation;
|
||||
|
||||
protected OperationReductionMigration(boolean shouldWarn,
|
||||
ReductionOperation context) {
|
||||
super(shouldWarn, "reduce()");
|
||||
myReductionOperation = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
PsiElement migrate(@NotNull Project project, @NotNull PsiStatement body, @NotNull TerminalBlock tb) {
|
||||
PsiAssignmentExpression assignment = tb.getSingleExpression(PsiAssignmentExpression.class);
|
||||
if (assignment == null) return null;
|
||||
PsiVariable var = StreamApiMigrationInspection.extractAccumulator(assignment, myReductionOperation.getCompoundAssignmentOp());
|
||||
if (var == null) return null;
|
||||
|
||||
PsiExpression operand = StreamApiMigrationInspection.extractOperand(assignment, myReductionOperation.getCompoundAssignmentOp());
|
||||
if (operand == null) return null;
|
||||
PsiType type = var.getType();
|
||||
|
||||
PsiType operandType = operand.getType();
|
||||
if (operandType != null && !TypeConversionUtil.isAssignable(type, operandType)) {
|
||||
operand = JavaPsiFacade.getElementFactory(project).createExpressionFromText(
|
||||
"(" + type.getCanonicalText() + ")" + ParenthesesUtils.getText(operand, ParenthesesUtils.MULTIPLICATIVE_PRECEDENCE), operand);
|
||||
}
|
||||
JavaCodeStyleManager javaStyle = JavaCodeStyleManager.getInstance(project);
|
||||
String leftOperand = javaStyle.suggestUniqueVariableName("a", body, true);
|
||||
String rightOperand = javaStyle.suggestUniqueVariableName("b", body, true);
|
||||
|
||||
if(type.equals(PsiType.BOOLEAN)) {
|
||||
type = PsiType.BOOLEAN.getBoxedType(body); // hack to avoid .map(b -> b) when boxing needed
|
||||
}
|
||||
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
String identity = initializer != null && myReductionOperation.getInitializerExpressionRestriction().test(initializer)
|
||||
? initializer.getText()
|
||||
: myReductionOperation.myIdentity;
|
||||
String stream = tb.add(new StreamApiMigrationInspection.MapOp(operand, tb.getVariable(), type)).generate()
|
||||
+ String.format(Locale.ENGLISH, ".reduce(%s, (%s, %s) -> %s %s %s)",
|
||||
identity, leftOperand, rightOperand, leftOperand,
|
||||
myReductionOperation.getOperation(), rightOperand);
|
||||
return replaceWithOperation(tb.getMainLoop(), var, stream, type, myReductionOperation);
|
||||
}
|
||||
|
||||
static class ReductionOperation {
|
||||
private final IElementType myCompoundAssignmentOp;
|
||||
private final Predicate<PsiExpression> myInitializerReplaceCondition;
|
||||
private final Predicate<PsiVariable> myAccumulatorRestriction;
|
||||
private final String myIdentity;
|
||||
private final String myOperation;
|
||||
|
||||
|
||||
public ReductionOperation(IElementType compoundAssignmentOp,
|
||||
Predicate<PsiExpression> initializerReplaceCondition,
|
||||
Predicate<PsiVariable> accumulatorRestriction,
|
||||
String identity,
|
||||
String operation) {
|
||||
myCompoundAssignmentOp = compoundAssignmentOp;
|
||||
myInitializerReplaceCondition = initializerReplaceCondition;
|
||||
myAccumulatorRestriction = accumulatorRestriction;
|
||||
myIdentity = identity;
|
||||
myOperation = operation;
|
||||
}
|
||||
|
||||
public IElementType getCompoundAssignmentOp() {
|
||||
return myCompoundAssignmentOp;
|
||||
}
|
||||
|
||||
public Predicate<PsiExpression> getInitializerExpressionRestriction() {
|
||||
return myInitializerReplaceCondition;
|
||||
}
|
||||
|
||||
public String getIdentity() {
|
||||
return myIdentity;
|
||||
}
|
||||
|
||||
public String getOperation() {
|
||||
return myOperation;
|
||||
}
|
||||
|
||||
public Predicate<PsiVariable> getAccumulatorRestriction() {
|
||||
return myAccumulatorRestriction;
|
||||
}
|
||||
}
|
||||
|
||||
static final ReductionOperation SUM_OPERATION = new ReductionOperation(
|
||||
JavaTokenType.PLUSEQ,
|
||||
ExpressionUtils::isZero,
|
||||
OperationReductionMigration::arithmeticTypeRestriction,
|
||||
"0",
|
||||
"+"
|
||||
);
|
||||
|
||||
static final ReductionOperation[] OPERATIONS = {
|
||||
new ReductionOperation(
|
||||
JavaTokenType.ASTERISKEQ,
|
||||
ExpressionUtils::isOne,
|
||||
OperationReductionMigration::arithmeticTypeRestriction,
|
||||
"1",
|
||||
"*"
|
||||
),
|
||||
new ReductionOperation(
|
||||
JavaTokenType.ANDEQ,
|
||||
expression -> Boolean.TRUE.equals(ExpressionUtils.computeConstantExpression(expression)),
|
||||
OperationReductionMigration::booleanTypeRestriction,
|
||||
"true",
|
||||
"&&"
|
||||
),
|
||||
new ReductionOperation(
|
||||
JavaTokenType.OREQ,
|
||||
expression -> Boolean.FALSE.equals(ExpressionUtils.computeConstantExpression(expression)),
|
||||
OperationReductionMigration::booleanTypeRestriction,
|
||||
"false",
|
||||
"||"
|
||||
),
|
||||
new ReductionOperation(
|
||||
JavaTokenType.OREQ,
|
||||
ExpressionUtils::isZero,
|
||||
OperationReductionMigration::arithmeticTypeRestriction,
|
||||
"0",
|
||||
"|"
|
||||
),
|
||||
new ReductionOperation(
|
||||
JavaTokenType.ANDEQ,
|
||||
OperationReductionMigration::isMinusOne,
|
||||
OperationReductionMigration::bitwiseTypeRestriction,
|
||||
"-1",
|
||||
"&"
|
||||
),
|
||||
new ReductionOperation(
|
||||
JavaTokenType.XOREQ,
|
||||
ExpressionUtils::isZero,
|
||||
OperationReductionMigration::bitwiseTypeRestriction,
|
||||
"0",
|
||||
"^"
|
||||
)
|
||||
};
|
||||
|
||||
private static boolean isMinusOne(PsiExpression expression) {
|
||||
Object constant = ExpressionUtils.computeConstantExpression(expression);
|
||||
if(constant == null) {
|
||||
return false;
|
||||
}
|
||||
return (constant instanceof Integer || constant instanceof Long) && ((Number)constant).longValue() == -1;
|
||||
}
|
||||
|
||||
static boolean bitwiseTypeRestriction(@NotNull PsiVariable variable) {
|
||||
return variable.getType() instanceof PsiPrimitiveType
|
||||
&& (variable.getType().equals(PsiType.INT) || variable.getType().equals(PsiType.LONG));
|
||||
}
|
||||
|
||||
static boolean arithmeticTypeRestriction(@NotNull PsiVariable variable) {
|
||||
return variable.getType() instanceof PsiPrimitiveType && !variable.getType().equals(PsiType.FLOAT);
|
||||
}
|
||||
|
||||
private static boolean booleanTypeRestriction(@NotNull PsiVariable variable) {
|
||||
return variable.getType().equalsToText("boolean") || variable.getType().equalsToText(CommonClassNames.JAVA_LANG_BOOLEAN);
|
||||
}
|
||||
}
|
||||
+143
-106
@@ -34,6 +34,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
@@ -51,6 +52,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.intellij.codeInspection.streamMigration.OperationReductionMigration.SUM_OPERATION;
|
||||
import static com.intellij.util.ObjectUtils.tryCast;
|
||||
import static com.siyeh.ig.psiutils.ControlFlowUtils.InitializerUsageStatus.UNKNOWN;
|
||||
|
||||
@@ -109,22 +111,22 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
@Nullable
|
||||
static PsiReturnStatement getNextReturnStatement(PsiStatement statement) {
|
||||
PsiElement nextStatement = PsiTreeUtil.skipWhitespacesAndCommentsForward(statement);
|
||||
if(nextStatement instanceof PsiReturnStatement) return (PsiReturnStatement)nextStatement;
|
||||
if (nextStatement instanceof PsiReturnStatement) return (PsiReturnStatement)nextStatement;
|
||||
PsiElement parent = statement.getParent();
|
||||
if(parent instanceof PsiCodeBlock) {
|
||||
if (parent instanceof PsiCodeBlock) {
|
||||
PsiStatement[] statements = ((PsiCodeBlock)parent).getStatements();
|
||||
if(statements.length == 0 || statements[statements.length-1] != statement) return null;
|
||||
if (statements.length == 0 || statements[statements.length - 1] != statement) return null;
|
||||
parent = parent.getParent();
|
||||
if(!(parent instanceof PsiBlockStatement)) return null;
|
||||
if (!(parent instanceof PsiBlockStatement)) return null;
|
||||
parent = parent.getParent();
|
||||
}
|
||||
if(parent instanceof PsiIfStatement) return getNextReturnStatement((PsiStatement)parent);
|
||||
if (parent instanceof PsiIfStatement) return getNextReturnStatement((PsiStatement)parent);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Contract("null, null -> true; null, !null -> false")
|
||||
private static boolean sameReference(PsiExpression expr1, PsiExpression expr2) {
|
||||
if(expr1 == null && expr2 == null) return true;
|
||||
if (expr1 == null && expr2 == null) return true;
|
||||
if (!(expr1 instanceof PsiReferenceExpression) || !(expr2 instanceof PsiReferenceExpression)) return false;
|
||||
PsiReferenceExpression ref1 = (PsiReferenceExpression)expr1;
|
||||
PsiReferenceExpression ref2 = (PsiReferenceExpression)expr2;
|
||||
@@ -140,36 +142,53 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
*/
|
||||
@Nullable
|
||||
static PsiExpression extractAddend(PsiAssignmentExpression assignment) {
|
||||
if(JavaTokenType.PLUSEQ.equals(assignment.getOperationTokenType())) {
|
||||
return assignment.getRExpression();
|
||||
} else if(JavaTokenType.EQ.equals(assignment.getOperationTokenType())) {
|
||||
if (assignment.getRExpression() instanceof PsiBinaryExpression) {
|
||||
PsiBinaryExpression binOp = (PsiBinaryExpression)assignment.getRExpression();
|
||||
if(JavaTokenType.PLUS.equals(binOp.getOperationTokenType())) {
|
||||
if(sameReference(binOp.getLOperand(), assignment.getLExpression())) {
|
||||
return binOp.getROperand();
|
||||
}
|
||||
if(sameReference(binOp.getROperand(), assignment.getLExpression())) {
|
||||
return binOp.getLOperand();
|
||||
}
|
||||
return extractOperand(assignment, JavaTokenType.PLUSEQ);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
static PsiExpression extractOperand(PsiAssignmentExpression assignment, IElementType compoundAssignmentOp) {
|
||||
if (compoundAssignmentOp.equals(assignment.getOperationTokenType())) {
|
||||
return assignment.getRExpression();
|
||||
}
|
||||
else if (JavaTokenType.EQ.equals(assignment.getOperationTokenType())) {
|
||||
if (assignment.getRExpression() instanceof PsiBinaryExpression) {
|
||||
PsiBinaryExpression binOp = (PsiBinaryExpression)assignment.getRExpression();
|
||||
IElementType op = TypeConversionUtil.convertEQtoOperation(compoundAssignmentOp);
|
||||
if (op.equals(binOp.getOperationTokenType())) {
|
||||
if (sameReference(binOp.getLOperand(), assignment.getLExpression())) {
|
||||
return binOp.getROperand();
|
||||
}
|
||||
if (sameReference(binOp.getROperand(), assignment.getLExpression())) {
|
||||
return binOp.getLOperand();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
static PsiVariable extractAccumulator(PsiAssignmentExpression assignment) {
|
||||
static PsiVariable extractSumAccumulator(PsiAssignmentExpression assignment) {
|
||||
return extractAccumulator(assignment, JavaTokenType.PLUSEQ);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
static PsiVariable extractAccumulator(PsiAssignmentExpression assignment, IElementType compoundAssignmentOp) {
|
||||
PsiReferenceExpression lExpr = tryCast(assignment.getLExpression(), PsiReferenceExpression.class);
|
||||
if(lExpr == null) return null;
|
||||
if (lExpr == null) return null;
|
||||
PsiVariable var = tryCast(lExpr.resolve(), PsiVariable.class);
|
||||
if(var == null) return null;
|
||||
if(JavaTokenType.PLUSEQ.equals(assignment.getOperationTokenType())) {
|
||||
if (var == null) return null;
|
||||
if (compoundAssignmentOp.equals(assignment.getOperationTokenType())) {
|
||||
return var;
|
||||
} else if(JavaTokenType.EQ.equals(assignment.getOperationTokenType())) {
|
||||
}
|
||||
else if (JavaTokenType.EQ.equals(assignment.getOperationTokenType())) {
|
||||
if (assignment.getRExpression() instanceof PsiBinaryExpression) {
|
||||
PsiBinaryExpression binOp = (PsiBinaryExpression)assignment.getRExpression();
|
||||
if(JavaTokenType.PLUS.equals(binOp.getOperationTokenType())) {
|
||||
IElementType op = TypeConversionUtil.convertEQtoOperation(compoundAssignmentOp);
|
||||
if (op.equals(binOp.getOperationTokenType())) {
|
||||
PsiExpression left = binOp.getLOperand();
|
||||
PsiExpression right = binOp.getROperand();
|
||||
if (sameReference(left, lExpr) || sameReference(right, lExpr)) {
|
||||
@@ -189,17 +208,19 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
*/
|
||||
@Contract("null -> null")
|
||||
static PsiExpression extractIncrementedLValue(PsiExpression expression) {
|
||||
if(expression instanceof PsiPostfixExpression) {
|
||||
if(JavaTokenType.PLUSPLUS.equals(((PsiPostfixExpression)expression).getOperationTokenType())) {
|
||||
if (expression instanceof PsiPostfixExpression) {
|
||||
if (JavaTokenType.PLUSPLUS.equals(((PsiPostfixExpression)expression).getOperationTokenType())) {
|
||||
return ((PsiPostfixExpression)expression).getOperand();
|
||||
}
|
||||
} else if(expression instanceof PsiPrefixExpression) {
|
||||
if(JavaTokenType.PLUSPLUS.equals(((PsiPrefixExpression)expression).getOperationTokenType())) {
|
||||
}
|
||||
else if (expression instanceof PsiPrefixExpression) {
|
||||
if (JavaTokenType.PLUSPLUS.equals(((PsiPrefixExpression)expression).getOperationTokenType())) {
|
||||
return ((PsiPrefixExpression)expression).getOperand();
|
||||
}
|
||||
} else if(expression instanceof PsiAssignmentExpression) {
|
||||
}
|
||||
else if (expression instanceof PsiAssignmentExpression) {
|
||||
PsiAssignmentExpression assignment = (PsiAssignmentExpression)expression;
|
||||
if(ExpressionUtils.isLiteral(extractAddend(assignment), 1)) {
|
||||
if (ExpressionUtils.isLiteral(extractAddend(assignment), 1)) {
|
||||
return assignment.getLExpression();
|
||||
}
|
||||
}
|
||||
@@ -209,11 +230,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
@Nullable
|
||||
private static PsiLocalVariable getIncrementedVariable(PsiExpression expression, TerminalBlock tb, List<PsiVariable> variables) {
|
||||
// have only one non-final variable
|
||||
if(variables.size() != 1) return null;
|
||||
if (variables.size() != 1) return null;
|
||||
|
||||
// have single expression which is either ++x or x++ or x+=1 or x=x+1
|
||||
PsiReferenceExpression operand = tryCast(extractIncrementedLValue(expression), PsiReferenceExpression.class);
|
||||
if(operand == null) return null;
|
||||
if (operand == null) return null;
|
||||
PsiLocalVariable variable = tryCast(operand.resolve(), PsiLocalVariable.class);
|
||||
|
||||
// the referred variable is the same as non-final variable and not used in intermediate operations
|
||||
@@ -224,23 +245,26 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiVariable getAccumulatedVariable(TerminalBlock tb, List<PsiVariable> variables) {
|
||||
private static PsiVariable getAccumulatedVariable(TerminalBlock tb,
|
||||
List<PsiVariable> variables,
|
||||
OperationReductionMigration.ReductionOperation operation) {
|
||||
IElementType compoundAssignmentOp = operation.getCompoundAssignmentOp();
|
||||
// have only one non-final variable
|
||||
if(variables.size() != 1) return null;
|
||||
if (variables.size() != 1) return null;
|
||||
|
||||
PsiAssignmentExpression assignment = tb.getSingleExpression(PsiAssignmentExpression.class);
|
||||
if(assignment == null) return null;
|
||||
PsiVariable var = extractAccumulator(assignment);
|
||||
if (assignment == null) return null;
|
||||
PsiVariable var = extractAccumulator(assignment, compoundAssignmentOp);
|
||||
|
||||
// the referred variable is the same as non-final variable
|
||||
if(var == null || !variables.contains(var)) return null;
|
||||
if (!(var.getType() instanceof PsiPrimitiveType) || var.getType().equalsToText("float")) return null;
|
||||
if (var == null || !variables.contains(var)) return null;
|
||||
if (!operation.getAccumulatorRestriction().test(var)) return null;
|
||||
|
||||
// the referred variable is not used in intermediate operations
|
||||
if(tb.isReferencedInOperations(var)) return null;
|
||||
PsiExpression addend = extractAddend(assignment);
|
||||
LOG.assertTrue(addend != null);
|
||||
if(VariableAccessUtils.variableIsUsed(var, addend)) return null;
|
||||
if (tb.isReferencedInOperations(var)) return null;
|
||||
PsiExpression operand = extractOperand(assignment, compoundAssignmentOp);
|
||||
LOG.assertTrue(operand != null);
|
||||
if (VariableAccessUtils.variableIsUsed(var, operand)) return null;
|
||||
return var;
|
||||
}
|
||||
|
||||
@@ -284,7 +308,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
if (tb.isEmpty()) {
|
||||
// like "if(++count == limit) break"
|
||||
variable = getIncrementedVariable(counter, tb, nonFinalVariables);
|
||||
} else if (!ExpressionUtils.isReferenceTo(counter, variable)) {
|
||||
}
|
||||
else if (!ExpressionUtils.isReferenceTo(counter, variable)) {
|
||||
return false;
|
||||
}
|
||||
return variable != null &&
|
||||
@@ -310,7 +335,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
|
||||
static boolean isVariableSuitableForStream(PsiVariable variable, PsiStatement statement, TerminalBlock tb) {
|
||||
if(ReferencesSearch.search(variable).forEach(ref -> {
|
||||
if (ReferencesSearch.search(variable).forEach(ref -> {
|
||||
PsiExpression expression = tryCast(ref.getElement(), PsiExpression.class);
|
||||
return expression == null ||
|
||||
!PsiUtil.isAccessedForWriting(expression) ||
|
||||
@@ -324,14 +349,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
static String tryUnbox(PsiVariable variable) {
|
||||
PsiType type = variable.getType();
|
||||
String mapOp = null;
|
||||
if(type.equals(PsiType.INT)) {
|
||||
if (type.equals(PsiType.INT)) {
|
||||
mapOp = "mapToInt";
|
||||
} else if(type.equals(PsiType.LONG)) {
|
||||
}
|
||||
else if (type.equals(PsiType.LONG)) {
|
||||
mapOp = "mapToLong";
|
||||
} else if(type.equals(PsiType.DOUBLE)) {
|
||||
}
|
||||
else if (type.equals(PsiType.DOUBLE)) {
|
||||
mapOp = "mapToDouble";
|
||||
}
|
||||
return mapOp == null ? "" : "."+mapOp+"("+variable.getName()+" -> "+variable.getName()+")";
|
||||
return mapOp == null ? "" : "." + mapOp + "(" + variable.getName() + " -> " + variable.getName() + ")";
|
||||
}
|
||||
|
||||
static boolean isExpressionDependsOnUpdatedCollections(PsiExpression condition,
|
||||
@@ -403,9 +430,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
|
||||
void processLoop(PsiLoopStatement statement) {
|
||||
final PsiStatement body = statement.getBody();
|
||||
if(body == null) return;
|
||||
if (body == null) return;
|
||||
StreamSource source = StreamSource.tryCreate(statement);
|
||||
if(source == null) return;
|
||||
if (source == null) return;
|
||||
if (!ExceptionUtil.getThrownCheckedExceptions(body).isEmpty()) return;
|
||||
TerminalBlock tb = TerminalBlock.from(source, body);
|
||||
|
||||
@@ -435,7 +462,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
int startOffset = controlFlow.getStartOffset(body);
|
||||
int endOffset = controlFlow.getEndOffset(body);
|
||||
if(startOffset < 0 || endOffset < 0) return null;
|
||||
if (startOffset < 0 || endOffset < 0) return null;
|
||||
PsiElement surrounder = PsiTreeUtil.getParentOfType(loop, PsiLambdaExpression.class, PsiClass.class);
|
||||
final List<PsiVariable> nonFinalVariables = StreamEx.of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset))
|
||||
.remove(variable -> variable instanceof PsiField)
|
||||
@@ -447,11 +474,11 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
if (nonFinalVariables.isEmpty()) {
|
||||
CollectMigration.CollectTerminal terminal = CollectMigration.extractCollectTerminal(tb);
|
||||
if(terminal != null) {
|
||||
if (terminal != null) {
|
||||
boolean addAll = loop instanceof PsiForeachStatement && !tb.hasOperations() && isAddAllCall(tb);
|
||||
// Don't suggest to convert the loop which can be trivially replaced via addAll:
|
||||
// this is covered by UseBulkOperationInspection and ManualArrayToCollectionCopyInspection
|
||||
if(addAll) return null;
|
||||
if (addAll) return null;
|
||||
boolean shouldWarn = REPLACE_TRIVIAL_FOREACH ||
|
||||
tb.hasOperations() ||
|
||||
tb.getLastOperation() instanceof BufferedReaderLines ||
|
||||
@@ -463,9 +490,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
if (nonFinalVariables.isEmpty() && extractArray(tb) != null) {
|
||||
return new ToArrayMigration(true);
|
||||
}
|
||||
if (getAccumulatedVariable(tb, nonFinalVariables) != null) {
|
||||
if (getAccumulatedVariable(tb, nonFinalVariables, SUM_OPERATION) != null) {
|
||||
return new SumMigration(true);
|
||||
}
|
||||
for (OperationReductionMigration.ReductionOperation reductionOperation : OperationReductionMigration.OPERATIONS) {
|
||||
if (getAccumulatedVariable(tb, nonFinalVariables, reductionOperation) != null) {
|
||||
return new OperationReductionMigration(true, reductionOperation);
|
||||
}
|
||||
}
|
||||
Collection<PsiStatement> exitPoints = tb.findExitPoints(controlFlow);
|
||||
if (exitPoints == null) return null;
|
||||
if (exitPoints.isEmpty() && nonFinalVariables.isEmpty()) {
|
||||
@@ -508,14 +540,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
if (nonFinalVariables.size() == 1) {
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(statement);
|
||||
if(assignment == null) return null;
|
||||
if (assignment == null) return null;
|
||||
PsiReferenceExpression lValue = tryCast(assignment.getLExpression(), PsiReferenceExpression.class);
|
||||
if (lValue == null) return null;
|
||||
PsiVariable var = tryCast(lValue.resolve(), PsiVariable.class);
|
||||
if(var == null || !nonFinalVariables.contains(var)) return null;
|
||||
if (var == null || !nonFinalVariables.contains(var)) return null;
|
||||
PsiExpression rValue = assignment.getRExpression();
|
||||
if(rValue == null || VariableAccessUtils.variableIsUsed(var, rValue)) return null;
|
||||
if(tb.getVariable().getType() instanceof PsiPrimitiveType && !ExpressionUtils.isReferenceTo(rValue, tb.getVariable())) return null;
|
||||
if (rValue == null || VariableAccessUtils.variableIsUsed(var, rValue)) return null;
|
||||
if (tb.getVariable().getType() instanceof PsiPrimitiveType && !ExpressionUtils.isReferenceTo(rValue, tb.getVariable())) return null;
|
||||
return new FindFirstMigration(shouldWarn);
|
||||
}
|
||||
return null;
|
||||
@@ -537,12 +569,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
else {
|
||||
methodName = "noneMatch";
|
||||
FilterOp lastFilter = tb.getLastOperation(FilterOp.class);
|
||||
if(lastFilter != null && (lastFilter.isNegated() ^ BoolUtils.isNegation(lastFilter.getExpression()))) {
|
||||
if (lastFilter != null && (lastFilter.isNegated() ^ BoolUtils.isNegation(lastFilter.getExpression()))) {
|
||||
methodName = "allMatch";
|
||||
}
|
||||
}
|
||||
if(nextReturnStatement.getParent() == statement.getParent() ||
|
||||
ExpressionUtils.isLiteral(nextReturnStatement.getReturnValue(), !foundResult)) {
|
||||
if (nextReturnStatement.getParent() == statement.getParent() ||
|
||||
ExpressionUtils.isLiteral(nextReturnStatement.getReturnValue(), !foundResult)) {
|
||||
return new MatchMigration(shouldWarn, methodName);
|
||||
}
|
||||
}
|
||||
@@ -553,8 +585,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
return new MatchMigration(shouldWarn, "anyMatch");
|
||||
}
|
||||
if(nextReturnStatement != null && ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue())
|
||||
&& (!(tb.getVariable().getType() instanceof PsiPrimitiveType) || ExpressionUtils.isReferenceTo(value, tb.getVariable()))) {
|
||||
if (nextReturnStatement != null && ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue())
|
||||
&& (!(tb.getVariable().getType() instanceof PsiPrimitiveType) || ExpressionUtils.isReferenceTo(value, tb.getVariable()))) {
|
||||
return new FindFirstMigration(shouldWarn);
|
||||
}
|
||||
return null;
|
||||
@@ -564,7 +596,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
private TextRange getRange(boolean shouldWarn, PsiLoopStatement statement) {
|
||||
boolean wholeStatement =
|
||||
myIsOnTheFly && (!shouldWarn || InspectionProjectProfileManager.isInformationLevel(getShortName(), statement));
|
||||
if(statement instanceof PsiForeachStatement) {
|
||||
if (statement instanceof PsiForeachStatement) {
|
||||
PsiJavaToken rParenth = ((PsiForeachStatement)statement).getRParenth();
|
||||
if (wholeStatement && rParenth != null) {
|
||||
return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
|
||||
@@ -572,7 +604,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
PsiExpression iteratedValue = ((PsiForeachStatement)statement).getIteratedValue();
|
||||
LOG.assertTrue(iteratedValue != null);
|
||||
return iteratedValue.getTextRange();
|
||||
} else if(statement instanceof PsiForStatement) {
|
||||
}
|
||||
else if (statement instanceof PsiForStatement) {
|
||||
PsiJavaToken rParenth = ((PsiForStatement)statement).getRParenth();
|
||||
if (wholeStatement && rParenth != null) {
|
||||
return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
|
||||
@@ -580,14 +613,16 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
PsiStatement initialization = ((PsiForStatement)statement).getInitialization();
|
||||
LOG.assertTrue(initialization != null);
|
||||
return initialization.getTextRange();
|
||||
} else if(statement instanceof PsiWhileStatement) {
|
||||
}
|
||||
else if (statement instanceof PsiWhileStatement) {
|
||||
PsiJavaToken rParenth = ((PsiWhileStatement)statement).getRParenth();
|
||||
if (wholeStatement && rParenth != null) {
|
||||
return new TextRange(statement.getTextOffset(), rParenth.getTextOffset() + 1);
|
||||
}
|
||||
return statement.getFirstChild().getTextRange();
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected statement type: "+statement);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unexpected statement type: " + statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -595,28 +630,28 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
@Nullable
|
||||
static PsiLocalVariable extractArray(TerminalBlock tb) {
|
||||
CountingLoopSource loop = tb.getLastOperation(CountingLoopSource.class);
|
||||
if(loop == null || loop.myIncluding) return null;
|
||||
if (loop == null || loop.myIncluding) return null;
|
||||
PsiAssignmentExpression assignment = tb.getSingleExpression(PsiAssignmentExpression.class);
|
||||
if(assignment == null || !assignment.getOperationTokenType().equals(JavaTokenType.EQ)) return null;
|
||||
if (assignment == null || !assignment.getOperationTokenType().equals(JavaTokenType.EQ)) return null;
|
||||
PsiArrayAccessExpression arrayAccess = tryCast(assignment.getLExpression(), PsiArrayAccessExpression.class);
|
||||
if(arrayAccess == null) return null;
|
||||
if(!ExpressionUtils.isReferenceTo(arrayAccess.getIndexExpression(), loop.getVariable())) return null;
|
||||
if (arrayAccess == null) return null;
|
||||
if (!ExpressionUtils.isReferenceTo(arrayAccess.getIndexExpression(), loop.getVariable())) return null;
|
||||
PsiReferenceExpression arrayReference = tryCast(arrayAccess.getArrayExpression(), PsiReferenceExpression.class);
|
||||
if(arrayReference == null) return null;
|
||||
if (arrayReference == null) return null;
|
||||
PsiLocalVariable arrayVariable = tryCast(arrayReference.resolve(), PsiLocalVariable.class);
|
||||
if(arrayVariable == null || ControlFlowUtils.getInitializerUsageStatus(arrayVariable, tb.getMainLoop()) == UNKNOWN) return null;
|
||||
if (arrayVariable == null || ControlFlowUtils.getInitializerUsageStatus(arrayVariable, tb.getMainLoop()) == UNKNOWN) return null;
|
||||
PsiNewExpression initializer = tryCast(arrayVariable.getInitializer(), PsiNewExpression.class);
|
||||
if(initializer == null) return null;
|
||||
if (initializer == null) return null;
|
||||
PsiArrayType arrayType = tryCast(initializer.getType(), PsiArrayType.class);
|
||||
if(arrayType == null || !StreamApiUtil.isSupportedStreamElement(arrayType.getComponentType())) return null;
|
||||
if (arrayType == null || !StreamApiUtil.isSupportedStreamElement(arrayType.getComponentType())) return null;
|
||||
PsiExpression dimension = ArrayUtil.getFirstElement(initializer.getArrayDimensions());
|
||||
if(dimension == null) return null;
|
||||
if (dimension == null) return null;
|
||||
PsiExpression bound = loop.myBound;
|
||||
if (!PsiEquivalenceUtil.areElementsEquivalent(dimension, bound) &&
|
||||
!ExpressionUtils.isReferenceTo(ExpressionUtils.getArrayFromLengthExpression(bound), arrayVariable)) {
|
||||
return null;
|
||||
}
|
||||
if(VariableAccessUtils.variableIsUsed(arrayVariable, assignment.getRExpression())) return null;
|
||||
if (VariableAccessUtils.variableIsUsed(arrayVariable, assignment.getRExpression())) return null;
|
||||
return arrayVariable;
|
||||
}
|
||||
|
||||
@@ -712,8 +747,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
|
||||
@Override
|
||||
PsiExpression makeIntermediateExpression(PsiElementFactory factory) {
|
||||
return factory.createExpressionFromText(myFlatMapOp.getStreamExpression()+".anyMatch("+
|
||||
LambdaUtil.createLambda(myMatchVariable, myExpression)+")", myExpression);
|
||||
return factory.createExpressionFromText(myFlatMapOp.getStreamExpression() + ".anyMatch(" +
|
||||
LambdaUtil.createLambda(myMatchVariable, myExpression) + ")", myExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -760,16 +795,18 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
PsiType inType = myVariable.getType();
|
||||
PsiType outType = mySource.getVariable().getType();
|
||||
String lambda = myVariable.getName() + " -> " + getStreamExpression();
|
||||
if(outType instanceof PsiPrimitiveType && !outType.equals(inType)) {
|
||||
if(outType.equals(PsiType.INT)) {
|
||||
if (outType instanceof PsiPrimitiveType && !outType.equals(inType)) {
|
||||
if (outType.equals(PsiType.INT)) {
|
||||
operation = "flatMapToInt";
|
||||
} else if(outType.equals(PsiType.LONG)) {
|
||||
}
|
||||
else if (outType.equals(PsiType.LONG)) {
|
||||
operation = "flatMapToLong";
|
||||
} else if(outType.equals(PsiType.DOUBLE)) {
|
||||
}
|
||||
else if (outType.equals(PsiType.DOUBLE)) {
|
||||
operation = "flatMapToDouble";
|
||||
}
|
||||
}
|
||||
if(inType instanceof PsiPrimitiveType && !outType.equals(inType)) {
|
||||
if (inType instanceof PsiPrimitiveType && !outType.equals(inType)) {
|
||||
return ".mapToObj(" + lambda + ")." + operation + "(" + CommonClassNames.JAVA_UTIL_FUNCTION_FUNCTION + ".identity())";
|
||||
}
|
||||
return "." + operation + "(" + lambda + ")";
|
||||
@@ -827,7 +864,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
|
||||
@Override
|
||||
void cleanUp() {
|
||||
if(myCounterVariable != null) {
|
||||
if (myCounterVariable != null) {
|
||||
myCounterVariable.delete();
|
||||
}
|
||||
}
|
||||
@@ -838,7 +875,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
|
||||
private String getLimitExpression() {
|
||||
if(myDelta == 0) {
|
||||
if (myDelta == 0) {
|
||||
return myExpression.getText();
|
||||
}
|
||||
if (myExpression instanceof PsiLiteralExpression) {
|
||||
@@ -876,14 +913,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
|
||||
@Contract("null -> null")
|
||||
static StreamSource tryCreate(PsiLoopStatement statement) {
|
||||
if(statement instanceof PsiForStatement) {
|
||||
if (statement instanceof PsiForStatement) {
|
||||
return CountingLoopSource.from((PsiForStatement)statement);
|
||||
}
|
||||
if(statement instanceof PsiForeachStatement) {
|
||||
if (statement instanceof PsiForeachStatement) {
|
||||
ArrayStream source = ArrayStream.from((PsiForeachStatement)statement);
|
||||
return source == null ? CollectionStream.from((PsiForeachStatement)statement) : source;
|
||||
}
|
||||
if(statement instanceof PsiWhileStatement) {
|
||||
if (statement instanceof PsiWhileStatement) {
|
||||
return BufferedReaderLines.from((PsiWhileStatement)statement);
|
||||
}
|
||||
return null;
|
||||
@@ -897,7 +934,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
|
||||
@Override
|
||||
String createReplacement() {
|
||||
return myExpression.getText()+".lines()";
|
||||
return myExpression.getText() + ".lines()";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -914,30 +951,30 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
public static BufferedReaderLines from(PsiWhileStatement whileLoop) {
|
||||
// while ((line = br.readLine()) != null)
|
||||
PsiBinaryExpression binOp = tryCast(PsiUtil.skipParenthesizedExprDown(whileLoop.getCondition()), PsiBinaryExpression.class);
|
||||
if(binOp == null) return null;
|
||||
if(!JavaTokenType.NE.equals(binOp.getOperationTokenType())) return null;
|
||||
if (binOp == null) return null;
|
||||
if (!JavaTokenType.NE.equals(binOp.getOperationTokenType())) return null;
|
||||
PsiExpression operand = ExpressionUtils.getValueComparedWithNull(binOp);
|
||||
if(operand == null) return null;
|
||||
if (operand == null) return null;
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(PsiUtil.skipParenthesizedExprDown(operand));
|
||||
if(assignment == null) return null;
|
||||
if (assignment == null) return null;
|
||||
PsiReferenceExpression lValue = tryCast(assignment.getLExpression(), PsiReferenceExpression.class);
|
||||
if(lValue == null) return null;
|
||||
if (lValue == null) return null;
|
||||
PsiLocalVariable var = tryCast(lValue.resolve(), PsiLocalVariable.class);
|
||||
if(var == null) return null;
|
||||
if(!ReferencesSearch.search(var).forEach(ref -> {
|
||||
if (var == null) return null;
|
||||
if (!ReferencesSearch.search(var).forEach(ref -> {
|
||||
return PsiTreeUtil.isAncestor(whileLoop, ref.getElement(), true);
|
||||
})) {
|
||||
return null;
|
||||
}
|
||||
PsiMethodCallExpression call = tryCast(PsiUtil.skipParenthesizedExprDown(assignment.getRExpression()), PsiMethodCallExpression.class);
|
||||
if (call == null || call.getArgumentList().getExpressions().length != 0) return null;
|
||||
if(!"readLine".equals(call.getMethodExpression().getReferenceName())) return null;
|
||||
if (!"readLine".equals(call.getMethodExpression().getReferenceName())) return null;
|
||||
PsiExpression readerExpression = call.getMethodExpression().getQualifierExpression();
|
||||
if(readerExpression == null) return null;
|
||||
if (readerExpression == null) return null;
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if(method == null) return null;
|
||||
if (method == null) return null;
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if(aClass == null || !"java.io.BufferedReader".equals(aClass.getQualifiedName())) return null;
|
||||
if (aClass == null || !"java.io.BufferedReader".equals(aClass.getQualifiedName())) return null;
|
||||
return new BufferedReaderLines(whileLoop, var, readerExpression);
|
||||
}
|
||||
}
|
||||
@@ -1053,7 +1090,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
public String createReplacement() {
|
||||
String className = myVariable.getType().equals(PsiType.LONG) ? "java.util.stream.LongStream" : "java.util.stream.IntStream";
|
||||
String methodName = myIncluding ? "rangeClosed" : "range";
|
||||
return className+"."+methodName+"("+myExpression.getText()+", "+myBound.getText()+")";
|
||||
return className + "." + methodName + "(" + myExpression.getText() + ", " + myBound.getText() + ")";
|
||||
}
|
||||
|
||||
CountingLoopSource withBound(PsiExpression bound) {
|
||||
@@ -1062,9 +1099,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
|
||||
@Override
|
||||
boolean isWriteAllowed(PsiVariable variable, PsiExpression reference) {
|
||||
if(variable == myVariable) {
|
||||
if (variable == myVariable) {
|
||||
PsiForStatement forStatement = PsiTreeUtil.getParentOfType(variable, PsiForStatement.class);
|
||||
if(forStatement != null) {
|
||||
if (forStatement != null) {
|
||||
return PsiTreeUtil.isAncestor(forStatement.getUpdate(), reference, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.ig.psiutils.ParenthesesUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import static com.intellij.codeInspection.streamMigration.OperationReductionMigration.SUM_OPERATION;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
@@ -33,7 +35,7 @@ class SumMigration extends BaseStreamApiMigration {
|
||||
PsiElement migrate(@NotNull Project project, @NotNull PsiStatement body, @NotNull TerminalBlock tb) {
|
||||
PsiAssignmentExpression assignment = tb.getSingleExpression(PsiAssignmentExpression.class);
|
||||
if (assignment == null) return null;
|
||||
PsiVariable var = StreamApiMigrationInspection.extractAccumulator(assignment);
|
||||
PsiVariable var = StreamApiMigrationInspection.extractSumAccumulator(assignment);
|
||||
if (var == null) return null;
|
||||
|
||||
PsiExpression addend = StreamApiMigrationInspection.extractAddend(assignment);
|
||||
@@ -49,6 +51,6 @@ class SumMigration extends BaseStreamApiMigration {
|
||||
"(" + type.getCanonicalText() + ")" + ParenthesesUtils.getText(addend, ParenthesesUtils.MULTIPLICATIVE_PRECEDENCE), addend);
|
||||
}
|
||||
String stream = tb.add(new MapOp(addend, tb.getVariable(), type)).generate()+".sum()";
|
||||
return replaceWithNumericAddition(tb.getMainLoop(), var, stream, type);
|
||||
return replaceWithOperation(tb.getMainLoop(), var, stream, type, SUM_OPERATION);
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAnd() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12443;
|
||||
acc &= Arrays.stream(arr).reduce(-1, (a, b) -> a & b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndHighestBit() {
|
||||
int[] arr = {0x80000000, 0xffffffff};
|
||||
int acc = Arrays.stream(arr).reduce(-1, (a, b) -> a & b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndReplacingInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = Arrays.stream(arr).reduce(0xFFFFFFFF, (a, b) -> a & b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndReplacingInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = Arrays.stream(arr).reduce(-1, (a, b) -> a & b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndReplacingLongInitializer() {
|
||||
long[] arr = new long[]{1, 2, 3, 4};
|
||||
long acc = Arrays.stream(arr).reduce(-1l, (a, b) -> a & b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testConjunction() {
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
boolean acc = booleans.stream().reduce(true, (a, b) -> a && b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testConjunctionBoxed() {
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
Boolean acc = booleans.stream().reduce(true, (a, b) -> a && b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testDisjunction() {
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
boolean acc = booleans.stream().reduce(false, (a, b) -> a || b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiply() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = Arrays.stream(arr).reduce(1, (a, b) -> a * b);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithComplexInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int x = 10;
|
||||
int acc = 12 + x;
|
||||
acc *= Arrays.stream(arr).reduce(1, (a, b) -> a * b);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithConflictingNamesInScope() {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int b1 = 3;
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = Arrays.stream(arr).reduce(1, (a1, b2) -> a1 * b2);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithNarrowingTypeInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
short acc = (byte) 12;
|
||||
acc *= Arrays.stream(arr).map(i -> (short) i).reduce(1, (a, b) -> a * b);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithNotOneInitializerConstant() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12;
|
||||
acc *= Arrays.stream(arr).reduce(1, (a, b) -> a * b);
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithMapping() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = Arrays.stream(arr).map(i -> i + 2).reduce(1, (a, b) -> a * b);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseOr() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12443;
|
||||
acc |= Arrays.stream(arr).reduce(0, (a, b) -> a | b);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseXor() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12443;
|
||||
acc ^= Arrays.stream(arr).reduce(0, (a, b) -> a ^ b);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseXorLong() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
long acc = 12443;
|
||||
acc ^= Arrays.stream(arr).asLongStream().reduce(0, (a, b) -> a ^ b);
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAnd() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12443;
|
||||
for <caret> (int i: arr) {
|
||||
acc &= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndHighestBit() {
|
||||
int[] arr = {0x80000000, 0xffffffff};
|
||||
int acc = -1;
|
||||
for <caret> (int i: arr) {
|
||||
acc &= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndReplacingInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 0xFFFFFFFF;
|
||||
for <caret> (int i: arr) {
|
||||
acc &= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndReplacingInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = -1;
|
||||
for <caret> (int i: arr) {
|
||||
acc &= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseAndReplacingLongInitializer() {
|
||||
long[] arr = new long[]{1, 2, 3, 4};
|
||||
long acc = -1l;
|
||||
for <caret> (long i: arr) {
|
||||
acc &= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testConjunction() {
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
boolean acc = true;
|
||||
for <caret> (Boolean bool : booleans) {
|
||||
acc &= bool;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testConjunctionBoxed() {
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
Boolean acc = true;
|
||||
for <caret> (Boolean bool : booleans) {
|
||||
acc &= bool;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testDisjunction() {
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
boolean acc = false;
|
||||
for <caret> (Boolean bool : booleans) {
|
||||
acc |= bool;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiply() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 1;
|
||||
for <caret> (int i : arr) {
|
||||
acc *= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithComplexInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int x = 10;
|
||||
int acc = 12 + x;
|
||||
for <caret> (int i : arr) {
|
||||
acc *= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithConflictingNamesInScope() {
|
||||
int a = 1;
|
||||
int b = 2;
|
||||
int b1 = 3;
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 1;
|
||||
for <caret> (int i : arr) {
|
||||
acc *= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithNarrowingTypeInitializer() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
short acc = (byte) 12;
|
||||
for <caret> (int i : arr) {
|
||||
acc *= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithNotOneInitializerConstant() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12;
|
||||
for <caret> (int i : arr) {
|
||||
acc *= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testMultiplyWithMapping() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 1;
|
||||
for <caret> (int i : arr) {
|
||||
acc *= i + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseOr() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12443;
|
||||
for <caret> (int i: arr) {
|
||||
acc |= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseXor() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
int acc = 12443;
|
||||
for <caret> (int i: arr) {
|
||||
acc ^= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with reduce()" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public void testBitwiseXorLong() {
|
||||
int[] arr = new int[]{1, 2, 3, 4};
|
||||
long acc = 12443;
|
||||
for <caret> (int i: arr) {
|
||||
acc ^= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user