diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt index 086e465a324..92cab272061 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/ConversionsRunner.kt @@ -81,6 +81,7 @@ object ConversionsRunner { +MethodReferenceToLambdaConversion(context) +BuiltinMembersConversion(context) +ImplicitCastsConversion(context) + +LiteralConversion() +CollectImportsConversion(context) +SortClassMembersConversion() diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ImplicitCastsConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ImplicitCastsConversion.kt index 2a5dee349e3..1ffd359e1a9 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ImplicitCastsConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/ImplicitCastsConversion.kt @@ -92,7 +92,6 @@ class ImplicitCastsConversion(private val context: NewJ2kConverterContext) : Rec } } - private fun JKExpression.castStringToRegex(toType: JKType): JKExpression? { if (toType.safeAs()?.classReference?.fqName != "java.util.regex.Pattern") return null val expressionType = type(context.symbolProvider) ?: return null @@ -133,7 +132,7 @@ class ImplicitCastsConversion(private val context: NewJ2kConverterContext) : Rec return JKJavaLiteralExpressionImpl( literal, expectedType - ).fixLiteral(expectedType) + ) } } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaStandartMethodsConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaStandartMethodsConversion.kt deleted file mode 100644 index 66db4affac8..00000000000 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/JavaStandartMethodsConversion.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.nj2k.conversions - -import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext -import org.jetbrains.kotlin.j2k.ast.Nullability -import org.jetbrains.kotlin.nj2k.tree.* -import org.jetbrains.kotlin.nj2k.tree.impl.* - -class JavaStandartMethodsConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() { - override fun applyToElement(element: JKTreeElement): JKTreeElement { - if (element !is JKClass) return recurse(element) - for (declaration in element.classBody.declarations) { - if (declaration !is JKJavaMethodImpl) continue - if (fixToStringMethod(declaration)) continue - if (fixFinalizeMethod(declaration, element)) continue - if (fixCloneMethod(declaration)) { - element.inheritance.implements += - JKTypeElementImpl( - JKClassTypeImpl( - JKUnresolvedClassSymbol("Cloneable"), - emptyList(), Nullability.NotNull - ) - ) - continue - } - } - return recurse(element) - } - - private fun fixToStringMethod(method: JKJavaMethodImpl): Boolean { - if (method.name.value != "toString") return false - if (method.parameters.isNotEmpty()) return false - val type = (method.returnType.type as? JKClassType) - ?.takeIf { it.classReference.name == "String" } - ?.updateNullability(Nullability.NotNull) ?: return false - method.returnType = JKTypeElementImpl(type) - return true - } - - private fun fixCloneMethod(method: JKJavaMethodImpl): Boolean { - if (method.name.value != "clone") return false - if (method.parameters.isNotEmpty()) return false - val type = (method.returnType.type as? JKClassType) - ?.takeIf { it.classReference.name == "Object" } - ?.updateNullability(Nullability.NotNull) ?: return false - method.returnType = JKTypeElementImpl(type) - return true - } - - private fun fixFinalizeMethod(method: JKJavaMethodImpl, containingClass: JKClass): Boolean { - if (method.name.value != "finalize") return false - if (method.parameters.isNotEmpty()) return false - if (method.returnType.type != JKJavaVoidType) return false - if (method.modality == Modality.OVERRIDE) { - method.modality = - if (containingClass.modality == Modality.OPEN) Modality.OPEN - else Modality.FINAL - } - return true - } -} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/LiteralConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/LiteralConversion.kt index 02945de1a52..4541f0ad7c2 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/LiteralConversion.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/LiteralConversion.kt @@ -5,13 +5,112 @@ package org.jetbrains.kotlin.nj2k.conversions -import org.jetbrains.kotlin.nj2k.fixLiteral -import org.jetbrains.kotlin.nj2k.tree.JKJavaLiteralExpression -import org.jetbrains.kotlin.nj2k.tree.JKTreeElement +import org.jetbrains.kotlin.nj2k.tree.* +import org.jetbrains.kotlin.nj2k.tree.impl.JKKtLiteralExpressionImpl +import java.math.BigInteger class LiteralConversion : RecursiveApplicableConversionBase() { override fun applyToElement(element: JKTreeElement): JKTreeElement { if (element !is JKJavaLiteralExpression) return recurse(element) - return element.fixLiteral(element.type) + return element.convertLiteral() } + + private fun JKLiteralExpression.convertLiteral(): JKLiteralExpression = + when (type) { + JKLiteralExpression.LiteralType.DOUBLE -> toDoubleLiteral() + JKLiteralExpression.LiteralType.FLOAT -> toFloatLiteral() + JKLiteralExpression.LiteralType.LONG -> toLongLiteral() + JKLiteralExpression.LiteralType.INT -> toIntLiteral() + JKLiteralExpression.LiteralType.CHAR -> convertCharLiteral() + JKLiteralExpression.LiteralType.STRING -> toStringLiteral() + else -> this + }.withNonCodeElementsFrom(this) + + private fun JKLiteralExpression.toDoubleLiteral() = + JKKtLiteralExpressionImpl( + literal.cleanFloatAndDoubleLiterals() + .let { text -> + if (!text.contains(".") && !text.contains("e", true)) + "$text." + else text + }.let { text -> + if (text.endsWith(".")) "${text}0" else text + }, + JKLiteralExpression.LiteralType.DOUBLE + ) + + + private fun JKLiteralExpression.toFloatLiteral() = + JKKtLiteralExpressionImpl( + literal.cleanFloatAndDoubleLiterals() + .let { text -> + if (!text.endsWith("f")) "${text}f" + else text + }, + JKLiteralExpression.LiteralType.FLOAT + ) + + private fun JKLiteralExpression.toStringLiteral() = + JKKtLiteralExpressionImpl(literal.replace("((?:\\\\)*)\\\\([0-3]?[0-7]{1,2})".toRegex()) { matchResult -> + val leadingBackslashes = matchResult.groupValues[1] + if (leadingBackslashes.length % 2 == 0) + kotlin.String.format("%s\\u%04x", leadingBackslashes, java.lang.Integer.parseInt(matchResult.groupValues[2], 8)) + else matchResult.value + }.replace("\\$([A-Za-z]+|\\{)".toRegex(), "\\\\$0"), JKLiteralExpression.LiteralType.STRING) + + + private fun JKLiteralExpression.convertCharLiteral(): JKKtLiteralExpression = + JKKtLiteralExpressionImpl( + literal.replace("\\\\([0-3]?[0-7]{1,2})".toRegex()) { + String.format("\\u%04x", Integer.parseInt(it.groupValues[1], 8)) + }, + JKLiteralExpression.LiteralType.CHAR + ) + + + private fun JKLiteralExpression.toIntLiteral(): JKKtLiteralExpression = + JKKtLiteralExpressionImpl( + literal + .replace("l", "", ignoreCase = true) + .convertHexLiteral(isLongLiteral = false) + .convertOctalLiteral(), + JKLiteralExpression.LiteralType.INT + ) + + + private fun JKLiteralExpression.toLongLiteral(): JKKtLiteralExpression = + JKKtLiteralExpressionImpl( + literal + .replace("l", "", ignoreCase = true) + .convertHexLiteral(isLongLiteral = true) + .convertOctalLiteral() + "L", + JKLiteralExpression.LiteralType.LONG + ) + + private fun String.convertHexLiteral(isLongLiteral: Boolean): String { + if (!startsWith("0x", ignoreCase = true)) return this + val value = BigInteger(drop(2), 16) + return when { + isLongLiteral && value.bitLength() > 63 -> + "-0x${value.toLong().toString(16).substring(1)}" + + !isLongLiteral && value.bitLength() > 31 -> + "-0x${value.toInt().toString(16).substring(1)}" + + else -> this + } + } + + private fun String.convertOctalLiteral(): String { + if (!startsWith("0") || length == 1 || get(1).toLowerCase() == 'x') return this + val value = BigInteger(drop(1), 8) + return value.toString() + } + + private fun String.cleanFloatAndDoubleLiterals() = + replace("L", "", ignoreCase = true) + .replace("d", "", ignoreCase = true) + .replace(".e", "e", ignoreCase = true) + .replace(".f", "", ignoreCase = true) + .replace("f", "", ignoreCase = true) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt index cca1f09a84d..9ebcb92a6f1 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/expressions.kt @@ -18,7 +18,6 @@ import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs -import java.math.BigInteger fun kotlinTypeByName(name: String, symbolProvider: JKSymbolProvider, nullability: Nullability = Nullability.Nullable): JKClassType = JKClassTypeImpl( @@ -375,104 +374,6 @@ fun JKVariable.hasWritableUsages(scope: JKTreeElement, context: NewJ2kConverterC || it.isInDecrementOrIncrement() } -fun JKLiteralExpression.fixLiteral(expectedType: JKLiteralExpression.LiteralType): JKLiteralExpression = - when (expectedType) { - JKLiteralExpression.LiteralType.DOUBLE -> convertDoubleLiteral(literal) - JKLiteralExpression.LiteralType.FLOAT -> convertFloatLiteral(literal) - JKLiteralExpression.LiteralType.LONG, JKLiteralExpression.LiteralType.INT -> convertIntegerLiteral(this) - JKLiteralExpression.LiteralType.CHAR -> convertCharLiteral(literal) - JKLiteralExpression.LiteralType.STRING -> convertStringLiteral(literal) - else -> this - }.withNonCodeElementsFrom(this) - -private fun convertDoubleLiteral(text: String): JKKtLiteralExpression { - var newText = - text.replace("L", "", true) - .replace("d", "", true) - .replace(".e", "e", true) - .replace(".f", "", true) - .replace("f", "", true) - - if (!newText.contains(".") && !newText.contains("e", true)) - newText += "." - if (newText.endsWith(".")) - newText += "0" - - - return JKKtLiteralExpressionImpl( - newText, - JKLiteralExpression.LiteralType.DOUBLE - ) -} - -private fun convertFloatLiteral(text: String): JKKtLiteralExpressionImpl { - return JKKtLiteralExpressionImpl( - text.replace("L", "", true) - .replace(".f", "f", true) - .replace("F", "f") - .replace(".e", "e", true) - .let { - if (!it.endsWith("f")) "${it}f" - else it - }, - JKLiteralExpression.LiteralType.FLOAT - ) -} - -private fun convertStringLiteral(text: String): JKKtLiteralExpressionImpl { - var newText = text.replace("((?:\\\\)*)\\\\([0-3]?[0-7]{1,2})".toRegex()) { - val leadingBackslashes = it.groupValues[1] - if (leadingBackslashes.length % 2 == 0) { - String.format("%s\\u%04x", leadingBackslashes, Integer.parseInt(it.groupValues[2], 8)) - } else { - it.value - } - } - newText = newText.replace("\\$([A-Za-z]+|\\{)".toRegex(), "\\\\$0") - - return JKKtLiteralExpressionImpl(newText, JKLiteralExpression.LiteralType.STRING) -} - -private fun convertCharLiteral(text: String): JKKtLiteralExpression { - return JKKtLiteralExpressionImpl( - text.replace("\\\\([0-3]?[0-7]{1,2})".toRegex()) { - String.format("\\u%04x", Integer.parseInt(it.groupValues[1], 8)) - }, - JKLiteralExpression.LiteralType.CHAR - ) -} - -private fun convertIntegerLiteral(element: JKLiteralExpression): JKKtLiteralExpression { - var text = element.literal - if (element.type == JKLiteralExpression.LiteralType.LONG) { - text = text.replace("l", "L").let { - if (!it.endsWith("L")) it + "L" else it - } - } - - fun isHexLiteral(text: String) = text.startsWith("0x") || text.startsWith("0X") - - if ((element.type == JKLiteralExpression.LiteralType.LONG || element.type == JKLiteralExpression.LiteralType.INT) && isHexLiteral(text)) { - val v = BigInteger(text.substring(2).replace("L", ""), 16) - if (text.contains("L")) { - if (v.bitLength() > 63) { - text = "-0x${v.toLong().toString(16).substring(1)}L" - } - } else { - if (v.bitLength() > 31) { - text = "-0x${v.toInt().toString(16).substring(1)}" - } - } - } else if (element.type == JKLiteralExpression.LiteralType.INT) { - text = element.literal - } - - return JKKtLiteralExpressionImpl( - text, - element.type - ) -} - fun equalsExpression(left: JKExpression, right: JKExpression, symbolProvider: JKSymbolProvider) = kotlinBinaryExpression( left,