mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ControlFlowUtils#statementBreaksLoop; StreamApiMigrationInspection#getInitializerUsageStatus simplified
This commit is contained in:
+4
-1
@@ -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.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -69,7 +70,9 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
|
||||
}
|
||||
}
|
||||
PsiStatement[] statements = tb.getStatements();
|
||||
if (!(statements.length == 1 || (statements.length == 2 && statements[1] instanceof PsiBreakStatement))) return null;
|
||||
if (!(statements.length == 1 || (statements.length == 2 && ControlFlowUtils.statementBreaksLoop(statements[1], foreachStatement)))) {
|
||||
return null;
|
||||
}
|
||||
restoreComments(foreachStatement, body);
|
||||
String streamText = generateStream(iteratedValue, tb.getLastOperation()).toString();
|
||||
streamText = addTerminalOperation(streamText, "anyMatch", foreachStatement, tb);
|
||||
|
||||
+3
-7
@@ -39,6 +39,7 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.IntArrayList;
|
||||
import com.siyeh.ig.psiutils.BoolUtils;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.EquivalenceChecker;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import one.util.streamex.EntryStream;
|
||||
@@ -415,10 +416,6 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiStatement nextStatement) {
|
||||
if(!(var instanceof PsiLocalVariable) || var.getInitializer() == null) return UNKNOWN;
|
||||
if(isDeclarationJustBefore(var, nextStatement)) return DECLARED_JUST_BEFORE;
|
||||
PsiElement declaration = var.getParent();
|
||||
// Check if variable is not referenced in the same declaration like "int a = 0, b = a;"
|
||||
if(!PsiTreeUtil.processElements(declaration, e -> !(e instanceof PsiReferenceExpression) ||
|
||||
((PsiReferenceExpression)e).resolve() != var)) return UNKNOWN;
|
||||
// Check that variable is declared in the same method or the same lambda expression
|
||||
if(PsiTreeUtil.getParentOfType(var, PsiLambdaExpression.class, PsiMethod.class) !=
|
||||
PsiTreeUtil.getParentOfType(nextStatement, PsiLambdaExpression.class, PsiMethod.class)) return UNKNOWN;
|
||||
@@ -432,7 +429,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
catch (AnalysisCanceledException ignored) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
int start = controlFlow.getEndOffset(declaration);
|
||||
int start = controlFlow.getEndOffset(var.getInitializer())+1;
|
||||
int stop = controlFlow.getStartOffset(nextStatement);
|
||||
if(ControlFlowUtil.isVariableReferencedBetween(controlFlow, start, stop, var)) return UNKNOWN;
|
||||
if (!ControlFlowUtil.isValueUsedWithoutVisitingStop(controlFlow, start, stop, var)) return AT_WANTED_PLACE_ONLY;
|
||||
@@ -559,8 +556,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
PsiStatement[] statements = tb.getStatements();
|
||||
if (statements.length == 2) {
|
||||
PsiStatement breakStatement = statements[1];
|
||||
if (!(breakStatement instanceof PsiBreakStatement) ||
|
||||
((PsiBreakStatement)breakStatement).findExitedStatement() != statement) {
|
||||
if (!ControlFlowUtils.statementBreaksLoop(breakStatement, statement)) {
|
||||
return;
|
||||
}
|
||||
if (ReferencesSearch.search(tb.getVariable(), new LocalSearchScope(statements)).findFirst() == null
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testAnyMatch(List<List<String>> data) {
|
||||
if (!data.isEmpty()) {
|
||||
if (data.stream().flatMap(Collection::stream).anyMatch(str -> !str.isEmpty())) {
|
||||
System.out.println("Found!");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public List<Integer> testFindFirstIfPresent(List<List<String>> data) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
if (!data.isEmpty()) {
|
||||
data.stream().flatMap(Collection::stream).filter(str -> !str.isEmpty()).findFirst().ifPresent(str -> result.add(str.length()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testAnyMatch(List<List<String>> data) {
|
||||
if (!data.isEmpty()) {
|
||||
for (List<String> list : dat<caret>a) {
|
||||
for (String str : list) {
|
||||
if (!str.isEmpty()) {
|
||||
System.out.println("Found!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// "Replace with anyMatch()" "false"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testAnyMatch(List<List<String>> data) {
|
||||
if (!data.isEmpty()) {
|
||||
for (List<String> list : dat<caret>a) {
|
||||
for (String str : list) {
|
||||
if (!str.isEmpty()) {
|
||||
System.out.println("Found!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// "Replace with anyMatch()" "false"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public boolean testAnyMatch(List<List<String>> data) {
|
||||
if (!data.isEmpty()) {
|
||||
for (List<String> list : dat<caret>a) {
|
||||
for (String str : list) {
|
||||
if (!str.isEmpty()) {
|
||||
System.out.println("Found!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Oops");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public List<Integer> testFindFirstIfPresent(List<List<String>> data) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
if (!data.isEmpty()) {
|
||||
for (List<String> list : da<caret>ta) {
|
||||
for (String str : list) {
|
||||
if (!str.isEmpty()) {
|
||||
result.add(str.length());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -17,6 +17,7 @@ package com.siyeh.ig.psiutils;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -544,6 +545,61 @@ public class ControlFlowUtils {
|
||||
return breakFinder.breakFound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given statement effectively breaks given loop. Returns true
|
||||
* if the statement is {@link PsiBreakStatement} having given loop as a target. Also may return
|
||||
* true in other cases if the statement is semantically equivalent to break like this:
|
||||
*
|
||||
* <pre>{@code
|
||||
* int myMethod(int[] data) {
|
||||
* for(int val : data) {
|
||||
* if(val == 5) {
|
||||
* System.out.println(val);
|
||||
* return 0; // this statement is semantically equivalent to break.
|
||||
* }
|
||||
* }
|
||||
* return 0;
|
||||
* }}</pre>
|
||||
*
|
||||
* @param statement statement which may break the loop
|
||||
* @param loop a loop to break
|
||||
* @return true if the statement actually breaks the loop
|
||||
*/
|
||||
@Contract("null, _ -> false")
|
||||
public static boolean statementBreaksLoop(PsiStatement statement, PsiLoopStatement loop) {
|
||||
if(statement instanceof PsiBreakStatement) {
|
||||
return ((PsiBreakStatement)statement).findExitedStatement() == loop;
|
||||
}
|
||||
if(statement instanceof PsiReturnStatement) {
|
||||
PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
|
||||
PsiElement cur = loop;
|
||||
for(PsiElement parent = cur.getParent();;parent = cur.getParent()) {
|
||||
if(parent instanceof PsiLabeledStatement) {
|
||||
cur = parent;
|
||||
} else if(parent instanceof PsiCodeBlock) {
|
||||
PsiCodeBlock block = (PsiCodeBlock)parent;
|
||||
PsiStatement[] statements = block.getStatements();
|
||||
if(block.getParent() instanceof PsiBlockStatement && statements.length > 0 && statements[statements.length-1] == cur) {
|
||||
cur = block.getParent();
|
||||
} else break;
|
||||
} else if(parent instanceof PsiIfStatement) {
|
||||
if(cur == ((PsiIfStatement)parent).getThenBranch() || cur == ((PsiIfStatement)parent).getElseBranch()) {
|
||||
cur = parent;
|
||||
} else break;
|
||||
} else break;
|
||||
}
|
||||
PsiElement nextElement = PsiTreeUtil.skipSiblingsForward(cur, PsiComment.class, PsiWhiteSpace.class);
|
||||
if(nextElement instanceof PsiReturnStatement) {
|
||||
return EquivalenceChecker.getCanonicalPsiEquivalence()
|
||||
.expressionsAreEquivalent(returnValue, ((PsiReturnStatement)nextElement).getReturnValue());
|
||||
}
|
||||
if(nextElement == null && returnValue == null && cur.getParent() instanceof PsiMethod) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class NakedBreakFinder extends JavaRecursiveElementWalkingVisitor {
|
||||
private boolean m_found;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user