mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-inspections] IDEA-278390 SuspiciousToArrayCall inspection: better recognizing of Stream API semantics
GitOrigin-RevId: 334190f498fef1624c6d58719bd698a0352340a5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
0ba7cf9228
commit
30fb27b314
+46
-11
@@ -28,10 +28,8 @@ import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.InspectionGadgetsFix;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.FunctionalExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.StreamApiUtil;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import com.siyeh.ig.callMatcher.CallMatcher;
|
||||
import com.siyeh.ig.psiutils.*;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -77,10 +75,8 @@ public class SuspiciousToArrayCallInspection extends BaseInspection {
|
||||
if (qualifierExpression == null) {
|
||||
return;
|
||||
}
|
||||
final PsiType type = qualifierExpression.getType();
|
||||
if (!(type instanceof PsiClassType)) {
|
||||
return;
|
||||
}
|
||||
final PsiClassType classType = ObjectUtils.tryCast(qualifierExpression.getType(), PsiClassType.class);
|
||||
if (classType == null || classType.isRaw()) return;
|
||||
final PsiExpressionList argumentList = expression.getArgumentList();
|
||||
final PsiExpression[] arguments = argumentList.getExpressions();
|
||||
if (arguments.length != 1) {
|
||||
@@ -89,8 +85,6 @@ public class SuspiciousToArrayCallInspection extends BaseInspection {
|
||||
final PsiExpression argument = PsiUtil.skipParenthesizedExprDown(arguments[0]);
|
||||
if (argument == null) return;
|
||||
|
||||
final PsiClassType classType = (PsiClassType)type;
|
||||
if (classType.isRaw()) return;
|
||||
final PsiClass aClass = classType.resolve();
|
||||
if (aClass == null) {
|
||||
return;
|
||||
@@ -106,11 +100,52 @@ public class SuspiciousToArrayCallInspection extends BaseInspection {
|
||||
else if (InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_STREAM)) {
|
||||
PsiType argumentType = getIntFunctionParameterType(argument);
|
||||
if (argumentType != null) {
|
||||
checkArrayTypes(argument, expression, argumentType, StreamApiUtil.getStreamElementType(classType, false));
|
||||
checkArrayTypes(argument, expression, argumentType, getStreamElementType(qualifierExpression));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final CallMatcher STREAM_FILTER = CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_STREAM_STREAM, "filter")
|
||||
.parameterTypes(CommonClassNames.JAVA_UTIL_FUNCTION_PREDICATE);
|
||||
private static final CallMatcher CLASS_INSTANCEOF = CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_CLASS, "isInstance")
|
||||
.parameterCount(1);
|
||||
|
||||
/**
|
||||
* @param expression stream expression
|
||||
* @return type of elements inside the stream. Tries to take into account previous filters by element type
|
||||
*/
|
||||
private static @Nullable PsiType getStreamElementType(PsiExpression expression) {
|
||||
PsiMethodCallExpression call =
|
||||
ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(expression), PsiMethodCallExpression.class);
|
||||
while (STREAM_FILTER.test(call)) {
|
||||
PsiExpression predicate = PsiUtil.skipParenthesizedExprDown(call.getArgumentList().getExpressions()[0]);
|
||||
if (predicate instanceof PsiMethodReferenceExpression) {
|
||||
if (CLASS_INSTANCEOF.methodReferenceMatches((PsiMethodReferenceExpression)predicate)) {
|
||||
PsiExpression qualifier = PsiUtil.skipParenthesizedExprDown(((PsiMethodReferenceExpression)predicate).getQualifierExpression());
|
||||
if (qualifier instanceof PsiClassObjectAccessExpression) {
|
||||
return ((PsiClassObjectAccessExpression)qualifier).getOperand().getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (predicate instanceof PsiLambdaExpression) {
|
||||
PsiParameter[] parameters = ((PsiLambdaExpression)predicate).getParameterList().getParameters();
|
||||
if (parameters.length == 1) {
|
||||
PsiExpression lambdaBody =
|
||||
PsiUtil.skipParenthesizedExprDown(LambdaUtil.extractSingleExpressionFromBody(((PsiLambdaExpression)predicate).getBody()));
|
||||
if (lambdaBody instanceof PsiInstanceOfExpression &&
|
||||
ExpressionUtils.isReferenceTo(((PsiInstanceOfExpression)lambdaBody).getOperand(), parameters[0])) {
|
||||
PsiTypeElement checkType = ((PsiInstanceOfExpression)lambdaBody).getCheckType();
|
||||
if (checkType != null) {
|
||||
return checkType.getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
call = MethodCallUtils.getQualifierMethodCall(call);
|
||||
}
|
||||
return StreamApiUtil.getStreamElementType(expression.getType(), false);
|
||||
}
|
||||
|
||||
private static PsiType getIntFunctionParameterType(PsiExpression argument) {
|
||||
PsiType argumentType = FunctionalExpressionUtils.getFunctionalExpressionType(argument);
|
||||
return PsiUtil.substituteTypeParameter(argumentType, "java.util.function.IntFunction", 0, false);
|
||||
|
||||
+20
@@ -136,6 +136,26 @@ public class SuspiciousToArrayCallInspectionTest extends LightJavaInspectionTest
|
||||
"class Bar extends Foo {}");
|
||||
}
|
||||
|
||||
public void testStreamFilter() {
|
||||
doTest("import java.util.Arrays;\n" +
|
||||
"class Parent {}\n" +
|
||||
"class Child extends Parent {}\n" +
|
||||
"class Test {\n" +
|
||||
" void test(Parent[] parent) {\n" +
|
||||
" Child[] children = Arrays.stream(parent)\n" +
|
||||
" .filter(t -> t instanceof Child)\n" +
|
||||
" .toArray(Child[]::new);\n" +
|
||||
" Child[] children2 = Arrays.stream(parent)\n" +
|
||||
" .filter(Child.class::isInstance)\n" +
|
||||
" .toArray(Child[]::new);\n" +
|
||||
" Child[] children3 = Arrays.stream(parent)\n" +
|
||||
" .filter(Child.class::isInstance)\n" +
|
||||
" .filter(c -> c.hashCode() > 0)\n" +
|
||||
" .toArray(Child[]::new);\n" +
|
||||
" }\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
|
||||
Reference in New Issue
Block a user