Use OverrideMemberChooserObject to generate also abstract actual decls
Relates to KT-27093 and similar problems
This commit is contained in:
@@ -186,6 +186,7 @@ interface DescriptorRendererOptions {
|
||||
var withoutReturnType: Boolean
|
||||
var normalizedVisibilities: Boolean
|
||||
var renderDefaultVisibility: Boolean
|
||||
var renderDefaultModality: Boolean
|
||||
var uninferredTypeParameterAsName: Boolean
|
||||
var overrideRenderingPolicy: OverrideRenderingPolicy
|
||||
var valueParametersHandler: DescriptorRenderer.ValueParametersHandler
|
||||
|
||||
@@ -478,17 +478,33 @@ internal class DescriptorRendererImpl(
|
||||
builder.append(renderKeyword(visibility.displayName)).append(" ")
|
||||
}
|
||||
|
||||
private fun renderModality(modality: Modality, builder: StringBuilder) {
|
||||
private fun renderModality(modality: Modality, builder: StringBuilder, defaultModality: Modality) {
|
||||
if (!renderDefaultModality && modality == defaultModality) return
|
||||
renderModifier(builder, DescriptorRendererModifier.MODALITY in modifiers, modality.name.toLowerCase())
|
||||
}
|
||||
|
||||
private fun MemberDescriptor.implicitModalityWithoutExtensions(): Modality {
|
||||
if (this is ClassDescriptor) {
|
||||
return if (kind == ClassKind.INTERFACE) Modality.ABSTRACT else Modality.FINAL
|
||||
}
|
||||
val containingClassDescriptor = containingDeclaration as? ClassDescriptor ?: return Modality.FINAL
|
||||
if (this !is CallableMemberDescriptor) return Modality.FINAL
|
||||
if (this.overriddenDescriptors.isNotEmpty()) {
|
||||
if (containingClassDescriptor.modality != Modality.FINAL) return Modality.OPEN
|
||||
}
|
||||
if (containingClassDescriptor.kind == ClassKind.INTERFACE && this.visibility != Visibilities.PRIVATE) {
|
||||
return if (this.modality == Modality.ABSTRACT) Modality.ABSTRACT else Modality.OPEN
|
||||
}
|
||||
return Modality.FINAL
|
||||
}
|
||||
|
||||
private fun renderModalityForCallable(callable: CallableMemberDescriptor, builder: StringBuilder) {
|
||||
if (!DescriptorUtils.isTopLevelDeclaration(callable) || callable.modality != Modality.FINAL) {
|
||||
if (overrideRenderingPolicy == OverrideRenderingPolicy.RENDER_OVERRIDE && callable.modality == Modality.OPEN &&
|
||||
overridesSomething(callable)) {
|
||||
return
|
||||
}
|
||||
renderModality(callable.modality, builder)
|
||||
renderModality(callable.modality, builder, callable.implicitModalityWithoutExtensions())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -913,7 +929,7 @@ internal class DescriptorRendererImpl(
|
||||
}
|
||||
if (!(klass.kind == ClassKind.INTERFACE && klass.modality == Modality.ABSTRACT ||
|
||||
klass.kind.isSingleton && klass.modality == Modality.FINAL)) {
|
||||
renderModality(klass.modality, builder)
|
||||
renderModality(klass.modality, builder, klass.implicitModalityWithoutExtensions())
|
||||
}
|
||||
renderMemberModifiers(klass, builder)
|
||||
renderModifier(builder, DescriptorRendererModifier.INNER in modifiers && klass.isInner, "inner")
|
||||
|
||||
@@ -81,6 +81,7 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions {
|
||||
override var enhancedTypes by property(false)
|
||||
override var normalizedVisibilities by property(false)
|
||||
override var renderDefaultVisibility by property(true)
|
||||
override var renderDefaultModality by property(true)
|
||||
override var uninferredTypeParameterAsName by property(false)
|
||||
override var includePropertyConstant by property(false)
|
||||
override var withoutTypeParameters by property(false)
|
||||
|
||||
+19
-12
@@ -142,7 +142,7 @@ private fun OverrideMemberChooserObject.generateMember(
|
||||
|
||||
val bodyType = when {
|
||||
targetClass?.hasExpectModifier() == true -> NO_BODY
|
||||
descriptor.extensionReceiverParameter != null -> FROM_TEMPLATE
|
||||
descriptor.extensionReceiverParameter != null && !forceActual -> FROM_TEMPLATE
|
||||
else -> bodyType
|
||||
}
|
||||
|
||||
@@ -211,27 +211,31 @@ private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
|
||||
}
|
||||
|
||||
private val ACTUAL_RENDERER = OVERRIDE_RENDERER.withOptions {
|
||||
modifiers = setOf(DescriptorRendererModifier.ANNOTATIONS)
|
||||
modifiers = DescriptorRendererModifier.ALL
|
||||
renderConstructorKeyword = true
|
||||
secondaryConstructorsAsPrimary = false
|
||||
renderDefaultVisibility = false
|
||||
renderDefaultModality = false
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.wrap(): PropertyDescriptor {
|
||||
val delegate = copy(containingDeclaration, Modality.OPEN, visibility, kind, true) as PropertyDescriptor
|
||||
private fun PropertyDescriptor.wrap(forceOverride: Boolean): PropertyDescriptor {
|
||||
val delegate = copy(containingDeclaration, if (forceOverride) Modality.OPEN else modality, visibility, kind, true) as PropertyDescriptor
|
||||
val newDescriptor = object : PropertyDescriptor by delegate {
|
||||
override fun isExpect() = false
|
||||
}
|
||||
newDescriptor.setSingleOverridden(this)
|
||||
if (forceOverride) {
|
||||
newDescriptor.setSingleOverridden(this)
|
||||
}
|
||||
return newDescriptor
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.wrap(): FunctionDescriptor {
|
||||
private fun FunctionDescriptor.wrap(forceOverride: Boolean, forceAbstract: Boolean): FunctionDescriptor {
|
||||
if (this is ClassConstructorDescriptor) return this.wrap()
|
||||
return object : FunctionDescriptor by this {
|
||||
override fun isExpect() = false
|
||||
override fun getModality() = Modality.OPEN
|
||||
override fun getModality() = if (forceAbstract) Modality.ABSTRACT else if (forceOverride) Modality.OPEN else this@wrap.modality
|
||||
override fun getReturnType() = this@wrap.returnType?.approximateFlexibleTypes(preferNotNull = true, preferStarForRaw = true)
|
||||
override fun getOverriddenDescriptors() = listOf(this@wrap)
|
||||
override fun getOverriddenDescriptors() = if (forceOverride) listOf(this@wrap) else emptyList()
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D) =
|
||||
visitor.visitFunctionDescriptor(this, data)
|
||||
}
|
||||
@@ -242,7 +246,7 @@ private fun ClassConstructorDescriptor.wrap(): ClassConstructorDescriptor {
|
||||
override fun isExpect() = false
|
||||
override fun getModality() = Modality.FINAL
|
||||
override fun getReturnType() = this@wrap.returnType.approximateFlexibleTypes(preferNotNull = true, preferStarForRaw = true)
|
||||
override fun getOverriddenDescriptors() = listOf(this@wrap)
|
||||
override fun getOverriddenDescriptors(): List<ClassConstructorDescriptor> = emptyList()
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D) =
|
||||
visitor.visitConstructorDescriptor(this, data)
|
||||
}
|
||||
@@ -254,7 +258,8 @@ private fun generateProperty(
|
||||
renderer: DescriptorRenderer,
|
||||
bodyType: OverrideMemberChooserObject.BodyType
|
||||
): KtProperty {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
val actualRendererUsed = renderer === ACTUAL_RENDERER
|
||||
val newDescriptor = descriptor.wrap(forceOverride = !actualRendererUsed)
|
||||
|
||||
val returnType = descriptor.returnType
|
||||
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
|
||||
@@ -274,7 +279,8 @@ private fun generateProperty(
|
||||
}
|
||||
|
||||
private fun generateConstructorParameter(project: Project, descriptor: PropertyDescriptor, renderer: DescriptorRenderer): KtParameter {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
val actualRendererUsed = renderer === ACTUAL_RENDERER
|
||||
val newDescriptor = descriptor.wrap(forceOverride = !actualRendererUsed)
|
||||
newDescriptor.setSingleOverridden(descriptor)
|
||||
return KtPsiFactory(project).createParameter(renderer.render(newDescriptor))
|
||||
}
|
||||
@@ -285,7 +291,8 @@ private fun generateFunction(
|
||||
renderer: DescriptorRenderer,
|
||||
bodyType: OverrideMemberChooserObject.BodyType
|
||||
): KtFunction {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
val actualRendererUsed = renderer === ACTUAL_RENDERER
|
||||
val newDescriptor = descriptor.wrap(forceAbstract = actualRendererUsed && bodyType == NO_BODY, forceOverride = !actualRendererUsed)
|
||||
|
||||
val returnType = descriptor.returnType
|
||||
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
|
||||
|
||||
@@ -25,17 +25,16 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.JavaDirectoryService
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||
import org.jetbrains.kotlin.idea.core.*
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType.NO_BODY
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.Companion.create
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.generateActualMember
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.generateTopLevelActual
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||
@@ -252,7 +251,6 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
} else {
|
||||
createClass(expectedText)
|
||||
}
|
||||
val isInterface = expectedClass is KtClass && expectedClass.isInterface()
|
||||
actualClass.declarations.forEach {
|
||||
if (it.exists()) {
|
||||
it.delete()
|
||||
@@ -261,16 +259,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
when (it) {
|
||||
is KtEnumEntry -> return@forEach
|
||||
is KtClassOrObject -> it.delete()
|
||||
is KtCallableDeclaration -> {
|
||||
if (!isInterface && !it.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
|
||||
it.delete()
|
||||
} else {
|
||||
it.addModifier(KtTokens.ACTUAL_KEYWORD)
|
||||
if (it is KtFunction) {
|
||||
it.removeParameterDefaultValues()
|
||||
}
|
||||
}
|
||||
}
|
||||
is KtCallableDeclaration -> it.delete()
|
||||
}
|
||||
}
|
||||
val primaryConstructor = actualClass.primaryConstructor
|
||||
@@ -307,9 +296,6 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
continue@declLoop
|
||||
}
|
||||
is KtCallableDeclaration -> {
|
||||
if (isInterface || expectedDeclaration.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
|
||||
continue@declLoop
|
||||
}
|
||||
when (expectedDeclaration) {
|
||||
is KtFunction -> generateFunction(project, expectedDeclaration, descriptor as FunctionDescriptor, actualClass)
|
||||
is KtProperty -> generateProperty(project, expectedDeclaration, descriptor as PropertyDescriptor, actualClass)
|
||||
@@ -346,8 +332,9 @@ private fun generateFunction(
|
||||
descriptor: FunctionDescriptor,
|
||||
targetClass: KtClassOrObject? = null
|
||||
): KtFunction {
|
||||
val memberChooserObject = OverrideMemberChooserObject.create(
|
||||
expectedFunction, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
|
||||
val memberChooserObject = create(
|
||||
expectedFunction, descriptor, descriptor,
|
||||
if (descriptor.modality == Modality.ABSTRACT) NO_BODY else EMPTY_OR_TEMPLATE
|
||||
)
|
||||
return if (targetClass != null) {
|
||||
memberChooserObject.generateActualMember(targetClass = targetClass, copyDoc = true)
|
||||
@@ -372,14 +359,14 @@ private fun generateProperty(
|
||||
descriptor: PropertyDescriptor,
|
||||
targetClass: KtClassOrObject? = null
|
||||
): KtProperty {
|
||||
val memberChooserObject = OverrideMemberChooserObject.create(
|
||||
expectedProperty, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
|
||||
val memberChooserObject = create(
|
||||
expectedProperty, descriptor, descriptor,
|
||||
if (descriptor.modality == Modality.ABSTRACT) NO_BODY else EMPTY_OR_TEMPLATE
|
||||
)
|
||||
return if (targetClass != null) {
|
||||
memberChooserObject.generateActualMember(targetClass = targetClass, copyDoc = true)
|
||||
} else {
|
||||
memberChooserObject.generateTopLevelActual(copyDoc = true, project = project)
|
||||
} as KtProperty
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// Abstract: to be implemented
|
||||
actual abstract class Abstract {
|
||||
|
||||
actual abstract fun String.bar(y: Double): Boolean
|
||||
|
||||
actual abstract var status: Int
|
||||
actual fun foo(param: String): Int {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
actual abstract fun String.bar(y: Double): Boolean
|
||||
actual val isGood: Boolean
|
||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
||||
actual abstract var status: Int
|
||||
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create actual class for module proj_JVM (JVM)" "true"
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
expect abstract class My<caret>Generator {
|
||||
abstract fun generate(): Random
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// "Create actual class for module proj_JVM (JVM)" "true"
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
expect abstract class MyGenerator {
|
||||
abstract fun generate(): Random
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
// MyGenerator: to be implemented
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
import kotlin.random.Random
|
||||
|
||||
// MyGenerator: to be implemented
|
||||
actual abstract class MyGenerator {
|
||||
actual abstract fun generate(): Random
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
// Interface: to be implemented
|
||||
actual interface Interface {
|
||||
actual fun foo(param: String): Int
|
||||
|
||||
actual fun String.bar(y: Double): Boolean
|
||||
|
||||
actual val isGood: Boolean
|
||||
|
||||
actual var status: Int
|
||||
|
||||
actual class Nested {
|
||||
|
||||
+5
@@ -30,6 +30,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
||||
runTest("idea/testData/multiModuleQuickFix/abstract/");
|
||||
}
|
||||
|
||||
@TestMetadata("abstractClassWithJdk")
|
||||
public void testAbstractClassWithJdk() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/abstractClassWithJdk/");
|
||||
}
|
||||
|
||||
@TestMetadata("actualImplementAsConstructorParam")
|
||||
public void testActualImplementAsConstructorParam() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/actualImplementAsConstructorParam/");
|
||||
|
||||
Reference in New Issue
Block a user