"Call chain may be simplified": fix false positive on Java Map

So #KT-25089 Fixed
This commit is contained in:
Toshiaki Kameyama
2018-07-25 04:23:04 +03:00
committed by Mikhail Glukhikh
parent c9a784ebb0
commit a059d50c8f
4 changed files with 36 additions and 7 deletions
@@ -8,10 +8,13 @@ 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.descriptors.ClassDescriptor
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.psi.qualifiedExpressionVisitor
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.isSubclassOf
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
@@ -20,16 +23,12 @@ class SimplifiableCallChainInspection : AbstractCallChainChecker() {
qualifiedExpressionVisitor(fun(expression) {
val conversion = findQualifiedConversion(expression, conversionGroups) check@{ conversion, firstResolvedCall, _, context ->
// 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
if (firstReceiverType != null) {
if (conversion.replacement == "mapNotNull" && KotlinBuiltIns.isPrimitiveArray(firstReceiverType)) return@check false
val builtIns = context[BindingContext.EXPRESSION_TYPE_INFO, expression]?.type?.builtIns ?: 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 (firstReceiverRawType.isMap(builtIns)) return@check false
}
if (conversion.replacement.startsWith("joinTo")) {
// Function parameter in map must have String result type
@@ -83,4 +82,9 @@ class SimplifiableCallChainInspection : AbstractCallChainChecker() {
Conversion("kotlin.collections.listOf", "kotlin.collections.filterNotNull", "listOfNotNull")
)
}
}
}
private fun KotlinType?.isMap(builtIns: KotlinBuiltIns): Boolean {
val classDescriptor = this?.constructor?.declarationDescriptor as? ClassDescriptor ?: return false
return classDescriptor.name.asString().endsWith("Map") && classDescriptor.isSubclassOf(builtIns.map)
}
@@ -0,0 +1,6 @@
// PROBLEM: none
// WITH_RUNTIME
fun test(data: HashMap<String, String>) {
val result = data.<caret>map { "${it.key}: ${it.value}" }.joinToString("\n")
}
@@ -0,0 +1,9 @@
// PROBLEM: none
// WITH_RUNTIME
import java.util.*
class MyMap: HashMap<String, String>()
fun test(data: MyMap) {
val result = data.<caret>map { "${it.key}: ${it.value}" }.joinToString("\n")
}
@@ -579,6 +579,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToString.kt");
}
@TestMetadata("joinToStringOnHashMap.kt")
public void testJoinToStringOnHashMap() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToStringOnHashMap.kt");
}
@TestMetadata("joinToStringOnHashMap2.kt")
public void testJoinToStringOnHashMap2() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToStringOnHashMap2.kt");
}
@TestMetadata("joinToStringOnMap.kt")
public void testJoinToStringOnMap() throws Exception {
runTest("idea/testData/inspectionsLocal/collections/simplifiableCallChain/joinToStringOnMap.kt");