"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.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
|
||||
|
||||
@@ -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<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() {
|
||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtParameter>? {
|
||||
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<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");
|
||||
}
|
||||
|
||||
@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")
|
||||
|
||||
Reference in New Issue
Block a user