AddTypeCast: automatically convert literals in common cases (IDEA-20480)

GitOrigin-RevId: f44030ecd28f1dd7e268474fafe9beb7f65e81fb
This commit is contained in:
Tagir Valeev
2020-06-26 06:40:29 +03:00
committed by intellij-monorepo-bot
parent 835656b76d
commit 14fa0849cd
17 changed files with 198 additions and 1 deletions
@@ -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,
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(1.0);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(1.0);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(123.0);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test((double) 0x123);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'float'" "true"
class a {
void test(Float f) {}
void foo() {
test(123F);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'long'" "true"
class a {
void test(Long l) {}
void foo() {
test(123L);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'int'" "true"
class a {
void test(int d) {}
void foo() {
test(123);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'int'" "true"
class a {
void test(int d) {}
void foo() {
test((int) 123_000_000_000L);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(<caret>1.0f);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(<caret>1f);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(<caret>123);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'double'" "true"
class a {
void test(Double d) {}
void foo() {
test(<caret>0x123);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'float'" "true"
class a {
void test(Float f) {}
void foo() {
test(<caret>123);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'long'" "true"
class a {
void test(Long l) {}
void foo() {
test(<caret>123);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'int'" "true"
class a {
void test(int d) {}
void foo() {
test(<caret>123L);
}
}
@@ -0,0 +1,9 @@
// "Cast parameter to 'int'" "true"
class a {
void test(int d) {}
void foo() {
test(<caret>123_000_000_000L);
}
}