diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index 5bf2daa302f..f8b0e4f6439 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -3346,6 +3346,15 @@ language="kotlin" /> + + diff --git a/idea/resources/inspectionDescriptions/ReplaceJavaIntegerToStringWithMember.html b/idea/resources/inspectionDescriptions/ReplaceJavaIntegerToStringWithMember.html new file mode 100644 index 00000000000..4d1e51524c9 --- /dev/null +++ b/idea/resources/inspectionDescriptions/ReplaceJavaIntegerToStringWithMember.html @@ -0,0 +1,5 @@ + + +This inspection reports explicit calls of Integer.toString(int) which can be replaced with int.toString() + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceJavaIntegerToStringWithMemberInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceJavaIntegerToStringWithMemberInspection.kt new file mode 100644 index 00000000000..b4b97851bcf --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceJavaIntegerToStringWithMemberInspection.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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.idea.inspections + +import com.intellij.codeInspection.LocalQuickFix +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe + +class ReplaceJavaIntegerToStringWithMemberInspection : AbstractKotlinInspection() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return dotQualifiedExpressionVisitor { dotQualifiedExpression -> + if (dotQualifiedExpression.isToString()) { + holder.registerProblem( + dotQualifiedExpression, + "Could be replaced with `int.toString()`", + ConvertIntegerToStringQuickFix() + ) + } + } + } +} + +private class ConvertIntegerToStringQuickFix : LocalQuickFix { + override fun getName() = "Replace with 'int.toString()'" + + override fun getFamilyName() = name + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val dotQualifiedExpression = descriptor.psiElement as? KtDotQualifiedExpression ?: return + val element = dotQualifiedExpression.selectorExpression as? KtCallExpression ?: return + val arguments = element.valueArguments + val integerArg = arguments.getOrNull(0) ?: return + val radixArg = arguments.getOrNull(1) + + dotQualifiedExpression.replace( + KtPsiFactory(element).createExpressionByPattern( + "$0.toString($1)", + integerArg.getArgumentExpression() ?: return, + radixArg?.getArgumentExpression() ?: "" + ) + ) + } +} + +private fun KtDotQualifiedExpression.isToString(): Boolean { + val calleeExpression = (selectorExpression as? KtCallExpression)?.calleeExpression ?: return false + val nameReference = calleeExpression as? KtNameReferenceExpression ?: return false + if (nameReference.getReferencedName() != "toString") return false + + val resolvedCall = this.resolveToCall() ?: return false + if (!resolvedCall.status.isSuccess) return false + val fqName = resolvedCall.resultingDescriptor.fqNameUnsafe.asString() + return fqName == "java.lang.Integer.toString" +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/.inspection b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/.inspection new file mode 100644 index 00000000000..9d06d60edc8 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.ReplaceJavaIntegerToStringWithMemberInspection diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/incorrectDescriptor.kt b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/incorrectDescriptor.kt new file mode 100644 index 00000000000..dbc1a5a8950 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/incorrectDescriptor.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME +// PROBLEM: none +// ERROR: None of the following functions can be called with the arguments supplied:
public open fun toString(i: Int): String! defined in java.lang.Integer
public open fun toString(i: Int, radix: Int): String! defined in java.lang.Integer + +fun main() { + println(Integer.toString()) +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt new file mode 100644 index 00000000000..d1842760e2f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun foo() { + Integer.toString(5) +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt.after b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt.after new file mode 100644 index 00000000000..f0e4044100e --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun foo() { + 5.toString() +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt new file mode 100644 index 00000000000..f00b732075c --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun foo() { + val list = arrayListOf() + list.add(5) + Integer.toString(list[0]) +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt.after b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt.after new file mode 100644 index 00000000000..d03ea1f37e7 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun foo() { + val list = arrayListOf() + list.add(5) + list[0].toString() +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt new file mode 100644 index 00000000000..26477931fd3 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME + +fun foo() { + var number = 5 + val numberString = Integer.toString(number) +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt.after b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt.after new file mode 100644 index 00000000000..f0431e73a07 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME + +fun foo() { + var number = 5 + val numberString = number.toString() +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt new file mode 100644 index 00000000000..0cb1fe70515 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME + +fun foo() { + var number = 5 + val numberString = Integer.toString(number, 2) +} diff --git a/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt.after b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt.after new file mode 100644 index 00000000000..f91049063f2 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt.after @@ -0,0 +1,6 @@ +// WITH_RUNTIME + +fun foo() { + var number = 5 + val numberString = number.toString(2) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 13a4303636c..03b371efe49 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -7046,6 +7046,44 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceJavaIntegerToStringWithMember extends AbstractLocalInspectionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInReplaceJavaIntegerToStringWithMember() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("incorrectDescriptor.kt") + public void testIncorrectDescriptor() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/incorrectDescriptor.kt"); + } + + @TestMetadata("replaceIntToString.kt") + public void testReplaceIntToString() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceIntToString.kt"); + } + + @TestMetadata("replaceListElementToString.kt") + public void testReplaceListElementToString() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceListElementToString.kt"); + } + + @TestMetadata("replaceToStringBase.kt") + public void testReplaceToStringBase() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringBase.kt"); + } + + @TestMetadata("replaceToStringWithRadix.kt") + public void testReplaceToStringWithRadix() throws Exception { + runTest("idea/testData/inspectionsLocal/replaceJavaIntegerToStringWithMember/replaceToStringWithRadix.kt"); + } + } + @TestMetadata("idea/testData/inspectionsLocal/replaceNegatedIsEmptyWithIsNotEmpty") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)