From 90529dfda45fb8d29c012b59ad2cb392480062c3 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Wed, 5 Sep 2018 13:18:59 +0900 Subject: [PATCH] "Remove redundant receiver" quick fix: Remove unused type parameter #KT-23512 --- .../UnusedReceiverParameterInspection.kt | 5 +- .../RemoveUnusedFunctionParameterFix.kt | 59 +++++++++++-------- .../functionWithTypeParameter.kt | 5 ++ .../functionWithTypeParameter.kt.after | 5 ++ .../functionWithTypeParameter2.kt | 5 ++ .../functionWithTypeParameter2.kt.after | 5 ++ .../functionWithTypeParameter3.kt | 7 +++ .../functionWithTypeParameter3.kt.after | 7 +++ .../functionWithTypeParameterInClass.kt | 7 +++ .../functionWithTypeParameterInClass.kt.after | 7 +++ .../functionWithTypeParameterInClass2.kt | 7 +++ ...functionWithTypeParameterInClass2.kt.after | 7 +++ .../propertyWithTypeParameter.kt | 6 ++ .../propertyWithTypeParameter.kt.after | 6 ++ .../propertyWithTypeParameterInClass.kt | 8 +++ .../propertyWithTypeParameterInClass.kt.after | 8 +++ .../propertyWithTypeParameterInClass2.kt | 8 +++ ...propertyWithTypeParameterInClass2.kt.after | 8 +++ .../LocalInspectionTestGenerated.java | 40 +++++++++++++ 19 files changed, 183 insertions(+), 27 deletions(-) create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt.after create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt create mode 100644 idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt index c4e957048da..184e9d16d30 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedReceiverParameterInspection.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.isOverridable import org.jetbrains.kotlin.idea.isMainFunction +import org.jetbrains.kotlin.idea.quickfix.RemoveUnusedFunctionParameterFix import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureConfiguration import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify @@ -133,12 +134,13 @@ class UnusedReceiverParameterInspection : AbstractKotlinInspection() { } override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - val element = descriptor.psiElement + val element = descriptor.psiElement as? KtTypeReference ?: return if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return val function = element.parent as? KtCallableDeclaration ?: return val callableDescriptor = function.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? CallableDescriptor ?: return + val typeParameters = RemoveUnusedFunctionParameterFix.typeParameters(element) if (inSameClass) { runWriteAction { val explicateAsTextForReceiver = callableDescriptor.explicateAsTextForReceiver() @@ -150,6 +152,7 @@ class UnusedReceiverParameterInspection : AbstractKotlinInspection() { } else { runChangeSignature(project, callableDescriptor, configureChangeSignature(), element, name) } + RemoveUnusedFunctionParameterFix.runRemoveUnusedTypeParameters(typeParameters) } override fun getFamilyName(): String = name diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt index 775897d38b3..1e0e315c0e6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RemoveUnusedFunctionParameterFix.kt @@ -40,7 +40,7 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA val parameterList = parameter.parent as? KtParameterList ?: return val parameterDescriptor = parameter.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return val parameterSize = parameterList.parameters.size - val typeParameters = typeParameters(parameter) + val typeParameters = typeParameters(parameter.typeReference) val primaryConstructor = parameterList.parent as? KtPrimaryConstructor ChangeFunctionSignatureFix.runRemoveParameter(parameterDescriptor, parameter) @@ -64,31 +64,6 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA } } - private fun typeParameters(parameter: KtParameter): List { - val parameterParent = parameter.getParentOfTypesAndPredicate(false, KtNamedFunction::class.java, KtClass::class.java) { true } - return parameter.typeReference?.typeElement - ?.collectDescendantsOfType { true } - ?.mapNotNull { - val typeParameter = it.reference?.resolve() as? KtTypeParameter ?: return@mapNotNull null - val parent = typeParameter.getParentOfTypesAndPredicate(false, KtNamedFunction::class.java, KtClass::class.java) { true } - if (parent == parameterParent) typeParameter else null - } ?: emptyList() - } - - private fun runRemoveUnusedTypeParameters(typeParameters: List) { - val unusedTypeParams = typeParameters.filter { ReferencesSearch.search(it).findFirst() == null } - if (unusedTypeParams.isEmpty()) return - runWriteAction { - unusedTypeParams.forEach { typeParameter -> - val typeParameterList = typeParameter.parent as? KtTypeParameterList ?: return@forEach - if (typeParameterList.parameters.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 @@ -96,5 +71,37 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA if (parameterOwner is KtFunctionLiteral || (parameterOwner is KtNamedFunction && parameterOwner.name == null)) return null return RemoveUnusedFunctionParameterFix(parameter) } + + fun typeParameters(typeReference: KtTypeReference?): List { + if (typeReference == null) return emptyList() + val parameterParent = typeReference.getParentOfTypesAndPredicate( + true, + KtNamedFunction::class.java, KtProperty::class.java, KtClass::class.java + ) { true } + return typeReference.typeElement + ?.collectDescendantsOfType { true } + ?.mapNotNull { + val typeParameter = it.reference?.resolve() as? KtTypeParameter ?: return@mapNotNull null + val parent = typeParameter.getParentOfTypesAndPredicate( + true, + KtNamedFunction::class.java, KtProperty::class.java, KtClass::class.java + ) { true } + if (parent == parameterParent) typeParameter else null + } ?: emptyList() + } + + fun runRemoveUnusedTypeParameters(typeParameters: List) { + val unusedTypeParams = typeParameters.filter { ReferencesSearch.search(it).findFirst() == null } + if (unusedTypeParams.isEmpty()) return + runWriteAction { + unusedTypeParams.forEach { typeParameter -> + val typeParameterList = typeParameter.parent as? KtTypeParameterList ?: return@forEach + if (typeParameterList.parameters.size == 1) + typeParameterList.delete() + else + EditCommaSeparatedListHelper.removeItem(typeParameter) + } + } + } } } diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt new file mode 100644 index 00000000000..31cc063de7c --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt @@ -0,0 +1,5 @@ +fun T.foo() {} + +fun test() { + "".foo() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt.after new file mode 100644 index 00000000000..21aac390229 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt.after @@ -0,0 +1,5 @@ +fun foo() {} + +fun test() { + foo() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt new file mode 100644 index 00000000000..85b0a7277fd --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt @@ -0,0 +1,5 @@ +fun T.foo(t: T) {} + +fun test() { + "".foo("") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt.after new file mode 100644 index 00000000000..fbee3b113c5 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt.after @@ -0,0 +1,5 @@ +fun foo(t: T) {} + +fun test() { + foo("") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt new file mode 100644 index 00000000000..ab56adc23f5 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt @@ -0,0 +1,7 @@ +interface TypeHolder + +fun TypeHolder.foo() {} + +fun test(holder: TypeHolder) { + holder.foo() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt.after new file mode 100644 index 00000000000..093381fa7d0 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt.after @@ -0,0 +1,7 @@ +interface TypeHolder + +fun foo() {} + +fun test(holder: TypeHolder) { + foo() +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt new file mode 100644 index 00000000000..b90e58be31d --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt @@ -0,0 +1,7 @@ +class Test { + fun T.foo() {} + + fun test(t: T) { + t.foo() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt.after new file mode 100644 index 00000000000..8dbab3d19c9 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt.after @@ -0,0 +1,7 @@ +class Test { + fun foo() {} + + fun test(t: T) { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt new file mode 100644 index 00000000000..ffebad27446 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt @@ -0,0 +1,7 @@ +class Test { + fun U.foo() {} + + fun test() { + "".foo() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt.after new file mode 100644 index 00000000000..bf1479d3594 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt.after @@ -0,0 +1,7 @@ +class Test { + fun foo() {} + + fun test() { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt new file mode 100644 index 00000000000..dc01233a4e4 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt @@ -0,0 +1,6 @@ +val T.bar: Int + get() = 1 + +fun test() { + "".bar +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt.after new file mode 100644 index 00000000000..1403d4d97fb --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt.after @@ -0,0 +1,6 @@ +val bar: Int + get() = 1 + +fun test() { + bar +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt new file mode 100644 index 00000000000..9521a682344 --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt @@ -0,0 +1,8 @@ +class Test { + val T.bar: Int + get() = 1 + + fun test(t: T) { + t.bar + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt.after new file mode 100644 index 00000000000..b332d85ed1b --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt.after @@ -0,0 +1,8 @@ +class Test { + val bar: Int + get() = 1 + + fun test(t: T) { + bar + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt new file mode 100644 index 00000000000..524f31f768e --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt @@ -0,0 +1,8 @@ +class Test { + val S.bar: Int + get() = 1 + + fun test() { + "".bar + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt.after b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt.after new file mode 100644 index 00000000000..8880ec2d0ff --- /dev/null +++ b/idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt.after @@ -0,0 +1,8 @@ +class Test { + val bar: Int + get() = 1 + + fun test() { + bar + } +} \ 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 90cbb42094a..262a5eec922 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -6475,6 +6475,31 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionInSameClass2.kt"); } + @TestMetadata("functionWithTypeParameter.kt") + public void testFunctionWithTypeParameter() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter.kt"); + } + + @TestMetadata("functionWithTypeParameter2.kt") + public void testFunctionWithTypeParameter2() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter2.kt"); + } + + @TestMetadata("functionWithTypeParameter3.kt") + public void testFunctionWithTypeParameter3() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameter3.kt"); + } + + @TestMetadata("functionWithTypeParameterInClass.kt") + public void testFunctionWithTypeParameterInClass() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass.kt"); + } + + @TestMetadata("functionWithTypeParameterInClass2.kt") + public void testFunctionWithTypeParameterInClass2() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionWithTypeParameterInClass2.kt"); + } + @TestMetadata("infix.kt") public void testInfix() throws Exception { runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/infix.kt"); @@ -6494,6 +6519,21 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { public void testPropertyInSameClass() throws Exception { runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/propertyInSameClass.kt"); } + + @TestMetadata("propertyWithTypeParameter.kt") + public void testPropertyWithTypeParameter() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameter.kt"); + } + + @TestMetadata("propertyWithTypeParameterInClass.kt") + public void testPropertyWithTypeParameterInClass() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass.kt"); + } + + @TestMetadata("propertyWithTypeParameterInClass2.kt") + public void testPropertyWithTypeParameterInClass2() throws Exception { + runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/propertyWithTypeParameterInClass2.kt"); + } } @TestMetadata("idea/testData/inspectionsLocal/unusedSymbol")