Anonymous function to lambda: add lambda parameter if type parameter is used, even if parameter is unused
#KT-39393 Fixed
This commit is contained in:
committed by
igoriakovlev
parent
311b2d7969
commit
e4a1c8dcef
+17
-9
@@ -9,7 +9,6 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
|
||||
import org.jetbrains.kotlin.idea.core.getLastLambdaExpression
|
||||
@@ -23,6 +22,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
|
||||
class AnonymousFunctionToLambdaIntention : SelfTargetingRangeIntention<KtNamedFunction>(
|
||||
@@ -46,10 +47,18 @@ class AnonymousFunctionToLambdaIntention : SelfTargetingRangeIntention<KtNamedFu
|
||||
override fun applyTo(element: KtNamedFunction, editor: Editor?) {
|
||||
val argument = element.getStrictParentOfType<KtValueArgument>() ?: return
|
||||
val callElement = argument.getStrictParentOfType<KtCallElement>() ?: return
|
||||
val functionParameterTypes = if (callElement.typeArgumentList == null) {
|
||||
callElement.resolveToCall()?.getParameterForArgument(argument)?.original?.type?.arguments.orEmpty()
|
||||
val typeParameterIndexes = if (callElement.typeArgumentList == null) {
|
||||
val functionalType = callElement.resolveToCall()?.getParameterForArgument(argument)?.let {
|
||||
if (it.isVararg) it.original.type.arguments.firstOrNull()?.type else it.original.type
|
||||
}
|
||||
val typeArguments = functionalType?.arguments?.let {
|
||||
if (it.isNotEmpty()) it.dropLast(1) else it
|
||||
}.orEmpty()
|
||||
typeArguments.mapIndexedNotNull { index, typeProjection ->
|
||||
if (typeProjection.type.isTypeParameter()) index else null
|
||||
}.toSet()
|
||||
} else {
|
||||
emptyList()
|
||||
emptySet()
|
||||
}
|
||||
|
||||
val commentSaver = CommentSaver(element)
|
||||
@@ -62,18 +71,17 @@ class AnonymousFunctionToLambdaIntention : SelfTargetingRangeIntention<KtNamedFu
|
||||
|
||||
val parameters = element.valueParameters
|
||||
|
||||
val needParameters =
|
||||
parameters.count() > 1 || parameters.any { parameter -> ReferencesSearch.search(parameter, LocalSearchScope(body)).any() }
|
||||
val needParameters = typeParameterIndexes.isNotEmpty() || parameters.count() > 1 || parameters.any { parameter ->
|
||||
ReferencesSearch.search(parameter, LocalSearchScope(body)).any()
|
||||
}
|
||||
if (needParameters) {
|
||||
parameters.forEachIndexed { index, parameter ->
|
||||
if (index > 0) {
|
||||
appendFixedText(",")
|
||||
}
|
||||
appendName(parameter.nameAsSafeName)
|
||||
val needParameterType =
|
||||
functionParameterTypes.getOrNull(index)?.type?.constructor?.declarationDescriptor is TypeParameterDescriptor
|
||||
val typeReference = parameter.typeReference
|
||||
if (needParameterType && typeReference != null) {
|
||||
if (typeReference != null && index in typeParameterIndexes) {
|
||||
appendFixedText(": ")
|
||||
appendTypeReference(typeReference)
|
||||
}
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
fun <T> foo(fn: (T) -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
foo(<caret>fun(x: String) {
|
||||
})
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
fun <T> foo(fn: (T) -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
foo { x: String -> }
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
fun <T> foo(fn: (String) -> T) {}
|
||||
|
||||
fun test() {
|
||||
foo(<caret>fun(x: String) {
|
||||
})
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
fun <T> foo(fn: (String) -> T) {}
|
||||
|
||||
fun test() {
|
||||
foo { }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fun foo(p: String) {}
|
||||
|
||||
fun <T> bar(vararg fn: (T) -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
bar(<caret>fun(x: String) {
|
||||
foo(x)
|
||||
})
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fun foo(p: String) {}
|
||||
|
||||
fun <T> bar(vararg fn: (T) -> Unit) {}
|
||||
|
||||
fun test() {
|
||||
bar({ x: String -> foo(x) })
|
||||
}
|
||||
@@ -2115,6 +2115,21 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
public void testTypeParameter3() throws Exception {
|
||||
runTest("idea/testData/intentions/anonymousFunctionToLambda/typeParameter3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterWithUnusedParameter.kt")
|
||||
public void testTypeParameterWithUnusedParameter() throws Exception {
|
||||
runTest("idea/testData/intentions/anonymousFunctionToLambda/typeParameterWithUnusedParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterWithUnusedParameter2.kt")
|
||||
public void testTypeParameterWithUnusedParameter2() throws Exception {
|
||||
runTest("idea/testData/intentions/anonymousFunctionToLambda/typeParameterWithUnusedParameter2.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeParameterWithVararg.kt")
|
||||
public void testTypeParameterWithVararg() throws Exception {
|
||||
runTest("idea/testData/intentions/anonymousFunctionToLambda/typeParameterWithVararg.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/intentions/branched")
|
||||
|
||||
Reference in New Issue
Block a user