mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
StreamApiMigrationInspection improvements: expression+break conversion to anyMatch; pull out cast of stream.findFirst().map(x -> (T)x).orElse(null) to (T) stream.findFirst().orElse(null)
This commit is contained in:
+24
-13
@@ -44,6 +44,7 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
|
||||
@NotNull List<Operation> operations) {
|
||||
PsiStatement statement = tb.getSingleStatement();
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
|
||||
String stream = generateStream(iteratedValue, operations).append(".findFirst()").toString();
|
||||
if (statement instanceof PsiReturnStatement) {
|
||||
PsiReturnStatement returnStatement = (PsiReturnStatement)statement;
|
||||
PsiExpression value = returnStatement.getReturnValue();
|
||||
@@ -52,14 +53,10 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
|
||||
if (nextReturnStatement == null) return;
|
||||
PsiExpression orElseExpression = nextReturnStatement.getReturnValue();
|
||||
if (!ExpressionUtils.isSimpleExpression(orElseExpression)) return;
|
||||
StringBuilder builder = generateStream(iteratedValue, operations).append(".findFirst()");
|
||||
if (!(value instanceof PsiReferenceExpression) || ((PsiReferenceExpression)value).resolve() != tb.getVariable()) {
|
||||
builder.append(".map(").append(tb.getVariable().getName()).append(" -> ").append(value.getText()).append(")");
|
||||
}
|
||||
builder.append(".orElse(").append(orElseExpression.getText()).append(")");
|
||||
stream = generateOptionalUnwrap(stream, tb, value, orElseExpression);
|
||||
restoreComments(foreachStatement, body);
|
||||
boolean siblings = nextReturnStatement.getParent() == foreachStatement.getParent();
|
||||
PsiElement result = foreachStatement.replace(elementFactory.createStatementFromText("return " + builder + ";", foreachStatement));
|
||||
PsiElement result = foreachStatement.replace(elementFactory.createStatementFromText("return " + stream + ";", foreachStatement));
|
||||
if (siblings) {
|
||||
nextReturnStatement.delete();
|
||||
}
|
||||
@@ -77,24 +74,38 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
|
||||
PsiVariable var = (PsiVariable)element;
|
||||
PsiExpression value = assignment.getRExpression();
|
||||
if (value == null) return;
|
||||
StringBuilder builder = generateStream(iteratedValue, operations).append(".findFirst()");
|
||||
if (!(value instanceof PsiReferenceExpression) || ((PsiReferenceExpression)value).resolve() != tb.getVariable()) {
|
||||
builder.append(".map(").append(tb.getVariable().getName()).append(" -> ").append(value.getText()).append(")");
|
||||
}
|
||||
restoreComments(foreachStatement, body);
|
||||
if (StreamApiMigrationInspection.isDeclarationJustBefore(var, foreachStatement)) {
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if (initializer != null) {
|
||||
PsiElement result =
|
||||
initializer.replace(elementFactory.createExpressionFromText(builder + ".orElse(" + initializer.getText() + ")", initializer));
|
||||
initializer.replace(elementFactory.createExpressionFromText(generateOptionalUnwrap(stream, tb, value, initializer), initializer));
|
||||
removeLoop(foreachStatement);
|
||||
simplifyAndFormat(project, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
PsiElement result = foreachStatement.replace(
|
||||
elementFactory.createStatementFromText(var.getName() + " = " + builder + ".orElse(" + var.getName() + ");", foreachStatement));
|
||||
PsiElement result = foreachStatement.replace(elementFactory.createStatementFromText(
|
||||
var.getName() + " = " + generateOptionalUnwrap(stream, tb, value, lValue) + ";", foreachStatement));
|
||||
simplifyAndFormat(project, result);
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateOptionalUnwrap(String stream, @NotNull StreamApiMigrationInspection.TerminalBlock tb,
|
||||
PsiExpression trueExpression, PsiExpression falseExpression) {
|
||||
PsiVariable var = tb.getVariable();
|
||||
if (!StreamApiMigrationInspection.isIdentityMapping(var, trueExpression)) {
|
||||
if(trueExpression instanceof PsiTypeCastExpression && ExpressionUtils.isNullLiteral(falseExpression)) {
|
||||
PsiTypeCastExpression castExpression = (PsiTypeCastExpression)trueExpression;
|
||||
PsiTypeElement castType = castExpression.getCastType();
|
||||
// pull cast outside to avoid the .map() step
|
||||
if(castType != null && StreamApiMigrationInspection.isIdentityMapping(var, castExpression.getOperand())) {
|
||||
return "(" + castType.getText() + ")" + stream + ".orElse(null)";
|
||||
}
|
||||
}
|
||||
stream += ".map(" + StreamApiMigrationInspection.createLambda(var, trueExpression) + ")";
|
||||
}
|
||||
stream += ".orElse(" + falseExpression.getText() + ")";
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
+55
-19
@@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.siyeh.ig.psiutils.BoolUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
@@ -51,31 +52,66 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
|
||||
@NotNull PsiStatement body,
|
||||
@NotNull StreamApiMigrationInspection.TerminalBlock tb,
|
||||
@NotNull List<Operation> operations) {
|
||||
PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
|
||||
PsiExpression value = returnStatement.getReturnValue();
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
|
||||
restoreComments(foreachStatement, body);
|
||||
if (StreamApiMigrationInspection.isLiteral(value, Boolean.TRUE) || StreamApiMigrationInspection.isLiteral(value, Boolean.FALSE)) {
|
||||
boolean foundResult = (boolean)((PsiLiteralExpression)value).getValue();
|
||||
PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(foreachStatement);
|
||||
if (nextReturnStatement != null && StreamApiMigrationInspection.isLiteral(nextReturnStatement.getReturnValue(), !foundResult)) {
|
||||
String methodName = foundResult ? "anyMatch" : "noneMatch";
|
||||
String streamText = generateStream(iteratedValue, operations).toString();
|
||||
streamText = addTerminalOperation(streamText, methodName, foreachStatement, tb);
|
||||
boolean siblings = nextReturnStatement.getParent() == foreachStatement.getParent();
|
||||
PsiElement result =
|
||||
foreachStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", foreachStatement));
|
||||
if (siblings) {
|
||||
nextReturnStatement.delete();
|
||||
if(tb.getSingleStatement() instanceof PsiReturnStatement) {
|
||||
PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
|
||||
PsiExpression value = returnStatement.getReturnValue();
|
||||
if (StreamApiMigrationInspection.isLiteral(value, Boolean.TRUE) || StreamApiMigrationInspection.isLiteral(value, Boolean.FALSE)) {
|
||||
boolean foundResult = (boolean)((PsiLiteralExpression)value).getValue();
|
||||
PsiReturnStatement nextReturnStatement = StreamApiMigrationInspection.getNextReturnStatement(foreachStatement);
|
||||
if (nextReturnStatement != null && StreamApiMigrationInspection.isLiteral(nextReturnStatement.getReturnValue(), !foundResult)) {
|
||||
String methodName = foundResult ? "anyMatch" : "noneMatch";
|
||||
String streamText = generateStream(iteratedValue, operations).toString();
|
||||
streamText = addTerminalOperation(streamText, methodName, foreachStatement, tb);
|
||||
restoreComments(foreachStatement, body);
|
||||
boolean siblings = nextReturnStatement.getParent() == foreachStatement.getParent();
|
||||
PsiElement result =
|
||||
foreachStatement.replace(elementFactory.createStatementFromText("return " + streamText + ";", foreachStatement));
|
||||
if (siblings) {
|
||||
nextReturnStatement.delete();
|
||||
}
|
||||
simplifyAndFormat(project, result);
|
||||
return;
|
||||
}
|
||||
simplifyAndFormat(project, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!StreamApiMigrationInspection.isVariableReferenced(tb.getVariable(), value)) {
|
||||
PsiStatement[] statements = tb.getStatements();
|
||||
if(statements.length == 1 || (statements.length == 2 && statements[1] instanceof PsiBreakStatement)) {
|
||||
restoreComments(foreachStatement, body);
|
||||
String streamText = generateStream(iteratedValue, operations).toString();
|
||||
streamText = addTerminalOperation(streamText, "anyMatch", foreachStatement, tb);
|
||||
String replacement = "if(" + streamText + "){" + returnStatement.getText() + "}";
|
||||
PsiStatement statement = statements[0];
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(statement);
|
||||
if(assignment != null) {
|
||||
PsiExpression lValue = assignment.getLExpression();
|
||||
PsiExpression rValue = assignment.getRExpression();
|
||||
if (!(lValue instanceof PsiReferenceExpression) || rValue == null) return;
|
||||
PsiElement maybeVar = ((PsiReferenceExpression)lValue).resolve();
|
||||
if(maybeVar instanceof PsiVariable) {
|
||||
// Simplify single assignments like this:
|
||||
// boolean flag = false;
|
||||
// for(....) if(...) {flag = true; break;}
|
||||
PsiVariable var = (PsiVariable)maybeVar;
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if(initializer != null && StreamApiMigrationInspection.isDeclarationJustBefore(var, foreachStatement)) {
|
||||
String replacement;
|
||||
if(StreamApiMigrationInspection.isLiteral(initializer, Boolean.FALSE) &&
|
||||
StreamApiMigrationInspection.isLiteral(rValue, Boolean.TRUE)) {
|
||||
replacement = streamText;
|
||||
} else if(StreamApiMigrationInspection.isLiteral(initializer, Boolean.TRUE) &&
|
||||
StreamApiMigrationInspection.isLiteral(rValue, Boolean.FALSE)) {
|
||||
replacement = "!"+streamText;
|
||||
} else {
|
||||
replacement = streamText + "?" + rValue.getText() + ":" + initializer.getText();
|
||||
}
|
||||
PsiElement result = initializer.replace(elementFactory.createExpressionFromText(replacement, initializer));
|
||||
removeLoop(foreachStatement);
|
||||
simplifyAndFormat(project, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
String replacement = "if(" + streamText + "){" + statement.getText() + "}";
|
||||
PsiElement result = foreachStatement.replace(elementFactory.createStatementFromText(replacement, foreachStatement));
|
||||
simplifyAndFormat(project, result);
|
||||
}
|
||||
|
||||
+16
-8
@@ -516,14 +516,19 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
if (nonFinalVariables.isEmpty() && tb.getSingleStatement() instanceof PsiReturnStatement) {
|
||||
handleSingleReturn(statement, tb, operations);
|
||||
}
|
||||
if (nonFinalVariables.size() == 1) {
|
||||
PsiStatement[] statements = tb.getStatements();
|
||||
if (statements.length == 2) {
|
||||
PsiStatement breakStatement = statements[1];
|
||||
if (!(breakStatement instanceof PsiBreakStatement) ||
|
||||
((PsiBreakStatement)breakStatement).findExitedStatement() != statement) {
|
||||
return;
|
||||
}
|
||||
PsiStatement[] statements = tb.getStatements();
|
||||
if (statements.length == 2) {
|
||||
PsiStatement breakStatement = statements[1];
|
||||
if (!(breakStatement instanceof PsiBreakStatement) ||
|
||||
((PsiBreakStatement)breakStatement).findExitedStatement() != statement) {
|
||||
return;
|
||||
}
|
||||
if (ReferencesSearch.search(tb.getVariable(), new LocalSearchScope(statements)).findFirst() == null
|
||||
&& exitPoints.size() == 1 && exitPoints.contains(breakStatement)) {
|
||||
registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch"));
|
||||
return;
|
||||
}
|
||||
if (nonFinalVariables.size() == 1) {
|
||||
PsiAssignmentExpression assignment = ExpressionUtils.getAssignment(statements[0]);
|
||||
if(assignment == null) return;
|
||||
PsiExpression lValue = assignment.getLExpression();
|
||||
@@ -566,6 +571,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
}
|
||||
if (!isVariableReferenced(tb.getVariable(), value)) {
|
||||
if(!REPLACE_TRIVIAL_FOREACH && operations.isEmpty() || (operations.size() == 1 && operations.get(0) instanceof FilterOp)) {
|
||||
return;
|
||||
}
|
||||
registerProblem(statement, "anyMatch", new ReplaceWithMatchFix("anyMatch"));
|
||||
}
|
||||
if(nextReturnStatement != null && ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue())
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
String found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty()) ? "yes" : "no";
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = !data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = false;
|
||||
if(Math.random() > 0.5) {
|
||||
found = true;
|
||||
} else {
|
||||
if (data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty())) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
if (data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty())) {
|
||||
System.out.println("Found!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testCast(List<Object> data) {
|
||||
String found = (String) data.stream().filter(obj -> obj instanceof String).findFirst().orElse(null);
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public String testCast(List<Object> data) {
|
||||
return (String) data.stream().filter(obj -> obj instanceof String).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
String found = "no";
|
||||
for(String str : da<caret>ta) {
|
||||
String trimmed = str.trim();
|
||||
if(!trimmed.isEmpty()) {
|
||||
found = "yes";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = false;
|
||||
for(String str : da<caret>ta) {
|
||||
String trimmed = str.trim();
|
||||
if(!trimmed.isEmpty()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = true;
|
||||
for(String str : da<caret>ta) {
|
||||
String trimmed = str.trim();
|
||||
if(!trimmed.isEmpty()) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = false;
|
||||
if(Math.random() > 0.5) {
|
||||
found = true;
|
||||
} else {
|
||||
for (String str : da<caret>ta) {
|
||||
String trimmed = str.trim();
|
||||
if (!trimmed.isEmpty()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
for (String str : d<caret>ata) {
|
||||
String trimmed = str.trim();
|
||||
if (!trimmed.isEmpty()) {
|
||||
System.out.println("Found!!!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testCast(List<Object> data) {
|
||||
String found = null;
|
||||
for (Object obj : da<caret>ta) {
|
||||
if(obj instanceof String) {
|
||||
found = (String)obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public String testCast(List<Object> data) {
|
||||
for (Object obj : d<caret>ata) {
|
||||
if(obj instanceof String) {
|
||||
return (String)obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user