Simplify call: Fix false positive in "filter {}" detection (KT-32468)
"Simplify filter {}" conversion changes semantics when the casted type is not a subtype if an initial collection element type.
This commit limits a replacement suggestion to subtype cases.
This commit is contained in:
+18
@@ -11,13 +11,18 @@ import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractKotlinInspection
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
|
||||
|
||||
class SimplifiableCallInspection : AbstractKotlinInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) =
|
||||
@@ -103,6 +108,19 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
||||
if (statement.isNegated) return null
|
||||
if (!statement.leftHandSide.isNameReferenceTo(lambdaParameterName)) return null
|
||||
val rightTypeReference = statement.typeReference ?: return null
|
||||
|
||||
val bindingContext = callExpression.analyze(BodyResolveMode.PARTIAL)
|
||||
val rightType = bindingContext[BindingContext.TYPE, rightTypeReference]
|
||||
val resolvedCall = callExpression.getResolvedCall(bindingContext)
|
||||
|
||||
if (resolvedCall != null && rightType != null) {
|
||||
val resultingElementType = resolvedCall.resultingDescriptor.returnType
|
||||
?.arguments?.singleOrNull()?.takeIf { !it.isStarProjection }?.type
|
||||
if (resultingElementType != null && !rightType.isSubtypeOf(resultingElementType)) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return "filterIsInstance<${rightTypeReference.text}>()"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// PROBLEM: none
|
||||
|
||||
interface Foo
|
||||
interface Bar
|
||||
|
||||
fun instanceOfMarkerInterface(x: List<Foo>): List<Foo> = x.<caret>filter { it is Bar }
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// WITH_RUNTIME
|
||||
// PROBLEM: none
|
||||
|
||||
interface Foo
|
||||
interface Bar : Foo
|
||||
|
||||
fun instanceOfMarkerInterface(x: List<Bar>): List<Bar> = x.<caret>filter { it is Foo }
|
||||
+10
@@ -1477,6 +1477,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/explicitLambdaParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterIsInstanceDisjointHierarchy.kt")
|
||||
public void testFilterIsInstanceDisjointHierarchy() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsInstanceDisjointHierarchy.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterIsInstanceReceiver.kt")
|
||||
public void testFilterIsInstanceReceiver() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsInstanceReceiver.kt");
|
||||
@@ -1487,6 +1492,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsInstanceSimple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterIsInstanceSupertype.kt")
|
||||
public void testFilterIsInstanceSupertype() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsInstanceSupertype.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("filterIsNotInstance.kt")
|
||||
public void testFilterIsNotInstance() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsNotInstance.kt");
|
||||
|
||||
Reference in New Issue
Block a user