From ad99c2d9b560816779598593694e4ee558ed052e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 26 Aug 2015 21:30:25 +0300 Subject: [PATCH] anonymous -> lambda: cast if overload would fail (IDEA-144372) --- .../AnonymousCanBeLambdaInspection.java | 86 ++++++------------- .../GuavaFunctionAndPredicateConverter.java | 2 +- .../intellij/psi/util/RedundantCastUtil.java | 11 +++ .../afterClassObjectAccess.java | 2 +- .../anonymous2lambda/afterFormalTypes.java | 2 +- .../anonymous2lambda/afterSameOverload.java | 14 +++ .../anonymous2lambda/beforeSameOverload.java | 19 ++++ 7 files changed, 71 insertions(+), 65 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterSameOverload.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeSameOverload.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java index 0ae52adb5325..953ac60f2bc1 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/AnonymousCanBeLambdaInspection.java @@ -206,7 +206,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection return false; } - public static PsiLambdaExpression replacePsiElementWithLambda(@NotNull PsiElement element, final boolean ignoreEqualsMethod) { + public static PsiExpression replacePsiElementWithLambda(@NotNull PsiElement element, final boolean ignoreEqualsMethod) { if (element instanceof PsiNewExpression) { if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return null; final PsiAnonymousClass anonymousClass = ((PsiNewExpression)element).getAnonymousClass(); @@ -215,7 +215,6 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection ChangeContextUtil.encodeContextInfo(anonymousClass, true); final PsiElement lambdaContext = anonymousClass.getParent().getParent(); - boolean validContext = LambdaUtil.isValidLambdaContext(lambdaContext); final String canonicalText = anonymousClass.getBaseClassType().getCanonicalText(); final PsiMethod method; @@ -254,8 +253,7 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection ReplaceWithLambdaFix .giveUniqueNames(project, anonymousClass, elementFactory, body, conflictingLocals.toArray(new PsiVariable[conflictingLocals.size()])); - final String lambdaWithTypesDeclared = ReplaceWithLambdaFix.composeLambdaText(method, true); - final String withoutTypesDeclared = ReplaceWithLambdaFix.composeLambdaText(method, false); + final String withoutTypesDeclared = ReplaceWithLambdaFix.composeLambdaText(method); PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)elementFactory.createExpressionFromText(withoutTypesDeclared, anonymousClass); @@ -275,47 +273,24 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection lambdaExpression.getBody().replace(singleExpr); } ChangeContextUtil.decodeContextInfo(lambdaExpression, null, null); - if (!validContext) { - final PsiParenthesizedExpression typeCast = - (PsiParenthesizedExpression)elementFactory.createExpressionFromText("((" + canonicalText + ")" + withoutTypesDeclared + ")", lambdaExpression); - final PsiExpression typeCastExpr = typeCast.getExpression(); - LOG.assertTrue(typeCastExpr != null); - final PsiExpression typeCastOperand = ((PsiTypeCastExpression)typeCastExpr).getOperand(); - LOG.assertTrue(typeCastOperand != null); - final PsiElement fromText = ((PsiLambdaExpression)typeCastOperand).getBody(); - LOG.assertTrue(fromText != null); - lambdaBody = lambdaExpression.getBody(); - LOG.assertTrue(lambdaBody != null); - fromText.replace(lambdaBody); - lambdaExpression.replace(typeCast); - return lambdaExpression; - } - PsiType interfaceType = lambdaExpression.getFunctionalInterfaceType(); - if (ReplaceWithLambdaFix.isInferred(lambdaExpression, interfaceType)) { - final PsiLambdaExpression withTypes = - (PsiLambdaExpression)elementFactory.createExpressionFromText(lambdaWithTypesDeclared, lambdaExpression); - final PsiElement withTypesBody = withTypes.getBody(); - LOG.assertTrue(withTypesBody != null); - lambdaBody = lambdaExpression.getBody(); - LOG.assertTrue(lambdaBody != null); - withTypesBody.replace(lambdaBody); - lambdaExpression = (PsiLambdaExpression)lambdaExpression.replace(withTypes); - - interfaceType = lambdaExpression.getFunctionalInterfaceType(); - if (ReplaceWithLambdaFix.isInferred(lambdaExpression, interfaceType)) { - final PsiTypeCastExpression typeCast = (PsiTypeCastExpression)elementFactory.createExpressionFromText("(" + canonicalText + ")" + withoutTypesDeclared, lambdaExpression); - final PsiExpression typeCastOperand = typeCast.getOperand(); - LOG.assertTrue(typeCastOperand instanceof PsiLambdaExpression); - final PsiElement fromText = ((PsiLambdaExpression)typeCastOperand).getBody(); - LOG.assertTrue(fromText != null); - lambdaBody = lambdaExpression.getBody(); - LOG.assertTrue(lambdaBody != null); - fromText.replace(lambdaBody); - lambdaExpression.replace(typeCast); - } + PsiTypeCastExpression typeCast = (PsiTypeCastExpression)elementFactory + .createExpressionFromText("(" + canonicalText + ")" + withoutTypesDeclared, lambdaExpression); + final PsiExpression typeCastOperand = typeCast.getOperand(); + LOG.assertTrue(typeCastOperand instanceof PsiLambdaExpression); + final PsiElement fromText = ((PsiLambdaExpression)typeCastOperand).getBody(); + LOG.assertTrue(fromText != null); + lambdaBody = lambdaExpression.getBody(); + LOG.assertTrue(lambdaBody != null); + fromText.replace(lambdaBody); + ((PsiLambdaExpression)typeCastOperand).getParameterList().replace(lambdaExpression.getParameterList()); + typeCast = (PsiTypeCastExpression)lambdaExpression.replace(typeCast); + if (RedundantCastUtil.isCastRedundant(typeCast)) { + final PsiExpression operand = typeCast.getOperand(); + LOG.assertTrue(operand != null); + return (PsiExpression)typeCast.replace(operand); } - return lambdaExpression; + return (PsiExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(typeCast); } return null; } @@ -385,45 +360,32 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection } } - private static boolean isInferred(PsiLambdaExpression lambdaExpression, PsiType interfaceType) { - return interfaceType == null || !LambdaUtil.isLambdaFullyInferred(lambdaExpression, interfaceType) || !LambdaUtil.isFunctionalType(interfaceType); - } - - private static String composeLambdaText(PsiMethod method, final boolean appendType) { + private static String composeLambdaText(PsiMethod method) { final StringBuilder buf = new StringBuilder(); final PsiParameter[] parameters = method.getParameterList().getParameters(); - if (parameters.length != 1 || appendType) { + if (parameters.length != 1) { buf.append("("); } buf.append(StringUtil.join(parameters, new Function() { @Override public String fun(PsiParameter parameter) { - return composeParameter(parameter, appendType); + return composeParameter(parameter); } }, ",")); - if (parameters.length != 1 || appendType) { + if (parameters.length != 1) { buf.append(")"); } buf.append("-> {}"); return buf.toString(); } - private static String composeParameter(PsiParameter parameter, - boolean appendType) { - final String parameterType; - if (appendType) { - final PsiTypeElement typeElement = parameter.getTypeElement(); - parameterType = typeElement != null ? (typeElement.getText() + " ") : ""; - } - else { - parameterType = ""; - } + private static String composeParameter(PsiParameter parameter) { String parameterName = parameter.getName(); if (parameterName == null) { parameterName = ""; } - return parameterType + parameterName; + return parameterName; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFunctionAndPredicateConverter.java b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFunctionAndPredicateConverter.java index c0e5d4d3c9d6..331e9f8ddaf6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFunctionAndPredicateConverter.java +++ b/java/java-impl/src/com/intellij/codeInspection/java18StreamApi/GuavaFunctionAndPredicateConverter.java @@ -56,7 +56,7 @@ public class GuavaFunctionAndPredicateConverter { if (expression instanceof PsiNewExpression) { final PsiAnonymousClass anonymousClass = ((PsiNewExpression)expression).getAnonymousClass(); if (anonymousClass != null && AnonymousCanBeLambdaInspection.canBeConvertedToLambda(anonymousClass, true)) { - final PsiLambdaExpression lambdaExpression = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true); + final PsiExpression lambdaExpression = AnonymousCanBeLambdaInspection.replacePsiElementWithLambda(expression, true); LOG.assertTrue(lambdaExpression != null); return lambdaExpression.getText(); } 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 260d93ec6637..586430d16408 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 @@ -157,6 +157,17 @@ public class RedundantCastUtil { super.visitAssignmentExpression(expression); } + @Override + public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { + PsiType type = expression.getType(); + if (type instanceof PsiArrayType) { + for (PsiExpression initializer : expression.getInitializers()) { + processPossibleTypeCast(initializer, ((PsiArrayType)type).getComponentType()); + } + } + super.visitArrayInitializerExpression(expression); + } + @Override public void visitVariable(PsiVariable variable) { processPossibleTypeCast(variable.getInitializer(), variable.getType()); super.visitVariable(variable); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterClassObjectAccess.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterClassObjectAccess.java index 8754508527e0..c606645f02dd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterClassObjectAccess.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterClassObjectAccess.java @@ -2,7 +2,7 @@ class Test { { ((Runnable) () -> { - + }).getClass();; } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java index a5358d3feb4e..7a6cfeb52d19 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterFormalTypes.java @@ -9,6 +9,6 @@ class Test2 { static I bar(I i){return i;} { - bar(list -> null); + bar((I) list -> null); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterSameOverload.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterSameOverload.java new file mode 100644 index 000000000000..41c66a5d0019 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/afterSameOverload.java @@ -0,0 +1,14 @@ +// "Replace with lambda" "true" +import java.util.concurrent.Callable; + +class A { + static void submit(Runnable r){} + + static T submit(Callable c){ + return null; + } + + public static void main(String[] args) { + submit((Runnable) () -> new A()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeSameOverload.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeSameOverload.java new file mode 100644 index 000000000000..92e8ecd566b2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/anonymous2lambda/beforeSameOverload.java @@ -0,0 +1,19 @@ +// "Replace with lambda" "true" +import java.util.concurrent.Callable; + +class A { + static void submit(Runnable r){} + + static T submit(Callable c){ + return null; + } + + public static void main(String[] args) { + submit(new Runnable() { + @Override + public void run() { + new A(); + } + }); + } +} \ No newline at end of file