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 normalizedVisibilities: Boolean
|
||||||
var renderDefaultVisibility: Boolean
|
var renderDefaultVisibility: Boolean
|
||||||
var renderDefaultModality: Boolean
|
var renderDefaultModality: Boolean
|
||||||
|
var renderActualAnnotationPropertiesInPrimaryConstructor: Boolean
|
||||||
var uninferredTypeParameterAsName: Boolean
|
var uninferredTypeParameterAsName: Boolean
|
||||||
var overrideRenderingPolicy: OverrideRenderingPolicy
|
var overrideRenderingPolicy: OverrideRenderingPolicy
|
||||||
var valueParametersHandler: DescriptorRenderer.ValueParametersHandler
|
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.constants.KClassValue
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
|
import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils.UninferredParameterTypeConstructor
|
import org.jetbrains.kotlin.types.ErrorUtils.UninferredParameterTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.TypeUtils.CANT_INFER_FUNCTION_PARAM_TYPE
|
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.isCrossinline, "crossinline")
|
||||||
renderModifier(builder, valueParameter.isNoinline, "noinline")
|
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)
|
renderVariable(valueParameter, includeName, builder, topLevel)
|
||||||
|
|
||||||
val withDefaultValue =
|
val withDefaultValue =
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions {
|
|||||||
override var normalizedVisibilities by property(false)
|
override var normalizedVisibilities by property(false)
|
||||||
override var renderDefaultVisibility by property(true)
|
override var renderDefaultVisibility by property(true)
|
||||||
override var renderDefaultModality by property(true)
|
override var renderDefaultModality by property(true)
|
||||||
|
override var renderActualAnnotationPropertiesInPrimaryConstructor by property(false)
|
||||||
override var uninferredTypeParameterAsName by property(false)
|
override var uninferredTypeParameterAsName by property(false)
|
||||||
override var includePropertyConstant by property(false)
|
override var includePropertyConstant by property(false)
|
||||||
override var withoutTypeParameters by property(false)
|
override var withoutTypeParameters by property(false)
|
||||||
|
|||||||
+8
-1
@@ -216,6 +216,7 @@ private val ACTUAL_RENDERER = OVERRIDE_RENDERER.withOptions {
|
|||||||
secondaryConstructorsAsPrimary = false
|
secondaryConstructorsAsPrimary = false
|
||||||
renderDefaultVisibility = false
|
renderDefaultVisibility = false
|
||||||
renderDefaultModality = false
|
renderDefaultModality = false
|
||||||
|
renderActualAnnotationPropertiesInPrimaryConstructor = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PropertyDescriptor.wrap(forceOverride: Boolean): PropertyDescriptor {
|
private fun PropertyDescriptor.wrap(forceOverride: Boolean): PropertyDescriptor {
|
||||||
@@ -306,7 +307,13 @@ private fun generateFunction(
|
|||||||
val factory = KtPsiFactory(project)
|
val factory = KtPsiFactory(project)
|
||||||
val functionText = renderer.render(newDescriptor) + body
|
val functionText = renderer.render(newDescriptor) + body
|
||||||
return when (descriptor) {
|
return when (descriptor) {
|
||||||
is ClassConstructorDescriptor -> factory.createSecondaryConstructor(functionText)
|
is ClassConstructorDescriptor -> {
|
||||||
|
if (descriptor.isPrimary) {
|
||||||
|
factory.createPrimaryConstructor(functionText)
|
||||||
|
} else {
|
||||||
|
factory.createSecondaryConstructor(functionText)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> factory.createFunction(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.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
@@ -55,14 +56,18 @@ class AddActualFix(
|
|||||||
element.primaryConstructor?.valueParameters?.filter { it.hasValOrVar() }.orEmpty() +
|
element.primaryConstructor?.valueParameters?.filter { it.hasValOrVar() }.orEmpty() +
|
||||||
listOfNotNull(element.primaryConstructor)
|
listOfNotNull(element.primaryConstructor)
|
||||||
)
|
)
|
||||||
for (declaration in pureActualClass.declarations) {
|
|
||||||
val actualDeclaration = element.addDeclaration(declaration)
|
fun PsiElement.clean() {
|
||||||
val reformatted = CodeStyleManager.getInstance(project).reformat(actualDeclaration)
|
val reformatted = CodeStyleManager.getInstance(project).reformat(this)
|
||||||
ShortenReferences.DEFAULT.process(reformatted as KtElement)
|
ShortenReferences.DEFAULT.process(reformatted as KtElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (declaration in pureActualClass.declarations) {
|
||||||
|
element.addDeclaration(declaration).clean()
|
||||||
|
}
|
||||||
val primaryConstructor = pureActualClass.primaryConstructor
|
val primaryConstructor = pureActualClass.primaryConstructor
|
||||||
if (element.primaryConstructor == null && primaryConstructor != null) {
|
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()
|
is KtCallableDeclaration -> it.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val primaryConstructor = actualClass.primaryConstructor
|
actualClass.primaryConstructor?.delete()
|
||||||
if (primaryConstructor != null && primaryConstructor.exists()) {
|
|
||||||
primaryConstructor.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
val context = expectedClass.analyzeWithContent()
|
val context = expectedClass.analyzeWithContent()
|
||||||
actualClass.superTypeListEntries.zip(expectedClass.superTypeListEntries).forEach { (actualEntry, expectedEntry) ->
|
actualClass.superTypeListEntries.zip(expectedClass.superTypeListEntries).forEach { (actualEntry, expectedEntry) ->
|
||||||
@@ -306,15 +303,13 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
|||||||
}
|
}
|
||||||
actualClass.addDeclaration(actualDeclaration)
|
actualClass.addDeclaration(actualDeclaration)
|
||||||
}
|
}
|
||||||
|
val expectedPrimaryConstructor = expectedClass.primaryConstructor
|
||||||
actualClass.primaryConstructor?.let {
|
if (actualClass is KtClass && expectedPrimaryConstructor?.exists() == false) {
|
||||||
it.addModifier(KtTokens.ACTUAL_KEYWORD)
|
val descriptor = expectedPrimaryConstructor.toDescriptor()
|
||||||
for (parameter in it.valueParameters) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
if (parameter.hasValOrVar()) {
|
val actualPrimaryConstructor = generateFunction(project, expectedPrimaryConstructor, descriptor, actualClass)
|
||||||
parameter.addModifier(KtTokens.ACTUAL_KEYWORD)
|
actualClass.createPrimaryConstructorIfAbsent().replace(actualPrimaryConstructor)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
it.removeParameterDefaultValues()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return actualClass
|
return actualClass
|
||||||
@@ -343,16 +338,6 @@ private fun generateFunction(
|
|||||||
} as KtFunction
|
} 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(
|
private fun generateProperty(
|
||||||
project: Project,
|
project: Project,
|
||||||
expectedProperty: KtProperty,
|
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/");
|
runTest("idea/testData/multiModuleQuickFix/companionAbsence/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("constructorWithJdk")
|
||||||
|
public void testConstructorWithJdk() throws Exception {
|
||||||
|
runTest("idea/testData/multiModuleQuickFix/constructorWithJdk/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("convertActualEnumToSealedClass")
|
@TestMetadata("convertActualEnumToSealedClass")
|
||||||
public void testConvertActualEnumToSealedClass() throws Exception {
|
public void testConvertActualEnumToSealedClass() throws Exception {
|
||||||
runTest("idea/testData/multiModuleQuickFix/convertActualEnumToSealedClass/");
|
runTest("idea/testData/multiModuleQuickFix/convertActualEnumToSealedClass/");
|
||||||
|
|||||||
Reference in New Issue
Block a user