KT-19390: Fix char + String in Java is converted to code with multiple type errors in Kotlin (#1235)
#KT-19390 Fixed
This commit is contained in:
committed by
Simon Ogorodnik
parent
1e940bde01
commit
2be27d5380
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.j2k
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.CommonClassNames.*
|
||||
import org.jetbrains.kotlin.j2k.ast.*
|
||||
|
||||
class CodeConverter(
|
||||
@@ -112,10 +111,15 @@ class CodeConverter(
|
||||
convertedExpression = BangBangExpression.surroundIfNullable(convertedExpression)
|
||||
}
|
||||
|
||||
if (needConversion(actualType, expectedType)) {
|
||||
if (actualType.needTypeConversion(expectedType)) {
|
||||
val expectedTypeStr = expectedType.canonicalText
|
||||
if (expression is PsiLiteralExpression) {
|
||||
if (expectedTypeStr == "float" || expectedTypeStr == "double") {
|
||||
if (actualType.canonicalText == "char" && expression.parent !is PsiExpressionList) {
|
||||
expression.getTypeConversionMethod(expectedType)?.also {
|
||||
convertedExpression = MethodCallExpression.buildNonNull(convertedExpression, it)
|
||||
}
|
||||
}
|
||||
else if (expectedTypeStr == "float" || expectedTypeStr == "double") {
|
||||
var text = convertedExpression.canonicalCode()
|
||||
if (text.last() in setOf('f', 'L')) {
|
||||
text = text.substring(0, text.length - 1)
|
||||
@@ -165,7 +169,7 @@ class CodeConverter(
|
||||
resultType = resultType.toNotNullType()
|
||||
}
|
||||
|
||||
if (needConversion(actualType, expectedType)) {
|
||||
if (actualType.needTypeConversion(expectedType)) {
|
||||
val expectedTypeStr = expectedType.canonicalText
|
||||
|
||||
val willConvert = if (convertedExpression is LiteralExpression
|
||||
@@ -186,21 +190,4 @@ class CodeConverter(
|
||||
private fun PsiPrefixExpression.isLiteralWithSign()
|
||||
= operand is PsiLiteralExpression && operationTokenType in setOf(JavaTokenType.PLUS, JavaTokenType.MINUS)
|
||||
|
||||
private fun needConversion(actual: PsiType, expected: PsiType): Boolean {
|
||||
val expectedStr = expected.canonicalText
|
||||
val actualStr = actual.canonicalText
|
||||
return expectedStr != actualStr &&
|
||||
expectedStr != typeConversionMap[actualStr] &&
|
||||
actualStr != typeConversionMap[expectedStr]
|
||||
}
|
||||
|
||||
private val typeConversionMap: Map<String, String> = mapOf(
|
||||
JAVA_LANG_BYTE to "byte",
|
||||
JAVA_LANG_SHORT to "short",
|
||||
JAVA_LANG_INTEGER to "int",
|
||||
JAVA_LANG_LONG to "long",
|
||||
JAVA_LANG_FLOAT to "float",
|
||||
JAVA_LANG_DOUBLE to "double",
|
||||
JAVA_LANG_CHARACTER to "char"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -486,3 +486,37 @@ class TypeConverter(val converter: Converter) {
|
||||
private val mutableKotlinClasses = toKotlinMutableTypesMap.values.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiExpression.getTypeConversionMethod(expectedType: PsiType): String? {
|
||||
val actualType = this.type ?: return null
|
||||
if (actualType == expectedType) return null
|
||||
if (expectedType.canonicalText == CommonClassNames.JAVA_LANG_STRING) return "toString"
|
||||
return when (expectedType) {
|
||||
PsiType.BYTE -> "toByte"
|
||||
PsiType.SHORT -> "toShort"
|
||||
PsiType.INT -> "toInt"
|
||||
PsiType.LONG -> "toLong"
|
||||
PsiType.FLOAT -> "toFloat"
|
||||
PsiType.DOUBLE -> "toDouble"
|
||||
PsiType.CHAR -> "toChar"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun PsiType.needTypeConversion(expected: PsiType): Boolean {
|
||||
val expectedStr = expected.canonicalText
|
||||
val actualStr = canonicalText
|
||||
return expectedStr != actualStr &&
|
||||
expectedStr != typeConversionMap[actualStr] &&
|
||||
actualStr != typeConversionMap[expectedStr]
|
||||
}
|
||||
|
||||
private val typeConversionMap: Map<String, String> = mapOf(
|
||||
CommonClassNames.JAVA_LANG_BYTE to "byte",
|
||||
CommonClassNames.JAVA_LANG_SHORT to "short",
|
||||
CommonClassNames.JAVA_LANG_INTEGER to "int",
|
||||
CommonClassNames.JAVA_LANG_LONG to "long",
|
||||
CommonClassNames.JAVA_LANG_FLOAT to "float",
|
||||
CommonClassNames.JAVA_LANG_DOUBLE to "double",
|
||||
CommonClassNames.JAVA_LANG_CHARACTER to "char"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
public class CharToNumber {
|
||||
private byte b = 'c';
|
||||
private short s = 'c';
|
||||
private int i = 'c';
|
||||
private long l = 'c';
|
||||
private float f = 'c';
|
||||
private double d = 'c';
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class CharToNumber {
|
||||
private val b: Byte = 'c'.toByte()
|
||||
private val s: Short = 'c'.toShort()
|
||||
private val i: Int = 'c'.toInt()
|
||||
private val l: Long = 'c'.toLong()
|
||||
private val f = 'c'.toFloat()
|
||||
private val d = 'c'.toDouble()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public class CharToString {
|
||||
private String value;
|
||||
|
||||
public String test() {
|
||||
return '"' + value + '"';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class CharToString {
|
||||
private val value: String? = null
|
||||
|
||||
fun test(): String {
|
||||
return '"'.toString() + value + '"'.toString()
|
||||
}
|
||||
}
|
||||
@@ -3359,6 +3359,18 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("charToNumber.java")
|
||||
public void testCharToNumber() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/literalExpression/charToNumber.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("charToString.java")
|
||||
public void testCharToString() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/literalExpression/charToString.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dollarInsideString.java")
|
||||
public void testDollarInsideString() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/literalExpression/dollarInsideString.java");
|
||||
|
||||
@@ -3359,6 +3359,18 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("charToNumber.java")
|
||||
public void testCharToNumber() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/literalExpression/charToNumber.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("charToString.java")
|
||||
public void testCharToString() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/literalExpression/charToString.java");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("dollarInsideString.java")
|
||||
public void testDollarInsideString() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/literalExpression/dollarInsideString.java");
|
||||
|
||||
Reference in New Issue
Block a user