Simplifiable call inspection: add filter -> filterIsInstance replacement
#KT-30501 Fixed
This commit is contained in:
+26
-18
@@ -26,13 +26,13 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
|||||||
val calleeExpression = callExpression.calleeExpression ?: return
|
val calleeExpression = callExpression.calleeExpression ?: return
|
||||||
val (conversion, resolvedCall) = callExpression.findConversionAndResolvedCall() ?: return
|
val (conversion, resolvedCall) = callExpression.findConversionAndResolvedCall() ?: return
|
||||||
if (!conversion.callChecker(resolvedCall)) return
|
if (!conversion.callChecker(resolvedCall)) return
|
||||||
val conversionSuffix = conversion.analyzer(callExpression) ?: return
|
val replacement = conversion.analyzer(callExpression) ?: return
|
||||||
|
|
||||||
holder.registerProblem(
|
holder.registerProblem(
|
||||||
calleeExpression,
|
calleeExpression,
|
||||||
"${conversion.fqName.shortName()} call could be simplified to ${conversion.replacement}$conversionSuffix",
|
"${conversion.fqName.shortName()} call could be simplified to $replacement",
|
||||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||||
SimplifyCallFix(conversion, conversionSuffix)
|
SimplifyCallFix(conversion, replacement)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -50,7 +50,6 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
|||||||
|
|
||||||
private data class Conversion(
|
private data class Conversion(
|
||||||
val callFqName: String,
|
val callFqName: String,
|
||||||
val replacement: String,
|
|
||||||
val analyzer: (KtCallExpression) -> String?,
|
val analyzer: (KtCallExpression) -> String?,
|
||||||
val callChecker: (ResolvedCall<*>) -> Boolean = { true }
|
val callChecker: (ResolvedCall<*>) -> Boolean = { true }
|
||||||
) {
|
) {
|
||||||
@@ -79,25 +78,34 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
|||||||
this is KtConstantExpression && this.node.elementType == KtNodeTypes.NULL
|
this is KtConstantExpression && this.node.elementType == KtNodeTypes.NULL
|
||||||
|
|
||||||
private val conversions = listOf(
|
private val conversions = listOf(
|
||||||
Conversion("kotlin.collections.flatMap", "flatten", fun(callExpression: KtCallExpression): String? {
|
Conversion("kotlin.collections.flatMap", fun(callExpression: KtCallExpression): String? {
|
||||||
val lambdaExpression = callExpression.singleLambdaExpression() ?: return null
|
val lambdaExpression = callExpression.singleLambdaExpression() ?: return null
|
||||||
val reference = lambdaExpression.singleStatement() ?: return null
|
val reference = lambdaExpression.singleStatement() ?: return null
|
||||||
val lambdaParameterName = lambdaExpression.singleLambdaParameterName() ?: return null
|
val lambdaParameterName = lambdaExpression.singleLambdaParameterName() ?: return null
|
||||||
if (!reference.isNameReferenceTo(lambdaParameterName)) return null
|
if (!reference.isNameReferenceTo(lambdaParameterName)) return null
|
||||||
return "()"
|
return "flatten()"
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Conversion("kotlin.collections.filter", "filterNotNull", analyzer = fun(callExpression: KtCallExpression): String? {
|
Conversion("kotlin.collections.filter", analyzer = fun(callExpression: KtCallExpression): String? {
|
||||||
val lambdaExpression = callExpression.singleLambdaExpression() ?: return null
|
val lambdaExpression = callExpression.singleLambdaExpression() ?: return null
|
||||||
val statement = lambdaExpression.singleStatement() as? KtBinaryExpression ?: return null
|
|
||||||
val lambdaParameterName = lambdaExpression.singleLambdaParameterName() ?: return null
|
val lambdaParameterName = lambdaExpression.singleLambdaParameterName() ?: return null
|
||||||
if (statement.operationToken != KtTokens.EXCLEQ && statement.operationToken != KtTokens.EXCLEQEQEQ) return null
|
when (val statement = lambdaExpression.singleStatement() ?: return null) {
|
||||||
val left = statement.left ?: return null
|
is KtBinaryExpression -> {
|
||||||
val right = statement.right ?: return null
|
if (statement.operationToken != KtTokens.EXCLEQ && statement.operationToken != KtTokens.EXCLEQEQEQ) return null
|
||||||
if (left.isNameReferenceTo(lambdaParameterName) && right.isNull()) {
|
val left = statement.left ?: return null
|
||||||
return "()"
|
val right = statement.right ?: return null
|
||||||
} else if (right.isNameReferenceTo(lambdaParameterName) && left.isNull()) {
|
if (left.isNameReferenceTo(lambdaParameterName) && right.isNull()) {
|
||||||
return "()"
|
return "filterNotNull()"
|
||||||
|
} else if (right.isNameReferenceTo(lambdaParameterName) && left.isNull()) {
|
||||||
|
return "filterNotNull()"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is KtIsExpression -> {
|
||||||
|
if (statement.isNegated) return null
|
||||||
|
if (!statement.leftHandSide.isNameReferenceTo(lambdaParameterName)) return null
|
||||||
|
val rightTypeReference = statement.typeReference ?: return null
|
||||||
|
return "filterIsInstance<${rightTypeReference.text}>()"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}, callChecker = fun(resolvedCall: ResolvedCall<*>): Boolean {
|
}, callChecker = fun(resolvedCall: ResolvedCall<*>): Boolean {
|
||||||
@@ -107,14 +115,14 @@ class SimplifiableCallInspection : AbstractKotlinInspection() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SimplifyCallFix(val conversion: Conversion, val conversionSuffix: String) : LocalQuickFix {
|
private class SimplifyCallFix(val conversion: Conversion, val replacement: String) : LocalQuickFix {
|
||||||
override fun getName() = "Convert '${conversion.fqName.shortName()}' call to '${conversion.replacement}$conversionSuffix'"
|
override fun getName() = "Convert '${conversion.fqName.shortName()}' call to '$replacement'"
|
||||||
|
|
||||||
override fun getFamilyName() = name
|
override fun getFamilyName() = name
|
||||||
|
|
||||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||||
val callExpression = descriptor.psiElement.parent as? KtCallExpression ?: return
|
val callExpression = descriptor.psiElement.parent as? KtCallExpression ?: return
|
||||||
callExpression.replace(KtPsiFactory(callExpression).createExpression("${conversion.replacement}$conversionSuffix"))
|
callExpression.replace(KtPsiFactory(callExpression).createExpression(replacement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(list: List<Any>) {
|
||||||
|
list.<caret>filter { it is String }
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(list: List<Any>) {
|
||||||
|
list.filterIsInstance<String>()
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// PROBLEM: none
|
||||||
|
fun test(list: List<Any>) {
|
||||||
|
list.<caret>filter { it !is String }
|
||||||
|
}
|
||||||
+10
@@ -1108,6 +1108,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
|||||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/explicitLambdaParameter.kt");
|
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/explicitLambdaParameter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("filterIsInstanceSimple.kt")
|
||||||
|
public void testFilterIsInstanceSimple() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsInstanceSimple.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("filterIsNotInstance.kt")
|
||||||
|
public void testFilterIsNotInstance() throws Exception {
|
||||||
|
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterIsNotInstance.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("filterNotNullBrackets.kt")
|
@TestMetadata("filterNotNullBrackets.kt")
|
||||||
public void testFilterNotNullBrackets() throws Exception {
|
public void testFilterNotNullBrackets() throws Exception {
|
||||||
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterNotNullBrackets.kt");
|
runTest("idea/testData/inspectionsLocal/collections/simplifiableCall/filterNotNullBrackets.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user