diff --git a/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddValVarToConstructorParameterFixFactory.kt b/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddValVarToConstructorParameterFixFactory.kt
index b0ff2ec4d464..fdd0d74043fb 100644
--- a/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddValVarToConstructorParameterFixFactory.kt
+++ b/plugins/kotlin/code-insight/fixes-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/fixes/AddValVarToConstructorParameterFixFactory.kt
@@ -9,11 +9,9 @@ import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
import org.jetbrains.kotlin.idea.base.psi.mustHaveOnlyValPropertiesInPrimaryConstructor
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory
-import org.jetbrains.kotlin.idea.codeinsight.utils.ValVarExpression
+import org.jetbrains.kotlin.idea.codeinsights.impl.base.intentions.addValVarToConstructorParameter
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtParameter
-import org.jetbrains.kotlin.psi.KtPsiFactory
-import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
internal object AddValVarToConstructorParameterFixFactory {
@@ -45,11 +43,7 @@ internal object AddValVarToConstructorParameterFixFactory {
actionContext: ActionContext,
element: KtParameter,
updater: ModPsiUpdater,
- ) {
- val valKeyword = element.addBefore(KtPsiFactory(actionContext.project).createValKeyword(), element.nameIdentifier)
- if (element.containingClass()?.mustHaveOnlyValPropertiesInPrimaryConstructor() == true) return
- updater.templateBuilder().field(valKeyword, ValVarExpression)
- }
+ ) = addValVarToConstructorParameter(actionContext.project, element, updater)
override fun getPresentation(
context: ActionContext,
diff --git a/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/intentions/AddValVarToConstructorParameterUtils.kt b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/intentions/AddValVarToConstructorParameterUtils.kt
new file mode 100644
index 000000000000..398a1a56bbf8
--- /dev/null
+++ b/plugins/kotlin/code-insight/impl-base/src/org/jetbrains/kotlin/idea/codeinsights/impl/base/intentions/AddValVarToConstructorParameterUtils.kt
@@ -0,0 +1,20 @@
+// 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.codeinsights.impl.base.intentions
+
+import com.intellij.modcommand.ModPsiUpdater
+import com.intellij.openapi.project.Project
+import org.jetbrains.kotlin.idea.base.psi.mustHaveOnlyValPropertiesInPrimaryConstructor
+import org.jetbrains.kotlin.idea.codeinsight.utils.ValVarExpression
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.psi.psiUtil.containingClass
+
+fun addValVarToConstructorParameter(
+ project: Project,
+ element: KtParameter,
+ updater: ModPsiUpdater,
+) {
+ val valKeyword = element.addBefore(KtPsiFactory(project).createValKeyword(), element.nameIdentifier)
+ if (element.containingClass()?.mustHaveOnlyValPropertiesInPrimaryConstructor() == true) return
+ updater.templateBuilder().field(valKeyword, ValVarExpression)
+}
diff --git a/plugins/kotlin/code-insight/intentions-k2/resources/kotlin.code-insight.intentions.k2.xml b/plugins/kotlin/code-insight/intentions-k2/resources/kotlin.code-insight.intentions.k2.xml
index fdc79c997110..3035fda91705 100644
--- a/plugins/kotlin/code-insight/intentions-k2/resources/kotlin.code-insight.intentions.k2.xml
+++ b/plugins/kotlin/code-insight/intentions-k2/resources/kotlin.code-insight.intentions.k2.xml
@@ -394,5 +394,12 @@
group.names.kotlin
+
+ kotlin
+ org.jetbrains.kotlin.idea.k2.codeinsight.intentions.AddValVarToConstructorParameterActionIntention
+ messages.KotlinBundle
+ group.names.kotlin
+
+
diff --git a/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/AddValVarToConstructorParameterActionIntention.kt b/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/AddValVarToConstructorParameterActionIntention.kt
new file mode 100644
index 000000000000..0fa8797899d1
--- /dev/null
+++ b/plugins/kotlin/code-insight/intentions-k2/src/org/jetbrains/kotlin/idea/k2/codeinsight/intentions/AddValVarToConstructorParameterActionIntention.kt
@@ -0,0 +1,51 @@
+// 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.intentions
+
+import com.intellij.modcommand.ActionContext
+import com.intellij.modcommand.ModPsiUpdater
+import com.intellij.modcommand.Presentation
+import com.intellij.openapi.util.TextRange
+import org.jetbrains.kotlin.analysis.api.KaSession
+import org.jetbrains.kotlin.idea.base.psi.mustHaveOnlyPropertiesInPrimaryConstructor
+import org.jetbrains.kotlin.idea.base.psi.mustHaveValOrVar
+import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
+import org.jetbrains.kotlin.idea.codeinsight.api.applicable.intentions.KotlinApplicableModCommandAction
+import org.jetbrains.kotlin.idea.codeinsights.impl.base.applicators.ApplicabilityRanges
+import org.jetbrains.kotlin.idea.codeinsights.impl.base.intentions.addValVarToConstructorParameter
+import org.jetbrains.kotlin.psi.KtClass
+import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.kotlin.psi.KtParameterList
+import org.jetbrains.kotlin.psi.KtPrimaryConstructor
+import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
+import org.jetbrains.kotlin.psi.psiUtil.isExpectDeclaration
+
+class AddValVarToConstructorParameterActionIntention : KotlinApplicableModCommandAction(KtParameter::class) {
+
+ override fun getFamilyName(): String = KotlinBundle.message("add.val.var.to.primary.constructor.parameter")
+
+ override fun getPresentation(context: ActionContext, element: KtParameter): Presentation {
+ val actionName = KotlinBundle.message("add.val.var.to.parameter.0", element.name ?: "")
+ return Presentation.of(actionName)
+ }
+
+ override fun isApplicableByPsi(element: KtParameter): Boolean {
+ if (element.valOrVarKeyword != null) return false
+ val constructor = (element.parent as? KtParameterList)?.parent as? KtPrimaryConstructor ?: return false
+ if (!constructor.mustHaveValOrVar() && constructor.isExpectDeclaration()) return false
+ val containingClass = element.getStrictParentOfType()?: return false
+ return !containingClass.mustHaveOnlyPropertiesInPrimaryConstructor()
+ }
+
+ override fun getApplicableRanges(element: KtParameter): List = ApplicabilityRanges.declarationName(element)
+
+ context(KaSession)
+ override fun prepareContext(element: KtParameter) {
+ }
+
+ override fun invoke(
+ actionContext: ActionContext,
+ element: KtParameter,
+ elementContext: Unit,
+ updater: ModPsiUpdater,
+ ) = addValVarToConstructorParameter(actionContext.project, element, updater)
+}
diff --git a/plugins/kotlin/code-insight/intentions-k2/tests/test/org/jetbrains/kotlin/idea/k2/intentions/tests/K2IntentionTestGenerated.java b/plugins/kotlin/code-insight/intentions-k2/tests/test/org/jetbrains/kotlin/idea/k2/intentions/tests/K2IntentionTestGenerated.java
index 6ddbc837e4b7..58fb2301ac6b 100644
--- a/plugins/kotlin/code-insight/intentions-k2/tests/test/org/jetbrains/kotlin/idea/k2/intentions/tests/K2IntentionTestGenerated.java
+++ b/plugins/kotlin/code-insight/intentions-k2/tests/test/org/jetbrains/kotlin/idea/k2/intentions/tests/K2IntentionTestGenerated.java
@@ -10379,7 +10379,79 @@ public abstract class K2IntentionTestGenerated extends AbstractK2IntentionTest {
+ @RunWith(JUnit3RunnerWithInners.class)
+ @TestMetadata("../../../idea/tests/testData/intentions/addValOrVar")
+ public static class AddValOrVar extends AbstractK2IntentionTest {
+ @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("actualClass.kt")
+ public void testActualClass() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/actualClass.kt");
+ }
+
+ @TestMetadata("addVal.kt")
+ public void testAddVal() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/addVal.kt");
+ }
+
+ @TestMetadata("dataClass.kt")
+ public void testDataClass() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/dataClass.kt");
+ }
+
+ @TestMetadata("expectAnnotation.kt")
+ public void testExpectAnnotation() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/expectAnnotation.kt");
+ }
+
+ @TestMetadata("expectClass.kt")
+ public void testExpectClass() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/expectClass.kt");
+ }
+
+ @TestMetadata("expectClass2.kt")
+ public void testExpectClass2() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/expectClass2.kt");
+ }
+
+ @TestMetadata("expectInlineClass.kt")
+ public void testExpectInlineClass() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/expectInlineClass.kt");
+ }
+
+ @TestMetadata("funParameter.kt")
+ public void testFunParameter() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/funParameter.kt");
+ }
+
+ @TestMetadata("hasVal.kt")
+ public void testHasVal() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/hasVal.kt");
+ }
+
+ @TestMetadata("hasVar.kt")
+ public void testHasVar() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/hasVar.kt");
+ }
+
+ @TestMetadata("outOfRange.kt")
+ public void testOutOfRange() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/outOfRange.kt");
+ }
+
+ @TestMetadata("secondaryConstructorParameter.kt")
+ public void testSecondaryConstructorParameter() throws Exception {
+ runTest("../../../idea/tests/testData/intentions/addValOrVar/secondaryConstructorParameter.kt");
+ }
+ }
diff --git a/plugins/kotlin/idea/tests/testData/intentions/addValOrVar/.k2Intention b/plugins/kotlin/idea/tests/testData/intentions/addValOrVar/.k2Intention
new file mode 100644
index 000000000000..deb2c3b18076
--- /dev/null
+++ b/plugins/kotlin/idea/tests/testData/intentions/addValOrVar/.k2Intention
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.k2.codeinsight.intentions.AddValVarToConstructorParameterActionIntention
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt b/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt
index 32b0be550791..47dee72de0c7 100644
--- a/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt
+++ b/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt
@@ -1,6 +1,6 @@
// "Add 'val' or 'var' to parameter 'x'" "true"
-/* IGNORE_K2 */
class Foo(vararg x: Int, val y: Int) {
}
-// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction$Intention
\ No newline at end of file
+// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction$Intention
+// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.intentions.AddValVarToConstructorParameterActionIntention
\ No newline at end of file
diff --git a/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt.after
index 731f8d96d2d7..bf10a5eb01e4 100644
--- a/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt.after
+++ b/plugins/kotlin/idea/tests/testData/quickfix/addValVar/addValAfterVarArg.kt.after
@@ -1,6 +1,6 @@
// "Add 'val' or 'var' to parameter 'x'" "true"
-/* IGNORE_K2 */
class Foo(vararg val x: Int, val y: Int) {
}
-// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction$Intention
\ No newline at end of file
+// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction$Intention
+// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.intentions.AddValVarToConstructorParameterActionIntention
\ No newline at end of file
diff --git a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2IntentionTests.kt b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2IntentionTests.kt
index 0f70a0094757..b18828449fab 100644
--- a/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2IntentionTests.kt
+++ b/plugins/kotlin/util/test-generator-fir/test/org/jetbrains/kotlin/fir/testGenerator/codeinsight/GenerateK2IntentionTests.kt
@@ -181,7 +181,7 @@ internal fun MutableTWorkspace.generateK2IntentionTests() {
model("${idea}intentions/convertReceiverToParameter", pattern = pattern)
model("${idea}intentions/convertUnsafeCastCallToUnsafeCast", pattern = pattern, isIgnored = true)
model("${idea}intentions/convertSnakeCaseTestFunctionToSpaced", pattern = pattern, isIgnored = true)
- model("${idea}intentions/addValOrVar", pattern = pattern, isIgnored = true)
+ model("${idea}intentions/addValOrVar", pattern = pattern)
model("${idea}intentions/convertBlockCommentToLineComment", pattern = pattern, isIgnored = true)
model("${idea}intentions/removeSingleExpressionStringTemplate", pattern = pattern, isIgnored = true)
model("${idea}intentions/convertLambdaToMultiLine", pattern = pattern, isIgnored = true)