diff --git a/java/java-analysis-impl/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-analysis-impl/src/com/intellij/psi/util/RedundantCastUtil.java index d3a5af50c61e..442dc66ebf24 100644 --- a/java/java-analysis-impl/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-analysis-impl/src/com/intellij/psi/util/RedundantCastUtil.java @@ -360,6 +360,24 @@ public class RedundantCastUtil { else if (arg instanceof PsiLambdaExpression) { checkLambdaReturnsInsideCall(i, (PsiLambdaExpression)arg, newArgs, expression, newCall, parameters); } + else if (arg instanceof PsiConditionalExpression) { + PsiType conditionalType = arg.getType(); + + PsiExpression newThenExpression = deparenthesizeExpression(((PsiConditionalExpression)Objects.requireNonNull(deparenthesizeExpression(newArgs[i]))).getThenExpression()); + PsiExpression thenExpression = ((PsiConditionalExpression)arg).getThenExpression(); + + PsiExpression newElseExpression = deparenthesizeExpression(((PsiConditionalExpression)Objects.requireNonNull(deparenthesizeExpression(newArgs[i]))).getElseExpression()); + PsiExpression elseExpression = ((PsiConditionalExpression)arg).getElseExpression(); + + if (newThenExpression instanceof PsiTypeCastExpression && + !castForBoxing(getInnerMostOperand(thenExpression), elseExpression != null ? elseExpression.getType() : null, conditionalType)) { + checkConditionalBranch(expression, newCall, oldMethod, thenExpression, newThenExpression); + } + if (newElseExpression instanceof PsiTypeCastExpression && + !castForBoxing(getInnerMostOperand(elseExpression), thenExpression != null ? thenExpression.getType() : null, conditionalType)) { + checkConditionalBranch(expression, newCall, oldMethod, elseExpression, newElseExpression); + } + } } } catch (IncorrectOperationException e) { @@ -369,6 +387,32 @@ public class RedundantCastUtil { processNestedCasts(args); } + private void checkConditionalBranch(PsiCall oldCall, + PsiCall newCall, + PsiMethod oldMethod, + PsiExpression oldBranchExpression, + PsiExpression newBranchExpression) { + PsiExpression operand = ((PsiTypeCastExpression)newBranchExpression).getOperand(); + if (operand != null) { + newBranchExpression = (PsiExpression)newBranchExpression.replace(operand); + JavaResolveResult newResult = resolveNewResult(oldCall, newCall); + if (newResult.getElement() == oldMethod && + newResult.isValidResult()) { + addToResults((PsiTypeCastExpression)oldBranchExpression); + } + else { + newBranchExpression.replace(oldBranchExpression); + } + } + } + + private static boolean castForBoxing(PsiExpression operand, PsiType oppositeType, PsiType conditionalType) { + return operand != null && + TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()) && + !(oppositeType instanceof PsiPrimitiveType) && + !(conditionalType instanceof PsiPrimitiveType); + } + private void checkLambdaReturnsInsideCall(int i, PsiLambdaExpression arg, PsiExpression[] newArgs, @@ -393,13 +437,17 @@ public class RedundantCastUtil { else if (returnExpression instanceof PsiConditionalExpression) { final PsiExpression thenExpression = deparenthesizeExpression(((PsiConditionalExpression)returnExpression).getThenExpression()); PsiExpression newThenExpression = deparenthesizeExpression(((PsiConditionalExpression)newReturnExpression).getThenExpression()); - if (thenExpression instanceof PsiTypeCastExpression) { - checkLambdaReturn(i, thenExpression, (PsiTypeCastExpression)newThenExpression, interfaceType, newLambdaExpression, oldCall, newCall, parameters); - } final PsiExpression elseExpression = deparenthesizeExpression(((PsiConditionalExpression)returnExpression).getElseExpression()); final PsiExpression newElseExpression = deparenthesizeExpression(((PsiConditionalExpression)newReturnExpression).getElseExpression()); - if (elseExpression instanceof PsiTypeCastExpression) { + + if (thenExpression instanceof PsiTypeCastExpression && + !castForBoxing(getInnerMostOperand(thenExpression), elseExpression != null ? elseExpression.getType() : null, returnExpression.getType())) { + checkLambdaReturn(i, thenExpression, (PsiTypeCastExpression)newThenExpression, interfaceType, newLambdaExpression, oldCall, newCall, parameters); + } + + if (elseExpression instanceof PsiTypeCastExpression && + !castForBoxing(getInnerMostOperand(elseExpression), thenExpression != null ? thenExpression.getType() : null, returnExpression.getType())) { checkLambdaReturn(i, elseExpression, (PsiTypeCastExpression)newElseExpression, interfaceType, newLambdaExpression, oldCall, newCall, parameters); } } @@ -439,8 +487,8 @@ public class RedundantCastUtil { final PsiEnumConstant enumConstant = (PsiEnumConstant)oldCall; PsiClass containingClass = enumConstant.getContainingClass(); final JavaPsiFacade facade = JavaPsiFacade.getInstance(enumConstant.getProject()); - final PsiClassType type = facade.getElementFactory().createType(containingClass); - newResult = facade.getResolveHelper().resolveConstructor(type, newCall.getArgumentList(), enumConstant); + final PsiClassType type = facade.getElementFactory().createType(Objects.requireNonNull(containingClass)); + newResult = facade.getResolveHelper().resolveConstructor(type, Objects.requireNonNull(newCall.getArgumentList()), enumConstant); } else { newResult = newCall.resolveMethodGenerics(); @@ -456,7 +504,7 @@ public class RedundantCastUtil { final PsiTypeElement castTypeElement = arg.getCastType(); final PsiType castType = castTypeElement != null ? castTypeElement.getType() : null; - PsiExpression castOperand = ((PsiTypeCastExpression)deparenthesizeExpression(newArgs[i])).getOperand(); + PsiExpression castOperand = ((PsiTypeCastExpression)Objects.requireNonNull(deparenthesizeExpression(newArgs[i]))).getOperand(); if (castOperand == null) return; newArgs[i] = (PsiExpression)newArgs[i].replace(castOperand); @@ -652,44 +700,6 @@ public class RedundantCastUtil { super.visitTypeCastExpression(typeCast); } - private static boolean checkResolveAfterRemoveCast(PsiElement parent) { - PsiElement grandPa = PsiUtil.skipParenthesizedExprUp(parent.getParent()); - if (grandPa instanceof PsiExpressionList) { - int idx = LambdaUtil.getLambdaIdx((PsiExpressionList)grandPa, parent); - PsiElement grandGrandPa = grandPa.getParent(); - if (grandGrandPa instanceof PsiCall) { - PsiMethod resolve = ((PsiCall)grandGrandPa).resolveMethod(); - if (resolve != null) { - PsiCall expression = LambdaUtil.copyTopLevelCall((PsiCall)grandGrandPa); - if (expression == null) return false; - PsiExpressionList argumentList = expression.getArgumentList(); - LOG.assertTrue(argumentList != null); - PsiExpression toReplace = deparenthesizeExpression(argumentList.getExpressions()[idx]); - if (toReplace instanceof PsiConditionalExpression) { - PsiExpression thenExpression = deparenthesizeExpression(((PsiConditionalExpression)toReplace).getThenExpression()); - PsiExpression elseExpression = deparenthesizeExpression(((PsiConditionalExpression)toReplace).getElseExpression()); - if (thenExpression instanceof PsiTypeCastExpression) { - final PsiExpression thenOperand = ((PsiTypeCastExpression)thenExpression).getOperand(); - if (thenOperand != null) { - thenExpression.replace(thenOperand); - } - } - if (elseExpression instanceof PsiTypeCastExpression) { - final PsiExpression elseOperand = ((PsiTypeCastExpression)elseExpression).getOperand(); - if (elseOperand != null) { - elseExpression.replace(elseOperand); - } - } - } - if (expression.resolveMethod() != resolve) { - return false; - } - } - } - } - return true; - } - @Override public void visitForeachStatement(PsiForeachStatement statement) { PsiExpression iteratedValue = deparenthesizeExpression(statement.getIteratedValue()); @@ -907,13 +917,19 @@ public class RedundantCastUtil { if (gParent instanceof PsiReturnStatement && PsiTreeUtil.getParentOfType(gParent, PsiMethod.class, PsiLambdaExpression.class) instanceof PsiLambdaExpression) return; - PsiExpression thenExpression = deparenthesizeExpression(conditionalExpression.getThenExpression()); - PsiExpression elseExpression = deparenthesizeExpression(conditionalExpression.getElseExpression()); - if (thenExpression instanceof PsiTypeCastExpression) { - visitConditional((PsiTypeCastExpression)thenExpression, conditionalExpression, getInnerMostOperand(elseExpression)); - } - if (elseExpression instanceof PsiTypeCastExpression) { - visitConditional((PsiTypeCastExpression)elseExpression, conditionalExpression, getInnerMostOperand(thenExpression)); + if (!(gParent instanceof PsiExpressionList)) { + PsiExpression thenExpression = deparenthesizeExpression(conditionalExpression.getThenExpression()); + PsiExpression elseExpression = deparenthesizeExpression(conditionalExpression.getElseExpression()); + if (thenExpression instanceof PsiTypeCastExpression) { + visitConditional((PsiTypeCastExpression)thenExpression, + conditionalExpression, + getInnerMostOperand(elseExpression)); + } + if (elseExpression instanceof PsiTypeCastExpression) { + visitConditional((PsiTypeCastExpression)elseExpression, + conditionalExpression, + getInnerMostOperand(deparenthesizeExpression(conditionalExpression.getThenExpression()))); + } } addIfNarrowing(conditionalExpression.getCondition(), PsiType.BOOLEAN); @@ -931,7 +947,7 @@ public class RedundantCastUtil { PsiType opType = operand.getType(); - if (castTo instanceof PsiClassType && opType instanceof PsiPrimitiveType && opType != PsiType.NULL) { + if (castTo instanceof PsiClassType && TypeConversionUtil.isPrimitiveAndNotNull(opType)) { if (oppositeOperand != null && !(oppositeOperand.getType() instanceof PsiPrimitiveType) && !(PsiTypesUtil.getExpectedTypeByParent(parent) instanceof PsiPrimitiveType)) { @@ -944,7 +960,6 @@ public class RedundantCastUtil { if (!PsiUtil.isLanguageLevel5OrHigher(typeCast)) { return; } - if (!checkResolveAfterRemoveCast(parent)) return; if (!PsiPolyExpressionUtil.isPolyExpression(parent)) { //branches need to be of the same type if (oppositeOperand == null || !Comparing.equal(conditionalType, oppositeOperand.getType())) return; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/BoxingInConditionalOfLambdaReturn.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/BoxingInConditionalOfLambdaReturn.java new file mode 100644 index 000000000000..457d02177df0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/redundantCast/BoxingInConditionalOfLambdaReturn.java @@ -0,0 +1,15 @@ +class RedundantCastTest { + + public static void main(String[] args) { + Integer bar = null; + print(() -> args == null || args.length == 0 ? bar : (Integer) 1); + } + + private static void print(I i) { + Integer myI = i.get(); + } + + interface I { + Integer get(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/LambdaRedundantCastTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/LambdaRedundantCastTest.java index d3783099b9b6..9428f8093091 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/LambdaRedundantCastTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/LambdaRedundantCastTest.java @@ -87,6 +87,7 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase { public void testErasedTargetType() { doTest(); } public void testThrowsStatementInLambdaBody() { doTest(); } public void testSynchronizeCasts() { doTest(); } + public void testBoxingInConditionalOfLambdaReturn() { doTest(); } public void testRejectReturnTypeChange() { doTest(); }