"Remove redundant receiver" quick fix: Remove unused type parameter #KT-23512
This commit is contained in:
committed by
Mikhail Glukhikh
parent
0cd25353bc
commit
90529dfda4
@@ -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.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.core.isOverridable
|
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||||
import org.jetbrains.kotlin.idea.isMainFunction
|
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.KotlinChangeSignatureConfiguration
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.modify
|
||||||
@@ -133,12 +134,13 @@ class UnusedReceiverParameterInspection : AbstractKotlinInspection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
val element = descriptor.psiElement
|
val element = descriptor.psiElement as? KtTypeReference ?: return
|
||||||
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return
|
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return
|
||||||
|
|
||||||
val function = element.parent as? KtCallableDeclaration ?: return
|
val function = element.parent as? KtCallableDeclaration ?: return
|
||||||
val callableDescriptor = function.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? CallableDescriptor ?: return
|
val callableDescriptor = function.resolveToDescriptorIfAny(BodyResolveMode.FULL) as? CallableDescriptor ?: return
|
||||||
|
|
||||||
|
val typeParameters = RemoveUnusedFunctionParameterFix.typeParameters(element)
|
||||||
if (inSameClass) {
|
if (inSameClass) {
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
val explicateAsTextForReceiver = callableDescriptor.explicateAsTextForReceiver()
|
val explicateAsTextForReceiver = callableDescriptor.explicateAsTextForReceiver()
|
||||||
@@ -150,6 +152,7 @@ class UnusedReceiverParameterInspection : AbstractKotlinInspection() {
|
|||||||
} else {
|
} else {
|
||||||
runChangeSignature(project, callableDescriptor, configureChangeSignature(), element, name)
|
runChangeSignature(project, callableDescriptor, configureChangeSignature(), element, name)
|
||||||
}
|
}
|
||||||
|
RemoveUnusedFunctionParameterFix.runRemoveUnusedTypeParameters(typeParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFamilyName(): String = name
|
override fun getFamilyName(): String = name
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA
|
|||||||
val parameterList = parameter.parent as? KtParameterList ?: return
|
val parameterList = parameter.parent as? KtParameterList ?: return
|
||||||
val parameterDescriptor = parameter.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return
|
val parameterDescriptor = parameter.resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return
|
||||||
val parameterSize = parameterList.parameters.size
|
val parameterSize = parameterList.parameters.size
|
||||||
val typeParameters = typeParameters(parameter)
|
val typeParameters = typeParameters(parameter.typeReference)
|
||||||
val primaryConstructor = parameterList.parent as? KtPrimaryConstructor
|
val primaryConstructor = parameterList.parent as? KtPrimaryConstructor
|
||||||
|
|
||||||
ChangeFunctionSignatureFix.runRemoveParameter(parameterDescriptor, parameter)
|
ChangeFunctionSignatureFix.runRemoveParameter(parameterDescriptor, parameter)
|
||||||
@@ -64,31 +64,6 @@ class RemoveUnusedFunctionParameterFix(parameter: KtParameter) : KotlinQuickFixA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun typeParameters(parameter: KtParameter): List<KtTypeParameter> {
|
|
||||||
val parameterParent = parameter.getParentOfTypesAndPredicate(false, KtNamedFunction::class.java, KtClass::class.java) { true }
|
|
||||||
return parameter.typeReference?.typeElement
|
|
||||||
?.collectDescendantsOfType<KtNameReferenceExpression> { 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<KtTypeParameter>) {
|
|
||||||
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() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtParameter>? {
|
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtParameter>? {
|
||||||
val parameter = Errors.UNUSED_PARAMETER.cast(diagnostic).psiElement
|
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
|
if (parameterOwner is KtFunctionLiteral || (parameterOwner is KtNamedFunction && parameterOwner.name == null)) return null
|
||||||
return RemoveUnusedFunctionParameterFix(parameter)
|
return RemoveUnusedFunctionParameterFix(parameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun typeParameters(typeReference: KtTypeReference?): List<KtTypeParameter> {
|
||||||
|
if (typeReference == null) return emptyList()
|
||||||
|
val parameterParent = typeReference.getParentOfTypesAndPredicate(
|
||||||
|
true,
|
||||||
|
KtNamedFunction::class.java, KtProperty::class.java, KtClass::class.java
|
||||||
|
) { true }
|
||||||
|
return typeReference.typeElement
|
||||||
|
?.collectDescendantsOfType<KtNameReferenceExpression> { 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<KtTypeParameter>) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun <T> <caret>T.foo() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
"".foo()
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun <T> <caret>T.foo(t: T) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
"".foo("")
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
fun <T> foo(t: T) {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo("")
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
interface TypeHolder<T, U>
|
||||||
|
|
||||||
|
fun <T, U> <caret>TypeHolder<T, U>.foo() {}
|
||||||
|
|
||||||
|
fun test(holder: TypeHolder<String, Int>) {
|
||||||
|
holder.foo()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
interface TypeHolder<T, U>
|
||||||
|
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
fun test(holder: TypeHolder<String, Int>) {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
class Test<T> {
|
||||||
|
fun <caret>T.foo() {}
|
||||||
|
|
||||||
|
fun test(t: T) {
|
||||||
|
t.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
class Test<T> {
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
fun test(t: T) {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
class Test<T> {
|
||||||
|
fun <U> <caret>U.foo() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
"".foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
class Test<T> {
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
val <T> <caret>T.bar: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
"".bar
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
val bar: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
bar
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
class Test<T> {
|
||||||
|
val <caret>T.bar: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
fun test(t: T) {
|
||||||
|
t.bar
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
class Test<T> {
|
||||||
|
val bar: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
fun test(t: T) {
|
||||||
|
bar
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
class Test<T> {
|
||||||
|
val <S> <caret>S.bar: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
"".bar
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
class Test<T> {
|
||||||
|
val bar: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
bar
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -6475,6 +6475,31 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/functionInSameClass2.kt");
|
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")
|
@TestMetadata("infix.kt")
|
||||||
public void testInfix() throws Exception {
|
public void testInfix() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/infix.kt");
|
runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/infix.kt");
|
||||||
@@ -6494,6 +6519,21 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
public void testPropertyInSameClass() throws Exception {
|
public void testPropertyInSameClass() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/unusedReceiverParameter/propertyInSameClass.kt");
|
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")
|
@TestMetadata("idea/testData/inspectionsLocal/unusedSymbol")
|
||||||
|
|||||||
Reference in New Issue
Block a user