Use OverrideMemberChooserObject to generate also primary constructors
Relates to KT-27093 and similar problems
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
+8
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create actual class for module proj_JVM (JVM)" "true"
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
expect class My<caret>Generator(r: Random) {
|
||||
val i: Int
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// "Create actual class for module proj_JVM (JVM)" "true"
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
expect class My<caret>Generator(r: Random) {
|
||||
val i: Int
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
// MyGenerator: to be implemented
|
||||
Vendored
+7
@@ -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.
|
||||
}
|
||||
+5
@@ -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/");
|
||||
|
||||
Reference in New Issue
Block a user