mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] ported ConvertExtensionToFunctionTypeFix to K2
^KTIJ-29490 fixed GitOrigin-RevId: 38a2f2a95d12cf8b1d32c84b20c0f53a15d12f7a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
cf6c17e165
commit
bd80926e8a
+58
@@ -0,0 +1,58 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.fixes
|
||||
|
||||
import com.intellij.util.containers.addIfNotNull
|
||||
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KaAnnotationRendererForSource
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.base.annotations.KaRendererAnnotationsFilter
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.types.KaTypeRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaFunctionType
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
internal object ConvertExtensionToFunctionTypeFixFactory {
|
||||
/**
|
||||
* Renders the [functionType] but moves a potential receiver type to be a parameter instead.
|
||||
*/
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
private fun KaSession.renderFunctionTypeWithoutReceiver(functionType: KaFunctionType, renderer: KaTypeRenderer): String {
|
||||
val renderedParametersList = buildList {
|
||||
addIfNotNull(functionType.receiverType)
|
||||
addAll(functionType.parameterTypes)
|
||||
}.joinToString(", ", "(", ")") {
|
||||
it.render(renderer, Variance.INVARIANT)
|
||||
}
|
||||
val renderedReturnType = functionType.returnType.render(renderer, Variance.INVARIANT)
|
||||
return "$renderedParametersList -> $renderedReturnType"
|
||||
}
|
||||
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
private val shortNameRenderer = KaTypeRendererForSource.WITH_SHORT_NAMES.with {
|
||||
annotationsRenderer = KaAnnotationRendererForSource.WITH_SHORT_NAMES.with {
|
||||
annotationFilter = KaRendererAnnotationsFilter.NONE
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
private fun KaSession.createQuickFix(typeReference: KtTypeReference): ConvertExtensionToFunctionTypeFix? {
|
||||
val type = typeReference.type as? KaFunctionType ?: return null
|
||||
if (!type.hasReceiver) return null
|
||||
// We do not support rendering context receivers
|
||||
if (type.contextReceivers.isNotEmpty()) return null
|
||||
|
||||
val shortName = renderFunctionTypeWithoutReceiver(type, shortNameRenderer)
|
||||
val longName = renderFunctionTypeWithoutReceiver(type, KaTypeRendererForSource.WITH_QUALIFIED_NAMES)
|
||||
return ConvertExtensionToFunctionTypeFix(typeReference, shortName, longName)
|
||||
}
|
||||
|
||||
val superTypeIsExtensionFunctionType =
|
||||
KotlinQuickFixFactory.ModCommandBased { diagnostic: KaFirDiagnostic.SupertypeIsExtensionFunctionType ->
|
||||
val typeReference = diagnostic.psi as? KtTypeReference ?: return@ModCommandBased emptyList()
|
||||
listOfNotNull(createQuickFix(typeReference))
|
||||
}
|
||||
}
|
||||
+2
@@ -442,6 +442,8 @@ class KotlinK2QuickFixRegistrar : KotlinQuickFixRegistrar() {
|
||||
registerFactory(ChangeMemberFunctionSignatureFixFactory.nothingToOverrideFixFactory)
|
||||
|
||||
registerFactory(ReplaceJvmFieldWithConstFixFactory.inapplicableJvmField)
|
||||
|
||||
registerFactory(ConvertExtensionToFunctionTypeFixFactory.superTypeIsExtensionFunctionType)
|
||||
}
|
||||
|
||||
private val optIn = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||
|
||||
+32
@@ -10216,7 +10216,39 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
|
||||
|
||||
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../../idea/tests/testData/quickfix/superTypeIsExtensionType")
|
||||
public static class SuperTypeIsExtensionType extends AbstractHighLevelQuickFixTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("typeWith1Argument.kt")
|
||||
public void testTypeWith1Argument() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/superTypeIsExtensionType/typeWith1Argument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeWithAnnotations.kt")
|
||||
public void testTypeWithAnnotations() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/superTypeIsExtensionType/typeWithAnnotations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeWithNoArgument.kt")
|
||||
public void testTypeWithNoArgument() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/superTypeIsExtensionType/typeWithNoArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeWithTypeArgument.kt")
|
||||
public void testTypeWithTypeArgument() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/superTypeIsExtensionType/typeWithTypeArgument.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../../idea/tests/testData/quickfix/surroundWithNullCheck")
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.modcommand.ActionContext
|
||||
import com.intellij.modcommand.ModPsiUpdater
|
||||
import com.intellij.modcommand.Presentation
|
||||
import com.intellij.modcommand.PsiUpdateModCommandAction
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.ShortenReferencesFacility
|
||||
import org.jetbrains.kotlin.idea.base.psi.replaced
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
|
||||
class ConvertExtensionToFunctionTypeFix(
|
||||
element: KtTypeReference,
|
||||
private val targetTypeStringShort: String,
|
||||
private val targetTypeStringLong: String
|
||||
) : PsiUpdateModCommandAction<KtTypeReference>(element) {
|
||||
override fun getPresentation(context: ActionContext, element: KtTypeReference): Presentation? {
|
||||
return Presentation.of(KotlinBundle.message("convert.supertype.to.0", targetTypeStringShort))
|
||||
}
|
||||
|
||||
override fun getFamilyName(): String = KotlinBundle.message("convert.extension.function.type.to.regular.function.type")
|
||||
|
||||
override fun invoke(
|
||||
context: ActionContext,
|
||||
element: KtTypeReference,
|
||||
updater: ModPsiUpdater
|
||||
) {
|
||||
val replaced = element.replaced(KtPsiFactory(context.project).createType(targetTypeStringLong))
|
||||
ShortenReferencesFacility.getInstance().shorten(replaced)
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.base.psi.replaced
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinQuickFixAction
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class ConvertExtensionToFunctionTypeFix(element: KtTypeReference, type: KotlinType) : KotlinQuickFixAction<KtTypeReference>(element) {
|
||||
|
||||
private val targetTypeStringShort = type.renderType(IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS)
|
||||
private val targetTypeStringLong = type.renderType(IdeDescriptorRenderers.SOURCE_CODE)
|
||||
|
||||
override fun getText() = KotlinBundle.message("convert.supertype.to.0", targetTypeStringShort)
|
||||
override fun getFamilyName() = KotlinBundle.message("convert.extension.function.type.to.regular.function.type")
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val element = element ?: return
|
||||
val replaced = element.replaced(KtPsiFactory(project).createType(targetTypeStringLong))
|
||||
ShortenReferences.DEFAULT.process(replaced)
|
||||
}
|
||||
|
||||
private fun KotlinType.renderType(renderer: DescriptorRenderer) = buildString {
|
||||
append('(')
|
||||
arguments.dropLast(1).joinTo(this@buildString, ", ") { renderer.renderType(it.type) }
|
||||
append(") -> ")
|
||||
append(renderer.renderType(this@renderType.getReturnTypeFromFunctionType()))
|
||||
}
|
||||
|
||||
companion object Factory : KotlinIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val casted = Errors.SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.cast(diagnostic)
|
||||
val element = casted.psiElement
|
||||
|
||||
val type = element.analyze(BodyResolveMode.PARTIAL).get(BindingContext.TYPE, element) ?: return emptyList()
|
||||
if (!type.isExtensionFunctionType) return emptyList()
|
||||
|
||||
return listOf(ConvertExtensionToFunctionTypeFix(element, type))
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
object ConvertExtensionToFunctionTypeFixFactory : KotlinIntentionActionsFactory() {
|
||||
private fun KotlinType.renderType(renderer: DescriptorRenderer) = buildString {
|
||||
append('(')
|
||||
arguments.dropLast(1).joinTo(this@buildString, ", ") { renderer.renderType(it.type) }
|
||||
append(") -> ")
|
||||
append(renderer.renderType(this@renderType.getReturnTypeFromFunctionType()))
|
||||
}
|
||||
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
|
||||
val casted = Errors.SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.cast(diagnostic)
|
||||
val element = casted.psiElement
|
||||
|
||||
val type = element.analyze(BodyResolveMode.PARTIAL).get(BindingContext.TYPE, element) ?: return emptyList()
|
||||
if (!type.isExtensionFunctionType) return emptyList()
|
||||
val targetTypeStringShort = type.renderType(IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS)
|
||||
val targetTypeStringLong = type.renderType(IdeDescriptorRenderers.SOURCE_CODE)
|
||||
|
||||
return listOf(ConvertExtensionToFunctionTypeFix(element, targetTypeStringShort, targetTypeStringLong).asIntention())
|
||||
}
|
||||
}
|
||||
@@ -577,7 +577,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
UNRESOLVED_REFERENCE.registerFactory(MakeConstructorParameterPropertyFix)
|
||||
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.registerFactory(SpecifyOverrideExplicitlyFix)
|
||||
|
||||
SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.registerFactory(ConvertExtensionToFunctionTypeFix)
|
||||
SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.registerFactory(ConvertExtensionToFunctionTypeFixFactory)
|
||||
|
||||
UNUSED_LAMBDA_EXPRESSION.registerFactory(AddRunToLambdaFix)
|
||||
|
||||
|
||||
+5
@@ -15834,6 +15834,11 @@ public abstract class K1QuickFixTestGenerated extends AbstractK1QuickFixTest {
|
||||
runTest("testData/quickfix/superTypeIsExtensionType/typeWith1Argument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeWithAnnotations.kt")
|
||||
public void testTypeWithAnnotations() throws Exception {
|
||||
runTest("testData/quickfix/superTypeIsExtensionType/typeWithAnnotations.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeWithNoArgument.kt")
|
||||
public void testTypeWithNoArgument() throws Exception {
|
||||
runTest("testData/quickfix/superTypeIsExtensionType/typeWithNoArgument.kt");
|
||||
|
||||
+2
-1
@@ -4,4 +4,5 @@ class Foo : <caret>String.(String) -> Unit {
|
||||
override fun invoke(p1: String, p2: String) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+2
-1
@@ -4,4 +4,5 @@ class Foo : <caret>(String, String) -> Unit {
|
||||
override fun invoke(p1: String, p2: String) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Convert supertype to '(String, T) -> Unit'" "true"
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TestA
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TestB
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TestC
|
||||
|
||||
class Foo<T> : (@TestA <caret>String).(@TestB T) -> @TestC Unit {
|
||||
override fun invoke(p1: String, p2: T) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Convert supertype to '(String, T) -> Unit'" "true"
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TestA
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TestB
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class TestC
|
||||
|
||||
class Foo<T> : (@TestA String, @TestB T) -> @TestC Unit {
|
||||
override fun invoke(p1: String, p2: T) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+2
-1
@@ -4,4 +4,5 @@ class Foo : <caret>String.() -> Unit {
|
||||
override fun invoke(p1: String) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+2
-1
@@ -4,4 +4,5 @@ class Foo : <caret>(String) -> Unit {
|
||||
override fun invoke(p1: String) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+2
-1
@@ -4,4 +4,5 @@ class Foo<T> : <caret>String.(T) -> Unit {
|
||||
override fun invoke(p1: String, p2: T) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+2
-1
@@ -4,4 +4,5 @@ class Foo<T> : <caret>(String, T) -> Unit {
|
||||
override fun invoke(p1: String, p2: T) {
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ConvertExtensionToFunctionTypeFix
|
||||
+1
-1
@@ -186,7 +186,7 @@ internal fun MutableTWorkspace.generateK2FixTests() {
|
||||
model("$idea/quickfix/specifyOverrideExplicitly", pattern = pattern)
|
||||
model("$idea/quickfix/specifySuperExplicitly", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/specifyTypeExplicitly", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/superTypeIsExtensionType", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/superTypeIsExtensionType", pattern = pattern)
|
||||
model("$idea/quickfix/surroundWithNullCheck", pattern = pattern)
|
||||
model("$idea/quickfix/suspiciousCollectionReassignment", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/tooLongCharLiteralToString", pattern = pattern)
|
||||
|
||||
Reference in New Issue
Block a user