[kotlin] J2K: Convert Java Math static method calls to Kotlin functions

^KTIJ-6060 Fixed

GitOrigin-RevId: 280320a77447fe79f0c0692454cd21d39704d318
This commit is contained in:
Alexey Belkov
2023-05-23 13:09:24 +00:00
committed by intellij-monorepo-bot
parent 8c5c1fee2c
commit 2e47b17302
7 changed files with 184 additions and 2 deletions
@@ -4,6 +4,7 @@ package org.jetbrains.kotlin.nj2k.conversions
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.config.ApiVersion
import org.jetbrains.kotlin.config.ApiVersion.Companion.KOTLIN_1_8
import org.jetbrains.kotlin.nj2k.*
import org.jetbrains.kotlin.nj2k.conversions.ReplaceType.REPLACE_SELECTOR
import org.jetbrains.kotlin.nj2k.conversions.ReplaceType.REPLACE_WITH_QUALIFIER
@@ -243,7 +244,8 @@ private class ConversionsHolder(private val symbolProvider: JKSymbolProvider, pr
throwableConversions +
stringConversions +
arrayConversions +
printlnConversions
printlnConversions +
mathConversions
return conversions.groupBy { it.from.fqName }
}
@@ -771,6 +773,49 @@ private class ConversionsHolder(private val symbolProvider: JKSymbolProvider, pr
withFilter ::isSystemOutCall
)
private val mathConversions: List<Conversion> = listOf(
Method("java.lang.Math.abs") convertTo Method("kotlin.math.abs") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.acos") convertTo Method("kotlin.math.acos") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.asin") convertTo Method("kotlin.math.asin") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.atan") convertTo Method("kotlin.math.atan") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.atan2") convertTo Method("kotlin.math.atan2") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.cbrt") convertTo Method("kotlin.math.cbrt") withReplaceType REPLACE_WITH_QUALIFIER sinceKotlin KOTLIN_1_8,
Method("java.lang.Math.ceil") convertTo Method("kotlin.math.ceil") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.cos") convertTo Method("kotlin.math.cos") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.cosh") convertTo Method("kotlin.math.cosh") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.exp") convertTo Method("kotlin.math.exp") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.expm1") convertTo Method("kotlin.math.expm1") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.floor") convertTo Method("kotlin.math.floor") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.hypot") convertTo Method("kotlin.math.hypot") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.IEEEremainder") convertTo ExtensionMethod("kotlin.math.IEEErem") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.log") convertTo Method("kotlin.math.ln") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.log1p") convertTo Method("kotlin.math.ln1p") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.log10") convertTo Method("kotlin.math.log10") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.max") convertTo Method("kotlin.math.max") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.min") convertTo Method("kotlin.math.min") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.nextDown") convertTo ExtensionMethod("kotlin.math.nextDown") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.nextAfter") convertTo ExtensionMethod("kotlin.math.nextTowards") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.nextUp") convertTo ExtensionMethod("kotlin.math.nextUp") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.pow") convertTo ExtensionMethod("kotlin.math.pow") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.rint") convertTo Method("kotlin.math.round") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.round") convertTo CustomExpression { expression: JKExpression ->
val arguments = (expression as JKCallExpression).arguments
if (arguments.arguments.isEmpty()) return@CustomExpression expression
val firstArgument = arguments.arguments[0]::value.detached()
val method = if (firstArgument.isDoubleType()) "roundToLong" else "roundToInt"
firstArgument.callOn(symbolProvider.provideMethodSymbol("kotlin.math.$method")).withFormattingFrom(expression)
} withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.signum") convertTo Method("kotlin.math.sign") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.sin") convertTo Method("kotlin.math.sin") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.sinh") convertTo Method("kotlin.math.sinh") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.sqrt") convertTo Method("kotlin.math.sqrt") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.tan") convertTo Method("kotlin.math.tan") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.tanh") convertTo Method("kotlin.math.tanh") withReplaceType REPLACE_WITH_QUALIFIER,
Method("java.lang.Math.copySign") convertTo ExtensionMethod("kotlin.math.withSign") withReplaceType REPLACE_WITH_QUALIFIER,
)
private fun castReceiverToJavaLangObject(): CustomExpression = CustomExpression { expr ->
val parent = expr.parent ?: return@CustomExpression expr
val (receiver, selector) = if (parent is JKQualifiedExpression) {
@@ -895,4 +940,7 @@ private class ConversionsHolder(private val symbolProvider: JKSymbolProvider, pr
private fun List<JKLiteralExpression>.containsNull(): Boolean =
any { it.isNull() }
private fun JKExpression?.isDoubleType(): Boolean =
this?.calculateType(typeFactory) == JKJavaPrimitiveType.DOUBLE
}
@@ -2639,6 +2639,16 @@ public abstract class NewJavaToKotlinConverterSingleFileTestGenerated extends Ab
runTest("testData/newJ2k/function/mainVararg.java");
}
@TestMetadata("mathCbrt17ApiVersion.java")
public void testMathCbrt17ApiVersion() throws Exception {
runTest("testData/newJ2k/function/mathCbrt17ApiVersion.java");
}
@TestMetadata("mathStaticMethods.java")
public void testMathStaticMethods() throws Exception {
runTest("testData/newJ2k/function/mathStaticMethods.java");
}
@TestMetadata("methodClassType.java")
public void testMethodClassType() throws Exception {
runTest("testData/newJ2k/function/methodClassType.java");
@@ -0,0 +1,6 @@
// API_VERSION: 1.7
public class J {
void foo(Double x) {
Math.cbrt(x);
}
}
@@ -0,0 +1,6 @@
// API_VERSION: 1.7
class J {
fun foo(x: Double?) {
Math.cbrt(x!!)
}
}
@@ -0,0 +1,38 @@
// TODO investigate why extension methods are unresolved in this test (imports are not added)
public class J {
void foo(double x, double y, float f) {
Math.abs(x);
Math.acos(x);
Math.asin(x);
Math.atan(x);
Math.atan2(x, y);
Math.cbrt(x);
Math.ceil(x);
Math.copySign(x, y);
Math.cos(x);
Math.cosh(x);
Math.exp(x);
Math.expm1(x);
Math.floor(x);
Math.hypot(x, y);
Math.IEEEremainder(x, y);
Math.log(x);
Math.log1p(x);
Math.log10(x);
Math.max(x, y);
Math.min(x, y);
Math.nextAfter(x, y);
Math.nextDown(x);
Math.nextUp(x);
Math.pow(x, y);
Math.rint(x);
Math.round(x);
Math.round(f);
Math.signum(x);
Math.sin(x);
Math.sinh(x);
Math.sqrt(x);
Math.tan(x);
Math.tanh(x);
}
}
@@ -0,0 +1,72 @@
// ERROR: Unresolved reference: withSign
// ERROR: Unresolved reference: IEEErem
// ERROR: Unresolved reference: nextTowards
// ERROR: Unresolved reference: nextDown
// ERROR: Unresolved reference: nextUp
// ERROR: Unresolved reference: pow
// ERROR: Unresolved reference: roundToLong
// ERROR: Unresolved reference: roundToInt
import kotlin.math.abs
import kotlin.math.acos
import kotlin.math.asin
import kotlin.math.atan
import kotlin.math.atan2
import kotlin.math.cbrt
import kotlin.math.ceil
import kotlin.math.cos
import kotlin.math.cosh
import kotlin.math.exp
import kotlin.math.expm1
import kotlin.math.floor
import kotlin.math.hypot
import kotlin.math.ln
import kotlin.math.ln1p
import kotlin.math.log10
import kotlin.math.max
import kotlin.math.min
import kotlin.math.round
import kotlin.math.sign
import kotlin.math.sin
import kotlin.math.sinh
import kotlin.math.sqrt
import kotlin.math.tan
import kotlin.math.tanh
// TODO investigate why extension methods are unresolved in this test (imports are not added)
class J {
fun foo(x: Double, y: Double, f: Float) {
abs(x)
acos(x)
asin(x)
atan(x)
atan2(x, y)
cbrt(x)
ceil(x)
x.withSign(y)
cos(x)
cosh(x)
exp(x)
expm1(x)
floor(x)
hypot(x, y)
x.IEEErem(y)
ln(x)
ln1p(x)
log10(x)
max(x, y)
min(x, y)
x.nextTowards(y)
x.nextDown()
x.nextUp()
x.pow(y)
round(x)
x.roundToLong()
f.roundToInt()
sign(x)
sin(x)
sinh(x)
sqrt(x)
tan(x)
tanh(x)
}
}
@@ -1,3 +1,5 @@
import kotlin.math.sqrt
internal class A {
private var d1 = 1.0
private var d2 = 1.0
@@ -5,7 +7,7 @@ internal class A {
private val d4 = 1.0
private val d5 = 1.0
private val d6 = 1.0
private val d7 = Math.sqrt(2.0) - 1
private val d7 = sqrt(2.0) - 1
private val d8 = 1.0
private val d9 = 1.0
private val x = 1 / (1.0 + 0)