Use OverrideMemberChooserObject to generate actual decls in quick-fixes
This can fix a lot of issues related to inexact generation, in particular #KT-27093 Fixed
This commit is contained in:
+2
-2
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
open class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction {
|
||||
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
|
||||
return OverrideResolver.getMissingImplementations(descriptor)
|
||||
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.EMPTY) }
|
||||
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE) }
|
||||
}
|
||||
|
||||
override fun getChooserTitle() = "Implement Members"
|
||||
@@ -67,6 +67,6 @@ class ImplementAsConstructorParameter : ImplementMembersHandler() {
|
||||
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
|
||||
return OverrideResolver.getMissingImplementations(descriptor)
|
||||
.filter { it is PropertyDescriptor }
|
||||
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.EMPTY, true) }
|
||||
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE, true) }
|
||||
}
|
||||
}
|
||||
+158
-75
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.TemplateKind
|
||||
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType.*
|
||||
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
|
||||
import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
|
||||
import org.jetbrains.kotlin.idea.kdoc.KDocElementFactory
|
||||
@@ -45,9 +46,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.setSingleOverridden
|
||||
import org.jetbrains.kotlin.util.findCallableMemberBySignature
|
||||
|
||||
interface OverrideMemberChooserObject : ClassMember {
|
||||
sealed class BodyType {
|
||||
sealed class BodyType(val requiresReturn: Boolean = true) {
|
||||
object NO_BODY : BodyType()
|
||||
object EMPTY : BodyType()
|
||||
object EMPTY_OR_TEMPLATE : BodyType(requiresReturn = false)
|
||||
object FROM_TEMPLATE : BodyType(requiresReturn = false)
|
||||
object SUPER : BodyType()
|
||||
object QUALIFIED_SUPER : BodyType()
|
||||
|
||||
@@ -60,27 +62,36 @@ interface OverrideMemberChooserObject : ClassMember {
|
||||
val preferConstructorParameter: Boolean
|
||||
|
||||
companion object {
|
||||
fun create(project: Project,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
immediateSuper: CallableMemberDescriptor,
|
||||
bodyType: BodyType,
|
||||
preferConstructorParameter: Boolean = false
|
||||
fun create(
|
||||
project: Project,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
immediateSuper: CallableMemberDescriptor,
|
||||
bodyType: BodyType,
|
||||
preferConstructorParameter: Boolean = false
|
||||
): OverrideMemberChooserObject {
|
||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
|
||||
return if (declaration != null) {
|
||||
WithDeclaration(descriptor, declaration, immediateSuper, bodyType, preferConstructorParameter)
|
||||
}
|
||||
else {
|
||||
create(declaration, descriptor, immediateSuper, bodyType, preferConstructorParameter)
|
||||
} else {
|
||||
WithoutDeclaration(descriptor, immediateSuper, bodyType, preferConstructorParameter)
|
||||
}
|
||||
}
|
||||
|
||||
fun create(
|
||||
declaration: PsiElement,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
immediateSuper: CallableMemberDescriptor,
|
||||
bodyType: BodyType,
|
||||
preferConstructorParameter: Boolean = false
|
||||
): OverrideMemberChooserObject =
|
||||
WithDeclaration(descriptor, declaration, immediateSuper, bodyType, preferConstructorParameter)
|
||||
|
||||
private class WithDeclaration(
|
||||
descriptor: CallableMemberDescriptor,
|
||||
declaration: PsiElement,
|
||||
override val immediateSuper: CallableMemberDescriptor,
|
||||
override val bodyType: BodyType,
|
||||
override val preferConstructorParameter: Boolean
|
||||
descriptor: CallableMemberDescriptor,
|
||||
declaration: PsiElement,
|
||||
override val immediateSuper: CallableMemberDescriptor,
|
||||
override val bodyType: BodyType,
|
||||
override val preferConstructorParameter: Boolean
|
||||
) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject {
|
||||
|
||||
override val descriptor: CallableMemberDescriptor
|
||||
@@ -88,40 +99,68 @@ interface OverrideMemberChooserObject : ClassMember {
|
||||
}
|
||||
|
||||
private class WithoutDeclaration(
|
||||
override val descriptor: CallableMemberDescriptor,
|
||||
override val immediateSuper: CallableMemberDescriptor,
|
||||
override val bodyType: BodyType,
|
||||
override val preferConstructorParameter: Boolean
|
||||
) : MemberChooserObjectBase(DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)), OverrideMemberChooserObject {
|
||||
override val descriptor: CallableMemberDescriptor,
|
||||
override val immediateSuper: CallableMemberDescriptor,
|
||||
override val bodyType: BodyType,
|
||||
override val preferConstructorParameter: Boolean
|
||||
) : MemberChooserObjectBase(
|
||||
DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)
|
||||
), OverrideMemberChooserObject {
|
||||
|
||||
override fun getParentNodeDelegate(): MemberChooserObject? {
|
||||
val parentClassifier = descriptor.containingDeclaration as? ClassifierDescriptor ?: return null
|
||||
return MemberChooserObjectBase(DescriptorMemberChooserObject.getText(parentClassifier), DescriptorMemberChooserObject.getIcon(null, parentClassifier))
|
||||
return MemberChooserObjectBase(
|
||||
DescriptorMemberChooserObject.getText(parentClassifier), DescriptorMemberChooserObject.getIcon(null, parentClassifier)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun OverrideMemberChooserObject.generateMember(targetClass: KtClassOrObject, copyDoc: Boolean): KtCallableDeclaration {
|
||||
val project = targetClass.project
|
||||
fun OverrideMemberChooserObject.generateTopLevelActual(
|
||||
copyDoc: Boolean,
|
||||
project: Project
|
||||
) = generateMember(null, copyDoc, project, forceActual = true)
|
||||
|
||||
fun OverrideMemberChooserObject.generateActualMember(
|
||||
targetClass: KtClassOrObject,
|
||||
copyDoc: Boolean
|
||||
) = generateMember(targetClass, copyDoc, targetClass.project, forceActual = true)
|
||||
|
||||
fun OverrideMemberChooserObject.generateMember(
|
||||
targetClass: KtClassOrObject,
|
||||
copyDoc: Boolean
|
||||
) = generateMember(targetClass, copyDoc, targetClass.project, forceActual = false)
|
||||
|
||||
private fun OverrideMemberChooserObject.generateMember(
|
||||
targetClass: KtClassOrObject?,
|
||||
copyDoc: Boolean,
|
||||
project: Project,
|
||||
forceActual: Boolean
|
||||
): KtCallableDeclaration {
|
||||
val descriptor = immediateSuper
|
||||
|
||||
val bodyType = when {
|
||||
targetClass.hasExpectModifier() -> OverrideMemberChooserObject.BodyType.NO_BODY
|
||||
descriptor.extensionReceiverParameter != null -> OverrideMemberChooserObject.BodyType.EMPTY
|
||||
targetClass?.hasExpectModifier() == true -> NO_BODY
|
||||
descriptor.extensionReceiverParameter != null -> FROM_TEMPLATE
|
||||
else -> bodyType
|
||||
}
|
||||
|
||||
if (preferConstructorParameter && descriptor is PropertyDescriptor) return generateConstructorParameter(project, descriptor)
|
||||
val renderer = if (forceActual) ACTUAL_RENDERER else OVERRIDE_RENDERER
|
||||
|
||||
if (preferConstructorParameter && descriptor is PropertyDescriptor) {
|
||||
return generateConstructorParameter(project, descriptor, renderer)
|
||||
}
|
||||
|
||||
val newMember: KtCallableDeclaration = when (descriptor) {
|
||||
is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType)
|
||||
is PropertyDescriptor -> generateProperty(project, descriptor, bodyType)
|
||||
is FunctionDescriptor -> generateFunction(project, descriptor, renderer, bodyType)
|
||||
is PropertyDescriptor -> generateProperty(project, descriptor, renderer, bodyType)
|
||||
else -> error("Unknown member to override: $descriptor")
|
||||
}
|
||||
|
||||
if (targetClass.hasActualModifier()) {
|
||||
if (forceActual) {
|
||||
newMember.addModifier(KtTokens.ACTUAL_KEYWORD)
|
||||
} else if (targetClass?.hasActualModifier() == true) {
|
||||
val expectClassDescriptors =
|
||||
targetClass.resolveToDescriptorIfAny()?.expectedDescriptors()?.filterIsInstance<ClassDescriptor>().orEmpty()
|
||||
if (expectClassDescriptors.any { expectClassDescriptor ->
|
||||
@@ -143,7 +182,7 @@ fun OverrideMemberChooserObject.generateMember(targetClass: KtClassOrObject, cop
|
||||
findDocComment(superDeclaration)
|
||||
is PsiDocCommentOwner -> {
|
||||
val kDocText = superDeclaration.docComment?.let { IdeaDocCommentConverter.convertDocComment(it) }
|
||||
if (kDocText.isNullOrEmpty()) null else KDocElementFactory(project).createKDocFromText(kDocText!!)
|
||||
if (kDocText.isNullOrEmpty()) null else KDocElementFactory(project).createKDocFromText(kDocText)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
@@ -171,6 +210,12 @@ private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
|
||||
presentableUnresolvedTypes = true
|
||||
}
|
||||
|
||||
private val ACTUAL_RENDERER = OVERRIDE_RENDERER.withOptions {
|
||||
modifiers = setOf(DescriptorRendererModifier.ANNOTATIONS)
|
||||
renderConstructorKeyword = true
|
||||
secondaryConstructorsAsPrimary = false
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.wrap(): PropertyDescriptor {
|
||||
val delegate = copy(containingDeclaration, Modality.OPEN, visibility, kind, true) as PropertyDescriptor
|
||||
val newDescriptor = object : PropertyDescriptor by delegate {
|
||||
@@ -181,74 +226,112 @@ private fun PropertyDescriptor.wrap(): PropertyDescriptor {
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.wrap(): FunctionDescriptor {
|
||||
if (this is ClassConstructorDescriptor) return this.wrap()
|
||||
return object : FunctionDescriptor by this {
|
||||
override fun isExpect() = false
|
||||
override fun getModality() = Modality.OPEN
|
||||
override fun getReturnType() = this@wrap.returnType?.approximateFlexibleTypes(preferNotNull = true, preferStarForRaw = true)
|
||||
override fun getOverriddenDescriptors() = listOf(this@wrap)
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D) = visitor.visitFunctionDescriptor(this, data)
|
||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D) =
|
||||
visitor.visitFunctionDescriptor(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateProperty(project: Project, descriptor: PropertyDescriptor, bodyType: OverrideMemberChooserObject.BodyType): KtProperty {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
val body =
|
||||
if (bodyType != OverrideMemberChooserObject.BodyType.NO_BODY) {
|
||||
buildString {
|
||||
append("\nget()")
|
||||
append(" = ")
|
||||
append(generateUnsupportedOrSuperCall(project, descriptor, bodyType))
|
||||
if (descriptor.isVar) {
|
||||
append("\nset(value) {}")
|
||||
}
|
||||
}
|
||||
} else ""
|
||||
return KtPsiFactory(project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
|
||||
private fun ClassConstructorDescriptor.wrap(): ClassConstructorDescriptor {
|
||||
return object : ClassConstructorDescriptor by this {
|
||||
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 <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D) =
|
||||
visitor.visitConstructorDescriptor(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateConstructorParameter(project: Project, descriptor: PropertyDescriptor): KtParameter {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
newDescriptor.setSingleOverridden(descriptor)
|
||||
return KtPsiFactory(project).createParameter(OVERRIDE_RENDERER.render(newDescriptor))
|
||||
}
|
||||
|
||||
private fun generateFunction(project: Project, descriptor: FunctionDescriptor, bodyType: OverrideMemberChooserObject.BodyType): KtNamedFunction {
|
||||
private fun generateProperty(
|
||||
project: Project,
|
||||
descriptor: PropertyDescriptor,
|
||||
renderer: DescriptorRenderer,
|
||||
bodyType: OverrideMemberChooserObject.BodyType
|
||||
): KtProperty {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
|
||||
val returnType = descriptor.returnType
|
||||
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
|
||||
|
||||
val body = if (bodyType != OverrideMemberChooserObject.BodyType.NO_BODY) {
|
||||
val delegation = generateUnsupportedOrSuperCall(project, descriptor, bodyType)
|
||||
"{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "\n}"
|
||||
}
|
||||
else ""
|
||||
val body =
|
||||
if (bodyType != NO_BODY) {
|
||||
buildString {
|
||||
append("\nget()")
|
||||
append(" = ")
|
||||
append(generateUnsupportedOrSuperCall(project, descriptor, bodyType, !returnsNotUnit))
|
||||
if (descriptor.isVar) {
|
||||
append("\nset(value) {}")
|
||||
}
|
||||
}
|
||||
} else ""
|
||||
return KtPsiFactory(project).createProperty(renderer.render(newDescriptor) + body)
|
||||
}
|
||||
|
||||
return KtPsiFactory(project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
|
||||
private fun generateConstructorParameter(project: Project, descriptor: PropertyDescriptor, renderer: DescriptorRenderer): KtParameter {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
newDescriptor.setSingleOverridden(descriptor)
|
||||
return KtPsiFactory(project).createParameter(renderer.render(newDescriptor))
|
||||
}
|
||||
|
||||
private fun generateFunction(
|
||||
project: Project,
|
||||
descriptor: FunctionDescriptor,
|
||||
renderer: DescriptorRenderer,
|
||||
bodyType: OverrideMemberChooserObject.BodyType
|
||||
): KtFunction {
|
||||
val newDescriptor = descriptor.wrap()
|
||||
|
||||
val returnType = descriptor.returnType
|
||||
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
|
||||
|
||||
val body = if (bodyType != NO_BODY) {
|
||||
val delegation = generateUnsupportedOrSuperCall(project, descriptor, bodyType, !returnsNotUnit)
|
||||
val returnPrefix = if (returnsNotUnit && bodyType.requiresReturn) "return " else ""
|
||||
"{$returnPrefix$delegation\n}"
|
||||
} else ""
|
||||
|
||||
val factory = KtPsiFactory(project)
|
||||
val functionText = renderer.render(newDescriptor) + body
|
||||
return when (descriptor) {
|
||||
is ClassConstructorDescriptor -> factory.createSecondaryConstructor(functionText)
|
||||
else -> factory.createFunction(functionText)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateUnsupportedOrSuperCall(
|
||||
project: Project,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
bodyType: OverrideMemberChooserObject.BodyType
|
||||
project: Project,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
bodyType: OverrideMemberChooserObject.BodyType,
|
||||
canBeEmpty: Boolean = true
|
||||
): String {
|
||||
if (bodyType == OverrideMemberChooserObject.BodyType.EMPTY) {
|
||||
val templateKind = if (descriptor is FunctionDescriptor) TemplateKind.FUNCTION else TemplateKind.PROPERTY_INITIALIZER
|
||||
return getFunctionBodyTextFromTemplate(project,
|
||||
templateKind,
|
||||
descriptor.name.asString(),
|
||||
descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "Unit",
|
||||
null)
|
||||
}
|
||||
else {
|
||||
return buildString {
|
||||
val effectiveBodyType = if (!canBeEmpty && bodyType == EMPTY_OR_TEMPLATE) FROM_TEMPLATE else bodyType
|
||||
when (effectiveBodyType) {
|
||||
EMPTY_OR_TEMPLATE -> return ""
|
||||
FROM_TEMPLATE -> {
|
||||
val templateKind = if (descriptor is FunctionDescriptor) TemplateKind.FUNCTION else TemplateKind.PROPERTY_INITIALIZER
|
||||
return getFunctionBodyTextFromTemplate(
|
||||
project,
|
||||
templateKind,
|
||||
descriptor.name.asString(),
|
||||
descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "Unit",
|
||||
null
|
||||
)
|
||||
}
|
||||
else -> return buildString {
|
||||
if (bodyType is OverrideMemberChooserObject.BodyType.Delegate) {
|
||||
append(bodyType.receiverName)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
append("super")
|
||||
if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) {
|
||||
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor)
|
||||
if (bodyType == QUALIFIED_SUPER) {
|
||||
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(
|
||||
descriptor.containingDeclaration as ClassifierDescriptor
|
||||
)
|
||||
append("<").append(superClassFqName).append(">")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ class OverrideMembersHandler(private val preferConstructorParameters: Boolean =
|
||||
descriptor.kind == ClassKind.INTERFACE && realSuper.builtIns.isMemberOfAny(realSuper) ->
|
||||
OverrideMemberChooserObject.BodyType.NO_BODY
|
||||
immediateSuperToUse.modality == Modality.ABSTRACT ->
|
||||
OverrideMemberChooserObject.BodyType.EMPTY
|
||||
OverrideMemberChooserObject.BodyType.FROM_TEMPLATE
|
||||
realSupersToUse.size == 1 ->
|
||||
OverrideMemberChooserObject.BodyType.SUPER
|
||||
else ->
|
||||
|
||||
Reference in New Issue
Block a user