From 2d2f1125a9704cd58d7f241722f86be88e7f7bdc Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Tue, 14 Aug 2018 07:29:23 +0300 Subject: [PATCH] "Remove redundant let": fix destructuring declaration false positive #KT-26042 Fixed --- .../ReplaceSingleLineLetIntention.kt | 34 +++++++++++++------ .../destructuringDeclaration.kt | 7 ++++ .../destructuringDeclaration.kt.after | 7 ++++ .../destructuringDeclaration2.kt | 7 ++++ .../destructuringDeclaration2.kt.after | 7 ++++ .../destructuringDeclaration3.kt | 8 +++++ .../destructuringDeclaration4.kt | 6 ++++ .../destructuringDeclaration5.kt | 6 ++++ .../intentions/IntentionTestGenerated.java | 25 ++++++++++++++ 9 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt.after create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt.after create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration3.kt create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration4.kt create mode 100644 idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration5.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt index 3a3143929ae..7ac2d198b34 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt @@ -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 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 { it != except && it.getReferencedName() == name } - private fun KtFunctionLiteral.valueParameterReferences(callExpression: KtCallExpression): List { + private fun KtFunctionLiteral.valueParameterReferences(callExpression: KtCallExpression): List { 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().filter { - it.text == name && it.getResolvedCall(context)?.resultingDescriptor == descriptor + arg.collectDescendantsOfType().filter { + val descriptor = variableDescriptorByName[it.getReferencedNameAsName()] + descriptor != null && it.getResolvedCall(context)?.resultingDescriptor == descriptor } } } diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt new file mode 100644 index 00000000000..a3b5bd3dbb7 --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test() { + (1 to 2).let { (i, j) -> foo() } +} + +fun foo() = 0 \ No newline at end of file diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt.after b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt.after new file mode 100644 index 00000000000..386e5e1cbf8 --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test() { + foo() +} + +fun foo() = 0 \ No newline at end of file diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt new file mode 100644 index 00000000000..9ce2788527d --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test() { + (1 to 2).let { (i, j) -> foo(1, 2) } +} + +fun foo(i: Int, j: Int) = i + j \ No newline at end of file diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt.after b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt.after new file mode 100644 index 00000000000..de6ae800842 --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration2.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test() { + foo(1, 2) +} + +fun foo(i: Int, j: Int) = i + j \ No newline at end of file diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration3.kt b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration3.kt new file mode 100644 index 00000000000..87530bfa984 --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration3.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false + +fun test() { + (1 to 2).let { (i, j) -> foo(i, 3) } +} + +fun foo(i: Int, j: Int) = i + j \ No newline at end of file diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration4.kt b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration4.kt new file mode 100644 index 00000000000..6e37d9866f4 --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration4.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false + +fun test(k: Int) { + (1 to 2).let { (i, j) -> i + k } +} \ No newline at end of file diff --git a/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration5.kt b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration5.kt new file mode 100644 index 00000000000..66ae96754f0 --- /dev/null +++ b/idea/testData/intentions/replaceSingleLineLetIntention/destructuringDeclaration5.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +// IS_APPLICABLE: false + +fun test() { + (1 to 2).let { (i, j) -> i.toLong() } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 530f5234011..cd652a7a174 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -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");