From 6da7838df47ffbc567320d16e3ae448e71caa057 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 12 Sep 2016 14:28:24 +0700 Subject: [PATCH] IDEA-161002 anyMatch/noneMatch disabled for non-final vars; allMatch is supported --- .../StreamApiMigrationInspection.java | 50 +++++++++++++++---- .../streamApiMigration/afterAllMatch.java | 9 ++++ .../afterAllMatchMethodRef.java | 9 ++++ .../streamApiMigration/beforeAllMatch.java | 14 ++++++ .../beforeAllMatchMethodRef.java | 14 ++++++ .../beforeAnyMatchNonFinal.java | 17 +++++++ 6 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatch.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatchMethodRef.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatch.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatchMethodRef.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnyMatchNonFinal.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java index ff2038601934..597af6bd83b0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java @@ -135,15 +135,14 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo .findExitPointsAndStatements(controlFlow, tb.getStartOffset(controlFlow), tb.getEndOffset(controlFlow), new IntArrayList(), PsiContinueStatement.class, PsiBreakStatement.class, PsiReturnStatement.class, PsiThrowStatement.class); + int startOffset = controlFlow.getStartOffset(body); + int endOffset = controlFlow.getEndOffset(body); + final List nonFinalVariables = StreamEx + .of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset)) + .remove(variable -> HighlightControlFlowUtil.isEffectivelyFinal(variable, body, null)) + .toList(); + if (exitPoints.isEmpty()) { - - int startOffset = controlFlow.getStartOffset(body); - int endOffset = controlFlow.getEndOffset(body); - final List nonFinalVariables = StreamEx - .of(ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset)) - .remove(variable -> HighlightControlFlowUtil.isEffectivelyFinal(variable, body, null)) - .toList(); - if(getIncrementedVariable(tb, operations, nonFinalVariables) != null) { registerProblem(holder, statement, "count", new ReplaceWithCountFix()); } @@ -181,7 +180,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo registerProblem(holder, statement, "forEach", fixes.toArray(new LocalQuickFix[fixes.size()])); } } else { - if(tb.getSingleStatement() instanceof PsiReturnStatement) { + if(nonFinalVariables.isEmpty() && tb.getSingleStatement() instanceof PsiReturnStatement) { PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement(); PsiExpression value = returnStatement.getReturnValue(); if(isLiteral(value, Boolean.TRUE) || isLiteral(value, Boolean.FALSE)) { @@ -190,7 +189,19 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo if(nextStatement instanceof PsiReturnStatement) { PsiReturnStatement nextReturnStatement = (PsiReturnStatement)nextStatement; if(isLiteral(nextReturnStatement.getReturnValue(), !foundResult)) { - String methodName = foundResult ? "anyMatch" : "noneMatch"; + String methodName; + if (foundResult) { + methodName = "anyMatch"; + } + else { + methodName = "noneMatch"; + if(!operations.isEmpty()) { + Operation lastOp = operations.get(operations.size() - 1); + if(lastOp instanceof FilterOp && BoolUtils.isNegation(lastOp.getExpression())) { + methodName = "allMatch"; + } + } + } registerProblem(holder, statement, methodName, new ReplaceWithMatchFix(methodName)); } } @@ -889,6 +900,25 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo if(!(stream instanceof PsiMethodCallExpression)) return; PsiElement nameElement = ((PsiMethodCallExpression)stream).getMethodExpression().getReferenceNameElement(); if(nameElement != null && nameElement.getText().equals("filter")) { + if(!foundResult) { + PsiExpression[] expressions = ((PsiMethodCallExpression)stream).getArgumentList().getExpressions(); + if(expressions.length == 1 && expressions[0] instanceof PsiLambdaExpression) { + PsiLambdaExpression lambda = (PsiLambdaExpression)expressions[0]; + PsiElement lambdaBody = lambda.getBody(); + if(lambdaBody instanceof PsiExpression && BoolUtils.isNegation((PsiExpression)lambdaBody)) { + PsiExpression negated = BoolUtils.getNegated((PsiExpression)lambdaBody); + LOG.assertTrue(negated != null); + String methodReferenceText = LambdaCanBeMethodReferenceInspection + .convertToMethodReference(negated, lambda.getParameterList().getParameters(), lambda.getFunctionalInterfaceType(), lambda); + if(methodReferenceText != null) { + lambda.replace(elementFactory.createExpressionFromText(methodReferenceText, lambda)); + } else { + lambdaBody.replace(negated); + } + methodName = "allMatch"; + } + } + } nameElement.replace(elementFactory.createIdentifier(methodName)); streamText = stream.getText(); } else { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatch.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatch.java new file mode 100644 index 000000000000..c3855eff9095 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatch.java @@ -0,0 +1,9 @@ +// "Replace with allMatch()" "true" + +import java.util.Arrays; + +public class Main { + boolean find(String[][] data) { + return Arrays.stream(data).flatMap(Arrays::stream).allMatch(str -> str.startsWith("xyz")); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatchMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatchMethodRef.java new file mode 100644 index 000000000000..dbde7cc4b9b0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterAllMatchMethodRef.java @@ -0,0 +1,9 @@ +// "Replace with allMatch()" "true" + +import java.util.Arrays; + +public class Main { + boolean allEmpty(String[][] data) { + return Arrays.stream(data).flatMap(Arrays::stream).allMatch(String::isEmpty); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatch.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatch.java new file mode 100644 index 000000000000..905ebecc4581 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatch.java @@ -0,0 +1,14 @@ +// "Replace with allMatch()" "true" + +public class Main { + boolean find(String[][] data) { + for(String[] arr : data) { + for(String str : arr) { + if(!str.startsWith("xyz")) { + return false; + } + } + } + return true; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatchMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatchMethodRef.java new file mode 100644 index 000000000000..ad9f44b767be --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAllMatchMethodRef.java @@ -0,0 +1,14 @@ +// "Replace with allMatch()" "true" + +public class Main { + boolean allEmpty(String[][] data) { + for(String[] arr : data) { + for(String str : arr) { + if(!str.isEmpty()) { + return false; + } + } + } + return true; + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnyMatchNonFinal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnyMatchNonFinal.java new file mode 100644 index 000000000000..404f0d02c67f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeAnyMatchNonFinal.java @@ -0,0 +1,17 @@ +// "Replace with anyMatch()" "false" + +import java.util.List; + +public class Main { + boolean find(List data, String prefix) { + if(prefix == null) + prefix = "xyz"; + for(String e : data) { + String trimmed = e.trim(); + if(trimmed.startsWith(prefix)) { + return true; + } + } + return false; + } +}