New J2K: Add support of binary expressions conversion to ImplicitCastsConversion
This commit is contained in:
committed by
Ilya Kirillov
parent
208c33a51d
commit
7e30b9e7f5
@@ -5,13 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.j2k.conversions
|
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.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.*
|
||||||
import org.jetbrains.kotlin.j2k.tree.impl.*
|
import org.jetbrains.kotlin.j2k.tree.impl.*
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||||
|
|
||||||
class ImplicitCastsConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
class ImplicitCastsConversion(private val context: ConversionContext) : RecursiveApplicableConversionBase() {
|
||||||
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
override fun applyToElement(element: JKTreeElement): JKTreeElement {
|
||||||
@@ -19,11 +17,71 @@ class ImplicitCastsConversion(private val context: ConversionContext) : Recursiv
|
|||||||
is JKVariable -> convertVariable(element)
|
is JKVariable -> convertVariable(element)
|
||||||
is JKForInStatement -> convertForInStatement(element)
|
is JKForInStatement -> convertForInStatement(element)
|
||||||
is JKMethodCallExpression -> convertMethodCallExpression(element)
|
is JKMethodCallExpression -> convertMethodCallExpression(element)
|
||||||
|
is JKBinaryExpression -> return recurse(convertBinaryExpression(element))
|
||||||
is JKKtAssignmentStatement -> convertAssignmentStatement(element)
|
is JKKtAssignmentStatement -> convertAssignmentStatement(element)
|
||||||
}
|
}
|
||||||
return recurse(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) {
|
private fun convertVariable(variable: JKVariable) {
|
||||||
if (variable.initializer is JKStubExpression) return
|
if (variable.initializer is JKStubExpression) return
|
||||||
variable.initializer.castTo(variable.type.type)?.also {
|
variable.initializer.castTo(variable.type.type)?.also {
|
||||||
@@ -78,11 +136,11 @@ class ImplicitCastsConversion(private val context: ConversionContext) : Recursiv
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JKExpression.castToAsPrimitiveTypes(toType: JKType): JKExpression? {
|
private fun JKExpression.castToAsPrimitiveTypes(toType: JKType, strict: Boolean): JKExpression? {
|
||||||
if (this is JKPrefixExpression
|
if (this is JKPrefixExpression
|
||||||
&& (operator.token.text == "+" || operator.token.text == "-")
|
&& (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)
|
return JKPrefixExpressionImpl(casted, operator)
|
||||||
}
|
}
|
||||||
val expressionTypeAsPrimitive = type(context.symbolProvider)?.asPrimitiveType() ?: return null
|
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 (toTypeAsPrimitive == expressionTypeAsPrimitive) return null
|
||||||
|
|
||||||
if (this is JKLiteralExpression) {
|
if (this is JKLiteralExpression) {
|
||||||
if (expressionTypeAsPrimitive == JKJavaPrimitiveTypeImpl.INT
|
if (!strict
|
||||||
|
&& expressionTypeAsPrimitive == JKJavaPrimitiveTypeImpl.INT
|
||||||
&& (toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.LONG ||
|
&& (toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.LONG ||
|
||||||
toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.SHORT ||
|
toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.SHORT ||
|
||||||
toTypeAsPrimitive == JKJavaPrimitiveTypeImpl.BYTE)
|
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)
|
val expressionType = type(context.symbolProvider)
|
||||||
if (expressionType == toType) return null
|
if (expressionType == toType) return null
|
||||||
castToAsPrimitiveTypes(toType)?.also { return it }
|
castToAsPrimitiveTypes(toType, strict)?.also { return it }
|
||||||
return addBangBang(toType)
|
return addBangBang(toType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,18 +110,48 @@ private fun JKKtOperatorToken.unaryExpressionMethodType(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val booleanOperators = TokenSet.create(
|
fun JKOperator.isComparationOperator() =
|
||||||
KtTokens.LT,
|
(token as? JKKtSingleValueOperatorToken)?.psiToken in comparationOperators
|
||||||
KtTokens.GT,
|
|
||||||
KtTokens.LTEQ,
|
fun JKOperator.isEquals() =
|
||||||
KtTokens.GTEQ,
|
(token as? JKKtSingleValueOperatorToken)?.psiToken in equalsOperators
|
||||||
KtTokens.EQEQEQ,
|
|
||||||
KtTokens.EXCLEQEQEQ,
|
fun JKOperator.isArithmetic() =
|
||||||
KtTokens.EQEQ,
|
(token as? JKKtSingleValueOperatorToken)?.psiToken in arithmeticOperators
|
||||||
KtTokens.EXCLEQ,
|
|
||||||
KtTokens.ANDAND,
|
fun JKOperator.isLessOrGreater() =
|
||||||
KtTokens.OROR
|
(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(
|
private val arithmeticOperators = TokenSet.create(
|
||||||
KtTokens.MUL,
|
KtTokens.MUL,
|
||||||
@@ -429,7 +459,9 @@ private fun convertCharLiteral(text: String): JKKtLiteralExpression {
|
|||||||
private fun convertIntegerLiteral(element: JKLiteralExpression): JKKtLiteralExpression {
|
private fun convertIntegerLiteral(element: JKLiteralExpression): JKKtLiteralExpression {
|
||||||
var text = element.literal
|
var text = element.literal
|
||||||
if (element.type == JKLiteralExpression.LiteralType.LONG) {
|
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")
|
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())
|
// 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? {
|
fun JKClassSymbol.toKtType(): KotlinType? {
|
||||||
val classDescriptor = when (this) {
|
val classDescriptor = when (this) {
|
||||||
|
|||||||
Reference in New Issue
Block a user