"Remove redundant let" inspection: do not report for long call chains #KT-26289 Fixed

This commit is contained in:
Toshiaki Kameyama
2018-08-26 07:14:33 +09:00
committed by Mikhail Glukhikh
parent c6db26ba91
commit ae4ff45750
15 changed files with 141 additions and 1 deletions
@@ -21,16 +21,36 @@ 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
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.lineCount
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class ReplaceSingleLineLetInspection : IntentionBasedInspection<KtCallExpression>(ReplaceSingleLineLetIntention::class) {
class ReplaceSingleLineLetInspection : IntentionBasedInspection<KtCallExpression>(
ReplaceSingleLineLetIntention::class,
{ element -> isApplicable(element) }
) {
override fun inspectionTarget(element: KtCallExpression) = element.calleeExpression
companion object {
fun isApplicable(element: KtCallExpression): Boolean {
val qualifiedExpression = element.getQualifiedExpressionForSelector() ?: return true
var receiver = qualifiedExpression.receiverExpression as? KtQualifiedExpression ?: return true
if (receiver.lineCount() > 1) return false
var count = 1
while (true) {
if (count > 2) return false
receiver = receiver.receiverExpression as? KtQualifiedExpression ?: break
count++
}
return true
}
}
}
class ReplaceSingleLineLetIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetInspection
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun test(list: List<Int>) {
list.filter { it > 1 }.filter { it > 2 }.let<caret> { println(it) }
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun test(list: List<Int>) {
println(list.filter { it > 1 }.filter { it > 2 })
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test(list: List<Int>) {
list.filter { it > 1 }.filter { it > 2 }
.let<caret> { println(it) }
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun test(list: List<Int>) {
println(list.filter { it > 1 }.filter { it > 2 })
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test(list: List<Int>) {
list.filter { it > 1 }.filter { it > 2 }.let<caret> {
println(it)
}
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun test(list: List<Int>) {
println(list.filter { it > 1 }.filter { it > 2 })
}
@@ -0,0 +1,8 @@
// WITH_RUNTIME
// PROBLEM: none
fun test(list: List<Int>) {
list.filter { it > 1 }
.filter { it > 2 }
.let<caret> { println(it) }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
// PROBLEM: none
fun test(list: List<Int>) {
list.filter { it > 1 }.filter { it > 2 }.filter { it > 3 }.let<caret> { println(it) }
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun String.test(): Int {
return let<caret> {
it.length
}
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun String.test(): Int {
return length
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test(s: String?): Int? {
return s?.let<caret> {
it.length
}
}
@@ -0,0 +1,5 @@
// WITH_RUNTIME
fun test(s: String?): Int? {
return s?.length
}
@@ -5007,6 +5007,54 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
}
}
@TestMetadata("idea/testData/inspectionsLocal/replaceSingleLineLet")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ReplaceSingleLineLet extends AbstractLocalInspectionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInReplaceSingleLineLet() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceSingleLineLet"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("callChain.kt")
public void testCallChain() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt");
}
@TestMetadata("callChain2.kt")
public void testCallChain2() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt");
}
@TestMetadata("callChain3.kt")
public void testCallChain3() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt");
}
@TestMetadata("callChainWithLineBreak.kt")
public void testCallChainWithLineBreak() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/callChainWithLineBreak.kt");
}
@TestMetadata("longCallChain.kt")
public void testLongCallChain() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/longCallChain.kt");
}
@TestMetadata("noReceiver.kt")
public void testNoReceiver() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt");
}
}
@TestMetadata("idea/testData/inspectionsLocal/replaceStringFormatWithLiteral")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)