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:
Mikhail Glukhikh
2018-11-13 15:41:23 +03:00
parent 5645b6c1b7
commit 3612c2983e
31 changed files with 261 additions and 162 deletions
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.resolve.OverrideResolver
open class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction { open class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction {
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> { override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
return OverrideResolver.getMissingImplementations(descriptor) 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" override fun getChooserTitle() = "Implement Members"
@@ -67,6 +67,6 @@ class ImplementAsConstructorParameter : ImplementMembersHandler() {
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> { override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
return OverrideResolver.getMissingImplementations(descriptor) return OverrideResolver.getMissingImplementations(descriptor)
.filter { it is PropertyDescriptor } .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) }
} }
} }
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.TemplateKind import org.jetbrains.kotlin.idea.core.TemplateKind
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate 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.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
import org.jetbrains.kotlin.idea.kdoc.KDocElementFactory import org.jetbrains.kotlin.idea.kdoc.KDocElementFactory
@@ -45,9 +46,10 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.setSingleOverridden
import org.jetbrains.kotlin.util.findCallableMemberBySignature import org.jetbrains.kotlin.util.findCallableMemberBySignature
interface OverrideMemberChooserObject : ClassMember { interface OverrideMemberChooserObject : ClassMember {
sealed class BodyType { sealed class BodyType(val requiresReturn: Boolean = true) {
object NO_BODY : BodyType() object NO_BODY : BodyType()
object EMPTY : BodyType() object EMPTY_OR_TEMPLATE : BodyType(requiresReturn = false)
object FROM_TEMPLATE : BodyType(requiresReturn = false)
object SUPER : BodyType() object SUPER : BodyType()
object QUALIFIED_SUPER : BodyType() object QUALIFIED_SUPER : BodyType()
@@ -60,27 +62,36 @@ interface OverrideMemberChooserObject : ClassMember {
val preferConstructorParameter: Boolean val preferConstructorParameter: Boolean
companion object { companion object {
fun create(project: Project, fun create(
descriptor: CallableMemberDescriptor, project: Project,
immediateSuper: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
bodyType: BodyType, immediateSuper: CallableMemberDescriptor,
preferConstructorParameter: Boolean = false bodyType: BodyType,
preferConstructorParameter: Boolean = false
): OverrideMemberChooserObject { ): OverrideMemberChooserObject {
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
return if (declaration != null) { return if (declaration != null) {
WithDeclaration(descriptor, declaration, immediateSuper, bodyType, preferConstructorParameter) create(declaration, descriptor, immediateSuper, bodyType, preferConstructorParameter)
} } else {
else {
WithoutDeclaration(descriptor, immediateSuper, bodyType, preferConstructorParameter) 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( private class WithDeclaration(
descriptor: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
declaration: PsiElement, declaration: PsiElement,
override val immediateSuper: CallableMemberDescriptor, override val immediateSuper: CallableMemberDescriptor,
override val bodyType: BodyType, override val bodyType: BodyType,
override val preferConstructorParameter: Boolean override val preferConstructorParameter: Boolean
) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject { ) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject {
override val descriptor: CallableMemberDescriptor override val descriptor: CallableMemberDescriptor
@@ -88,40 +99,68 @@ interface OverrideMemberChooserObject : ClassMember {
} }
private class WithoutDeclaration( private class WithoutDeclaration(
override val descriptor: CallableMemberDescriptor, override val descriptor: CallableMemberDescriptor,
override val immediateSuper: CallableMemberDescriptor, override val immediateSuper: CallableMemberDescriptor,
override val bodyType: BodyType, override val bodyType: BodyType,
override val preferConstructorParameter: Boolean override val preferConstructorParameter: Boolean
) : MemberChooserObjectBase(DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)), OverrideMemberChooserObject { ) : MemberChooserObjectBase(
DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)
), OverrideMemberChooserObject {
override fun getParentNodeDelegate(): MemberChooserObject? { override fun getParentNodeDelegate(): MemberChooserObject? {
val parentClassifier = descriptor.containingDeclaration as? ClassifierDescriptor ?: return null 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 { fun OverrideMemberChooserObject.generateTopLevelActual(
val project = targetClass.project 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 descriptor = immediateSuper
val bodyType = when { val bodyType = when {
targetClass.hasExpectModifier() -> OverrideMemberChooserObject.BodyType.NO_BODY targetClass?.hasExpectModifier() == true -> NO_BODY
descriptor.extensionReceiverParameter != null -> OverrideMemberChooserObject.BodyType.EMPTY descriptor.extensionReceiverParameter != null -> FROM_TEMPLATE
else -> bodyType 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) { val newMember: KtCallableDeclaration = when (descriptor) {
is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType) is FunctionDescriptor -> generateFunction(project, descriptor, renderer, bodyType)
is PropertyDescriptor -> generateProperty(project, descriptor, bodyType) is PropertyDescriptor -> generateProperty(project, descriptor, renderer, bodyType)
else -> error("Unknown member to override: $descriptor") else -> error("Unknown member to override: $descriptor")
} }
if (targetClass.hasActualModifier()) { if (forceActual) {
newMember.addModifier(KtTokens.ACTUAL_KEYWORD)
} else if (targetClass?.hasActualModifier() == true) {
val expectClassDescriptors = val expectClassDescriptors =
targetClass.resolveToDescriptorIfAny()?.expectedDescriptors()?.filterIsInstance<ClassDescriptor>().orEmpty() targetClass.resolveToDescriptorIfAny()?.expectedDescriptors()?.filterIsInstance<ClassDescriptor>().orEmpty()
if (expectClassDescriptors.any { expectClassDescriptor -> if (expectClassDescriptors.any { expectClassDescriptor ->
@@ -143,7 +182,7 @@ fun OverrideMemberChooserObject.generateMember(targetClass: KtClassOrObject, cop
findDocComment(superDeclaration) findDocComment(superDeclaration)
is PsiDocCommentOwner -> { is PsiDocCommentOwner -> {
val kDocText = superDeclaration.docComment?.let { IdeaDocCommentConverter.convertDocComment(it) } 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 else -> null
} }
@@ -171,6 +210,12 @@ private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
presentableUnresolvedTypes = true presentableUnresolvedTypes = true
} }
private val ACTUAL_RENDERER = OVERRIDE_RENDERER.withOptions {
modifiers = setOf(DescriptorRendererModifier.ANNOTATIONS)
renderConstructorKeyword = true
secondaryConstructorsAsPrimary = false
}
private fun PropertyDescriptor.wrap(): PropertyDescriptor { private fun PropertyDescriptor.wrap(): PropertyDescriptor {
val delegate = copy(containingDeclaration, Modality.OPEN, visibility, kind, true) as PropertyDescriptor val delegate = copy(containingDeclaration, Modality.OPEN, visibility, kind, true) as PropertyDescriptor
val newDescriptor = object : PropertyDescriptor by delegate { val newDescriptor = object : PropertyDescriptor by delegate {
@@ -181,74 +226,112 @@ private fun PropertyDescriptor.wrap(): PropertyDescriptor {
} }
private fun FunctionDescriptor.wrap(): FunctionDescriptor { private fun FunctionDescriptor.wrap(): FunctionDescriptor {
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() = Modality.OPEN
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() = 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 { private fun ClassConstructorDescriptor.wrap(): ClassConstructorDescriptor {
val newDescriptor = descriptor.wrap() return object : ClassConstructorDescriptor by this {
val body = override fun isExpect() = false
if (bodyType != OverrideMemberChooserObject.BodyType.NO_BODY) { override fun getModality() = Modality.FINAL
buildString { override fun getReturnType() = this@wrap.returnType.approximateFlexibleTypes(preferNotNull = true, preferStarForRaw = true)
append("\nget()") override fun getOverriddenDescriptors() = listOf(this@wrap)
append(" = ") override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D) =
append(generateUnsupportedOrSuperCall(project, descriptor, bodyType)) visitor.visitConstructorDescriptor(this, data)
if (descriptor.isVar) { }
append("\nset(value) {}")
}
}
} else ""
return KtPsiFactory(project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
} }
private fun generateConstructorParameter(project: Project, descriptor: PropertyDescriptor): KtParameter { private fun generateProperty(
val newDescriptor = descriptor.wrap() project: Project,
newDescriptor.setSingleOverridden(descriptor) descriptor: PropertyDescriptor,
return KtPsiFactory(project).createParameter(OVERRIDE_RENDERER.render(newDescriptor)) renderer: DescriptorRenderer,
} bodyType: OverrideMemberChooserObject.BodyType
): KtProperty {
private fun generateFunction(project: Project, descriptor: FunctionDescriptor, bodyType: OverrideMemberChooserObject.BodyType): KtNamedFunction {
val newDescriptor = descriptor.wrap() val newDescriptor = descriptor.wrap()
val returnType = descriptor.returnType val returnType = descriptor.returnType
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType) val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
val body = if (bodyType != OverrideMemberChooserObject.BodyType.NO_BODY) { val body =
val delegation = generateUnsupportedOrSuperCall(project, descriptor, bodyType) if (bodyType != NO_BODY) {
"{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "\n}" buildString {
} append("\nget()")
else "" 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( fun generateUnsupportedOrSuperCall(
project: Project, project: Project,
descriptor: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
bodyType: OverrideMemberChooserObject.BodyType bodyType: OverrideMemberChooserObject.BodyType,
canBeEmpty: Boolean = true
): String { ): String {
if (bodyType == OverrideMemberChooserObject.BodyType.EMPTY) { val effectiveBodyType = if (!canBeEmpty && bodyType == EMPTY_OR_TEMPLATE) FROM_TEMPLATE else bodyType
val templateKind = if (descriptor is FunctionDescriptor) TemplateKind.FUNCTION else TemplateKind.PROPERTY_INITIALIZER when (effectiveBodyType) {
return getFunctionBodyTextFromTemplate(project, EMPTY_OR_TEMPLATE -> return ""
templateKind, FROM_TEMPLATE -> {
descriptor.name.asString(), val templateKind = if (descriptor is FunctionDescriptor) TemplateKind.FUNCTION else TemplateKind.PROPERTY_INITIALIZER
descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "Unit", return getFunctionBodyTextFromTemplate(
null) project,
} templateKind,
else { descriptor.name.asString(),
return buildString { descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "Unit",
null
)
}
else -> return buildString {
if (bodyType is OverrideMemberChooserObject.BodyType.Delegate) { if (bodyType is OverrideMemberChooserObject.BodyType.Delegate) {
append(bodyType.receiverName) append(bodyType.receiverName)
} } else {
else {
append("super") append("super")
if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) { if (bodyType == QUALIFIED_SUPER) {
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor) val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(
descriptor.containingDeclaration as ClassifierDescriptor
)
append("<").append(superClassFqName).append(">") append("<").append(superClassFqName).append(">")
} }
} }
@@ -69,7 +69,7 @@ class OverrideMembersHandler(private val preferConstructorParameters: Boolean =
descriptor.kind == ClassKind.INTERFACE && realSuper.builtIns.isMemberOfAny(realSuper) -> descriptor.kind == ClassKind.INTERFACE && realSuper.builtIns.isMemberOfAny(realSuper) ->
OverrideMemberChooserObject.BodyType.NO_BODY OverrideMemberChooserObject.BodyType.NO_BODY
immediateSuperToUse.modality == Modality.ABSTRACT -> immediateSuperToUse.modality == Modality.ABSTRACT ->
OverrideMemberChooserObject.BodyType.EMPTY OverrideMemberChooserObject.BodyType.FROM_TEMPLATE
realSupersToUse.size == 1 -> realSupersToUse.size == 1 ->
OverrideMemberChooserObject.BodyType.SUPER OverrideMemberChooserObject.BodyType.SUPER
else -> else ->
@@ -184,7 +184,7 @@ abstract class KotlinGenerateTestSupportActionBase(
val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor
val overriddenDescriptors = functionDescriptor.overriddenDescriptors val overriddenDescriptors = functionDescriptor.overriddenDescriptors
val bodyText = when (overriddenDescriptors.size) { val bodyText = when (overriddenDescriptors.size) {
0 -> generateUnsupportedOrSuperCall(project, functionDescriptor, BodyType.EMPTY) 0 -> generateUnsupportedOrSuperCall(project, functionDescriptor, BodyType.FROM_TEMPLATE)
1 -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.single(), BodyType.SUPER) 1 -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.single(), BodyType.SUPER)
else -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.first(), BodyType.QUALIFIED_SUPER) else -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.first(), BodyType.QUALIFIED_SUPER)
} }
@@ -184,7 +184,7 @@ abstract class KotlinGenerateTestSupportActionBase(
val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor
val overriddenDescriptors = functionDescriptor.overriddenDescriptors val overriddenDescriptors = functionDescriptor.overriddenDescriptors
val bodyText = when (overriddenDescriptors.size) { val bodyText = when (overriddenDescriptors.size) {
0 -> generateUnsupportedOrSuperCall(project, functionDescriptor, BodyType.EMPTY) 0 -> generateUnsupportedOrSuperCall(project, functionDescriptor, BodyType.FROM_TEMPLATE)
1 -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.single(), BodyType.SUPER) 1 -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.single(), BodyType.SUPER)
else -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.first(), BodyType.QUALIFIED_SUPER) else -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.first(), BodyType.QUALIFIED_SUPER)
} }
@@ -80,6 +80,6 @@ fun confirmMemberRewrite(targetClass: KtClass, vararg descriptors: FunctionDescr
fun generateFunctionSkeleton(descriptor: FunctionDescriptor, targetClass: KtClassOrObject): KtNamedFunction { fun generateFunctionSkeleton(descriptor: FunctionDescriptor, targetClass: KtClassOrObject): KtNamedFunction {
return OverrideMemberChooserObject return OverrideMemberChooserObject
.create(targetClass.project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY) .create(targetClass.project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE)
.generateMember(targetClass, false) as KtNamedFunction .generateMember(targetClass, false) as KtNamedFunction
} }
@@ -126,7 +126,7 @@ abstract class ImplementAbstractMemberIntentionBase :
val chooserObject = OverrideMemberChooserObject.create(member.project, val chooserObject = OverrideMemberChooserObject.create(member.project,
descriptorToImplement, descriptorToImplement,
descriptorToImplement, descriptorToImplement,
OverrideMemberChooserObject.BodyType.EMPTY, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE,
preferConstructorParameters) preferConstructorParameters)
OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false) OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false)
} }
@@ -126,7 +126,7 @@ abstract class ImplementAbstractMemberIntentionBase :
val chooserObject = OverrideMemberChooserObject.create(member.project, val chooserObject = OverrideMemberChooserObject.create(member.project,
descriptorToImplement, descriptorToImplement,
descriptorToImplement, descriptorToImplement,
OverrideMemberChooserObject.BodyType.EMPTY, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE,
preferConstructorParameters) preferConstructorParameters)
OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false) OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false)
} }
@@ -19,13 +19,16 @@ 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.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
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.core.ShortenReferences
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
@@ -53,7 +56,9 @@ class AddActualFix(
listOfNotNull(element.primaryConstructor) listOfNotNull(element.primaryConstructor)
) )
for (declaration in pureActualClass.declarations) { for (declaration in pureActualClass.declarations) {
element.addDeclaration(declaration) val actualDeclaration = element.addDeclaration(declaration)
val reformatted = CodeStyleManager.getInstance(project).reformat(actualDeclaration)
ShortenReferences.DEFAULT.process(reformatted as KtElement)
} }
val primaryConstructor = pureActualClass.primaryConstructor val primaryConstructor = pureActualClass.primaryConstructor
if (element.primaryConstructor == null && primaryConstructor != null) { if (element.primaryConstructor == null && primaryConstructor != null) {
@@ -25,7 +25,6 @@ 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.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -36,10 +35,12 @@ 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.generateActualMember
import org.jetbrains.kotlin.idea.core.overrideImplement.generateTopLevelActual
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.actualsForExpected import org.jetbrains.kotlin.idea.util.actualsForExpected
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
@@ -192,7 +193,7 @@ class CreateActualPropertyFix(
actualPlatform: MultiTargetPlatform.Specific actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element -> ) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? PropertyDescriptor val descriptor = element.toDescriptor() as? PropertyDescriptor
descriptor?.let { generateProperty(project, element, descriptor, actualNeeded = true) } descriptor?.let { generateProperty(project, element, descriptor) }
}) { }) {
override val elementType = "property" override val elementType = "property"
@@ -204,7 +205,7 @@ class CreateActualFunctionFix(
actualPlatform: MultiTargetPlatform.Specific actualPlatform: MultiTargetPlatform.Specific
) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element -> ) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element ->
val descriptor = element.toDescriptor() as? FunctionDescriptor val descriptor = element.toDescriptor() as? FunctionDescriptor
descriptor?.let { generateFunction(project, element, descriptor, actualNeeded = true) } descriptor?.let { generateFunction(project, element, descriptor) }
}) { }) {
override val elementType = "function" override val elementType = "function"
@@ -294,6 +295,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
} }
} }
} }
actualClass.replaceExpectModifier(actualNeeded)
declLoop@ for (expectedDeclaration in expectedClass.declarations.filter { !it.exists() }) { declLoop@ for (expectedDeclaration in expectedClass.declarations.filter { !it.exists() }) {
val descriptor = expectedDeclaration.toDescriptor() ?: continue val descriptor = expectedDeclaration.toDescriptor() ?: continue
@@ -309,8 +311,8 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
continue@declLoop continue@declLoop
} }
when (expectedDeclaration) { when (expectedDeclaration) {
is KtFunction -> generateFunction(project, expectedDeclaration, descriptor as FunctionDescriptor, actualNeeded = true) is KtFunction -> generateFunction(project, expectedDeclaration, descriptor as FunctionDescriptor, actualClass)
is KtProperty -> generateProperty(project, expectedDeclaration, descriptor as PropertyDescriptor, actualNeeded = true) is KtProperty -> generateProperty(project, expectedDeclaration, descriptor as PropertyDescriptor, actualClass)
else -> continue@declLoop else -> continue@declLoop
} }
} }
@@ -329,9 +331,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
it.removeParameterDefaultValues() it.removeParameterDefaultValues()
} }
return actualClass.apply { return actualClass
replaceExpectModifier(actualNeeded)
}
} }
private val forbiddenAnnotationFqNames = setOf( private val forbiddenAnnotationFqNames = setOf(
@@ -340,41 +340,20 @@ private val forbiddenAnnotationFqNames = setOf(
ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME
) )
private fun KtPsiFactory.generateFunction( private fun generateFunction(
project: Project, project: Project,
expectedFunction: KtFunction, expectedFunction: KtFunction,
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
actualNeeded: Boolean targetClass: KtClassOrObject? = null
): KtFunction { ): KtFunction {
val returnType = descriptor.returnType val memberChooserObject = OverrideMemberChooserObject.create(
val body = run { expectedFunction, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
if (expectedFunction.hasBody()) { )
"" return if (targetClass != null) {
} else if (returnType != null && !KotlinBuiltIns.isUnit(returnType)) { memberChooserObject.generateActualMember(targetClass = targetClass, copyDoc = true)
val delegation = getFunctionBodyTextFromTemplate(
project,
TemplateKind.FUNCTION,
descriptor.name.asString(),
IdeDescriptorRenderers.SOURCE_CODE.renderType(returnType)
)
"{$delegation\n}"
} else {
"{}"
}
}
return (if (expectedFunction is KtSecondaryConstructor) {
createSecondaryConstructor(expectedFunction.text + " " + body)
} else { } else {
createFunction(expectedFunction.text + " " + body) memberChooserObject.generateTopLevelActual(copyDoc = true, project = project)
} as KtFunction).apply { } as KtFunction
replaceExpectModifier(actualNeeded)
if (returnType != null && KotlinBuiltIns.isUnit(returnType)) {
typeReference = null
}
removeParameterDefaultValues()
}
} }
private fun KtFunction.removeParameterDefaultValues() { private fun KtFunction.removeParameterDefaultValues() {
@@ -387,27 +366,20 @@ private fun KtFunction.removeParameterDefaultValues() {
} }
} }
private fun KtPsiFactory.generateProperty( private fun generateProperty(
project: Project, project: Project,
expectedProperty: KtProperty, expectedProperty: KtProperty,
descriptor: PropertyDescriptor, descriptor: PropertyDescriptor,
actualNeeded: Boolean targetClass: KtClassOrObject? = null
): KtProperty { ): KtProperty {
val body = buildString { val memberChooserObject = OverrideMemberChooserObject.create(
append("\nget()") expectedProperty, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
append(" = ") )
append(getFunctionBodyTextFromTemplate( return if (targetClass != null) {
project, memberChooserObject.generateActualMember(targetClass = targetClass, copyDoc = true)
TemplateKind.FUNCTION, } else {
descriptor.name.asString(), memberChooserObject.generateTopLevelActual(copyDoc = true, project = project)
descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "" } as KtProperty
))
if (descriptor.isVar) {
append("\nset(value) {}")
}
}
return createProperty(expectedProperty.text + " " + body).apply {
replaceExpectModifier(actualNeeded)
}
} }
@@ -9,5 +9,5 @@ actual abstract class Abstract {
} }
actual val isGood: Boolean actual val isGood: Boolean
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
} }
+4 -3
View File
@@ -8,16 +8,17 @@ actual class My {
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 fun baz() {} actual fun baz() {
}
actual constructor(flag: Boolean) { actual constructor(flag: Boolean) {
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 val isGood: Boolean actual val isGood: Boolean
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
actual var status: Int actual var status: Int
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
set(value) {} set(value) {}
} }
@@ -4,5 +4,6 @@
actual class My { actual class My {
actual constructor() actual constructor()
actual fun test() {} actual fun test() {
}
} }
@@ -4,5 +4,6 @@
actual class My { actual class My {
actual constructor(a: Int, b: String) actual constructor(a: Int, b: String)
actual fun test() {} actual fun test() {
}
} }
@@ -4,5 +4,6 @@
actual class My actual constructor(a: Int, b: String) { actual class My actual constructor(a: Int, b: String) {
actual constructor(b: String, a: Int) actual constructor(b: String, a: Int)
actual fun test() {} actual fun test() {
}
} }
@@ -3,5 +3,5 @@
actual class <caret>My(actual val name: String) { actual class <caret>My(actual val name: String) {
actual val age: String actual val age: String
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
} }
@@ -6,7 +6,7 @@ actual class <caret>My {
actual val correct = true actual val correct = true
actual val x: String actual val x: String
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
actual val pi: Double actual val pi: Double
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
} }
@@ -2,6 +2,6 @@
// DISABLE-ERRORS // DISABLE-ERRORS
actual class My { actual class My {
// Incompilable function actual fun foo() {
actual fun foo() {} }
} }
@@ -0,0 +1,7 @@
// "Create actual class for module proj_JVM (JVM)" "true"
import kotlin.random.Random
expect class My<caret>Generator {
fun generate(): Random
}
@@ -0,0 +1,7 @@
// "Create actual class for module proj_JVM (JVM)" "true"
import kotlin.random.Random
expect class MyGenerator {
fun generate(): Random
}
@@ -0,0 +1 @@
// MyGenerator: to be implemented
@@ -0,0 +1,8 @@
import kotlin.random.Random
// MyGenerator: to be implemented
actual class MyGenerator {
actual fun generate(): Random {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
@@ -3,7 +3,8 @@
actual class WithCompanion { actual class WithCompanion {
actual companion object { actual companion object {
actual fun foo() {} actual fun foo() {
}
} }
} }
@@ -1,4 +1,5 @@
// to be created // to be created
actual class C { actual class C {
actual fun f(p: Int) {} actual fun f(p: Int) {
}
} }
+1 -1
View File
@@ -5,6 +5,6 @@ actual enum class MyEnum {
LAST; LAST;
actual val num: Int actual val num: Int
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
} }
@@ -9,7 +9,8 @@ actual interface Interface {
actual var status: Int actual var status: Int
actual class Nested { actual class Nested {
actual fun bar() {} actual fun bar() {
}
} }
} }
@@ -5,11 +5,13 @@ actual class WithNested {
} }
actual class Nested { actual class Nested {
actual fun bar() {} actual fun bar() {
}
} }
actual inner class Inner { actual inner class Inner {
actual fun baz() {} actual fun baz() {
}
} }
} }
+1 -1
View File
@@ -1,4 +1,4 @@
// x: to be implemented // x: to be implemented
actual var x: Int actual var x: Int
get() = TODO("not implemented") //To change body of created functions use File | Settings | File Templates. get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
set(value) {} set(value) {}
@@ -3,4 +3,5 @@
package test package test
actual fun testHelper() {} actual fun testHelper() {
}
@@ -1,2 +1,3 @@
// testHelper: to be implemented // testHelper: to be implemented
actual fun testHelper() {} actual fun testHelper() {
}
@@ -144,6 +144,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
runTest("idea/testData/multiModuleQuickFix/classWithIncompilableFunction/"); runTest("idea/testData/multiModuleQuickFix/classWithIncompilableFunction/");
} }
@TestMetadata("classWithJdk")
public void testClassWithJdk() throws Exception {
runTest("idea/testData/multiModuleQuickFix/classWithJdk/");
}
@TestMetadata("companionAbsence") @TestMetadata("companionAbsence")
public void testCompanionAbsence() throws Exception { public void testCompanionAbsence() throws Exception {
runTest("idea/testData/multiModuleQuickFix/companionAbsence/"); runTest("idea/testData/multiModuleQuickFix/companionAbsence/");