From 14fa0849cd4c8fdf6eeb08bc08c064b750b63bb7 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 26 Jun 2020 10:40:29 +0700 Subject: [PATCH] AddTypeCast: automatically convert literals in common cases (IDEA-20480) GitOrigin-RevId: f44030ecd28f1dd7e268474fafe9beb7f65e81fb --- .../daemon/impl/quickfix/AddTypeCastFix.java | 55 ++++++++++++++++++- .../addTypeCast/afterFloatToDouble.java | 9 +++ .../addTypeCast/afterFloatToDouble2.java | 9 +++ .../addTypeCast/afterIntToDouble.java | 9 +++ .../addTypeCast/afterIntToDoubleHex.java | 9 +++ .../quickFix/addTypeCast/afterIntToFloat.java | 9 +++ .../quickFix/addTypeCast/afterIntToLong.java | 9 +++ .../quickFix/addTypeCast/afterLongToInt.java | 9 +++ .../addTypeCast/afterLongToIntTooBig.java | 9 +++ .../addTypeCast/beforeFloatToDouble.java | 9 +++ .../addTypeCast/beforeFloatToDouble2.java | 9 +++ .../addTypeCast/beforeIntToDouble.java | 9 +++ .../addTypeCast/beforeIntToDoubleHex.java | 9 +++ .../addTypeCast/beforeIntToFloat.java | 9 +++ .../quickFix/addTypeCast/beforeIntToLong.java | 9 +++ .../quickFix/addTypeCast/beforeLongToInt.java | 9 +++ .../addTypeCast/beforeLongToIntTooBig.java | 9 +++ 17 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDouble.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDoubleHex.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToFloat.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToLong.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToInt.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToIntTooBig.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble2.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDouble.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDoubleHex.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToFloat.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToLong.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToInt.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToIntTooBig.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java index 1b31450a9a50..813f7f900cb0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/AddTypeCastFix.java @@ -8,9 +8,11 @@ import com.intellij.codeInsight.guess.GuessManager; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.codeInsight.intention.impl.BaseIntentionAction; import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement; +import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; @@ -85,9 +87,13 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement if (expression == null) return null; if (type.equals(PsiType.NULL)) return null; + PsiElementFactory factory = JavaPsiFacade.getElementFactory(original.getProject()); + if (expression instanceof PsiLiteralExpression) { + PsiExpression newLiteral = tryConvertLiteral((PsiLiteralExpression)expression, factory, type); + if (newLiteral != null) return newLiteral; + } if (type instanceof PsiEllipsisType) type = ((PsiEllipsisType)type).toArrayType(); String text = "(" + type.getCanonicalText(false) + ")value"; - PsiElementFactory factory = JavaPsiFacade.getElementFactory(original.getProject()); PsiTypeCastExpression typeCast = (PsiTypeCastExpression)factory.createExpressionFromText(text, original); typeCast = (PsiTypeCastExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(typeCast); typeCast = (PsiTypeCastExpression)CodeStyleManager.getInstance(project).reformat(typeCast); @@ -121,6 +127,53 @@ public class AddTypeCastFix extends LocalQuickFixAndIntentionActionOnPsiElement return typeCast; } + @Nullable + private static PsiExpression tryConvertLiteral(@NotNull PsiLiteralExpression literal, + @NotNull PsiElementFactory factory, + PsiType wantedType) { + String newLiteral = null; + PsiType exprType = literal.getType(); + if (PsiType.INT.equals(exprType)) { + if (PsiType.LONG.equals(wantedType)) { + newLiteral = literal.getText() + "L"; + } + else if (PsiType.FLOAT.equals(wantedType)) { + String text = literal.getText(); + if (!text.startsWith("0")) { + newLiteral = text + "F"; + } + } + else if (PsiType.DOUBLE.equals(wantedType)) { + String text = literal.getText(); + if (!text.startsWith("0")) { + newLiteral = text + ".0"; + } + } + } + if (PsiType.LONG.equals(exprType) && PsiType.INT.equals(wantedType)) { + Object value = literal.getValue(); + if (value instanceof Long && Objects.requireNonNull(LongRangeSet.fromType(PsiType.INT)).contains((Long)value)) { + String text = literal.getText(); + if (text.endsWith("L") || text.endsWith("l")) { + newLiteral = text.substring(0, text.length() - 1); + } + } + } + if (PsiType.FLOAT.equals(exprType) && PsiType.DOUBLE.equals(wantedType)) { + String text = literal.getText(); + if (text.endsWith("F") || text.endsWith("f")) { + newLiteral = text.substring(0, text.length() - 1); + if (!StringUtil.containsAnyChar(newLiteral, ".eEpP")) { + newLiteral += ".0"; + } + } + } + if (newLiteral != null) { + return factory.createExpressionFromText(newLiteral, literal); + } + return null; + } + public static void registerFix(QuickFixActionRegistrar registrar, PsiExpression qualifier, PsiJavaCodeReferenceElement ref, diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble.java new file mode 100644 index 000000000000..77675a8df134 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(1.0); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble2.java new file mode 100644 index 000000000000..77675a8df134 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterFloatToDouble2.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(1.0); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDouble.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDouble.java new file mode 100644 index 000000000000..d559146064b1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDouble.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(123.0); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDoubleHex.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDoubleHex.java new file mode 100644 index 000000000000..bf64a80af10b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToDoubleHex.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test((double) 0x123); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToFloat.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToFloat.java new file mode 100644 index 000000000000..ddf9f017240a --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToFloat.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'float'" "true" +class a { + void test(Float f) {} + + void foo() { + test(123F); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToLong.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToLong.java new file mode 100644 index 000000000000..a6bdf63cced8 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterIntToLong.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'long'" "true" +class a { + void test(Long l) {} + + void foo() { + test(123L); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToInt.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToInt.java new file mode 100644 index 000000000000..4d74c7be7f99 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToInt.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'int'" "true" +class a { + void test(int d) {} + + void foo() { + test(123); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToIntTooBig.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToIntTooBig.java new file mode 100644 index 000000000000..d74910ed77d5 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/afterLongToIntTooBig.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'int'" "true" +class a { + void test(int d) {} + + void foo() { + test((int) 123_000_000_000L); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble.java new file mode 100644 index 000000000000..cf6e3ff655cd --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(1.0f); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble2.java new file mode 100644 index 000000000000..9b3e83d4673e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeFloatToDouble2.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(1f); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDouble.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDouble.java new file mode 100644 index 000000000000..37cf1e481a1b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDouble.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(123); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDoubleHex.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDoubleHex.java new file mode 100644 index 000000000000..e4015f3f13f7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToDoubleHex.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'double'" "true" +class a { + void test(Double d) {} + + void foo() { + test(0x123); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToFloat.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToFloat.java new file mode 100644 index 000000000000..b525fd9b3d4f --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToFloat.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'float'" "true" +class a { + void test(Float f) {} + + void foo() { + test(123); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToLong.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToLong.java new file mode 100644 index 000000000000..1f25de395c91 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeIntToLong.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'long'" "true" +class a { + void test(Long l) {} + + void foo() { + test(123); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToInt.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToInt.java new file mode 100644 index 000000000000..f063edb37bc7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToInt.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'int'" "true" +class a { + void test(int d) {} + + void foo() { + test(123L); + } +} + diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToIntTooBig.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToIntTooBig.java new file mode 100644 index 000000000000..05bf82a7208c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/addTypeCast/beforeLongToIntTooBig.java @@ -0,0 +1,9 @@ +// "Cast parameter to 'int'" "true" +class a { + void test(int d) {} + + void foo() { + test(123_000_000_000L); + } +} +