From 1d0a11cecd66c9288175e0bd9201e2c5adef4e84 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Fri, 13 Apr 2018 04:55:44 +0300 Subject: [PATCH] "Remove parameter" quick fix makes generic function call incompilable when type could be inferred from removed parameter only #KT-23511 Fixed --- .../RemoveUnusedFunctionParameterFix.kt | 52 ++++++++++++++++--- .../removeUnusedParameterWithTypeParameter.kt | 6 +++ ...eUnusedParameterWithTypeParameter.kt.after | 6 +++ ...removeUnusedParameterWithTypeParameter2.kt | 6 +++ ...UnusedParameterWithTypeParameter2.kt.after | 6 +++ ...removeUnusedParameterWithTypeParameter3.kt | 6 +++ ...UnusedParameterWithTypeParameter3.kt.after | 6 +++ ...removeUnusedParameterWithTypeParameter4.kt | 4 ++ ...UnusedParameterWithTypeParameter4.kt.after | 4 ++ ...removeUnusedParameterWithTypeParameter5.kt | 4 ++ ...UnusedParameterWithTypeParameter5.kt.after | 4 ++ ...removeUnusedParameterWithTypeParameter6.kt | 6 +++ ...UnusedParameterWithTypeParameter6.kt.after | 6 +++ .../idea/quickfix/QuickFixTestGenerated.java | 36 +++++++++++++ 14 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt.after create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt.after create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt.after create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt.after create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt.after create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt create mode 100644 idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt index 0e7830b5d1b..330f81962c1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project +import com.intellij.psi.search.searches.ReferencesSearch import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.caches.resolve.resolveToParameterDescriptorIfAny @@ -25,6 +26,8 @@ import org.jetbrains.kotlin.idea.intentions.RemoveEmptyPrimaryConstructorIntenti import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getChildOfType +import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -36,15 +39,25 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA override fun startInWriteAction(): Boolean = false override fun invoke(project: Project, editor: Editor?, file: KtFile) { - val element = element ?: return - val primaryConstructor = element.parent?.parent as? KtPrimaryConstructor - val parameterList = element.parent as? KtParameterList - val parameterDescriptor = element.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return - ChangeFunctionSignatureFix.runRemoveParameter(parameterDescriptor, element) - val nextParameter = parameterList?.parameters?.getOrNull(parameterDescriptor.index) - if (nextParameter != null) { - editor?.caretModel?.moveToOffset(nextParameter.startOffset) + val parameter = element ?: return + val parameterList = parameter.parent as? KtParameterList ?: return + val parameterDescriptor = parameter.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return + val parameterSize = parameterList.parameters.size + val redundantTypeParameter = redundantTypeParameter(parameter) + val primaryConstructor = parameterList.parent as? KtPrimaryConstructor + + ChangeFunctionSignatureFix.runRemoveParameter(parameterDescriptor, parameter) + if (redundantTypeParameter != null) { + runRemoveTypeParameter(redundantTypeParameter) } + + if (parameterSize > 1) { + val nextParameter = parameterList.parameters.getOrNull(parameterDescriptor.index) + if (nextParameter != null) { + editor?.caretModel?.moveToOffset(nextParameter.startOffset) + } + } + if (primaryConstructor != null) { val removeConstructorIntention = RemoveEmptyPrimaryConstructorIntention() if (removeConstructorIntention.isApplicableTo(primaryConstructor)) { @@ -56,6 +69,29 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA } } + private fun redundantTypeParameter(parameter: KtParameter): KtTypeParameter? { + val typeParameter = parameter.typeReference?.typeElement?.getChildOfType()?.reference?.resolve() + as? KtTypeParameter ?: return null + val parameterParent = + parameter.getParentOfTypesAndPredicate(false, KtNamedFunction::class.java, KtClass::class.java) { true } + val typeParameterParent = + typeParameter.getParentOfTypesAndPredicate(false, KtNamedFunction::class.java, KtClass::class.java) { true } + return if (parameterParent == typeParameterParent) typeParameter else null + } + + private fun runRemoveTypeParameter(typeParameter: KtTypeParameter) { + if (ReferencesSearch.search(typeParameter).findFirst() != null) return + + val typeParameterList = typeParameter.parent as? KtTypeParameterList ?: return + val typeParameters = typeParameterList.parameters + runWriteAction { + if (typeParameters.size == 1) + typeParameterList.delete() + else + EditCommaSeparatedListHelper.removeItem(typeParameter) + } + } + companion object : KotlinSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { val parameter = Errors.UNUSED_PARAMETER.cast(diagnostic).psiElement diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt new file mode 100644 index 00000000000..d51fb1e2b88 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +fun foo(x: X) {} + +fun test() { + foo(x = 1) +} \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt.after b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt.after new file mode 100644 index 00000000000..d7c51aa467a --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt.after @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +fun foo() {} + +fun test() { + foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt new file mode 100644 index 00000000000..1e3b86a7596 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +fun foo(x: X, x2: X) {} + +fun test() { + foo(x = 1, x2 = 2) +} \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt.after b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt.after new file mode 100644 index 00000000000..1a2a965dc0f --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt.after @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +fun foo(x2: X) {} + +fun test() { + foo(x2 = 2) +} \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt new file mode 100644 index 00000000000..c759a6906f6 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +fun foo(x: X, y: Y) {} + +fun test() { + foo(x = 1, y = 2) +} diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt.after b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt.after new file mode 100644 index 00000000000..d188bf8c8d1 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt.after @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +fun foo(y: Y) {} + +fun test() { + foo(y = 2) +} diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt new file mode 100644 index 00000000000..06c9dd1842d --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt @@ -0,0 +1,4 @@ +// "Remove parameter 'x'" "true" +class Bar { + fun foo(x: X) {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt.after b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt.after new file mode 100644 index 00000000000..f2018079ca4 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt.after @@ -0,0 +1,4 @@ +// "Remove parameter 'x'" "true" +class Bar { + fun foo() {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt new file mode 100644 index 00000000000..201e919c52d --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt @@ -0,0 +1,4 @@ +// "Remove parameter 'x'" "true" +class Foo(x: X) + +val foo = Foo(1) \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt.after b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt.after new file mode 100644 index 00000000000..a6470061943 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt.after @@ -0,0 +1,4 @@ +// "Remove parameter 'x'" "true" +class Foo + +val foo = Foo() \ No newline at end of file diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt new file mode 100644 index 00000000000..aea9b214a43 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +class Foo { + constructor(x: X) +} + +val foo = Foo(1) diff --git a/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt.after b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt.after new file mode 100644 index 00000000000..510a67c96a2 --- /dev/null +++ b/idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt.after @@ -0,0 +1,6 @@ +// "Remove parameter 'x'" "true" +class Foo { + constructor() +} + +val foo = Foo() diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index ea364654916..69e65b4b46a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1643,6 +1643,42 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/changeSignature/removeUnusedParameter.kt"); } + @TestMetadata("removeUnusedParameterWithTypeParameter.kt") + public void testRemoveUnusedParameterWithTypeParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter.kt"); + doTest(fileName); + } + + @TestMetadata("removeUnusedParameterWithTypeParameter2.kt") + public void testRemoveUnusedParameterWithTypeParameter2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter2.kt"); + doTest(fileName); + } + + @TestMetadata("removeUnusedParameterWithTypeParameter3.kt") + public void testRemoveUnusedParameterWithTypeParameter3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter3.kt"); + doTest(fileName); + } + + @TestMetadata("removeUnusedParameterWithTypeParameter4.kt") + public void testRemoveUnusedParameterWithTypeParameter4() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter4.kt"); + doTest(fileName); + } + + @TestMetadata("removeUnusedParameterWithTypeParameter5.kt") + public void testRemoveUnusedParameterWithTypeParameter5() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter5.kt"); + doTest(fileName); + } + + @TestMetadata("removeUnusedParameterWithTypeParameter6.kt") + public void testRemoveUnusedParameterWithTypeParameter6() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/changeSignature/removeUnusedParameterWithTypeParameter6.kt"); + doTest(fileName); + } + @TestMetadata("removeUnusedPrimaryConstructorParameter.kt") public void testRemoveUnusedPrimaryConstructorParameter() throws Exception { runTest("idea/testData/quickfix/changeSignature/removeUnusedPrimaryConstructorParameter.kt");