For each parameter unused: add quick-fix "introduce anonymous parameter"
Related to KT-22068
This commit is contained in:
+20
-2
@@ -5,13 +5,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.inspections
|
package org.jetbrains.kotlin.idea.inspections
|
||||||
|
|
||||||
|
import com.intellij.codeInspection.LocalQuickFix
|
||||||
|
import com.intellij.codeInspection.ProblemDescriptor
|
||||||
import com.intellij.codeInspection.ProblemHighlightType
|
import com.intellij.codeInspection.ProblemHighlightType
|
||||||
import com.intellij.codeInspection.ProblemsHolder
|
import com.intellij.codeInspection.ProblemsHolder
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElementVisitor
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl.WithDestructuringDeclaration
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl.WithDestructuringDeclaration
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.SpecifyExplicitLambdaSignatureIntention
|
||||||
import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
|
import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getThisLabelName
|
import org.jetbrains.kotlin.idea.refactoring.getThisLabelName
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -41,11 +45,11 @@ class ForEachParameterNotUsedInspection : AbstractKotlinInspection() {
|
|||||||
if (iterableParameter !is WithDestructuringDeclaration &&
|
if (iterableParameter !is WithDestructuringDeclaration &&
|
||||||
lambda.bodyExpression?.usesDescriptor(iterableParameter) != true
|
lambda.bodyExpression?.usesDescriptor(iterableParameter) != true
|
||||||
) {
|
) {
|
||||||
|
|
||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
calleeExpression,
|
calleeExpression,
|
||||||
"Loop parameter '${iterableParameter.getThisLabelName()}' is unused",
|
"Loop parameter '${iterableParameter.getThisLabelName()}' is unused",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
|
IntroduceAnonymousParameterFix()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,6 +57,20 @@ class ForEachParameterNotUsedInspection : AbstractKotlinInspection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class IntroduceAnonymousParameterFix : LocalQuickFix {
|
||||||
|
override fun getFamilyName() = "Introduce anonymous parameter"
|
||||||
|
|
||||||
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
|
val callExpression = descriptor.psiElement.parent as? KtCallExpression ?: return
|
||||||
|
val literal = callExpression.lambdaArguments.singleOrNull()?.getLambdaExpression()?.functionLiteral ?: return
|
||||||
|
val psiFactory = KtPsiFactory(project)
|
||||||
|
val newParameterList = psiFactory.createLambdaParameterList("_")
|
||||||
|
with (SpecifyExplicitLambdaSignatureIntention) {
|
||||||
|
literal.setParameterListIfAny(psiFactory, newParameterList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun KtBlockExpression.usesDescriptor(descriptor: VariableDescriptor): Boolean {
|
private fun KtBlockExpression.usesDescriptor(descriptor: VariableDescriptor): Boolean {
|
||||||
var used = false
|
var used = false
|
||||||
acceptChildren(object : KtVisitorVoid() {
|
acceptChildren(object : KtVisitorVoid() {
|
||||||
|
|||||||
+23
-14
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtParameterList
|
||||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
@@ -59,24 +61,31 @@ class SpecifyExplicitLambdaSignatureIntention : SelfTargetingOffsetIndependentIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
fun KtFunctionLiteral.setParameterListIfAny(psiFactory: KtPsiFactory, newParameterList: KtParameterList?) {
|
||||||
|
val oldParameterList = valueParameterList
|
||||||
|
if (oldParameterList != null && newParameterList != null) {
|
||||||
|
oldParameterList.replace(newParameterList)
|
||||||
|
} else {
|
||||||
|
val openBraceElement = lBrace
|
||||||
|
val nextSibling = openBraceElement.nextSibling
|
||||||
|
val addNewline = nextSibling is PsiWhiteSpace && nextSibling.text?.contains("\n") ?: false
|
||||||
|
val (whitespace, arrow) = psiFactory.createWhitespaceAndArrow()
|
||||||
|
addRangeAfter(whitespace, arrow, openBraceElement)
|
||||||
|
if (newParameterList != null) {
|
||||||
|
addAfter(newParameterList, openBraceElement)
|
||||||
|
}
|
||||||
|
if (addNewline) {
|
||||||
|
addAfter(psiFactory.createNewLine(), openBraceElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun applyWithParameters(element: KtLambdaExpression, parameterString: String) {
|
fun applyWithParameters(element: KtLambdaExpression, parameterString: String) {
|
||||||
val psiFactory = KtPsiFactory(element)
|
val psiFactory = KtPsiFactory(element)
|
||||||
val functionLiteral = element.functionLiteral
|
val functionLiteral = element.functionLiteral
|
||||||
val newParameterList = psiFactory.createLambdaParameterListIfAny(parameterString)
|
val newParameterList = psiFactory.createLambdaParameterListIfAny(parameterString)
|
||||||
val oldParameterList = functionLiteral.valueParameterList
|
functionLiteral.setParameterListIfAny(psiFactory, newParameterList)
|
||||||
if (oldParameterList != null && newParameterList != null) {
|
|
||||||
oldParameterList.replace(newParameterList)
|
|
||||||
} else {
|
|
||||||
val openBraceElement = functionLiteral.lBrace
|
|
||||||
val nextSibling = openBraceElement.nextSibling
|
|
||||||
val addNewline = nextSibling is PsiWhiteSpace && nextSibling.text?.contains("\n") ?: false
|
|
||||||
val (whitespace, arrow) = psiFactory.createWhitespaceAndArrow()
|
|
||||||
functionLiteral.addRangeAfter(whitespace, arrow, openBraceElement)
|
|
||||||
newParameterList?.let { functionLiteral.addAfter(it, openBraceElement) }
|
|
||||||
if (addNewline) {
|
|
||||||
functionLiteral.addAfter(psiFactory.createNewLine(), openBraceElement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ShortenReferences.DEFAULT.process(element.valueParameters)
|
ShortenReferences.DEFAULT.process(element.valueParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test(list: List<String>) {
|
||||||
|
list.for<caret>Each {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test(list: List<String>) {
|
||||||
|
list.forEach { _ -> }
|
||||||
|
}
|
||||||
+5
@@ -2177,6 +2177,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
public void testInvoke() throws Exception {
|
public void testInvoke() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/forEachParameterNotUsed/invoke.kt");
|
runTest("idea/testData/inspectionsLocal/forEachParameterNotUsed/invoke.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("normal.kt")
|
||||||
|
public void testNormal() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/forEachParameterNotUsed/normal.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/inspectionsLocal/ImplicitNullableNothingType")
|
@TestMetadata("idea/testData/inspectionsLocal/ImplicitNullableNothingType")
|
||||||
|
|||||||
Reference in New Issue
Block a user