"Remove parameter" quick fix makes generic function call incompilable when type could be inferred from removed parameter only

#KT-23511 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-04-13 04:55:44 +03:00
committed by Alexey Sedunov
parent 8271e85dbb
commit 1d0a11cecd
14 changed files with 144 additions and 8 deletions
@@ -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<KtNameReferenceExpression>()?.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<KtParameter>? {
val parameter = Errors.UNUSED_PARAMETER.cast(diagnostic).psiElement
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
fun <X> foo(<caret>x: X) {}
fun test() {
foo(x = 1)
}
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
fun foo(<caret>) {}
fun test() {
foo()
}
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
fun <X> foo(<caret>x: X, x2: X) {}
fun test() {
foo(x = 1, x2 = 2)
}
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
fun <X> foo(<caret>x2: X) {}
fun test() {
foo(x2 = 2)
}
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
fun <X, Y> foo(<caret>x: X, y: Y) {}
fun test() {
foo(x = 1, y = 2)
}
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
fun <Y> foo(<caret>y: Y) {}
fun test() {
foo(y = 2)
}
@@ -0,0 +1,4 @@
// "Remove parameter 'x'" "true"
class Bar<X> {
fun foo(<caret>x: X) {}
}
@@ -0,0 +1,4 @@
// "Remove parameter 'x'" "true"
class Bar<X> {
fun foo(<caret>) {}
}
@@ -0,0 +1,4 @@
// "Remove parameter 'x'" "true"
class Foo<X>(<caret>x: X)
val foo = Foo(1)
@@ -0,0 +1,4 @@
// "Remove parameter 'x'" "true"
class Foo<caret>
val foo = Foo()
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
class Foo<X> {
constructor(<caret>x: X)
}
val foo = Foo(1)
@@ -0,0 +1,6 @@
// "Remove parameter 'x'" "true"
class Foo {
constructor(<caret>)
}
val foo = Foo()
@@ -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");