"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
}
}
}