IDEA-161260 Migration to findFirst(): Support more expression kinds in the last return statement

This commit is contained in:
Tagir Valeev
2016-09-15 16:30:49 +07:00
parent 15d80a429e
commit 8c3bbd3b2c
10 changed files with 150 additions and 2 deletions
@@ -208,7 +208,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
return;
}
}
if(nextReturnStatement.getReturnValue() instanceof PsiLiteralExpression) {
if(ExpressionUtils.isSimpleExpression(nextReturnStatement.getReturnValue())) {
registerProblem(holder, isOnTheFly, statement, "findFirst", new ReplaceWithFindFirstFix());
}
}
@@ -916,7 +916,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
PsiReturnStatement nextReturnStatement = getNextReturnStatement(foreachStatement);
if(nextReturnStatement == null) return;
PsiExpression orElseExpression = nextReturnStatement.getReturnValue();
if(!(orElseExpression instanceof PsiLiteralExpression)) return;
if(!ExpressionUtils.isSimpleExpression(orElseExpression)) return;
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
StringBuilder builder = generateStream(iteratedValue, intermediateOps).append(".findFirst()");
if (!(value instanceof PsiReferenceExpression) || ((PsiReferenceExpression)value).resolve() != tb.getVariable()) {
@@ -0,0 +1,13 @@
// "Replace with findFirst()" "true"
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
public class Main {
enum MyEnum { FOO, BAR, BAZ }
public static MyEnum find(List<EnumSet<MyEnum>> list) {
return list.stream().flatMap(Collection::stream).filter(val -> val.name().startsWith("B")).findFirst().orElse(MyEnum.FOO);
}
}
@@ -0,0 +1,14 @@
// "Replace with findFirst()" "true"
import java.awt.*;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class Main {
private Point field = new Point(0, 0);
public Point find(List<Point> points) {
return points.stream().filter((Predicate<Point>) Objects::nonNull).findFirst().orElse(field);
}
}
@@ -0,0 +1,14 @@
// "Replace with findFirst()" "true"
import java.awt.*;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class Main {
private static Point ZERO = new Point(0, 0);
public static Point find(List<Point> points) {
return points.stream().filter((Predicate<Point>) Objects::nonNull).findFirst().orElse(ZERO);
}
}
@@ -0,0 +1,13 @@
// "Replace with findFirst()" "false"
import java.awt.*;
import java.util.List;
public class Main {
public Point find(List<Point> points, Main other) {
for (Point pt : poin<caret>ts) {
if (pt != null) return pt;
}
return new Point(0, 0);
}
}
@@ -0,0 +1,19 @@
// "Replace with findFirst()" "true"
import java.util.EnumSet;
import java.util.List;
public class Main {
enum MyEnum { FOO, BAR, BAZ }
public static MyEnum find(List<EnumSet<MyEnum>> list) {
for (EnumSet<MyEnum> set : lis<caret>t) {
for (MyEnum val : set) {
if (val.name().startsWith("B")) {
return val;
}
}
}
return MyEnum.FOO;
}
}
@@ -0,0 +1,15 @@
// "Replace with findFirst()" "true"
import java.awt.*;
import java.util.List;
public class Main {
private Point field = new Point(0, 0);
public Point find(List<Point> points) {
for (Point pt : poin<caret>ts) {
if (pt != null) return pt;
}
return field;
}
}
@@ -0,0 +1,15 @@
// "Replace with findFirst()" "false"
import java.awt.*;
import java.util.List;
public class Main {
private Point field = new Point(0, 0);
public Point find(List<Point> points, Main other) {
for (Point pt : poin<caret>ts) {
if (pt != null) return pt;
}
return other.field;
}
}
@@ -0,0 +1,15 @@
// "Replace with findFirst()" "true"
import java.awt.*;
import java.util.List;
public class Main {
private static Point ZERO = new Point(0, 0);
public static Point find(List<Point> points) {
for (Point pt : point<caret>s) {
if (pt != null) return pt;
}
return ZERO;
}
}
@@ -22,6 +22,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.ConstantExpressionUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -673,4 +674,33 @@ public class ExpressionUtils {
NullableNotNullManager.isNullable(modifierListOwner):
NullableNotNullManager.isNotNull(modifierListOwner);
}
/**
* Returns true if the expression can be moved to earlier point in program order without possible semantic change or
* notable performance handicap. Examples of simple expressions are:
* - literal (number, char, string, class literal, true, false, null)
* - this
* - static field access
* - instance field access having 'this' as qualifier
*
* @param expression an expression to test
* @return true if the supplied expression is simple
*/
@Contract("null -> false")
public static boolean isSimpleExpression(@Nullable PsiExpression expression) {
if (expression instanceof PsiLiteralExpression ||
expression instanceof PsiThisExpression ||
expression instanceof PsiClassObjectAccessExpression) {
return true;
}
if(expression instanceof PsiReferenceExpression) {
PsiExpression qualifier = ((PsiReferenceExpression)expression).getQualifierExpression();
if(qualifier == null || qualifier instanceof PsiThisExpression) return true;
if(qualifier instanceof PsiReferenceExpression) {
PsiElement resolvedQualifier = ((PsiReferenceExpression)qualifier).resolve();
if(resolvedQualifier instanceof PsiClass) return true;
}
}
return false;
}
}