From 89d1df1dc0e202bf8e6cb3b86c663957edc5684a Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 12 Nov 2014 11:54:09 +0100 Subject: [PATCH] redundant casts in lambda return expressions (IDEA-132723) --- .../intellij/psi/util/RedundantCastUtil.java | 76 ++++++++++++++++++- .../LambdaReturnExpressions.java | 40 ++++++++++ .../lambda/LambdaRedundantCastTest.java | 8 ++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/LambdaReturnExpressions.java diff --git a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java index ccb606d51376..eca80b6ee824 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java @@ -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 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() { + @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() { + @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() { + @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 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(); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/LambdaReturnExpressions.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/LambdaReturnExpressions.java new file mode 100644 index 000000000000..9222b984fa0f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/LambdaReturnExpressions.java @@ -0,0 +1,40 @@ +import java.util.function.Supplier; + +class Main { + private static void boom() {} + private static void map (Supplier fn) {} + private static void map1(Supplier 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(() -> (Runnable) Main::boom); + map1(() -> true ? (Runnable) Main::boom : (Runnable) Main::boom); + map1(() -> { + return true ? (Runnable) Main::boom : (Runnable) Main::boom; + }); + map1(() -> true ? (Runnable) Main::boom : r); + map1(() -> (true ? (Runnable) (Main::boom) : r)); + map1(() -> { + if (true) { + return (Runnable) Main::boom; + } + return (Runnable) Main::boom; + }); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java index ae5a97933ca8..f66b9b95ad3b 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java @@ -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(); + } }