Add restrictions for "simplifiable call chain" inspection
Do not use on maps; do not suggest for lambdas with return inside Related to KT-18274
This commit is contained in:
committed by
Mikhail Glukhikh
parent
2f0159a7ab
commit
fdca96634e
@@ -615,6 +615,11 @@ public abstract class KotlinBuiltIns {
|
||||
return getBuiltInClassByName("String");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor getCharSequence() {
|
||||
return getBuiltInClassByName("CharSequence");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public ClassDescriptor getComparable() {
|
||||
return getBuiltInClassByName("Comparable");
|
||||
|
||||
+14
-3
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.inspections.collections
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -29,6 +28,8 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.DefaultValueArgument
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
class SimplifiableCallChainInspection : AbstractKotlinInspection() {
|
||||
|
||||
@@ -46,11 +47,19 @@ class SimplifiableCallChainInspection : AbstractKotlinInspection() {
|
||||
firstCallExpression.calleeExpression?.text to secondCallExpression.calleeExpression?.text
|
||||
] ?: return
|
||||
|
||||
val context = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
val context = expression.analyze()
|
||||
val firstResolvedCall = firstQualifiedExpression.getResolvedCall(context) ?: return
|
||||
val conversion = actualConversions.firstOrNull {
|
||||
firstResolvedCall.resultingDescriptor.fqNameOrNull()?.asString() == it.firstFqName
|
||||
} ?: return
|
||||
// Do not apply on maps due to lack of relevant stdlib functions
|
||||
val firstReceiverType = firstResolvedCall.extensionReceiver?.type ?: return
|
||||
val builtIns = firstReceiverType.builtIns
|
||||
val mapType = builtIns.map.defaultType
|
||||
if (firstReceiverType.isSubtypeOf(mapType)) return
|
||||
// Do not apply for lambdas with return inside
|
||||
val lambdaArgument = firstCallExpression.lambdaArguments.firstOrNull()
|
||||
if (lambdaArgument?.anyDescendantOfType<KtReturnExpression>() == true) return
|
||||
|
||||
val secondResolvedCall = expression.getResolvedCall(context) ?: return
|
||||
val secondResultingDescriptor = secondResolvedCall.resultingDescriptor
|
||||
@@ -62,7 +71,9 @@ class SimplifiableCallChainInspection : AbstractKotlinInspection() {
|
||||
|
||||
if (conversion.replacement.startsWith("joinTo")) {
|
||||
// Function parameter in map must have String result type
|
||||
if (!firstResolvedCall.hasLastFunctionalParameterWithResult(context) { KotlinBuiltIns.isString(it) }) return
|
||||
if (!firstResolvedCall.hasLastFunctionalParameterWithResult(context) {
|
||||
it.isSubtypeOf(builtIns.charSequence.defaultType)
|
||||
}) return
|
||||
}
|
||||
|
||||
val descriptor = holder.manager.createProblemDescriptor(
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// PROBLEM: none
|
||||
// WITH_RUNTIME
|
||||
|
||||
val x = hashMapOf(1 to 2, 3 to 4).<caret>map { (key, value) -> key + value }.joinToString()
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// PROBLEM: none
|
||||
// WITH_RUNTIME
|
||||
|
||||
val x = mapOf(1 to 2, 3 to 4).<caret>map { (key, value) -> key + value }.joinToString()
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
val x = listOf(1, 2, 3).<caret>map {
|
||||
val sb = StringBuilder()
|
||||
sb.append(it).append(" + ").append(it)
|
||||
sb
|
||||
}.joinToString(prefix = "= ", separator = " + ")
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
val x = listOf(1, 2, 3).joinToString(prefix = "= ", separator = " + ") {
|
||||
val sb = StringBuilder()
|
||||
sb.append(it).append(" + ").append(it)
|
||||
sb
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// PROBLEM: none
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun test(args: List<Int>): String {
|
||||
return args.<caret>map {
|
||||
if (it == 0) return ""
|
||||
"$it * $it"
|
||||
}.joinToString(separator = " + ")
|
||||
}
|
||||
@@ -139,12 +139,30 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("joinToForHashMap.kt")
|
||||
public void testJoinToForHashMap() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToForHashMap.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("joinToForMap.kt")
|
||||
public void testJoinToForMap() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToForMap.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("joinToString.kt")
|
||||
public void testJoinToString() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToString.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("joinToStringViaBuilder.kt")
|
||||
public void testJoinToStringViaBuilder() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToStringViaBuilder.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("joinToStringWithReference.kt")
|
||||
public void testJoinToStringWithReference() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToStringWithReference.kt");
|
||||
@@ -162,6 +180,12 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/mapNotNull.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("mapWithReturn.kt")
|
||||
public void testMapWithReturn() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/collections/simplifiableCallChain/mapWithReturn.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/inspectionsLocal/collections/uselessCallOnCollection")
|
||||
|
||||
Reference in New Issue
Block a user