Don't suggest map{}.filterNotNull() -> mapNotNull{} on primitive array

So #KT-21556 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-05-14 06:38:58 +03:00
committed by Mikhail Glukhikh
parent e770aed084
commit bde9a57c9e
23 changed files with 206 additions and 5 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.inspections.collections
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.codeInspection.ProblemsHolder
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi.qualifiedExpressionVisitor
@@ -21,11 +22,14 @@ class SimplifiableCallChainInspection : AbstractCallChainChecker() {
// Do not apply on maps due to lack of relevant stdlib functions
val builtIns = context[BindingContext.EXPRESSION_TYPE_INFO, expression]?.type?.builtIns ?: return@check false
val firstReceiverType = firstResolvedCall.extensionReceiver?.type
val firstReceiverRawType = firstReceiverType?.constructor?.declarationDescriptor?.defaultType
if (firstReceiverRawType != null) {
if (firstReceiverRawType.isSubtypeOf(builtIns.map.defaultType) ||
firstReceiverRawType.isSubtypeOf(builtIns.mutableMap.defaultType)
) return@check false
if (firstReceiverType != null) {
if (conversion.replacement == "mapNotNull" && KotlinBuiltIns.isPrimitiveArray(firstReceiverType)) return@check false
val firstReceiverRawType = firstReceiverType.constructor.declarationDescriptor?.defaultType
if (firstReceiverRawType != null) {
if (firstReceiverRawType.isSubtypeOf(builtIns.map.defaultType) ||
firstReceiverRawType.isSubtypeOf(builtIns.mutableMap.defaultType)
) return@check false
}
}
if (conversion.replacement.startsWith("joinTo")) {
// Function parameter in map must have String result type
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.first()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>first { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.firstOrNull()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>firstOrNull { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.isEmpty()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>none { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.isNotEmpty()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>any { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.last()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>last { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.lastOrNull()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>lastOrNull { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.single()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>single { it > 0 }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>filter { it > 0 }.singleOrNull()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>singleOrNull { it > 0 }
}
@@ -0,0 +1,7 @@
// PROBLEM: none
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>map { if (it > 0) it else null }.filterNotNull()
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
val sb = StringBuilder()
array.<caret>map { "$it-$it" }.joinTo(sb)
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
val sb = StringBuilder()
array.<caret>joinTo(sb) { "$it-$it" }
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>map { "$it-$it" }.joinToString()
}
@@ -0,0 +1,6 @@
// WITH_RUNTIME
fun test() {
val array: IntArray = intArrayOf(0, 1, 2, 3)
array.<caret>joinToString { "$it-$it" }
}
@@ -613,6 +613,74 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
public void testMapWithReturn() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/mapWithReturn.kt");
}
@TestMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class PrimitiveArray extends AbstractLocalInspectionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInPrimitiveArray() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("filterFirst.kt")
public void testFilterFirst() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterFirst.kt");
}
@TestMetadata("filterFirstOrNull.kt")
public void testFilterFirstOrNull() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterFirstOrNull.kt");
}
@TestMetadata("filterIsEmpty.kt")
public void testFilterIsEmpty() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterIsEmpty.kt");
}
@TestMetadata("filterIsNotEmpty.kt")
public void testFilterIsNotEmpty() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterIsNotEmpty.kt");
}
@TestMetadata("filterLast.kt")
public void testFilterLast() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterLast.kt");
}
@TestMetadata("filterLastOrNull.kt")
public void testFilterLastOrNull() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterLastOrNull.kt");
}
@TestMetadata("filterSingle.kt")
public void testFilterSingle() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterSingle.kt");
}
@TestMetadata("filterSingleOrNull.kt")
public void testFilterSingleOrNull() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/filterSingleOrNull.kt");
}
@TestMetadata("mapFilterNotNull.kt")
public void testMapFilterNotNull() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/mapFilterNotNull.kt");
}
@TestMetadata("mapJoinTo.kt")
public void testMapJoinTo() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/mapJoinTo.kt");
}
@TestMetadata("mapJoinToString.kt")
public void testMapJoinToString() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/primitiveArray/mapJoinToString.kt");
}
}
}
@TestMetadata("idea/testData/inspectionsLocal/collections/uselessCallOnCollection")