J2K: cast right operand of equals for primitive types to left operand type

#KT-9997 Fixed
This commit is contained in:
Natalia Ukhorskaya
2015-12-18 09:56:23 +03:00
parent 1d787ed222
commit ecdef71580
7 changed files with 420 additions and 4 deletions
@@ -20,6 +20,7 @@ package org.jetbrains.kotlin.j2k
import com.intellij.openapi.project.Project
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.tree.IElementType
import com.intellij.psi.util.MethodSignature
import com.intellij.psi.util.MethodSignatureUtil
import com.intellij.psi.util.PsiTreeUtil
@@ -109,10 +110,19 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
override fun visitBinaryExpression(expression: PsiBinaryExpression) {
val left = expression.lOperand
val right = expression.rOperand
var leftConverted = codeConverter.convertExpression(left, null)
var rightConverted = codeConverter.convertExpression(right, null)
val operationTokenType = expression.operationTokenType
val leftOperandExpectedType = getOperandExpectedType(left, right, operationTokenType)
var leftConverted = codeConverter.convertExpression(left, leftOperandExpectedType)
var rightConverted = codeConverter.convertExpression(
right,
if (leftOperandExpectedType == null)
getOperandExpectedType(right, left, operationTokenType)
else
null
)
if (operationTokenType in NON_NULL_OPERAND_OPS) {
leftConverted = BangBangExpression.surroundIfNullable(leftConverted)
rightConverted = BangBangExpression.surroundIfNullable(rightConverted)
@@ -132,6 +142,54 @@ class DefaultExpressionConverter : JavaElementVisitor(), ExpressionConverter {
}
}
private fun getOperandExpectedType(current: PsiExpression?, other: PsiExpression?, operationTokenType: IElementType): PsiType? {
val currentType = current?.type
val otherType = other?.type
if (currentType !is PsiPrimitiveType || otherType !is PsiPrimitiveType) return null
if (currentType == PsiType.BOOLEAN || otherType == PsiType.BOOLEAN) return null
if (operationTokenType == JavaTokenType.EQEQ
|| operationTokenType == JavaTokenType.NE
|| currentType == PsiType.CHAR) {
if (currentType < otherType) return otherType
}
return null
}
infix operator fun PsiPrimitiveType.compareTo(other: PsiPrimitiveType): Int {
return when(this) {
other -> 0
PsiType.BYTE -> when(other) {
PsiType.CHAR -> 1
else -> -1
}
PsiType.SHORT -> when(other) {
PsiType.CHAR,
PsiType.BYTE -> 1
else -> -1
}
PsiType.INT -> when(other) {
PsiType.BYTE,
PsiType.SHORT,
PsiType.CHAR -> 1
else -> -1
}
PsiType.LONG -> when(other) {
PsiType.DOUBLE,
PsiType.FLOAT -> -1
else -> 1
}
PsiType.FLOAT -> when(other) {
PsiType.DOUBLE -> -1
else -> 1
}
PsiType.DOUBLE -> 1
PsiType.CHAR -> -1
else -> throw AssertionError("Unknown primitive type $this")
}
}
private fun canKeepEqEq(left: PsiExpression, right: PsiExpression?): Boolean {
if (left.isNullLiteral() || (right?.isNullLiteral() ?: false)) return true
val type = left.type
+128 -1
View File
@@ -1,5 +1,5 @@
class A {
public void foo() {
public void equals() {
int i = 1;
byte b = 1;
short s = 1;
@@ -7,5 +7,132 @@ class A {
double d = 1.0;
float f = 1.0f;
char c = 1;
t(i == i);
t(i == b);
t(i == s);
t(i == l);
t(i == d);
t(i == f);
t(i == c);
t(b == i);
t(b == b);
t(b == s);
t(b == l);
t(b == d);
t(b == f);
t(b == c);
t(s == i);
t(s == b);
t(s == s);
t(s == l);
t(s == d);
t(s == f);
t(s == c);
t(l == i);
t(l == b);
t(l == s);
t(l == l);
t(l == d);
t(l == f);
t(l == c);
t(d == i);
t(d == b);
t(d == s);
t(d == l);
t(d == d);
t(d == f);
t(d == c);
t(f == i);
t(f == b);
t(f == s);
t(f == l);
t(f == d);
t(f == f);
t(f == c);
t(c == i);
t(c == b);
t(c == s);
t(c == l);
t(c == d);
t(c == f);
t(c == c);
t(i != d);
}
public void compare() {
int i = 1;
byte b = 1;
short s = 1;
long l = 1;
double d = 1.0;
float f = 1.0f;
char c = 1;
t(i > i);
t(i > b);
t(i > s);
t(i > l);
t(i > d);
t(i > f);
t(i > c);
t(b > i);
t(b > b);
t(b > s);
t(b > l);
t(b > d);
t(b > f);
t(b > c);
t(s > i);
t(s > b);
t(s > s);
t(s > l);
t(s > d);
t(s > f);
t(s > c);
t(l > i);
t(l > b);
t(l > s);
t(l > l);
t(l > d);
t(l > f);
t(l > c);
t(d > i);
t(d > b);
t(d > s);
t(d > l);
t(d > d);
t(d > f);
t(d > c);
t(f > i);
t(f > b);
t(f > s);
t(f > l);
t(f > d);
t(f > f);
t(f > c);
t(c > i);
t(c > b);
t(c > s);
t(c > l);
t(c > d);
t(c > f);
t(c > c);
}
private void t(boolean b) {
}
}
+128 -1
View File
@@ -1,5 +1,5 @@
internal class A {
fun foo() {
fun equals() {
val i = 1
val b: Byte = 1
val s: Short = 1
@@ -7,5 +7,132 @@ internal class A {
val d = 1.0
val f = 1.0f
val c: Char = 1.toChar()
t(i == i)
t(i == b.toInt())
t(i == s.toInt())
t(i.toLong() == l)
t(i.toDouble() == d)
t(i.toFloat() == f)
t(i == c.toInt())
t(b.toInt() == i)
t(b == b)
t(b.toShort() == s)
t(b.toLong() == l)
t(b.toDouble() == d)
t(b.toFloat() == f)
t(b == c.toByte())
t(s.toInt() == i)
t(s == b.toShort())
t(s == s)
t(s.toLong() == l)
t(s.toDouble() == d)
t(s.toFloat() == f)
t(s == c.toShort())
t(l == i.toLong())
t(l == b.toLong())
t(l == s.toLong())
t(l == l)
t(l.toDouble() == d)
t(l.toFloat() == f)
t(l == c.toLong())
t(d == i.toDouble())
t(d == b.toDouble())
t(d == s.toDouble())
t(d == l.toDouble())
t(d == d)
t(d == f.toDouble())
t(d == c.toDouble())
t(f == i.toFloat())
t(f == b.toFloat())
t(f == s.toFloat())
t(f == l.toFloat())
t(f.toDouble() == d)
t(f == f)
t(f == c.toFloat())
t(c.toInt() == i)
t(c.toByte() == b)
t(c.toShort() == s)
t(c.toLong() == l)
t(c.toDouble() == d)
t(c.toFloat() == f)
t(c == c)
t(i.toDouble() != d)
}
fun compare() {
val i = 1
val b: Byte = 1
val s: Short = 1
val l: Long = 1
val d = 1.0
val f = 1.0f
val c: Char = 1.toChar()
t(i > i)
t(i > b)
t(i > s)
t(i > l)
t(i > d)
t(i > f)
t(i > c.toInt())
t(b > i)
t(b > b)
t(b > s)
t(b > l)
t(b > d)
t(b > f)
t(b > c.toByte())
t(s > i)
t(s > b)
t(s > s)
t(s > l)
t(s > d)
t(s > f)
t(s > c.toShort())
t(l > i)
t(l > b)
t(l > s)
t(l > l)
t(l > d)
t(l > f)
t(l > c.toLong())
t(d > i)
t(d > b)
t(d > s)
t(d > l)
t(d > d)
t(d > f)
t(d > c.toDouble())
t(f > i)
t(f > b)
t(f > s)
t(f > l)
t(f > d)
t(f > f)
t(f > c.toFloat())
t(c.toInt() > i)
t(c.toByte() > b)
t(c.toShort() > s)
t(c.toLong() > l)
t(c.toDouble() > d)
t(c.toFloat() > f)
t(c > c)
}
private fun t(b: Boolean) {
}
}
@@ -0,0 +1,45 @@
//file
class Test {
public void operationsWithChar() {
char c = 1;
int i = 1;
b(i > c);
b(i >= c);
b(i < c);
b(i <= c);
b(c > i);
b(c >= i);
b(c < i);
b(c <= i);
b(c == i);
b(c != i);
b(i == c);
b(i != c);
i(i + c);
i(i - c);
i(i / c);
i(i * c);
i(i % c);
i(i | c);
i(i & c);
i(i << c);
i(i >> c);
i(c + i);
i(c - i);
i(c / i);
i(c * i);
i(c % i);
i(c | i);
i(c & i);
i(c << i);
i(c >> i);
}
public void b(boolean b) {}
public void i(int i) {}
}
+47
View File
@@ -0,0 +1,47 @@
internal class Test {
fun operationsWithChar() {
val c: Char = 1.toChar()
val i = 1
b(i > c.toInt())
b(i >= c.toInt())
b(i < c.toInt())
b(i <= c.toInt())
b(c.toInt() > i)
b(c.toInt() >= i)
b(c.toInt() < i)
b(c.toInt() <= i)
b(c.toInt() == i)
b(c.toInt() != i)
b(i == c.toInt())
b(i != c.toInt())
i(i + c.toInt())
i(i - c.toInt())
i(i / c.toInt())
i(i * c.toInt())
i(i % c.toInt())
i(i or c.toInt())
i(i and c.toInt())
i(i shl c.toInt())
i(i shr c.toInt())
i(c.toInt() + i)
i(c.toInt() - i)
i(c.toInt() / i)
i(c.toInt() * i)
i(c.toInt() % i)
i(c.toInt() or i)
i(c.toInt() and i)
i(c.toInt() shl i)
i(c.toInt() shr i)
}
fun b(b: Boolean) {
}
fun i(i: Int) {
}
}
@@ -2791,6 +2791,12 @@ public class JavaToKotlinConverterForWebDemoTestGenerated extends AbstractJavaTo
doTest(fileName);
}
@TestMetadata("operationsWithChar.java")
public void testOperationsWithChar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/issues/operationsWithChar.java");
doTest(fileName);
}
@TestMetadata("qualifyStatic.java")
public void testQualifyStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/issues/qualifyStatic.java");
@@ -2791,6 +2791,12 @@ public class JavaToKotlinConverterSingleFileTestGenerated extends AbstractJavaTo
doTest(fileName);
}
@TestMetadata("operationsWithChar.java")
public void testOperationsWithChar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/issues/operationsWithChar.java");
doTest(fileName);
}
@TestMetadata("qualifyStatic.java")
public void testQualifyStatic() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("j2k/testData/fileOrElement/issues/qualifyStatic.java");