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 ->
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ abstract class KotlinGenerateTestSupportActionBase(
|
||||
val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor
|
||||
val overriddenDescriptors = functionDescriptor.overriddenDescriptors
|
||||
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)
|
||||
else -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.first(), BodyType.QUALIFIED_SUPER)
|
||||
}
|
||||
|
||||
+1
-1
@@ -184,7 +184,7 @@ abstract class KotlinGenerateTestSupportActionBase(
|
||||
val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor
|
||||
val overriddenDescriptors = functionDescriptor.overriddenDescriptors
|
||||
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)
|
||||
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 {
|
||||
return OverrideMemberChooserObject
|
||||
.create(targetClass.project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY)
|
||||
.create(targetClass.project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE)
|
||||
.generateMember(targetClass, false) as KtNamedFunction
|
||||
}
|
||||
@@ -126,7 +126,7 @@ abstract class ImplementAbstractMemberIntentionBase :
|
||||
val chooserObject = OverrideMemberChooserObject.create(member.project,
|
||||
descriptorToImplement,
|
||||
descriptorToImplement,
|
||||
OverrideMemberChooserObject.BodyType.EMPTY,
|
||||
OverrideMemberChooserObject.BodyType.FROM_TEMPLATE,
|
||||
preferConstructorParameters)
|
||||
OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false)
|
||||
}
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ abstract class ImplementAbstractMemberIntentionBase :
|
||||
val chooserObject = OverrideMemberChooserObject.create(member.project,
|
||||
descriptorToImplement,
|
||||
descriptorToImplement,
|
||||
OverrideMemberChooserObject.BodyType.EMPTY,
|
||||
OverrideMemberChooserObject.BodyType.FROM_TEMPLATE,
|
||||
preferConstructorParameters)
|
||||
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.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
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.KotlinSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||
@@ -53,7 +56,9 @@ class AddActualFix(
|
||||
listOfNotNull(element.primaryConstructor)
|
||||
)
|
||||
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
|
||||
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.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
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.resolve.analyzeWithContent
|
||||
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.KotlinSingleIntentionActionFactory
|
||||
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.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
@@ -192,7 +193,7 @@ class CreateActualPropertyFix(
|
||||
actualPlatform: MultiTargetPlatform.Specific
|
||||
) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, element ->
|
||||
val descriptor = element.toDescriptor() as? PropertyDescriptor
|
||||
descriptor?.let { generateProperty(project, element, descriptor, actualNeeded = true) }
|
||||
descriptor?.let { generateProperty(project, element, descriptor) }
|
||||
}) {
|
||||
|
||||
override val elementType = "property"
|
||||
@@ -204,7 +205,7 @@ class CreateActualFunctionFix(
|
||||
actualPlatform: MultiTargetPlatform.Specific
|
||||
) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, element ->
|
||||
val descriptor = element.toDescriptor() as? FunctionDescriptor
|
||||
descriptor?.let { generateFunction(project, element, descriptor, actualNeeded = true) }
|
||||
descriptor?.let { generateFunction(project, element, descriptor) }
|
||||
}) {
|
||||
|
||||
override val elementType = "function"
|
||||
@@ -294,6 +295,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
}
|
||||
}
|
||||
}
|
||||
actualClass.replaceExpectModifier(actualNeeded)
|
||||
|
||||
declLoop@ for (expectedDeclaration in expectedClass.declarations.filter { !it.exists() }) {
|
||||
val descriptor = expectedDeclaration.toDescriptor() ?: continue
|
||||
@@ -309,8 +311,8 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
continue@declLoop
|
||||
}
|
||||
when (expectedDeclaration) {
|
||||
is KtFunction -> generateFunction(project, expectedDeclaration, descriptor as FunctionDescriptor, actualNeeded = true)
|
||||
is KtProperty -> generateProperty(project, expectedDeclaration, descriptor as PropertyDescriptor, actualNeeded = true)
|
||||
is KtFunction -> generateFunction(project, expectedDeclaration, descriptor as FunctionDescriptor, actualClass)
|
||||
is KtProperty -> generateProperty(project, expectedDeclaration, descriptor as PropertyDescriptor, actualClass)
|
||||
else -> continue@declLoop
|
||||
}
|
||||
}
|
||||
@@ -329,9 +331,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
it.removeParameterDefaultValues()
|
||||
}
|
||||
|
||||
return actualClass.apply {
|
||||
replaceExpectModifier(actualNeeded)
|
||||
}
|
||||
return actualClass
|
||||
}
|
||||
|
||||
private val forbiddenAnnotationFqNames = setOf(
|
||||
@@ -340,41 +340,20 @@ private val forbiddenAnnotationFqNames = setOf(
|
||||
ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME
|
||||
)
|
||||
|
||||
private fun KtPsiFactory.generateFunction(
|
||||
private fun generateFunction(
|
||||
project: Project,
|
||||
expectedFunction: KtFunction,
|
||||
descriptor: FunctionDescriptor,
|
||||
actualNeeded: Boolean
|
||||
targetClass: KtClassOrObject? = null
|
||||
): KtFunction {
|
||||
val returnType = descriptor.returnType
|
||||
val body = run {
|
||||
if (expectedFunction.hasBody()) {
|
||||
""
|
||||
} else if (returnType != null && !KotlinBuiltIns.isUnit(returnType)) {
|
||||
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)
|
||||
val memberChooserObject = OverrideMemberChooserObject.create(
|
||||
expectedFunction, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
|
||||
)
|
||||
return if (targetClass != null) {
|
||||
memberChooserObject.generateActualMember(targetClass = targetClass, copyDoc = true)
|
||||
} else {
|
||||
createFunction(expectedFunction.text + " " + body)
|
||||
} as KtFunction).apply {
|
||||
replaceExpectModifier(actualNeeded)
|
||||
if (returnType != null && KotlinBuiltIns.isUnit(returnType)) {
|
||||
typeReference = null
|
||||
}
|
||||
removeParameterDefaultValues()
|
||||
}
|
||||
memberChooserObject.generateTopLevelActual(copyDoc = true, project = project)
|
||||
} as KtFunction
|
||||
}
|
||||
|
||||
private fun KtFunction.removeParameterDefaultValues() {
|
||||
@@ -387,27 +366,20 @@ private fun KtFunction.removeParameterDefaultValues() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtPsiFactory.generateProperty(
|
||||
private fun generateProperty(
|
||||
project: Project,
|
||||
expectedProperty: KtProperty,
|
||||
descriptor: PropertyDescriptor,
|
||||
actualNeeded: Boolean
|
||||
targetClass: KtClassOrObject? = null
|
||||
): KtProperty {
|
||||
val body = buildString {
|
||||
append("\nget()")
|
||||
append(" = ")
|
||||
append(getFunctionBodyTextFromTemplate(
|
||||
project,
|
||||
TemplateKind.FUNCTION,
|
||||
descriptor.name.asString(),
|
||||
descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: ""
|
||||
))
|
||||
if (descriptor.isVar) {
|
||||
append("\nset(value) {}")
|
||||
}
|
||||
}
|
||||
return createProperty(expectedProperty.text + " " + body).apply {
|
||||
replaceExpectModifier(actualNeeded)
|
||||
}
|
||||
val memberChooserObject = OverrideMemberChooserObject.create(
|
||||
expectedProperty, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE
|
||||
)
|
||||
return if (targetClass != null) {
|
||||
memberChooserObject.generateActualMember(targetClass = targetClass, copyDoc = true)
|
||||
} else {
|
||||
memberChooserObject.generateTopLevelActual(copyDoc = true, project = project)
|
||||
} as KtProperty
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,5 +9,5 @@ actual abstract class Abstract {
|
||||
}
|
||||
|
||||
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
@@ -8,16 +8,17 @@ actual class My {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
actual fun baz() {}
|
||||
actual fun baz() {
|
||||
}
|
||||
|
||||
actual constructor(flag: Boolean) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
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
|
||||
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) {}
|
||||
|
||||
}
|
||||
+2
-1
@@ -4,5 +4,6 @@
|
||||
actual class My {
|
||||
actual constructor()
|
||||
|
||||
actual fun test() {}
|
||||
actual fun test() {
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-1
@@ -4,5 +4,6 @@
|
||||
actual class My {
|
||||
actual constructor(a: Int, b: String)
|
||||
|
||||
actual fun test() {}
|
||||
actual fun test() {
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -4,5 +4,6 @@
|
||||
actual class My actual constructor(a: Int, b: String) {
|
||||
actual constructor(b: String, a: Int)
|
||||
|
||||
actual fun test() {}
|
||||
actual fun test() {
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,5 +3,5 @@
|
||||
|
||||
actual class <caret>My(actual val name: 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 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
|
||||
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
-2
@@ -2,6 +2,6 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
actual class My {
|
||||
// Incompilable function
|
||||
actual fun foo() {}
|
||||
actual fun foo() {
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -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
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create actual class for module proj_JVM (JVM)" "true"
|
||||
|
||||
import kotlin.random.Random
|
||||
|
||||
expect class MyGenerator {
|
||||
fun generate(): Random
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
// MyGenerator: to be implemented
|
||||
+8
@@ -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.
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
|
||||
actual class WithCompanion {
|
||||
actual companion object {
|
||||
actual fun foo() {}
|
||||
actual fun foo() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
// to be created
|
||||
actual class C {
|
||||
actual fun f(p: Int) {}
|
||||
actual fun f(p: Int) {
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@ actual enum class MyEnum {
|
||||
LAST;
|
||||
|
||||
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 class Nested {
|
||||
actual fun bar() {}
|
||||
actual fun bar() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,11 +5,13 @@ actual class WithNested {
|
||||
}
|
||||
|
||||
actual class Nested {
|
||||
actual fun bar() {}
|
||||
actual fun bar() {
|
||||
}
|
||||
}
|
||||
|
||||
actual inner class Inner {
|
||||
actual fun baz() {}
|
||||
actual fun baz() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// x: to be implemented
|
||||
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) {}
|
||||
+2
-1
@@ -3,4 +3,5 @@
|
||||
|
||||
package test
|
||||
|
||||
actual fun testHelper() {}
|
||||
actual fun testHelper() {
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
// testHelper: to be implemented
|
||||
actual fun testHelper() {}
|
||||
actual fun testHelper() {
|
||||
}
|
||||
+5
@@ -144,6 +144,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
||||
runTest("idea/testData/multiModuleQuickFix/classWithIncompilableFunction/");
|
||||
}
|
||||
|
||||
@TestMetadata("classWithJdk")
|
||||
public void testClassWithJdk() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/classWithJdk/");
|
||||
}
|
||||
|
||||
@TestMetadata("companionAbsence")
|
||||
public void testCompanionAbsence() throws Exception {
|
||||
runTest("idea/testData/multiModuleQuickFix/companionAbsence/");
|
||||
|
||||
Reference in New Issue
Block a user