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.bindingContextUtil.getTargetFunctionDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.isFlexible
|
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.isUnit
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
|||||||
lambda: KtLambdaExpression,
|
lambda: KtLambdaExpression,
|
||||||
functionDescriptor: FunctionDescriptor,
|
functionDescriptor: FunctionDescriptor,
|
||||||
functionName: String = "",
|
functionName: String = "",
|
||||||
|
typeParameters: Map<String, KtTypeReference> = emptyMap(),
|
||||||
replaceElement: (KtNamedFunction) -> KtExpression = { lambda.replaced(it) }
|
replaceElement: (KtNamedFunction) -> KtExpression = { lambda.replaced(it) }
|
||||||
): KtExpression? {
|
): KtExpression? {
|
||||||
val functionLiteral = lambda.functionLiteral
|
val functionLiteral = lambda.functionLiteral
|
||||||
@@ -76,7 +78,12 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
|||||||
name(functionName)
|
name(functionName)
|
||||||
for (parameter in functionDescriptor.valueParameters) {
|
for (parameter in functionDescriptor.valueParameters) {
|
||||||
val type = parameter.type.let { if (it.isFlexible()) it.makeNotNullable() else it }
|
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 {
|
functionDescriptor.returnType?.takeIf { !it.isUnit() }?.let {
|
||||||
val lastStatement = bodyExpression.statements.lastOrNull()
|
val lastStatement = bodyExpression.statements.lastOrNull()
|
||||||
@@ -86,7 +93,12 @@ class LambdaToAnonymousFunctionIntention : SelfTargetingIntention<KtLambdaExpres
|
|||||||
lastStatement.replace(psiFactory.createExpressionByPattern("return $0", lastStatement))
|
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()
|
} ?: noReturnType()
|
||||||
blockBody(" " + bodyExpression.text)
|
blockBody(" " + bodyExpression.text)
|
||||||
}.asString()
|
}.asString()
|
||||||
|
|||||||
+8
-2
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.intentions
|
|||||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
@@ -84,9 +85,14 @@ class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention<KtCa
|
|||||||
functionName: String
|
functionName: String
|
||||||
) {
|
) {
|
||||||
val interfaceName = call.calleeExpression?.text ?: return
|
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)
|
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");
|
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")
|
@TestMetadata("usedSameFunction.kt")
|
||||||
public void testUsedSameFunction() throws Exception {
|
public void testUsedSameFunction() throws Exception {
|
||||||
runTest("idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt");
|
runTest("idea/testData/intentions/samConversionToAnonymousObject/usedSameFunction.kt");
|
||||||
|
|||||||
@@ -2499,6 +2499,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
runTest("idea/testData/quickfix/convertToAnonymousObject/simple.kt");
|
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")
|
@TestMetadata("unit.kt")
|
||||||
public void testUnit() throws Exception {
|
public void testUnit() throws Exception {
|
||||||
runTest("idea/testData/quickfix/convertToAnonymousObject/unit.kt");
|
runTest("idea/testData/quickfix/convertToAnonymousObject/unit.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user