"Remove redundant let": fix destructuring declaration false positive

#KT-26042 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-08-14 07:29:23 +03:00
committed by Mikhail Glukhikh
parent 7e8521d9dc
commit 2d2f1125a9
9 changed files with 97 additions and 10 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
@@ -105,11 +106,20 @@ class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<Kt
val bodyExpression = lambdaExpression.bodyExpression?.children?.singleOrNull() ?: return false
return when (bodyExpression) {
is KtBinaryExpression -> element.parent !is KtSafeQualifiedExpression && bodyExpression.isApplicable(parameterName)
is KtDotQualifiedExpression -> bodyExpression.isApplicable(parameterName)
is KtCallExpression -> element.parent !is KtSafeQualifiedExpression
&& lambdaExpression.functionLiteral.valueParameterReferences(bodyExpression).count() <= 1
else -> false
is KtBinaryExpression ->
element.parent !is KtSafeQualifiedExpression && bodyExpression.isApplicable(parameterName)
is KtDotQualifiedExpression ->
bodyExpression.isApplicable(parameterName)
is KtCallExpression ->
if (element.parent is KtSafeQualifiedExpression) {
false
} else {
val count = lambdaExpression.functionLiteral.valueParameterReferences(bodyExpression).count()
val destructuringDeclaration = lambdaExpression.functionLiteral.valueParameters.firstOrNull()?.destructuringDeclaration
count == 0 || (count == 1 && destructuringDeclaration == null)
}
else ->
false
}
}
@@ -163,13 +173,17 @@ class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<Kt
private fun KtExpression.nameUsed(name: String, except: KtNameReferenceExpression? = null): Boolean =
anyDescendantOfType<KtNameReferenceExpression> { it != except && it.getReferencedName() == name }
private fun KtFunctionLiteral.valueParameterReferences(callExpression: KtCallExpression): List<KtReferenceExpression> {
private fun KtFunctionLiteral.valueParameterReferences(callExpression: KtCallExpression): List<KtNameReferenceExpression> {
val context = analyze(BodyResolveMode.PARTIAL)
val descriptor = context[BindingContext.FUNCTION, this]?.valueParameters?.singleOrNull() ?: return emptyList()
val name = descriptor.name.asString()
val parameterDescriptor = context[BindingContext.FUNCTION, this]?.valueParameters?.singleOrNull() ?: return emptyList()
val variableDescriptorByName = if (parameterDescriptor is ValueParameterDescriptorImpl.WithDestructuringDeclaration)
parameterDescriptor.destructuringVariables.associate { it.name to it }
else
mapOf(parameterDescriptor.name to parameterDescriptor)
return callExpression.valueArguments.flatMap { arg ->
arg.collectDescendantsOfType<KtReferenceExpression>().filter {
it.text == name && it.getResolvedCall(context)?.resultingDescriptor == descriptor
arg.collectDescendantsOfType<KtNameReferenceExpression>().filter {
val descriptor = variableDescriptorByName[it.getReferencedNameAsName()]
descriptor != null && it.getResolvedCall(context)?.resultingDescriptor == descriptor
}
}
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test() {
(1 to 2).let<caret> { (i, j) -> foo() }
}
fun foo() = 0
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test() {
foo()
}
fun foo() = 0
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test() {
(1 to 2).let<caret> { (i, j) -> foo(1, 2) }
}
fun foo(i: Int, j: Int) = i + j
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test() {
foo(1, 2)
}
fun foo(i: Int, j: Int) = i + j
@@ -0,0 +1,8 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun test() {
(1 to 2).let<caret> { (i, j) -> foo(i, 3) }
}
fun foo(i: Int, j: Int) = i + j
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun test(k: Int) {
(1 to 2).let<caret> { (i, j) -> i + k }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
fun test() {
(1 to 2).let<caret> { (i, j) -> i.toLong() }
}
@@ -13912,6 +13912,31 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/comparisons.kt");
}
@TestMetadata("destructuringDeclaration.kt")
public void testDestructuringDeclaration() throws Exception {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt");
}
@TestMetadata("destructuringDeclaration2.kt")
public void testDestructuringDeclaration2() throws Exception {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt");
}
@TestMetadata("destructuringDeclaration3.kt")
public void testDestructuringDeclaration3() throws Exception {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration3.kt");
}
@TestMetadata("destructuringDeclaration4.kt")
public void testDestructuringDeclaration4() throws Exception {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration4.kt");
}
@TestMetadata("destructuringDeclaration5.kt")
public void testDestructuringDeclaration5() throws Exception {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration5.kt");
}
@TestMetadata("dotWithComparison.kt")
public void testDotWithComparison() throws Exception {
runTest("idea/testData/intentions/replaceSingleLineLetIntention/dotWithComparison.kt");