New J2K: Add support of binary expressions conversion to ImplicitCastsConversion

This commit is contained in:
Ilya Kirillov
2019-01-29 16:20:33 +03:00
committed by Ilya Kirillov
parent 208c33a51d
commit 7e30b9e7f5
3 changed files with 129 additions and 22 deletions
@@ -5,13 +5,11 @@
package org.jetbrains.kotlin.j2k.conversions
import org.jetbrains.kotlin.j2k.ConversionContext
import org.jetbrains.kotlin.j2k.*
import org.jetbrains.kotlin.j2k.ast.Nullability
import org.jetbrains.kotlin.j2k.bangedBangedExpr
import org.jetbrains.kotlin.j2k.copyTreeAndDetach
import org.jetbrains.kotlin.j2k.fixLiteral
import org.jetbrains.kotlin.j2k.tree.*
import org.jetbrains.kotlin.j2k.tree.impl.*
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
class ImplicitCastsConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
override fun applyToElement(element: JKTreeElement): JKTreeElement {
@@ -19,11 +17,71 @@ class ImplicitCastsConversion(private val context: ConversionContext) : Recursiv
is JKVariable -> convertVariable(element)
is JKForInStatement -> convertForInStatement(element)
is JKMethodCallExpression -> convertMethodCallExpression(element)
is JKBinaryExpression -> return recurse(convertBinaryExpression(element))
is JKKtAssignmentStatement -> convertAssignmentStatement(element)
}
return recurse(element)
}
private fun convertBinaryExpression(binaryExpression: JKBinaryExpression): JKExpression {
fun JKBinaryExpression.addBangBang(): JKBinaryExpression {
fun JKType.isAcceptable() = asPrimitiveType() != null
if (operator.isEquals()) return this
val leftType = left.type(context.symbolProvider) ?: return this
val rightType = right.type(context.symbolProvider) ?: return this
return if (leftType.isAcceptable()
&& rightType.isAcceptable()
&& (leftType.isNullable() || rightType.isNullable())
&& (operator.isArithmetic() || operator.isLessOrGreater())
) {
JKBinaryExpressionImpl(
::left.detached().bangedBangedExpr(context.symbolProvider),
::right.detached().bangedBangedExpr(context.symbolProvider),
operator
)
} else this
}
fun JKBinaryExpression.convertComparationExpression(): JKBinaryExpression {
if (!operator.isComparationOperator()) return this
val leftType = left.type(context.symbolProvider)?.asPrimitiveType() ?: return this
val rightType = right.type(context.symbolProvider)?.asPrimitiveType() ?: return this
val leftOperandCastedCasted by lazy {
JKBinaryExpressionImpl(
::left.detached().let { it.castTo(rightType, strict = true) ?: it },
::right.detached(),
operator
)
}
val rightOperandCastedCasted by lazy {
JKBinaryExpressionImpl(
::left.detached(),
::right.detached().let { it.castTo(leftType, strict = true) ?: it },
operator
)
}
println()
return when {
leftType.jvmPrimitiveType == rightType.jvmPrimitiveType -> this
leftType.jvmPrimitiveType == JvmPrimitiveType.CHAR -> leftOperandCastedCasted
rightType.jvmPrimitiveType == JvmPrimitiveType.CHAR -> rightOperandCastedCasted
operator.isEquals() ->
if (rightType isStrongerThan leftType) leftOperandCastedCasted
else rightOperandCastedCasted
else -> this
}
}
return binaryExpression.convertComparationExpression().addBangBang()
}
private fun convertVariable(variable: JKVariable) {
if (variable.initializer is JKStubExpression) return
variable.initializer.castTo(variable.type.type)?.also {
@@ -78,11 +136,11 @@ class ImplicitCastsConversion(private val context: ConversionContext) : Recursiv
return null
}
private fun JKExpression.castToAsPrimitiveTypes(toType: JKType): JKExpression? {
private fun JKExpression.castToAsPrimitiveTypes(toType: JKType, strict: Boolean): JKExpression? {
if (this is JKPrefixExpression
&& (operator.token.text == "+" || operator.token.text == "-")
) {
val casted = expression.castToAsPrimitiveTypes(toType) ?: return null
val casted = expression.castToAsPrimitiveTypes(toType, strict) ?: return null
return JKPrefixExpressionImpl(casted, operator)
}
val expressionTypeAsPrimitive = type(context.symbolProvider)?.asPrimitiveType() ?: return null
@@ -90,7 +148,8 @@ class ImplicitCastsConversion(private val context: ConversionContext) : Recursiv
if (toTypeAsPrimitive == expressionTypeAsPrimitive) return null
if (this is JKLiteralExpression) {
if (expressionTypeAsPrimitive == JKJavaPrimitiveTypeImpl.INT
if (!strict
&& expressionTypeAsPrimitive == JKJavaPrimitiveTypeImpl.INT
&& (toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.LONG ||
toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.SHORT ||
toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.BYTE)
@@ -118,10 +177,10 @@ class ImplicitCastsConversion(private val context: ConversionContext) : Recursiv
}
private fun JKExpression.castTo(toType: JKType): JKExpression? {
private fun JKExpression.castTo(toType: JKType, strict: Boolean = false): JKExpression? {
val expressionType = type(context.symbolProvider)
if (expressionType == toType) return null
castToAsPrimitiveTypes(toType)?.also { return it }
castToAsPrimitiveTypes(toType, strict)?.also { return it }
return addBangBang(toType)
}
}
@@ -110,18 +110,48 @@ private fun JKKtOperatorToken.unaryExpressionMethodType(
}
}
private val booleanOperators = TokenSet.create(
KtTokens.LT,
KtTokens.GT,
KtTokens.LTEQ,
KtTokens.GTEQ,
KtTokens.EQEQEQ,
KtTokens.EXCLEQEQEQ,
KtTokens.EQEQ,
KtTokens.EXCLEQ,
KtTokens.ANDAND,
KtTokens.OROR
)
fun JKOperator.isComparationOperator() =
(token as? JKKtSingleValueOperatorToken)?.psiToken in comparationOperators
fun JKOperator.isEquals() =
(token as? JKKtSingleValueOperatorToken)?.psiToken in equalsOperators
fun JKOperator.isArithmetic() =
(token as? JKKtSingleValueOperatorToken)?.psiToken in arithmeticOperators
fun JKOperator.isLessOrGreater() =
(token as? JKKtSingleValueOperatorToken)?.psiToken in lessGreaterOperators
private val equalsOperators =
TokenSet.create(
KtTokens.EQEQEQ,
KtTokens.EXCLEQEQEQ,
KtTokens.EQEQ,
KtTokens.EXCLEQ
)
private val lessGreaterOperators =
TokenSet.create(
KtTokens.LT,
KtTokens.GT,
KtTokens.LTEQ,
KtTokens.GTEQ
)
private val comparationOperators =
TokenSet.orSet(
lessGreaterOperators,
equalsOperators
)
private val booleanOperators =
TokenSet.orSet(
comparationOperators,
TokenSet.create(
KtTokens.ANDAND,
KtTokens.OROR
)
)
private val arithmeticOperators = TokenSet.create(
KtTokens.MUL,
@@ -429,7 +459,9 @@ private fun convertCharLiteral(text: String): JKKtLiteralExpression {
private fun convertIntegerLiteral(element: JKLiteralExpression): JKKtLiteralExpression {
var text = element.literal
if (element.type == JKLiteralExpression.LiteralType.LONG) {
text = text.replace("l", "L")
text = text.replace("l", "L").let {
if (!it.endsWith("L")) it + "L" else it
}
}
fun isHexLiteral(text: String) = text.startsWith("0x") || text.startsWith("0X")
@@ -155,6 +155,22 @@ fun JKType.toKtType(symbolProvider: JKSymbolProvider): KotlinType? =
// else -> TODO(this::class.java.toString())
}
infix fun JKJavaPrimitiveType.isStrongerThan(other: JKJavaPrimitiveType) =
jvmPrimitivePrioritypriority.getValue(this.jvmPrimitiveType.primitiveType) >
jvmPrimitivePrioritypriority.getValue(other.jvmPrimitiveType.primitiveType)
private val jvmPrimitivePrioritypriority =
mapOf(
PrimitiveType.BOOLEAN to -1,
PrimitiveType.CHAR to 0,
PrimitiveType.BYTE to 1,
PrimitiveType.SHORT to 2,
PrimitiveType.INT to 3,
PrimitiveType.LONG to 4,
PrimitiveType.FLOAT to 5,
PrimitiveType.DOUBLE to 6
)
fun JKClassSymbol.toKtType(): KotlinType? {
val classDescriptor = when (this) {