From ae4ff45750ebd2c103ef665a7681d8bd6cc92b4f Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Sun, 26 Aug 2018 07:14:33 +0900 Subject: [PATCH] "Remove redundant let" inspection: do not report for long call chains #KT-26289 Fixed --- .../ReplaceSingleLineLetIntention.kt | 22 ++++++++- .../replaceSingleLineLet/.inspection | 1 + .../replaceSingleLineLet/callChain.kt | 5 ++ .../replaceSingleLineLet/callChain.kt.after | 5 ++ .../replaceSingleLineLet/callChain2.kt | 6 +++ .../replaceSingleLineLet/callChain2.kt.after | 5 ++ .../replaceSingleLineLet/callChain3.kt | 7 +++ .../replaceSingleLineLet/callChain3.kt.after | 5 ++ .../callChainWithLineBreak.kt | 8 ++++ .../replaceSingleLineLet/longCallChain.kt | 6 +++ .../replaceSingleLineLet/noReceiver.kt | 7 +++ .../replaceSingleLineLet/noReceiver.kt.after | 5 ++ .../replaceSingleLineLet/simple.kt | 7 +++ .../replaceSingleLineLet/simple.kt.after | 5 ++ .../LocalInspectionTestGenerated.java | 48 +++++++++++++++++++ 15 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/.inspection create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt.after create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt.after create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt.after create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/callChainWithLineBreak.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/longCallChain.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt.after create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt create mode 100644 idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt index 7ac2d198b34..a3199e6d3cc 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ReplaceSingleLineLetIntention.kt @@ -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(ReplaceSingleLineLetIntention::class) { +class ReplaceSingleLineLetInspection : IntentionBasedInspection( + 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( diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/.inspection b/idea/testData/inspectionsLocal/replaceSingleLineLet/.inspection new file mode 100644 index 00000000000..d31c39c5252 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt new file mode 100644 index 00000000000..24d82b01d4f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun test(list: List) { + list.filter { it > 1 }.filter { it > 2 }.let { println(it) } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt.after b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt.after new file mode 100644 index 00000000000..92b1bd87c81 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun test(list: List) { + println(list.filter { it > 1 }.filter { it > 2 }) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt new file mode 100644 index 00000000000..779ceb99c3f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME + +fun test(list: List) { + list.filter { it > 1 }.filter { it > 2 } + .let { println(it) } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt.after b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt.after new file mode 100644 index 00000000000..92b1bd87c81 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain2.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun test(list: List) { + println(list.filter { it > 1 }.filter { it > 2 }) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt new file mode 100644 index 00000000000..1d15f692211 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test(list: List) { + list.filter { it > 1 }.filter { it > 2 }.let { + println(it) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt.after b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt.after new file mode 100644 index 00000000000..92b1bd87c81 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChain3.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun test(list: List) { + println(list.filter { it > 1 }.filter { it > 2 }) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/callChainWithLineBreak.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChainWithLineBreak.kt new file mode 100644 index 00000000000..d5dae68cf54 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/callChainWithLineBreak.kt @@ -0,0 +1,8 @@ +// WITH_RUNTIME +// PROBLEM: none + +fun test(list: List) { + list.filter { it > 1 } + .filter { it > 2 } + .let { println(it) } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/longCallChain.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/longCallChain.kt new file mode 100644 index 00000000000..f1087232e22 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/longCallChain.kt @@ -0,0 +1,6 @@ +// WITH_RUNTIME +// PROBLEM: none + +fun test(list: List) { + list.filter { it > 1 }.filter { it > 2 }.filter { it > 3 }.let { println(it) } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt new file mode 100644 index 00000000000..646c2110677 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun String.test(): Int { + return let { + it.length + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt.after b/idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt.after new file mode 100644 index 00000000000..254481e3906 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/noReceiver.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun String.test(): Int { + return length +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt b/idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt new file mode 100644 index 00000000000..89f56de232e --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test(s: String?): Int? { + return s?.let { + it.length + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt.after b/idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt.after new file mode 100644 index 00000000000..1d77116d7d7 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceSingleLineLet/simple.kt.after @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +fun test(s: String?): Int? { + return s?.length +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index b78ecc2eb3d..24c3d5d183c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -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)