Use OverrideMemberChooserObject to generate also abstract actual decls

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