Use OverrideMemberChooserObject to generate also primary constructors

Relates to KT-27093 and similar problems
This commit is contained in:
Mikhail Glukhikh
2018-11-14 12:45:39 +03:00
parent cd041cca71
commit 90a2f70fd1
11 changed files with 60 additions and 27 deletions
@@ -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)
@@ -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,
@@ -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
}
@@ -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
}
@@ -0,0 +1 @@
// MyGenerator: to be implemented
@@ -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.
}
@@ -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/");