diff --git a/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddGenericUpperBoundFixFactories.kt b/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddGenericUpperBoundFixFactories.kt new file mode 100644 index 000000000000..778024be79b0 --- /dev/null +++ b/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddGenericUpperBoundFixFactories.kt @@ -0,0 +1,46 @@ +// 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.modcommand.ModCommandAction +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.types.impl.KaTypeRendererForSource +import org.jetbrains.kotlin.analysis.api.types.KaType +import org.jetbrains.kotlin.analysis.api.types.KaTypeParameterType +import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory +import org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +import org.jetbrains.kotlin.psi.KtTypeParameter +import org.jetbrains.kotlin.types.Variance + +internal object AddGenericUpperBoundFixFactories { + + val upperBoundViolatedFixFactory = KotlinQuickFixFactory.ModCommandBased { diagnostic: KaFirDiagnostic.UpperBoundViolated -> + listOfNotNull( + createActionIfAvailable(diagnostic.expectedUpperBound, diagnostic.actualUpperBound) + ) + } + + val upperBoundViolatedBasedOnJavaAnnotationsFixFactory = KotlinQuickFixFactory.ModCommandBased { diagnostic: KaFirDiagnostic.UpperBoundViolatedBasedOnJavaAnnotations -> + listOfNotNull( + createActionIfAvailable(diagnostic.expectedUpperBound, diagnostic.actualUpperBound) + ) + } + + @OptIn(KaExperimentalApi::class) + private fun KaSession.createActionIfAvailable( + expectedUpperBound: KaType, + actualUpperBound: KaType, + ): ModCommandAction? { + val typeParameter = (actualUpperBound as? KaTypeParameterType)?.symbol?.psi as? KtTypeParameter ?: return null + if (typeParameter.name == null || typeParameter.extendsBound != null) return null + + return AddGenericUpperBoundFix( + element = typeParameter, + renderedUpperBound = expectedUpperBound.render( + renderer = KaTypeRendererForSource.WITH_QUALIFIED_NAMES, + position = Variance.IN_VARIANCE, + ) + ) + } +} diff --git a/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/KotlinK2QuickFixRegistrar.kt b/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/KotlinK2QuickFixRegistrar.kt index 4edc6a1477ee..e7b4a88413dc 100644 --- a/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/KotlinK2QuickFixRegistrar.kt +++ b/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/KotlinK2QuickFixRegistrar.kt @@ -180,6 +180,8 @@ class KotlinK2QuickFixRegistrar : KotlinQuickFixRegistrar() { registerFactory(ConvertKClassToClassFixFactories.initializerTypeMismatchFixFactory) registerFactory(ConvertKClassToClassFixFactories.returnTypeMismatchFixFactory) registerFactory(PropertyInitializerInInterfaceFixFactories.convertPropertyInitializerToGetterFixFactory) + registerFactory(AddGenericUpperBoundFixFactories.upperBoundViolatedFixFactory) + registerFactory(AddGenericUpperBoundFixFactories.upperBoundViolatedBasedOnJavaAnnotationsFixFactory) } private val addAbstract = KtQuickFixesListBuilder.registerPsiQuickFix { diff --git a/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixMultiFileTestGenerated.java b/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixMultiFileTestGenerated.java index 772408072be0..564e01d09797 100644 --- a/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixMultiFileTestGenerated.java +++ b/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixMultiFileTestGenerated.java @@ -1059,4 +1059,23 @@ public abstract class HighLevelQuickFixMultiFileTestGenerated extends AbstractHi runTest("../../../idea/tests/testData/quickfix/modifiers/addOpenToClassDeclaration/finalJavaUpperBound.before.Main.kt"); } } + + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../../idea/tests/testData/quickfix/addGenericUpperBound") + public static class AddGenericUpperBound extends AbstractHighLevelQuickFixMultiFileTest { + @java.lang.Override + @org.jetbrains.annotations.NotNull + public final KotlinPluginMode getPluginMode() { + return KotlinPluginMode.K2; + } + + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, this, testDataFilePath); + } + + @TestMetadata("javaUpperBoundViolated.test") + public void testJavaUpperBoundViolated() throws Exception { + runTest("../../../idea/tests/testData/quickfix/addGenericUpperBound/javaUpperBoundViolated.test"); + } + } } diff --git a/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixTestGenerated.java b/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixTestGenerated.java index e965df73f1bc..e8f891eafc1e 100644 --- a/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixTestGenerated.java +++ b/plugins/kotlin/code-insight/fixes-k2/tests/test/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/HighLevelQuickFixTestGenerated.java @@ -6129,7 +6129,44 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu } } + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../../../idea/tests/testData/quickfix/addGenericUpperBound") + public static class AddGenericUpperBound 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("basic.kt") + public void testBasic() throws Exception { + runTest("../../../idea/tests/testData/quickfix/addGenericUpperBound/basic.kt"); + } + + @TestMetadata("boundAlreadyExists.kt") + public void testBoundAlreadyExists() throws Exception { + runTest("../../../idea/tests/testData/quickfix/addGenericUpperBound/boundAlreadyExists.kt"); + } + + @TestMetadata("inferenceTwoParams.kt") + public void testInferenceTwoParams() throws Exception { + runTest("../../../idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt"); + } + + @TestMetadata("paramAsBound.kt") + public void testParamAsBound() throws Exception { + runTest("../../../idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt"); + } + + @TestMetadata("withinDeclaration.kt") + public void testWithinDeclaration() throws Exception { + runTest("../../../idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt"); + } + } @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../../../idea/tests/testData/quickfix/addInline") diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt index c1e52028bb26..26e5bf23af95 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt @@ -4,4 +4,5 @@ fun foo() = 1 fun bar() = foo>() -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt.after index b42d004c3719..b45b814b816f 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt.after +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/basic.kt.after @@ -4,4 +4,5 @@ fun foo() = 1 fun bar() = foo() -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt index 686882c149c0..203f1d180f90 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt @@ -5,4 +5,6 @@ fun foo(x: T, y: U) = 1 fun bar(x: E, y: F) = foo(x, y) -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.HighPriorityMakeUpperBoundNonNullableFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.HighPriorityMakeUpperBoundNonNullableFix +// TODO: KTIJ-29580 +/* IGNORE_K2 */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt.after index dc3b8d715566..1e32564d239e 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt.after +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/inferenceTwoParams.kt.after @@ -5,4 +5,6 @@ fun foo(x: T, y: U) = 1 fun bar(x: E, y: F) = foo(x, y) -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.HighPriorityMakeUpperBoundNonNullableFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.HighPriorityMakeUpperBoundNonNullableFix +// TODO: KTIJ-29580 +/* IGNORE_K2 */ \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt index 6d52343c9d52..cfec3e831650 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt @@ -4,4 +4,5 @@ fun foo() = 1 fun bar() = foo>() -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt.after index 2aa9f4235859..994f1718a42d 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt.after +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/paramAsBound.kt.after @@ -4,4 +4,5 @@ fun foo() = 1 fun bar() = foo>() -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt index 8e7acabbf23c..4a296cb48597 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt @@ -3,4 +3,5 @@ class A fun bar(x: A>) {} -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt.after index 0365d07b827e..382709afd806 100644 --- a/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt.after +++ b/plugins/kotlin/idea/tests/testData/quickfix/addGenericUpperBound/withinDeclaration.kt.after @@ -3,4 +3,5 @@ class A fun bar(x: A>) {} -// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file +// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix +// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.AddGenericUpperBoundFix \ No newline at end of file diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2QuickFixTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2QuickFixTests.kt index b4b77dce4f6c..296033f59486 100644 --- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2QuickFixTests.kt +++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2QuickFixTests.kt @@ -73,7 +73,7 @@ internal fun MutableTWorkspace.generateK2FixTests() { model("$idea/quickfix/addEmptyArgumentList", pattern = pattern) model("$idea/quickfix/addEqEqTrue", pattern = pattern) model("$idea/quickfix/addFunModifier", pattern = pattern) - model("$idea/quickfix/addGenericUpperBound", pattern = pattern, isIgnored = true) + model("$idea/quickfix/addGenericUpperBound", pattern = pattern) model("$idea/quickfix/addInline", pattern = pattern) model("$idea/quickfix/addInlineToReifiedFunctionFix", pattern = pattern) model("$idea/quickfix/addIsToWhenCondition", pattern = pattern) @@ -228,6 +228,11 @@ internal fun MutableTWorkspace.generateK2FixTests() { pattern = pattern, testMethodName = testMethodName, ) + model( + "$idea/quickfix/addGenericUpperBound", + pattern = pattern, + testMethodName = testMethodName, + ) } testClass {