Remove redundant let in "Safe access to if-then" #KT-13515 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
443b1834bc
commit
7e8521d9dc
+34
-7
@@ -21,16 +21,24 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.replaced
|
||||
import org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.convertToIfNotNullExpression
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceValueForCondition
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableSimpleExpression
|
||||
import org.jetbrains.kotlin.idea.intentions.callExpression
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedExpression>(KtSafeQualifiedExpression::class.java, "Replace safe access expression with 'if' expression"), LowPriorityAction {
|
||||
class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedExpression>(
|
||||
KtSafeQualifiedExpression::class.java,
|
||||
"Replace safe access expression with 'if' expression"
|
||||
), LowPriorityAction {
|
||||
override fun applicabilityRange(element: KtSafeQualifiedExpression): TextRange? {
|
||||
if (element.selectorExpression == null) return null
|
||||
return element.operationTokenNode.textRange
|
||||
@@ -57,14 +65,33 @@ class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedE
|
||||
isAssignment = true
|
||||
}
|
||||
|
||||
if (!receiverIsStable) {
|
||||
val valueToExtract = if (isAssignment)
|
||||
((ifExpression.then as? KtBinaryExpression)?.left as? KtDotQualifiedExpression)?.receiverExpression
|
||||
else
|
||||
(ifExpression.then as? KtDotQualifiedExpression)?.receiverExpression
|
||||
val isRedundantLetCallRemoved = ifExpression.removeRedundantLetCallIfPossible(editor)
|
||||
|
||||
if (!receiverIsStable) {
|
||||
val valueToExtract = when {
|
||||
isAssignment ->
|
||||
((ifExpression.then as? KtBinaryExpression)?.left as? KtDotQualifiedExpression)?.receiverExpression
|
||||
isRedundantLetCallRemoved -> {
|
||||
val context = ifExpression.analyze(BodyResolveMode.PARTIAL)
|
||||
val descriptor = (ifExpression.condition as? KtBinaryExpression)?.left?.getResolvedCall(context)?.resultingDescriptor
|
||||
ifExpression.then?.findDescendantOfType<KtNameReferenceExpression> {
|
||||
it.getReferencedNameAsName() == descriptor?.name && it.getResolvedCall(context)?.resultingDescriptor == descriptor
|
||||
}
|
||||
}
|
||||
else ->
|
||||
(ifExpression.then as? KtDotQualifiedExpression)?.receiverExpression
|
||||
}
|
||||
if (valueToExtract != null) ifExpression.introduceValueForCondition(valueToExtract, editor)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun KtIfExpression.removeRedundantLetCallIfPossible(editor: Editor?): Boolean {
|
||||
val callExpression = (then as? KtQualifiedExpression)?.callExpression ?: return false
|
||||
if (callExpression.calleeExpression?.text != "let") return false
|
||||
val replaceSingleLineLetIntention = ReplaceSingleLineLetIntention()
|
||||
if (!replaceSingleLineLetIntention.isApplicableTo(callExpression)) return false
|
||||
replaceSingleLineLetIntention.applyTo(callExpression, editor)
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(value: Int?): Int? {
|
||||
return value<caret>?.let { it + 1 }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(value: Int?): Int? {
|
||||
return if (value != null) value + 1 else null
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(value: Int?): Int? {
|
||||
return value<caret>?.let { baz(it) }
|
||||
}
|
||||
|
||||
fun baz(i: Int) = i + i
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(value: Int?): Int? {
|
||||
return if (value != null) baz(value) else null
|
||||
}
|
||||
|
||||
fun baz(i: Int) = i + i
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(a: Int, b: Int?): Int? {
|
||||
return b<caret>?.let { a + b }
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(a: Int, b: Int?): Int? {
|
||||
return if (b != null) b.let { a + b } else null
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(value: Int?): Int? {
|
||||
return value<caret>?.let {
|
||||
println()
|
||||
it + 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun foo(value: Int?): Int? {
|
||||
return if (value != null) value.let {
|
||||
println()
|
||||
it + 1
|
||||
} else null
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
var a: String? = "A"
|
||||
fun main(args: Array<String>) {
|
||||
a<caret>?.let { it.length + 1 }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
var a: String? = "A"
|
||||
fun main(args: Array<String>) {
|
||||
val a1 = a
|
||||
if (a1 != null) a1.length + 1
|
||||
}
|
||||
@@ -2796,6 +2796,31 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/equality.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("let.kt")
|
||||
public void testLet() throws Exception {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/let.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("let2.kt")
|
||||
public void testLet2() throws Exception {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/let2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("let3.kt")
|
||||
public void testLet3() throws Exception {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/let3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("letNotRedundant.kt")
|
||||
public void testLetNotRedundant() throws Exception {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/letNotRedundant.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("letTopLevelVar.kt")
|
||||
public void testLetTopLevelVar() throws Exception {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/letTopLevelVar.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("localValAsReceiver.kt")
|
||||
public void testLocalValAsReceiver() throws Exception {
|
||||
runTest("idea/testData/intentions/branched/safeAccessToIfThen/localValAsReceiver.kt");
|
||||
|
||||
Reference in New Issue
Block a user