Don't suggest 'remove let' when 'it' is used multiple times

So #KT-16857 Fixed
This commit is contained in:
Mikhail Glukhikh
2017-03-23 15:32:36 +03:00
parent 4687a867c3
commit b121990368
3 changed files with 30 additions and 32 deletions
@@ -78,7 +78,7 @@ class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<Kt
}
override fun isApplicableTo(element: KtCallExpression): Boolean {
if (!isLetMethod(element)) return false
if (!element.isLetMethodCall()) return false
val lambdaExpression = element.lambdaArguments.firstOrNull()?.getLambdaExpression() ?: return false
val parameterName = lambdaExpression.getParameterName() ?: return false
val bodyExpression = lambdaExpression.bodyExpression?.children?.singleOrNull() ?: return false
@@ -99,32 +99,26 @@ class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<Kt
}
val right = right ?: return false
when (right) {
is KtNameReferenceExpression -> return right.text != parameterName
is KtDotQualifiedExpression -> {
if (right.isParameterLeftMostReceiver(parameterName)) return false
if (right.hasLambdaExpression()) return false
return !right.receiverUsedAsArgument(parameterName)
}
is KtConstantExpression -> return true
else -> return false
return when (right) {
is KtNameReferenceExpression -> right.text != parameterName
is KtDotQualifiedExpression -> !right.hasLambdaExpression() && !right.nameUsed(parameterName)
is KtConstantExpression -> true
else -> false
}
}
private fun KtDotQualifiedExpression.isApplicable(parameterName: String): Boolean {
if (!isParameterLeftMostReceiver(parameterName)) return false
if (hasLambdaExpression()) return false
return !receiverUsedAsArgument(parameterName)
}
private fun KtDotQualifiedExpression.isApplicable(parameterName: String) =
!hasLambdaExpression() && getLeftMostReceiverExpression().let { receiver ->
receiver is KtNameReferenceExpression &&
receiver.getReferencedName() == parameterName &&
!nameUsed(parameterName, except = receiver)
}
private fun KtDotQualifiedExpression.hasLambdaExpression()
= selectorExpression?.anyDescendantOfType<KtLambdaExpression>() ?: false
private fun KtDotQualifiedExpression.isParameterLeftMostReceiver(parameterName: String)
= getLeftMostReceiverExpression().text == parameterName
private fun isLetMethod(element: KtCallExpression) =
element.calleeExpression?.text == "let" && element.isMethodCall("kotlin.let")
private fun KtCallExpression.isLetMethodCall() =
calleeExpression?.text == "let" && isMethodCall("kotlin.let")
private fun KtLambdaExpression.getParameterName(): String? {
val parameters = valueParameters
@@ -132,16 +126,6 @@ class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<Kt
return if (parameters.size == 1) parameters[0].text else "it"
}
private fun KtDotQualifiedExpression.receiverUsedAsArgument(receiverName: String): Boolean {
(selectorExpression as? KtCallExpression)?.valueArguments?.let {
if (it.any { it.receiverUsedAsArgument(receiverName) }) return true
}
return (receiverExpression as? KtDotQualifiedExpression)?.receiverUsedAsArgument(receiverName) ?: false
}
private fun KtValueArgument.receiverUsedAsArgument(receiverName: String) =
text == receiverName || anyDescendantOfType<KtDotQualifiedExpression> {
it.getLeftMostReceiverExpression().text == receiverName ||
it.receiverUsedAsArgument(receiverName)
}
private fun KtExpression.nameUsed(name: String, except: KtNameReferenceExpression? = null): Boolean =
anyDescendantOfType<KtNameReferenceExpression> { it != except && it.getReferencedName() == name }
}
@@ -0,0 +1,8 @@
// IS_APPLICABLE: false
// WITH_RUNTIME
fun foo(s: String) {
if (s.substring(1).let<caret> { it.startsWith("a") || it[1].isLowerCase() }) {
}
}
@@ -13368,6 +13368,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("multipleUsages.kt")
public void testMultipleUsages() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/replaceSingleLineLetIntention/multipleUsages.kt");
doTest(fileName);
}
@TestMetadata("plusNullable.kt")
public void testPlusNullable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/replaceSingleLineLetIntention/plusNullable.kt");