diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt index 098dde1d191..a8429449d38 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt @@ -187,6 +187,7 @@ interface DescriptorRendererOptions { var normalizedVisibilities: Boolean var renderDefaultVisibility: Boolean var renderDefaultModality: Boolean + var renderActualAnnotationPropertiesInPrimaryConstructor: Boolean var uninferredTypeParameterAsName: Boolean var overrideRenderingPolicy: OverrideRenderingPolicy var valueParametersHandler: DescriptorRenderer.ValueParametersHandler diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index 70e102db453..98d1ddfd64e 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.KClassValue import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue +import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.ErrorUtils.UninferredParameterTypeConstructor import org.jetbrains.kotlin.types.TypeUtils.CANT_INFER_FUNCTION_PARAM_TYPE @@ -795,6 +796,12 @@ internal class DescriptorRendererImpl( renderModifier(builder, valueParameter.isCrossinline, "crossinline") renderModifier(builder, valueParameter.isNoinline, "noinline") + val containingDeclaration = valueParameter.containingDeclaration + if (renderActualAnnotationPropertiesInPrimaryConstructor && containingDeclaration.isAnnotationConstructor()) { + renderModifier(builder, true, "actual") + renderModifier(builder, true, "val") + } + renderVariable(valueParameter, includeName, builder, topLevel) val withDefaultValue = diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt index ec1404c26ae..ed26f60aefb 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt @@ -82,6 +82,7 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions { override var normalizedVisibilities by property(false) override var renderDefaultVisibility by property(true) override var renderDefaultModality by property(true) + override var renderActualAnnotationPropertiesInPrimaryConstructor by property(false) override var uninferredTypeParameterAsName by property(false) override var includePropertyConstant by property(false) override var withoutTypeParameters by property(false) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt index 0273614169b..68a8259a78f 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt @@ -216,6 +216,7 @@ private val ACTUAL_RENDERER = OVERRIDE_RENDERER.withOptions { secondaryConstructorsAsPrimary = false renderDefaultVisibility = false renderDefaultModality = false + renderActualAnnotationPropertiesInPrimaryConstructor = true } private fun PropertyDescriptor.wrap(forceOverride: Boolean): PropertyDescriptor { @@ -306,7 +307,13 @@ private fun generateFunction( val factory = KtPsiFactory(project) val functionText = renderer.render(newDescriptor) + body return when (descriptor) { - is ClassConstructorDescriptor -> factory.createSecondaryConstructor(functionText) + is ClassConstructorDescriptor -> { + if (descriptor.isPrimary) { + factory.createPrimaryConstructor(functionText) + } else { + factory.createSecondaryConstructor(functionText) + } + } else -> factory.createFunction(functionText) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt index 652ade8a564..11b13ec07dd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.quickfix.expectactual import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleManager import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -55,14 +56,18 @@ class AddActualFix( element.primaryConstructor?.valueParameters?.filter { it.hasValOrVar() }.orEmpty() + listOfNotNull(element.primaryConstructor) ) - for (declaration in pureActualClass.declarations) { - val actualDeclaration = element.addDeclaration(declaration) - val reformatted = CodeStyleManager.getInstance(project).reformat(actualDeclaration) + + fun PsiElement.clean() { + val reformatted = CodeStyleManager.getInstance(project).reformat(this) ShortenReferences.DEFAULT.process(reformatted as KtElement) } + + for (declaration in pureActualClass.declarations) { + element.addDeclaration(declaration).clean() + } val primaryConstructor = pureActualClass.primaryConstructor if (element.primaryConstructor == null && primaryConstructor != null) { - element.addAfter(primaryConstructor, element.nameIdentifier) + element.addAfter(primaryConstructor, element.nameIdentifier).clean() } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt index 4170abda245..18ee46d42d3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt @@ -262,10 +262,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass( is KtCallableDeclaration -> it.delete() } } - val primaryConstructor = actualClass.primaryConstructor - if (primaryConstructor != null && primaryConstructor.exists()) { - primaryConstructor.delete() - } + actualClass.primaryConstructor?.delete() val context = expectedClass.analyzeWithContent() actualClass.superTypeListEntries.zip(expectedClass.superTypeListEntries).forEach { (actualEntry, expectedEntry) -> @@ -306,15 +303,13 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass( } actualClass.addDeclaration(actualDeclaration) } - - actualClass.primaryConstructor?.let { - it.addModifier(KtTokens.ACTUAL_KEYWORD) - for (parameter in it.valueParameters) { - if (parameter.hasValOrVar()) { - parameter.addModifier(KtTokens.ACTUAL_KEYWORD) - } + val expectedPrimaryConstructor = expectedClass.primaryConstructor + if (actualClass is KtClass && expectedPrimaryConstructor?.exists() == false) { + val descriptor = expectedPrimaryConstructor.toDescriptor() + if (descriptor is FunctionDescriptor) { + val actualPrimaryConstructor = generateFunction(project, expectedPrimaryConstructor, descriptor, actualClass) + actualClass.createPrimaryConstructorIfAbsent().replace(actualPrimaryConstructor) } - it.removeParameterDefaultValues() } return actualClass @@ -343,16 +338,6 @@ private fun generateFunction( } as KtFunction } -private fun KtFunction.removeParameterDefaultValues() { - for (valueParameter in valueParameters) { - val defaultValue = valueParameter.defaultValue - if (defaultValue != null) { - val equalsToken = valueParameter.equalsToken - valueParameter.deleteChildRange(equalsToken, defaultValue) - } - } -} - private fun generateProperty( project: Project, expectedProperty: KtProperty, diff --git a/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_common_dep(stdlib)/common.kt b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_common_dep(stdlib)/common.kt new file mode 100644 index 00000000000..33986ed5610 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_common_dep(stdlib)/common.kt @@ -0,0 +1,7 @@ +// "Create actual class for module proj_JVM (JVM)" "true" + +import kotlin.random.Random + +expect class MyGenerator(r: Random) { + val i: Int +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_common_dep(stdlib)/common.kt.after b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_common_dep(stdlib)/common.kt.after new file mode 100644 index 00000000000..33986ed5610 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_common_dep(stdlib)/common.kt.after @@ -0,0 +1,7 @@ +// "Create actual class for module proj_JVM (JVM)" "true" + +import kotlin.random.Random + +expect class MyGenerator(r: Random) { + val i: Int +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_jvm_dep(stdlib)/MyGenerator.kt b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_jvm_dep(stdlib)/MyGenerator.kt new file mode 100644 index 00000000000..e0c26053d3e --- /dev/null +++ b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_jvm_dep(stdlib)/MyGenerator.kt @@ -0,0 +1 @@ +// MyGenerator: to be implemented \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_jvm_dep(stdlib)/MyGenerator.kt.after b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_jvm_dep(stdlib)/MyGenerator.kt.after new file mode 100644 index 00000000000..f1922acbbd0 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/constructorWithJdk/proj_jvm_dep(stdlib)/MyGenerator.kt.after @@ -0,0 +1,7 @@ +import kotlin.random.Random + +// MyGenerator: to be implemented +actual class MyGenerator actual constructor(r: Random) { + actual val i: Int + get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates. +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java index ce2e86aeb3d..9a60c5251c4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java @@ -159,6 +159,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul runTest("idea/testData/multiModuleQuickFix/companionAbsence/"); } + @TestMetadata("constructorWithJdk") + public void testConstructorWithJdk() throws Exception { + runTest("idea/testData/multiModuleQuickFix/constructorWithJdk/"); + } + @TestMetadata("convertActualEnumToSealedClass") public void testConvertActualEnumToSealedClass() throws Exception { runTest("idea/testData/multiModuleQuickFix/convertActualEnumToSealedClass/");