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 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)
@@ -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,
@@ -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/"); 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/");