mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
redundant casts in lambda return expressions (IDEA-132723)
This commit is contained in:
@@ -25,6 +25,7 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -341,6 +342,47 @@ public class RedundantCastUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (arg instanceof PsiLambdaExpression) {
|
||||
final PsiType interfaceType = ((PsiLambdaExpression)arg).getFunctionalInterfaceType();
|
||||
if (interfaceType != null) {
|
||||
List<PsiExpression> expressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)arg);
|
||||
for (int returnExprIdx = 0; returnExprIdx < expressions.size(); returnExprIdx++) {
|
||||
PsiExpression returnExpression = deparenthesizeExpression(expressions.get(returnExprIdx));
|
||||
if (returnExpression instanceof PsiTypeCastExpression) {
|
||||
processLambdaReturnExpression(expression, i, interfaceType, (PsiTypeCastExpression)returnExpression, returnExprIdx,
|
||||
new Function<PsiExpression, PsiTypeCastExpression>() {
|
||||
@Override
|
||||
public PsiTypeCastExpression fun(PsiExpression expression) {
|
||||
return (PsiTypeCastExpression)expression;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (returnExpression instanceof PsiConditionalExpression) {
|
||||
final PsiExpression thenExpression = ((PsiConditionalExpression)returnExpression).getThenExpression();
|
||||
if (thenExpression instanceof PsiTypeCastExpression) {
|
||||
processLambdaReturnExpression(expression, i, interfaceType, (PsiTypeCastExpression)thenExpression,
|
||||
returnExprIdx, new Function<PsiExpression, PsiTypeCastExpression>() {
|
||||
@Override
|
||||
public PsiTypeCastExpression fun(PsiExpression expression) {
|
||||
return (PsiTypeCastExpression)((PsiConditionalExpression)expression).getThenExpression();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final PsiExpression elseExpression = ((PsiConditionalExpression)returnExpression).getElseExpression();
|
||||
if (elseExpression instanceof PsiTypeCastExpression) {
|
||||
processLambdaReturnExpression(expression, i, interfaceType, (PsiTypeCastExpression)elseExpression,
|
||||
returnExprIdx, new Function<PsiExpression, PsiTypeCastExpression>() {
|
||||
@Override
|
||||
public PsiTypeCastExpression fun(PsiExpression expression) {
|
||||
return (PsiTypeCastExpression)((PsiConditionalExpression)expression).getElseExpression();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
@@ -360,6 +402,29 @@ public class RedundantCastUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private void processLambdaReturnExpression(PsiCall expression,
|
||||
int i,
|
||||
PsiType interfaceType,
|
||||
PsiTypeCastExpression returnExpression,
|
||||
int returnExprIdx,
|
||||
Function<PsiExpression, PsiTypeCastExpression> computeCastExpression) {
|
||||
final PsiCall newCall = (PsiCall)expression.copy();
|
||||
final PsiExpressionList newArgsList = newCall.getArgumentList();
|
||||
LOG.assertTrue(newArgsList != null);
|
||||
final PsiExpression[] newArgs = newArgsList.getExpressions();
|
||||
final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)deparenthesizeExpression(newArgs[i]);
|
||||
LOG.assertTrue(lambdaExpression != null, newCall);
|
||||
final PsiExpression newReturnExpression = deparenthesizeExpression(LambdaUtil.getReturnExpressions(lambdaExpression).get(returnExprIdx));
|
||||
PsiTypeCastExpression castExpression = computeCastExpression.fun(newReturnExpression);
|
||||
PsiExpression castOperand = castExpression.getOperand();
|
||||
if (castOperand == null) return;
|
||||
castExpression.replace(castOperand);
|
||||
final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
|
||||
if (interfaceType.equals(functionalInterfaceType)) {
|
||||
addToResults(returnExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void visitTypeCastExpression(PsiTypeCastExpression typeCast) {
|
||||
PsiExpression operand = typeCast.getOperand();
|
||||
if (operand == null) return;
|
||||
@@ -404,7 +469,7 @@ public class RedundantCastUtil {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(typeCast, true);
|
||||
final PsiType functionalInterfaceType = PsiTypesUtil.getExpectedTypeByParent(typeCast);
|
||||
if (topCastType != null && functionalInterfaceType != null && !TypeConversionUtil.isAssignable(topCastType, functionalInterfaceType, false)) return;
|
||||
}
|
||||
processAlreadyHasTypeCast(typeCast);
|
||||
@@ -456,6 +521,15 @@ public class RedundantCastUtil {
|
||||
if (parent instanceof PsiReturnStatement) return;
|
||||
if (parent instanceof PsiTypeCastExpression) return;
|
||||
|
||||
if (parent instanceof PsiLambdaExpression) return;
|
||||
|
||||
if (parent instanceof PsiConditionalExpression) {
|
||||
PsiElement gParent = PsiUtil.skipParenthesizedExprUp(parent.getParent());
|
||||
if (gParent instanceof PsiLambdaExpression) return;
|
||||
if (gParent instanceof PsiReturnStatement &&
|
||||
PsiTreeUtil.getParentOfType(gParent, PsiMethod.class, PsiLambdaExpression.class) instanceof PsiLambdaExpression) return;
|
||||
}
|
||||
|
||||
if (isTypeCastSemantic(typeCast)) return;
|
||||
|
||||
PsiTypeElement typeElement = typeCast.getCastType();
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class Main {
|
||||
private static void boom() {}
|
||||
private static <R> void map (Supplier<R> fn) {}
|
||||
private static void map1(Supplier<Runnable> fn) {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Runnable r = () -> {};
|
||||
map(() -> (Runnable) Main::boom );
|
||||
map(() -> true ? (Runnable) Main::boom : (Runnable) Main::boom );
|
||||
map(() -> {
|
||||
return true ? (Runnable) Main::boom : (Runnable) Main::boom;
|
||||
});
|
||||
|
||||
map(() -> true ? (Runnable) Main::boom : r );
|
||||
map(() -> (true ? (Runnable)(Main::boom) : r));
|
||||
|
||||
map(() -> {
|
||||
if (true) {
|
||||
return (Runnable) Main::boom;
|
||||
}
|
||||
return (Runnable) Main::boom;
|
||||
});
|
||||
|
||||
map1(() -> (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom);
|
||||
map1(() -> true ? (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom : (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom);
|
||||
map1(() -> {
|
||||
return true ? (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom : (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom;
|
||||
});
|
||||
map1(() -> true ? (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom : r);
|
||||
map1(() -> (true ? (<warning descr="Casting '(Main::boom)' to 'Runnable' is redundant">Runnable</warning>) (Main::boom) : r));
|
||||
map1(() -> {
|
||||
if (true) {
|
||||
return (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom;
|
||||
}
|
||||
return (<warning descr="Casting 'Main::boom' to 'Runnable' is redundant">Runnable</warning>) Main::boom;
|
||||
});
|
||||
}
|
||||
}
|
||||
+8
@@ -18,6 +18,8 @@ package com.intellij.codeInsight.daemon.lambda;
|
||||
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.redundantCast.RedundantCastInspection;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -34,7 +36,13 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase {
|
||||
|
||||
public void testIntersection() { doTest(); }
|
||||
public void testSer() { doTest(); }
|
||||
public void testLambdaReturnExpressions() { doTest(); }
|
||||
private void doTest() {
|
||||
doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return IdeaTestUtil.getMockJdk18();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user