diff --git a/idea/resources/inspectionDescriptions/ConvertPairConstructorToToFunction.html b/idea/resources/inspectionDescriptions/ConvertPairConstructorToToFunction.html new file mode 100644 index 00000000000..6c3374f79e2 --- /dev/null +++ b/idea/resources/inspectionDescriptions/ConvertPairConstructorToToFunction.html @@ -0,0 +1,5 @@ + + +This inspection reports Pair constructor that can be converted to 'to' function. + + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index c629cdd6d6c..5779c94318e 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2734,6 +2734,15 @@ language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConvertPairConstructorToToFunctionInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConvertPairConstructorToToFunctionInspection.kt new file mode 100644 index 00000000000..efac24a2091 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConvertPairConstructorToToFunctionInspection.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2018 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.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.callExpressionVisitor +import org.jetbrains.kotlin.psi.createExpressionByPattern +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe + +class ConvertPairConstructorToToFunctionInspection : AbstractKotlinInspection() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return callExpressionVisitor { expression -> + if (expression.isPairConstructorCall()) { + holder.registerProblem( + expression, + "Can be converted to 'to'", + ProblemHighlightType.INFORMATION, + ConvertPairConstructorToToFix() + ) + } + } + } +} + +private class ConvertPairConstructorToToFix : LocalQuickFix { + override fun getName() = "Convert to 'to'" + + override fun getFamilyName() = name + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val expression = descriptor.psiElement as? KtCallExpression ?: return + val args = expression.valueArguments.mapNotNull { it.getArgumentExpression() }.toTypedArray() + expression.replace(KtPsiFactory(expression).createExpressionByPattern("$0 to $1", *args)) + } +} + +private fun KtCallExpression.isPairConstructorCall(): Boolean { + if (valueArguments.size != 2) return false + if (valueArguments.mapNotNull { it.getArgumentExpression() }.size != 2) return false + return getCallableDescriptor()?.containingDeclaration?.fqNameSafe == FqName("kotlin.Pair") +} diff --git a/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/.inspection b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/.inspection new file mode 100644 index 00000000000..30d850e18fb --- /dev/null +++ b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.ConvertPairConstructorToToFunctionInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/invalidArgs.kt b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/invalidArgs.kt new file mode 100644 index 00000000000..966bc5f6166 --- /dev/null +++ b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/invalidArgs.kt @@ -0,0 +1,8 @@ +// PROBLEM: none +// WITH_RUNTIME +// ERROR: No value passed for parameter 'second' +// ERROR: Type inference failed: Not enough information to infer parameter B in constructor Pair(first: A, second: B)
Please specify it explicitly.
+import kotlin.Pair +fun test() { + val p = Pair(1, ) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt new file mode 100644 index 00000000000..ce589caced6 --- /dev/null +++ b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME +import kotlin.Pair +fun test() { + val p = Pair(1, "foo") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt.after b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt.after new file mode 100644 index 00000000000..62e3878d352 --- /dev/null +++ b/idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME +import kotlin.Pair +fun test() { + val p = 1 to "foo" +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index dd7ebc8aa17..5628df2e1c2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1213,6 +1213,27 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/convertPairConstructorToToFunction") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertPairConstructorToToFunction extends AbstractLocalInspectionTest { + public void testAllFilesPresentInConvertPairConstructorToToFunction() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/convertPairConstructorToToFunction"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("invalidArgs.kt") + public void testInvalidArgs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/convertPairConstructorToToFunction/invalidArgs.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/convertPairConstructorToToFunction/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/inspectionsLocal/copyWithoutNamedArguments") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)