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 bb2d9e42640c..3c3f3a9043d0 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 @@ -132,38 +132,44 @@ public class RedundantCastUtil { IElementType tokenType = expression.getOperationTokenType(); PsiExpression[] operands = expression.getOperands(); if (operands.length >= 2) { - PsiType lType = operands[0].getType(); - processBinaryExpressionOperand(deparenthesizeExpression(operands[0]), operands[1].getType(), tokenType); + PsiType lType = processBinaryExpressionOperand(deparenthesizeExpression(operands[0]), operands[1].getType(), tokenType); + for (int i = 1; i < operands.length; i++) { PsiExpression operand = deparenthesizeExpression(operands[i]); if (operand == null) continue; - processBinaryExpressionOperand(operand, lType, tokenType); - lType = TypeConversionUtil.calcTypeForBinaryExpression(lType, operand.getType(), tokenType, true); + PsiType rType = processBinaryExpressionOperand(operand, lType, tokenType); + lType = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, tokenType, true); } } + processNestedCasts(expression.getOperands()); super.visitPolyadicExpression(expression); } - private void processBinaryExpressionOperand(final PsiExpression operand, - final PsiType otherType, - final IElementType binaryToken) { + private @Nullable PsiType processBinaryExpressionOperand(final PsiExpression operand, + final PsiType otherType, + final IElementType binaryToken) { if (operand instanceof PsiTypeCastExpression) { PsiTypeCastExpression typeCast = (PsiTypeCastExpression)operand; PsiExpression toCast = typeCast.getOperand(); - if (toCast != null && TypeConversionUtil.isBinaryOperatorApplicable(binaryToken, toCast.getType(), otherType, false)) { + if (toCast != null && otherType != null && TypeConversionUtil.isBinaryOperatorApplicable(binaryToken, toCast.getType(), otherType, false)) { addToResults(typeCast); + return toCast.getType(); } } + return operand != null ? operand.getType() : null; } private void processPossibleTypeCast(PsiExpression rExpr, @Nullable PsiType lType) { rExpr = deparenthesizeExpression(rExpr); if (rExpr instanceof PsiTypeCastExpression) { - PsiExpression castOperand = ((PsiTypeCastExpression)rExpr).getOperand(); + PsiExpression castOperand = PsiUtil.skipParenthesizedExprDown(((PsiTypeCastExpression)rExpr).getOperand()); if (castOperand != null) { PsiType operandType; if (castOperand instanceof PsiTypeCastExpression) { - final PsiExpression nestedCastOperand = ((PsiTypeCastExpression)castOperand).getOperand(); + PsiExpression nestedCastOperand = ((PsiTypeCastExpression)castOperand).getOperand(); + while (nestedCastOperand instanceof PsiTypeCastExpression) { + nestedCastOperand = PsiUtil.skipParenthesizedExprDown(((PsiTypeCastExpression)nestedCastOperand).getOperand()); + } operandType = nestedCastOperand != null ? nestedCastOperand.getType() : null; } else if (castOperand instanceof PsiFunctionalExpression && lType != null) { @@ -298,30 +304,17 @@ public class RedundantCastUtil { PsiParameter[] parameters = oldMethod.getParameterList().getParameters(); try { + PsiCall newCall = null; for (int i = 0; i < args.length; i++) { ProgressManager.checkCanceled(); final PsiExpression arg = deparenthesizeExpression(args[i]); if (arg instanceof PsiTypeCastExpression) { PsiTypeCastExpression cast = (PsiTypeCastExpression)arg; final PsiType typeByParent = PsiTypesUtil.getExpectedTypeByParent(expression); - final PsiCall newCall; - if (typeByParent != null) { - newCall = (PsiCall)LambdaUtil.copyWithExpectedType(expression, typeByParent); - } - else { - final PsiCall call = LambdaUtil.treeWalkUp(expression); - if (call != null) { - Object marker = new Object(); - PsiTreeUtil.mark(expression, marker); - final PsiCall callCopy = LambdaUtil.copyTopLevelCall(call); - if (callCopy == null) return; - newCall = (PsiCall)PsiTreeUtil.releaseMark(callCopy, marker); - if (newCall == null) return; - } - else { - newCall = (PsiCall)expression.copy(); - } + if (newCall == null) { + newCall = copyCallExpression(expression, typeByParent); } + if (newCall == null) return; final PsiExpressionList argList = newCall.getArgumentList(); LOG.assertTrue(argList != null); PsiExpression[] newArgs = argList.getExpressions(); @@ -371,6 +364,9 @@ public class RedundantCastUtil { elseType != null && targetType.isAssignableFrom(elseType)) { addToResults(cast); } + else { + newArg.replace(arg); + } } else if (!(newArg instanceof PsiFunctionalExpression)) { addToResults(cast); @@ -387,8 +383,14 @@ public class RedundantCastUtil { if (Comparing.equal(castType, ((PsiFunctionalExpression)newArg).getGroundTargetType(newArgType))) { addToResults(cast); } + else { + newArg.replace(arg); + } } } + else { + newArgs[i].replace(arg); + } } else if (arg instanceof PsiLambdaExpression) { final PsiType interfaceType = ((PsiLambdaExpression)arg).getFunctionalInterfaceType(); @@ -425,6 +427,10 @@ public class RedundantCastUtil { return; } + processNestedCasts(args); + } + + private void processNestedCasts(PsiExpression[] args) { for (PsiExpression arg : args) { if (arg instanceof PsiTypeCastExpression) { PsiExpression castOperand = ((PsiTypeCastExpression)arg).getOperand(); @@ -438,6 +444,26 @@ public class RedundantCastUtil { } } + @Nullable + private static PsiCall copyCallExpression(PsiCall expression, PsiType typeByParent) { + if (typeByParent != null) { + return (PsiCall)LambdaUtil.copyWithExpectedType(expression, typeByParent); + } + else { + final PsiCall call = LambdaUtil.treeWalkUp(expression); + if (call != null) { + Object marker = new Object(); + PsiTreeUtil.mark(expression, marker); + final PsiCall callCopy = LambdaUtil.copyTopLevelCall(call); + if (callCopy == null) return null; + return (PsiCall)PsiTreeUtil.releaseMark(callCopy, marker); + } + else { + return (PsiCall)expression.copy(); + } + } + } + private void processLambdaReturnExpression(PsiCall expression, int i, PsiType interfaceType, @@ -574,6 +600,7 @@ public class RedundantCastUtil { if (parent instanceof PsiExpressionList) return; // do not replace in arg lists - should be handled by parent if (parent instanceof PsiReturnStatement) return; if (parent instanceof PsiTypeCastExpression) return; + if (parent instanceof PsiPolyadicExpression) return; if (parent instanceof PsiLambdaExpression) return; diff --git a/java/java-tests/testData/inspection/redundantCast/OneOfTwo.java b/java/java-tests/testData/inspection/redundantCast/OneOfTwo.java index afd86e482f1a..cf3b584d0826 100644 --- a/java/java-tests/testData/inspection/redundantCast/OneOfTwo.java +++ b/java/java-tests/testData/inspection/redundantCast/OneOfTwo.java @@ -8,3 +8,27 @@ class Test { f((String)o, (String)o); } } + +class Test1 { + public Test1(int width, int height) { + this((double)width, (double)height); + } + + private Test1(double width, double height) { } + + private String foo(Object[] array, int index1, int index2) { + return (String) array[index1] + (String) array[index2]; + } + + private static void triple(Object obj) { + String s = (String) (CharSequence) (String) obj; + } + + private Integer parenthesis(Object[] array, int index) { + return (Integer) ((Integer) array[index]); + } + + private String binary(Object[] array, int index1, int index2) { + return (String) array[index1] + (String) array[index2]; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/redundantCast/generics/Inference3.java b/java/java-tests/testData/inspection/redundantCast/generics/Inference3.java index 76a1a74593e5..228c1f88e24a 100644 --- a/java/java-tests/testData/inspection/redundantCast/generics/Inference3.java +++ b/java/java-tests/testData/inspection/redundantCast/generics/Inference3.java @@ -27,5 +27,5 @@ class Test { final Set strings = null; final Pair, Set> x = Boolean.TRUE.booleanValue() ? Pair.create(strings, strings) - : Pair.create(((Set) null), (Set) null); //both casts are marked, but one is required for correct inference + : Pair.create(((Set) null), (Set) null); //both casts are marked, but one is required for correct inference }