Convert to anonymous object: don't remove type arguments
#KT-30208 Fixed
This commit is contained in:
committed by
Dmitry Gridin
parent
075620daad
commit
f2c7b6b8c4
+14
-2
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.isFlexible
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
|
||||
@@ -54,6 +55,7 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
||||
lambda: KtLambdaExpression,
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
functionName: String = "",
|
||||
typeParameters: Map<String, KtTypeReference> = emptyMap(),
|
||||
replaceElement: (KtNamedFunction) -> KtExpression = { lambda.replaced(it) }
|
||||
): KtExpression? {
|
||||
val functionLiteral = lambda.functionLiteral
|
||||
@@ -76,7 +78,12 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
||||
name(functionName)
|
||||
for (parameter in functionDescriptor.valueParameters) {
|
||||
val type = parameter.type.let { if (it.isFlexible()) it.makeNotNullable() else it }
|
||||
param(parameter.name.asString(), typeSourceCode.renderType(type))
|
||||
val renderType = typeSourceCode.renderType(type)
|
||||
if (type.isTypeParameter()) {
|
||||
param(parameter.name.asString(), typeParameters[renderType]?.text ?: renderType)
|
||||
} else {
|
||||
param(parameter.name.asString(), renderType)
|
||||
}
|
||||
}
|
||||
functionDescriptor.returnType?.takeIf { !it.isUnit() }?.let {
|
||||
val lastStatement = bodyExpression.statements.lastOrNull()
|
||||
@@ -86,7 +93,12 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
||||
lastStatement.replace(psiFactory.createExpressionByPattern("return $0", lastStatement))
|
||||
}
|
||||
}
|
||||
returnType(typeSourceCode.renderType(it))
|
||||
val renderType = typeSourceCode.renderType(it)
|
||||
if (it.isTypeParameter()) {
|
||||
returnType(typeParameters[renderType]?.text ?: renderType)
|
||||
} else {
|
||||
returnType(renderType)
|
||||
}
|
||||
} ?: noReturnType()
|
||||
blockBody(" " + bodyExpression.text)
|
||||
}.asString()
|
||||
|
||||
+8
-2
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.intentions
|
||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
@@ -84,9 +85,14 @@ class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention<KtCa
|
||||
functionName: String
|
||||
) {
|
||||
val interfaceName = call.calleeExpression?.text ?: return
|
||||
LambdaToAnonymousFunctionIntention.convertLambdaToFunction(lambda, functionDescriptor, functionName = functionName) {
|
||||
val typeArguments = call.typeArguments.mapNotNull { it.typeReference }
|
||||
val typeArgumentsText =
|
||||
if (typeArguments.isEmpty()) "" else typeArguments.joinToString(prefix = "<", postfix = ">", separator = ", ") { it.text }
|
||||
val classDescriptor = functionDescriptor.containingDeclaration as? ClassDescriptor
|
||||
val typeParameters = classDescriptor?.declaredTypeParameters?.map { it.name.asString() }?.zip(typeArguments)?.toMap().orEmpty()
|
||||
LambdaToAnonymousFunctionIntention.convertLambdaToFunction(lambda, functionDescriptor, functionName, typeParameters) {
|
||||
it.addModifier(KtTokens.OVERRIDE_KEYWORD)
|
||||
call.replaced(KtPsiFactory(it).createExpression("object : $interfaceName { ${it.text} }"))
|
||||
call.replaced(KtPsiFactory(it).createExpression("object : $interfaceName$typeArgumentsText { ${it.text} }"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
public interface A <T, U> {
|
||||
U foo(T x);
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
public interface A <T, U> {
|
||||
U foo(T x);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
val a = <caret>A<Int, String> { "" }
|
||||
@@ -0,0 +1,5 @@
|
||||
val a = object : A<Int, String> {
|
||||
override fun foo(it: Int): String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Convert to anonymous object" "true"
|
||||
interface B<T, U> {
|
||||
fun bar(x: T): U
|
||||
}
|
||||
|
||||
val b = <caret>B<Int, String> { "" }
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Convert to anonymous object" "true"
|
||||
interface B<T, U> {
|
||||
fun bar(x: T): U
|
||||
}
|
||||
|
||||
val b = object : B<Int, String> {
|
||||
override fun bar(x: Int): String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -16178,6 +16178,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
runTest("idea/testData/intentions/samConversionToAnonymousObject/simple3.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeArgument.kt")
|
||||
public void testTypeArgument() throws Exception {
|
||||
runTest("idea/testData/intentions/samConversionToAnonymousObject/typeArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("usedSameFunction.kt")
|
||||
public void testUsedSameFunction() throws Exception {
|
||||
runTest("idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt");
|
||||
|
||||
@@ -2499,6 +2499,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
runTest("idea/testData/quickfix/convertToAnonymousObject/simple.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeArgument.kt")
|
||||
public void testTypeArgument() throws Exception {
|
||||
runTest("idea/testData/quickfix/convertToAnonymousObject/typeArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("unit.kt")
|
||||
public void testUnit() throws Exception {
|
||||
runTest("idea/testData/quickfix/convertToAnonymousObject/unit.kt");
|
||||
|
||||
Reference in New Issue
Block a user