ReplaceJavaStaticMethodWithKotlinAnalogInspection: introduce Transformation for extension with non-null receiver
This commit is contained in:
+40
-23
@@ -29,8 +29,9 @@ class ReplaceJavaStaticMethodWithKotlinAnalogInspection : AbstractKotlinInspecti
|
||||
?.filter { it.filter(call) && it.transformation.isApplicable(call) }
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let { list ->
|
||||
val callDescriptor = call.getResolvedCall(call.analyze(BodyResolveMode.PARTIAL)) ?: return
|
||||
list.filter { callDescriptor.isCalling(FqName(it.javaMethodFqName)) }
|
||||
val context = call.analyze(BodyResolveMode.PARTIAL)
|
||||
val callDescriptor = call.getResolvedCall(context) ?: return
|
||||
list.filter { callDescriptor.isCalling(FqName(it.javaMethodFqName)) && it.transformation.isApplicable(call, context) }
|
||||
}
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.map(::ReplaceWithKotlinAnalogFunction)
|
||||
@@ -66,13 +67,21 @@ class ReplaceJavaStaticMethodWithKotlinAnalogInspection : AbstractKotlinInspecti
|
||||
"Float" to "Float"
|
||||
).flatMap { (javaPrimitive, kotlinPrimitive) ->
|
||||
listOf(
|
||||
Replacement("java.lang.$javaPrimitive.toString", "kotlin.text.toString", ToExtensionFunction) {
|
||||
Replacement("java.lang.$javaPrimitive.toString", "kotlin.text.toString", ToExtensionFunctionWithNonNullableReceiver) {
|
||||
it.valueArguments.size == 2
|
||||
},
|
||||
Replacement("java.lang.$javaPrimitive.toString", "kotlin.primitives.$kotlinPrimitive.toString", ToExtensionFunction) {
|
||||
Replacement(
|
||||
"java.lang.$javaPrimitive.toString",
|
||||
"kotlin.primitives.$kotlinPrimitive.toString",
|
||||
ToExtensionFunctionWithNullableReceiver
|
||||
) {
|
||||
it.valueArguments.size == 1
|
||||
},
|
||||
Replacement("java.lang.$javaPrimitive.compare", "kotlin.primitives.$kotlinPrimitive.compareTo", ToExtensionFunction)
|
||||
Replacement(
|
||||
"java.lang.$javaPrimitive.compare",
|
||||
"kotlin.primitives.$kotlinPrimitive.compareTo",
|
||||
ToExtensionFunctionWithNonNullableReceiver
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -100,38 +109,38 @@ class ReplaceJavaStaticMethodWithKotlinAnalogInspection : AbstractKotlinInspecti
|
||||
Replacement("java.lang.Math.expm1", "kotlin.math.expm1"),
|
||||
Replacement("java.lang.Math.floor", "kotlin.math.floor"),
|
||||
Replacement("java.lang.Math.hypot", "kotlin.math.hypot"),
|
||||
Replacement("java.lang.Math.IEEEremainder", "kotlin.math.IEEErem", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.IEEEremainder", "kotlin.math.IEEErem", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.log", "kotlin.math.ln"),
|
||||
Replacement("java.lang.Math.log1p", "kotlin.math.ln1p"),
|
||||
Replacement("java.lang.Math.log10", "kotlin.math.log10"),
|
||||
Replacement("java.lang.Math.max", "kotlin.math.max"),
|
||||
Replacement("java.lang.Math.max", "kotlin.ranges.coerceAtLeast", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.max", "kotlin.ranges.coerceAtLeast", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.min", "kotlin.math.min"),
|
||||
Replacement("java.lang.Math.min", "kotlin.ranges.coerceAtMost", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.nextDown", "kotlin.math.nextDown", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.nextAfter", "kotlin.math.nextTowards", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.nextUp", "kotlin.math.nextUp", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.pow", "kotlin.math.pow", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.min", "kotlin.ranges.coerceAtMost", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.nextDown", "kotlin.math.nextDown", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.nextAfter", "kotlin.math.nextTowards", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.nextUp", "kotlin.math.nextUp", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.pow", "kotlin.math.pow", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.rint", "kotlin.math.round"),
|
||||
Replacement("java.lang.Math.round", "kotlin.math.roundToLong", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.round", "kotlin.math.roundToInt", ToExtensionFunction),
|
||||
Replacement("java.lang.Math.round", "kotlin.math.roundToLong", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.round", "kotlin.math.roundToInt", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.lang.Math.signum", "kotlin.math.sign"),
|
||||
Replacement("java.lang.Math.sin", "kotlin.math.sin"),
|
||||
Replacement("java.lang.Math.sinh", "kotlin.math.sinh"),
|
||||
Replacement("java.lang.Math.sqrt", "kotlin.math.sqrt"),
|
||||
Replacement("java.lang.Math.tan", "kotlin.math.tan"),
|
||||
Replacement("java.lang.Math.tanh", "kotlin.math.tanh"),
|
||||
Replacement("java.lang.Math.copySign", "kotlin.math.withSign", ToExtensionFunction)
|
||||
Replacement("java.lang.Math.copySign", "kotlin.math.withSign", ToExtensionFunctionWithNonNullableReceiver)
|
||||
)
|
||||
|
||||
private val JAVA_COLLECTIONS = listOf(
|
||||
Replacement("java.util.Arrays.copyOf", "kotlin.collections.copyOf", ToExtensionFunction) {
|
||||
Replacement("java.util.Arrays.copyOf", "kotlin.collections.copyOf", ToExtensionFunctionWithNonNullableReceiver) {
|
||||
it.valueArguments.size == 2
|
||||
},
|
||||
Replacement("java.util.Arrays.copyOfRange", "kotlin.collections.copyOfRange", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.copyOfRange", "kotlin.collections.copyOfRange", ToExtensionFunctionWithNonNullableReceiver),
|
||||
// Replacement("java.util.Arrays.binarySearch", "kotlin.collections.binarySearch", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.equals", "kotlin.collections.contentEquals", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.deepEquals", "kotlin.collections.contentDeepEquals", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.equals", "kotlin.collections.contentEquals", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.util.Arrays.deepEquals", "kotlin.collections.contentDeepEquals", ToExtensionFunctionWithNonNullableReceiver),
|
||||
// Replacement("java.util.Arrays.fill", "kotlin.collections.fill", ToExtensionFunction),
|
||||
// Replacement("java.util.Arrays.sort", "kotlin.collections.sort", ToExtensionFunction) {
|
||||
// it.valueArguments.size == 3
|
||||
@@ -139,10 +148,18 @@ class ReplaceJavaStaticMethodWithKotlinAnalogInspection : AbstractKotlinInspecti
|
||||
// Replacement("java.util.Arrays.sort", "kotlin.collections.sortWith", ToExtensionFunction) {
|
||||
// it.valueArguments.size != 3
|
||||
// },
|
||||
Replacement("java.util.Arrays.deepHashCode", "kotlin.collections.contentDeepHashCode", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.hashCode", "kotlin.collections.contentHashCode", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.deepToString", "kotlin.collections.contentDeepToString", ToExtensionFunction),
|
||||
Replacement("java.util.Arrays.toString", "kotlin.collections.contentToString", ToExtensionFunction),
|
||||
Replacement(
|
||||
"java.util.Arrays.deepHashCode",
|
||||
"kotlin.collections.contentDeepHashCode",
|
||||
ToExtensionFunctionWithNonNullableReceiver
|
||||
),
|
||||
Replacement("java.util.Arrays.hashCode", "kotlin.collections.contentHashCode", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement(
|
||||
"java.util.Arrays.deepToString",
|
||||
"kotlin.collections.contentDeepToString",
|
||||
ToExtensionFunctionWithNonNullableReceiver
|
||||
),
|
||||
Replacement("java.util.Arrays.toString", "kotlin.collections.contentToString", ToExtensionFunctionWithNonNullableReceiver),
|
||||
Replacement("java.util.Arrays.asList", "kotlin.collections.listOf"),
|
||||
Replacement("java.util.Arrays.asList", "kotlin.collections.mutableListOf"),
|
||||
Replacement("java.util.Set.of", "kotlin.collections.setOf"),
|
||||
|
||||
@@ -14,10 +14,14 @@ import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtOperationExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||
import org.jetbrains.kotlin.types.isNullable
|
||||
|
||||
interface Transformation {
|
||||
operator fun invoke(callExpression: KtCallExpression, replacement: Replacement)
|
||||
fun isApplicable(call: KtCallExpression): Boolean = true
|
||||
fun isApplicable(callExpression: KtCallExpression): Boolean = true
|
||||
fun isApplicable(callExpression: KtCallExpression, context: BindingContext): Boolean = true
|
||||
}
|
||||
|
||||
object WithoutAdditionalTransformation : Transformation {
|
||||
@@ -31,7 +35,7 @@ object WithoutAdditionalTransformation : Transformation {
|
||||
}
|
||||
}
|
||||
|
||||
object ToExtensionFunction : Transformation {
|
||||
object ToExtensionFunctionWithNonNullableReceiver : Transformation {
|
||||
override fun invoke(callExpression: KtCallExpression, replacement: Replacement) {
|
||||
val file = callExpression.containingKtFile
|
||||
val psiFactory = KtPsiFactory(callExpression)
|
||||
@@ -49,5 +53,22 @@ object ToExtensionFunction : Transformation {
|
||||
}
|
||||
}
|
||||
|
||||
override fun isApplicable(call: KtCallExpression): Boolean = call.valueArguments.isNotEmpty()
|
||||
override fun isApplicable(callExpression: KtCallExpression): Boolean = callExpression.valueArguments.isNotEmpty()
|
||||
|
||||
override fun isApplicable(callExpression: KtCallExpression, context: BindingContext): Boolean = callExpression
|
||||
.valueArguments.firstOrNull()
|
||||
?.getArgumentExpression()
|
||||
?.getType(context)
|
||||
?.isNullable() == false
|
||||
}
|
||||
|
||||
object ToExtensionFunctionWithNullableReceiver : Transformation {
|
||||
override fun invoke(callExpression: KtCallExpression, replacement: Replacement) = ToExtensionFunctionWithNonNullableReceiver(
|
||||
callExpression,
|
||||
replacement
|
||||
)
|
||||
|
||||
override fun isApplicable(callExpression: KtCallExpression): Boolean = ToExtensionFunctionWithNonNullableReceiver.isApplicable(
|
||||
callExpression
|
||||
)
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
// PROBLEM: none
|
||||
import java.util.Arrays
|
||||
|
||||
fun test() {
|
||||
val a: Array<*>? = arrayOf(1)
|
||||
val str = Arrays.<caret>toString(a)
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo() {
|
||||
val a: Int? = 5
|
||||
val t: String = Integer.<caret>toString(a)
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo() {
|
||||
val a: Int? = 5
|
||||
val t: String = a.toString()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// PROBLEM: none
|
||||
// ERROR: Type mismatch: inferred type is Int? but Int was expected
|
||||
fun foo() {
|
||||
val a: Int? = 5
|
||||
val t: String = Integer.<caret>toString(a, 5)
|
||||
}
|
||||
+15
@@ -9140,6 +9140,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
public void testToString() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/collections/toString.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toStringWithNullableReceiver.kt")
|
||||
public void testToStringWithNullableReceiver() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/collections/toStringWithNullableReceiver.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/compare")
|
||||
@@ -9491,6 +9496,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/toString/longToString2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableIntToString.kt")
|
||||
public void testNullableIntToString() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/toString/nullableIntToString.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullableIntToString2.kt")
|
||||
public void testNullableIntToString2() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/toString/nullableIntToString2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("replaceIntToString.kt")
|
||||
public void testReplaceIntToString() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/replaceJavaStaticMethodWithKotlinAnalog/toString/replaceIntToString.kt");
|
||||
|
||||
Reference in New Issue
Block a user