FIR IDE: extract common logic idea.core.overrideImplement

Also rename OverrideImplementMemberHandler to GenerateMemberHandler to
align with the naming of its member functions.
This commit is contained in:
Tianyu Geng
2021-04-12 14:15:33 -07:00
committed by TeamCityServer
parent 06ba143afe
commit 34387e228f
24 changed files with 264 additions and 195 deletions
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiElement
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
fun <T : KtDeclaration> insertMembersAfterAndReformat(
editor: Editor?,
classOrObject: KtClassOrObject,
members: Collection<T>,
anchor: PsiElement? = null,
getAnchor: (KtDeclaration) -> PsiElement? = { null },
): List<T> {
val codeStyleManager = CodeStyleManager.getInstance(classOrObject.project)
return runWriteAction {
val insertedMembersElementPointers = insertMembersAfter(editor, classOrObject, members, anchor, getAnchor)
val firstElement = insertedMembersElementPointers.firstOrNull() ?: return@runWriteAction emptyList()
fun insertedMembersElements() = insertedMembersElementPointers.mapNotNull { it.element }
ShortenReferences.DEFAULT.process(insertedMembersElements())
if (editor != null) {
firstElement.element?.let { moveCaretIntoGeneratedElement(editor, it) }
}
insertedMembersElementPointers.onEach { it.element?.let { element -> codeStyleManager.reformat(element) } }
insertedMembersElements()
}
}
fun <T : KtDeclaration> insertMember(editor: Editor?, classOrObject: KtClassOrObject, declaration: T, anchor: PsiElement? = null): T {
return insertMembersAfterAndReformat(editor, classOrObject, listOf(declaration), anchor).single()
}
@@ -16,28 +16,18 @@
package org.jetbrains.kotlin.idea.core.overrideImplement package org.jetbrains.kotlin.idea.core.overrideImplement
import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.hint.HintManager
import com.intellij.ide.util.MemberChooser
import com.intellij.lang.LanguageCodeInsightActionHandler
import com.intellij.openapi.application.ApplicationManager
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.openapi.ui.DialogWrapper
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.insertMembersAfter import org.jetbrains.kotlin.idea.core.insertMembersAfterAndReformat
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtParameter import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.prevSiblingOfSameType import org.jetbrains.kotlin.psi.psiUtil.prevSiblingOfSameType
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -45,74 +35,24 @@ import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.util.findCallableMemberBySignature import org.jetbrains.kotlin.util.findCallableMemberBySignature
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandler { abstract class GenerateMembersHandler : AbstractGenerateMembersHandler<OverrideMemberChooserObject>() {
fun collectMembersToGenerate(classOrObject: KtClassOrObject): Collection<OverrideMemberChooserObject> { override fun collectMembersToGenerate(classOrObject: KtClassOrObject): Collection<OverrideMemberChooserObject> {
val descriptor = classOrObject.resolveToDescriptorIfAny() ?: return emptySet() val descriptor = classOrObject.resolveToDescriptorIfAny() ?: return emptySet()
return collectMembersToGenerate(descriptor, classOrObject.project) return collectMembersToGenerate(descriptor, classOrObject.project)
} }
protected abstract fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> protected abstract fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject>
private fun showOverrideImplementChooser( override fun generateMembers(
project: Project, editor: Editor,
members: Array<OverrideMemberChooserObject> classOrObject: KtClassOrObject,
): MemberChooser<OverrideMemberChooserObject>? { selectedElements: Collection<OverrideMemberChooserObject>,
val chooser = MemberChooser(members, true, true, project) copyDoc: Boolean
chooser.title = getChooserTitle() ) {
chooser.show() return Companion.generateMembers(editor, classOrObject, selectedElements, copyDoc)
if (chooser.exitCode != DialogWrapper.OK_EXIT_CODE) return null
return chooser
} }
protected abstract fun getChooserTitle(): String
protected open fun isValidForClass(classOrObject: KtClassOrObject) = true
override fun isValidFor(editor: Editor, file: PsiFile): Boolean {
if (file !is KtFile) return false
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType<KtClassOrObject>()
return classOrObject != null && isValidForClass(classOrObject)
}
protected abstract fun getNoMembersFoundHint(): String
fun invoke(project: Project, editor: Editor, file: PsiFile, implementAll: Boolean) {
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType<KtClassOrObject>() ?: return
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return
val members = collectMembersToGenerate(classOrObject)
if (members.isEmpty() && !implementAll) {
HintManager.getInstance().showErrorHint(editor, getNoMembersFoundHint())
return
}
val copyDoc: Boolean
val selectedElements: Collection<OverrideMemberChooserObject>
if (implementAll) {
selectedElements = members
copyDoc = false
} else {
val chooser = showOverrideImplementChooser(project, members.toTypedArray()) ?: return
selectedElements = chooser.selectedElements ?: return
copyDoc = chooser.isCopyJavadoc
}
if (selectedElements.isEmpty()) return
PsiDocumentManager.getInstance(project).commitAllDocuments()
generateMembers(editor, classOrObject, selectedElements, copyDoc)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
invoke(project, editor, file, implementAll = ApplicationManager.getApplication().isUnitTestMode)
}
override fun startInWriteAction(): Boolean = false
companion object { companion object {
fun generateMembers( fun generateMembers(
editor: Editor?, editor: Editor?,
@@ -124,7 +64,7 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
val classBody = classOrObject.body val classBody = classOrObject.body
if (classBody == null) { if (classBody == null) {
insertMembersAfter(editor, classOrObject, selectedMemberDescriptors.keys) insertMembersAfterAndReformat(editor, classOrObject, selectedMemberDescriptors.keys)
return return
} }
val offset = editor?.caretModel?.offset ?: classBody.startOffset val offset = editor?.caretModel?.offset ?: classBody.startOffset
@@ -132,7 +72,7 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
it.parent == classBody it.parent == classBody
} }
if (offsetCursorElement != null && offsetCursorElement != classBody.rBrace) { if (offsetCursorElement != null && offsetCursorElement != classBody.rBrace) {
insertMembersAfter(editor, classOrObject, selectedMemberDescriptors.keys) insertMembersAfterAndReformat(editor, classOrObject, selectedMemberDescriptors.keys)
return return
} }
val classLeftBrace = classBody.lBrace val classLeftBrace = classBody.lBrace
@@ -173,7 +113,7 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
return lastElement return lastElement
} }
insertMembersAfter(editor, classOrObject, selectedMemberDescriptors.keys) { getAnchor(it) } insertMembersAfterAndReformat(editor, classOrObject, selectedMemberDescriptors.keys) { getAnchor(it) }
} }
} }
} }
@@ -22,8 +22,8 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.util.KotlinIdeaCoreBundle
import org.jetbrains.kotlin.idea.util.expectedDescriptors import org.jetbrains.kotlin.idea.util.expectedDescriptors
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
@@ -31,24 +31,24 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.resolve.OverrideResolver import org.jetbrains.kotlin.resolve.OverrideResolver
open class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction { open class ImplementMembersHandler : GenerateMembersHandler(), 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.FROM_TEMPLATE) } .map { OverrideMemberChooserObject.create(project, it, it, BodyType.FROM_TEMPLATE) }
} }
override fun getChooserTitle() = KotlinIdeaCoreBundle.message("implement.members.handler.title") override fun getChooserTitle() = KotlinBundle.message("implement.members.handler.title")
override fun getNoMembersFoundHint() = KotlinIdeaCoreBundle.message("implement.members.handler.no.members.hint") override fun getNoMembersFoundHint() = KotlinBundle.message("implement.members.handler.no.members.hint")
override fun getText() = familyName override fun getText() = familyName
override fun getFamilyName() = KotlinIdeaCoreBundle.message("implement.members.handler.family") override fun getFamilyName() = KotlinBundle.message("implement.members.handler.family")
override fun isAvailable(project: Project, editor: Editor, file: PsiFile) = isValidFor(editor, file) override fun isAvailable(project: Project, editor: Editor, file: PsiFile) = isValidFor(editor, file)
} }
class ImplementAsConstructorParameter : ImplementMembersHandler() { class ImplementAsConstructorParameter : ImplementMembersHandler() {
override fun getText() = KotlinIdeaCoreBundle.message("action.text.implement.as.constructor.parameters") override fun getText() = KotlinBundle.message("action.text.implement.as.constructor.parameters")
override fun isValidForClass(classOrObject: KtClassOrObject): Boolean { override fun isValidForClass(classOrObject: KtClassOrObject): Boolean {
if (classOrObject !is KtClass || classOrObject is KtEnumEntry || classOrObject.isInterface()) return false if (classOrObject !is KtClass || classOrObject is KtEnumEntry || classOrObject.isInterface()) return false
@@ -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)
.filterIsInstance<PropertyDescriptor>() .filterIsInstance<PropertyDescriptor>()
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.FROM_TEMPLATE, true) } .map { OverrideMemberChooserObject.create(project, it, it, BodyType.FROM_TEMPLATE, true) }
} }
} }
@@ -17,7 +17,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.overrideImplement.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
@@ -40,15 +40,6 @@ 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(val requiresReturn: Boolean = true) {
object NO_BODY : BodyType()
object EMPTY_OR_TEMPLATE : BodyType(requiresReturn = false)
object FROM_TEMPLATE : BodyType(requiresReturn = false)
object SUPER : BodyType()
object QUALIFIED_SUPER : BodyType()
class Delegate(val receiverName: String) : BodyType()
}
val descriptor: CallableMemberDescriptor val descriptor: CallableMemberDescriptor
val immediateSuper: CallableMemberDescriptor val immediateSuper: CallableMemberDescriptor
@@ -111,12 +102,6 @@ interface OverrideMemberChooserObject : ClassMember {
} }
} }
enum class MemberGenerateMode {
OVERRIDE,
ACTUAL,
EXPECT
}
fun OverrideMemberChooserObject.generateMember( fun OverrideMemberChooserObject.generateMember(
targetClass: KtClassOrObject, targetClass: KtClassOrObject,
copyDoc: Boolean copyDoc: Boolean
@@ -271,7 +256,7 @@ private fun generateProperty(
project: Project, project: Project,
descriptor: PropertyDescriptor, descriptor: PropertyDescriptor,
renderer: DescriptorRenderer, renderer: DescriptorRenderer,
bodyType: OverrideMemberChooserObject.BodyType, bodyType: BodyType,
forceOverride: Boolean forceOverride: Boolean
): KtProperty { ): KtProperty {
val newDescriptor = descriptor.wrap(forceOverride) val newDescriptor = descriptor.wrap(forceOverride)
@@ -308,7 +293,7 @@ private fun generateFunction(
project: Project, project: Project,
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
renderer: DescriptorRenderer, renderer: DescriptorRenderer,
bodyType: OverrideMemberChooserObject.BodyType, bodyType: BodyType,
forceOverride: Boolean forceOverride: Boolean
): KtFunction { ): KtFunction {
val newDescriptor = descriptor.wrap(forceOverride) val newDescriptor = descriptor.wrap(forceOverride)
@@ -336,13 +321,13 @@ private fun generateFunction(
} }
} }
private fun OverrideMemberChooserObject.BodyType.effectiveBodyType(canBeEmpty: Boolean): OverrideMemberChooserObject.BodyType = private fun BodyType.effectiveBodyType(canBeEmpty: Boolean): BodyType =
if (!canBeEmpty && this == EMPTY_OR_TEMPLATE) FROM_TEMPLATE else this if (!canBeEmpty && this == EMPTY_OR_TEMPLATE) FROM_TEMPLATE else this
fun generateUnsupportedOrSuperCall( fun generateUnsupportedOrSuperCall(
project: Project, project: Project,
descriptor: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
bodyType: OverrideMemberChooserObject.BodyType, bodyType: BodyType,
canBeEmpty: Boolean = true canBeEmpty: Boolean = true
): String { ): String {
when (bodyType.effectiveBodyType(canBeEmpty)) { when (bodyType.effectiveBodyType(canBeEmpty)) {
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import java.util.* import java.util.*
class OverrideMembersHandler(private val preferConstructorParameters: Boolean = false) : OverrideImplementMembersHandler() { class OverrideMembersHandler(private val preferConstructorParameters: Boolean = false) : GenerateMembersHandler() {
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> { override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
val result = ArrayList<OverrideMemberChooserObject>() val result = ArrayList<OverrideMemberChooserObject>()
for (member in descriptor.unsubstitutedMemberScope.getContributedDescriptors()) { for (member in descriptor.unsubstitutedMemberScope.getContributedDescriptors()) {
@@ -56,13 +56,13 @@ class OverrideMembersHandler(private val preferConstructorParameters: Boolean =
val bodyType = when { val bodyType = when {
descriptor.kind == ClassKind.INTERFACE && realSuper.builtIns.isMemberOfAny(realSuper) -> descriptor.kind == ClassKind.INTERFACE && realSuper.builtIns.isMemberOfAny(realSuper) ->
OverrideMemberChooserObject.BodyType.NO_BODY BodyType.NO_BODY
immediateSuperToUse.modality == Modality.ABSTRACT -> immediateSuperToUse.modality == Modality.ABSTRACT ->
OverrideMemberChooserObject.BodyType.FROM_TEMPLATE BodyType.FROM_TEMPLATE
realSupersToUse.size == 1 -> realSupersToUse.size == 1 ->
OverrideMemberChooserObject.BodyType.SUPER BodyType.SUPER
else -> else ->
OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER BodyType.QUALIFIED_SUPER
} }
result.add( result.add(
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -9,17 +9,14 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ScrollType import com.intellij.openapi.editor.ScrollType
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.SmartList import com.intellij.util.SmartList
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.ifEmpty
import kotlin.math.min import kotlin.math.min
fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) { fun moveCaretIntoGeneratedElement(editor: Editor, element: PsiElement) {
@@ -200,75 +197,55 @@ private fun removeAfterOffset(offset: Int, whiteSpace: PsiWhiteSpace): PsiElemen
return whiteSpace return whiteSpace
} }
@JvmOverloads
fun <T : KtDeclaration> insertMembersAfter( fun <T : KtDeclaration> insertMembersAfter(
editor: Editor?, editor: Editor?,
classOrObject: KtClassOrObject, classOrObject: KtClassOrObject,
members: Collection<T>, members: Collection<T>,
anchor: PsiElement? = null, anchor: PsiElement? = null,
getAnchor: (KtDeclaration) -> PsiElement? = { null } getAnchor: (KtDeclaration) -> PsiElement? = { null },
): List<T> { ): List<SmartPsiElementPointer<T>> {
members.ifEmpty { return emptyList() } members.ifEmpty { return emptyList() }
val project = classOrObject.project val insertedMembers = SmartList<SmartPsiElementPointer<T>>()
return runWriteAction { val (parameters, otherMembers) = members.partition { it is KtParameter }
val insertedMembers = SmartList<SmartPsiElementPointer<T>>()
fun insertedMembersElements() = insertedMembers.mapNotNull { it.element }
val (parameters, otherMembers) = members.partition { it is KtParameter } parameters.mapNotNullTo(insertedMembers) {
if (classOrObject !is KtClass) return@mapNotNullTo null
parameters.mapNotNullTo(insertedMembers) { @Suppress("UNCHECKED_CAST")
if (classOrObject !is KtClass) return@mapNotNullTo null SmartPointerManager.createPointer(
classOrObject.createPrimaryConstructorParameterListIfAbsent().addParameter(it as KtParameter) as T
)
}
if (otherMembers.isNotEmpty()) {
val body = classOrObject.getOrCreateBody()
var afterAnchor = anchor ?: findInsertAfterAnchor(editor, body) ?: return emptyList()
otherMembers.mapTo(insertedMembers) {
afterAnchor = getAnchor(it) ?: afterAnchor
if (classOrObject is KtClass && classOrObject.isEnum()) {
val enumEntries = classOrObject.declarations.filterIsInstance<KtEnumEntry>()
val bound = (enumEntries.lastOrNull() ?: classOrObject.allChildren.firstOrNull { element ->
element.node.elementType == KtTokens.SEMICOLON
})
if (it !is KtEnumEntry) {
if (bound != null && afterAnchor.startOffset <= bound.startOffset) {
afterAnchor = bound
}
} else if (bound == null && body.declarations.isNotEmpty()) {
afterAnchor = body.lBrace!!
} else if (bound != null && afterAnchor.startOffset > bound.startOffset) {
afterAnchor = bound.prevSibling!!
}
}
it.removeModifier(KtTokens.EXTERNAL_KEYWORD)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
SmartPointerManager.createPointer( SmartPointerManager.createPointer((body.addAfter(it, afterAnchor) as T).apply { afterAnchor = this })
classOrObject.createPrimaryConstructorParameterListIfAbsent().addParameter(it as KtParameter) as T
)
} }
if (otherMembers.isNotEmpty()) {
val body = classOrObject.getOrCreateBody()
var afterAnchor = anchor ?: findInsertAfterAnchor(editor, body) ?: return@runWriteAction emptyList<T>()
otherMembers.mapTo(insertedMembers) {
afterAnchor = getAnchor(it) ?: afterAnchor
if (classOrObject is KtClass && classOrObject.isEnum()) {
val enumEntries = classOrObject.declarations.filterIsInstance<KtEnumEntry>()
val bound = (enumEntries.lastOrNull() ?: classOrObject.allChildren.firstOrNull { element ->
element.node.elementType == KtTokens.SEMICOLON
})
if (it !is KtEnumEntry) {
if (bound != null && afterAnchor.startOffset <= bound.startOffset) {
afterAnchor = bound
}
} else if (bound == null && body.declarations.isNotEmpty()) {
afterAnchor = body.lBrace!!
} else if (bound != null && afterAnchor.startOffset > bound.startOffset) {
afterAnchor = bound.prevSibling!!
}
}
it.removeModifier(KtTokens.EXTERNAL_KEYWORD)
@Suppress("UNCHECKED_CAST")
SmartPointerManager.createPointer((body.addAfter(it, afterAnchor) as T).apply { afterAnchor = this })
}
}
ShortenReferences.DEFAULT.process(insertedMembersElements())
val firstElement = insertedMembersElements().firstOrNull() ?: return@runWriteAction emptyList()
if (editor != null) {
moveCaretIntoGeneratedElement(editor, firstElement)
}
val codeStyleManager = CodeStyleManager.getInstance(project)
insertedMembersElements().forEach { codeStyleManager.reformat(it) }
insertedMembersElements().toList()
} }
}
fun <T : KtDeclaration> insertMember(editor: Editor?, classOrObject: KtClassOrObject, declaration: T, anchor: PsiElement? = null): T { return insertedMembers
return insertMembersAfter(editor, classOrObject, listOf(declaration), anchor).single()
} }
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.overrideImplement
import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.generation.ClassMember
import com.intellij.codeInsight.hint.HintManager
import com.intellij.ide.util.MemberChooser
import com.intellij.lang.LanguageCodeInsightActionHandler
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
abstract class AbstractGenerateMembersHandler<T : ClassMember> : LanguageCodeInsightActionHandler {
abstract fun collectMembersToGenerate(classOrObject: KtClassOrObject): Collection<T>
protected abstract fun getChooserTitle(): String
protected abstract fun getNoMembersFoundHint(): String
protected abstract fun generateMembers(
editor: Editor,
classOrObject: KtClassOrObject,
selectedElements: Collection<T>,
copyDoc: Boolean
)
protected open fun isValidForClass(classOrObject: KtClassOrObject) = true
private fun showOverrideImplementChooser(
project: Project,
members: Collection<T>
): MemberChooser<T>? {
@Suppress("UNCHECKED_CAST")
val memberArray = members.toTypedArray<ClassMember>() as Array<T>
val chooser = MemberChooser(memberArray, true, true, project)
chooser.title = getChooserTitle()
chooser.show()
if (chooser.exitCode != DialogWrapper.OK_EXIT_CODE) return null
return chooser
}
override fun isValidFor(editor: Editor, file: PsiFile): Boolean {
if (file !is KtFile) return false
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType<KtClassOrObject>()
return classOrObject != null && isValidForClass(classOrObject)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
invoke(project, editor, file, implementAll = ApplicationManager.getApplication().isUnitTestMode)
}
fun invoke(project: Project, editor: Editor, file: PsiFile, implementAll: Boolean) {
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType<KtClassOrObject>() ?: return
if (!FileModificationService.getInstance().prepareFileForWrite(file)) return
val members = collectMembersToGenerate(classOrObject)
if (members.isEmpty() && !implementAll) {
HintManager.getInstance().showErrorHint(editor, getNoMembersFoundHint())
return
}
val copyDoc: Boolean
val selectedElements: Collection<T
>
if (implementAll) {
selectedElements = members
copyDoc = false
} else {
val chooser = showOverrideImplementChooser(project, members) ?: return
selectedElements = chooser.selectedElements ?: return
copyDoc = chooser.isCopyJavadoc
}
if (selectedElements.isEmpty()) return
PsiDocumentManager.getInstance(project).commitAllDocuments()
generateMembers(editor, classOrObject, selectedElements, copyDoc)
}
override fun startInWriteAction(): Boolean = false
}
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.overrideImplement
sealed class BodyType(val requiresReturn: Boolean = true) {
object NO_BODY : BodyType()
object EMPTY_OR_TEMPLATE : BodyType(requiresReturn = false)
object FROM_TEMPLATE : BodyType(requiresReturn = false)
object SUPER : BodyType()
object QUALIFIED_SUPER : BodyType()
class Delegate(val receiverName: String) : BodyType()
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.core.overrideImplement
enum class MemberGenerateMode {
OVERRIDE,
ACTUAL,
EXPECT
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.CollectingNameValidator import org.jetbrains.kotlin.idea.core.CollectingNameValidator
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.insertMembersAfter import org.jetbrains.kotlin.idea.core.insertMembersAfterAndReformat
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.platform import org.jetbrains.kotlin.idea.project.platform
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -326,6 +326,6 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
addIfNotNull(generateHashCode(project, info, targetClass)) addIfNotNull(generateHashCode(project, info, targetClass))
} }
val anchor = with(targetClass.declarations) { lastIsInstanceOrNull<KtNamedFunction>() ?: lastOrNull() } val anchor = with(targetClass.declarations) { lastIsInstanceOrNull<KtNamedFunction>() ?: lastOrNull() }
return insertMembersAfter(editor, targetClass, prototypes, anchor) return insertMembersAfterAndReformat(editor, targetClass, prototypes, anchor)
} }
} }
@@ -124,7 +124,7 @@ class KotlinGenerateSecondaryConstructorAction : KotlinGenerateMemberActionBase<
return emptyList() return emptyList()
} }
insertMembersAfter(editor, targetClass, prototypes, findAnchor()) insertMembersAfterAndReformat(editor, targetClass, prototypes, findAnchor())
} }
} }
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.insertMember import org.jetbrains.kotlin.idea.core.insertMember
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType
import org.jetbrains.kotlin.idea.core.overrideImplement.generateUnsupportedOrSuperCall import org.jetbrains.kotlin.idea.core.overrideImplement.generateUnsupportedOrSuperCall
import org.jetbrains.kotlin.idea.j2k.j2k import org.jetbrains.kotlin.idea.j2k.j2k
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.setupEditorSelection import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.setupEditorSelection
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.insertMembersAfter import org.jetbrains.kotlin.idea.core.insertMembersAfterAndReformat
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -202,6 +202,6 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
val targetClass = info.classDescriptor.source.getPsi() as KtClass val targetClass = info.classDescriptor.source.getPsi() as KtClass
val prototype = generateToString(targetClass, info) ?: return emptyList() val prototype = generateToString(targetClass, info) ?: return emptyList()
val anchor = with(targetClass.declarations) { lastIsInstanceOrNull<KtNamedFunction>() ?: lastOrNull() } val anchor = with(targetClass.declarations) { lastIsInstanceOrNull<KtNamedFunction>() ?: lastOrNull() }
return insertMembersAfter(editor, targetClass, listOf(prototype), anchor) return insertMembersAfterAndReformat(editor, targetClass, listOf(prototype), anchor)
} }
} }
@@ -11,6 +11,7 @@ import com.intellij.openapi.ui.Messages
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -70,6 +71,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.FROM_TEMPLATE) .create(targetClass.project, descriptor, descriptor, BodyType.FROM_TEMPLATE)
.generateMember(targetClass, false) as KtNamedFunction .generateMember(targetClass, false) as KtNamedFunction
} }
@@ -30,7 +30,8 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType
import org.jetbrains.kotlin.idea.core.overrideImplement.GenerateMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress import org.jetbrains.kotlin.idea.core.util.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.refactoring.isAbstract import org.jetbrains.kotlin.idea.refactoring.isAbstract
@@ -120,10 +121,10 @@ abstract class ImplementAbstractMemberIntentionBase : SelfTargetingRangeIntentio
member.project, member.project,
descriptorToImplement, descriptorToImplement,
descriptorToImplement, descriptorToImplement,
OverrideMemberChooserObject.BodyType.FROM_TEMPLATE, BodyType.FROM_TEMPLATE,
preferConstructorParameters preferConstructorParameters
) )
OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false) GenerateMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false)
} }
private fun implementInJavaClass(member: KtNamedDeclaration, targetClass: PsiClass) { private fun implementInJavaClass(member: KtNamedDeclaration, targetClass: PsiClass) {
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.GenerateMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -60,7 +60,7 @@ class MakePrivateAndOverrideMemberFix(
if (makePrivate) { if (makePrivate) {
element.addModifier(KtTokens.PRIVATE_KEYWORD) element.addModifier(KtTokens.PRIVATE_KEYWORD)
} }
OverrideImplementMembersHandler.generateMembers(editor, containingClassOrObject, listOf(memberToOverride), false) GenerateMembersHandler.generateMembers(editor, containingClassOrObject, listOf(memberToOverride), false)
} }
object AccidentalOverrideFactory : KotlinSingleIntentionActionFactory() { object AccidentalOverrideFactory : KotlinSingleIntentionActionFactory() {
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
@@ -72,7 +73,7 @@ class SpecifyOverrideExplicitlyFix(
val overrideMemberChooserObject = OverrideMemberChooserObject.create( val overrideMemberChooserObject = OverrideMemberChooserObject.create(
project, delegatedDescriptor, overriddenDescriptor, project, delegatedDescriptor, overriddenDescriptor,
OverrideMemberChooserObject.BodyType.Delegate(delegateTargetDescriptor.name.asString()) BodyType.Delegate(delegateTargetDescriptor.name.asString())
) )
val member = overrideMemberChooserObject.generateMember(element, copyDoc = false) val member = overrideMemberChooserObject.generateMember(element, copyDoc = false)
val insertedMember = element.addDeclaration(member) val insertedMember = element.addDeclaration(member)
@@ -20,8 +20,8 @@ import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.findOrCreateDirectoryForPackage import org.jetbrains.kotlin.idea.core.findOrCreateDirectoryForPackage
import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix import org.jetbrains.kotlin.idea.core.getFqNameWithImplicitPrefix
import org.jetbrains.kotlin.idea.core.overrideImplement.MemberGenerateMode import org.jetbrains.kotlin.idea.core.overrideImplement.MemberGenerateMode
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType.EMPTY_OR_TEMPLATE import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType.EMPTY_OR_TEMPLATE
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType.NO_BODY import org.jetbrains.kotlin.idea.core.overrideImplement.BodyType.NO_BODY
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.Companion.create import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.Companion.create
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual
@@ -19,7 +19,7 @@ import com.intellij.util.SmartList
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.GenerateMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMembersHandler
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
@@ -88,33 +88,33 @@ abstract class AbstractOverrideImplementTest : KotlinLightCodeInsightFixtureTest
myFixture.checkResultByFile(getTestName(true) + "/foo/JavaClass.java.after") myFixture.checkResultByFile(getTestName(true) + "/foo/JavaClass.java.after")
} }
private fun doFileTest(handler: OverrideImplementMembersHandler, memberToOverride: String? = null) { private fun doFileTest(handler: GenerateMembersHandler, memberToOverride: String? = null) {
myFixture.configureByFile(getTestName(true) + ".kt") myFixture.configureByFile(getTestName(true) + ".kt")
doOverrideImplement(handler, memberToOverride) doOverrideImplement(handler, memberToOverride)
checkResultByFile(getTestName(true) + ".kt.after") checkResultByFile(getTestName(true) + ".kt.after")
} }
private fun doMultiFileTest(handler: OverrideImplementMembersHandler) { private fun doMultiFileTest(handler: GenerateMembersHandler) {
myFixture.configureByFile(getTestName(true) + ".kt") myFixture.configureByFile(getTestName(true) + ".kt")
doMultiOverrideImplement(handler) doMultiOverrideImplement(handler)
checkResultByFile(getTestName(true) + ".kt.after") checkResultByFile(getTestName(true) + ".kt.after")
} }
private fun doDirectoryTest(handler: OverrideImplementMembersHandler, memberToOverride: String? = null) { private fun doDirectoryTest(handler: GenerateMembersHandler, memberToOverride: String? = null) {
myFixture.copyDirectoryToProject(getTestName(true), "") myFixture.copyDirectoryToProject(getTestName(true), "")
myFixture.configureFromTempProjectFile("foo/Impl.kt") myFixture.configureFromTempProjectFile("foo/Impl.kt")
doOverrideImplement(handler, memberToOverride) doOverrideImplement(handler, memberToOverride)
checkResultByFile(getTestName(true) + "/foo/Impl.kt.after") checkResultByFile(getTestName(true) + "/foo/Impl.kt.after")
} }
private fun doMultiDirectoryTest(handler: OverrideImplementMembersHandler) { private fun doMultiDirectoryTest(handler: GenerateMembersHandler) {
myFixture.copyDirectoryToProject(getTestName(true), "") myFixture.copyDirectoryToProject(getTestName(true), "")
myFixture.configureFromTempProjectFile("foo/Impl.kt") myFixture.configureFromTempProjectFile("foo/Impl.kt")
doMultiOverrideImplement(handler) doMultiOverrideImplement(handler)
checkResultByFile(getTestName(true) + "/foo/Impl.kt.after") checkResultByFile(getTestName(true) + "/foo/Impl.kt.after")
} }
private fun doOverrideImplement(handler: OverrideImplementMembersHandler, memberToOverride: String?) { private fun doOverrideImplement(handler: GenerateMembersHandler, memberToOverride: String?) {
val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset) val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)
val classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, KtClassOrObject::class.java) val classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, KtClassOrObject::class.java)
?: error("Caret should be inside class or object") ?: error("Caret should be inside class or object")
@@ -138,7 +138,7 @@ abstract class AbstractOverrideImplementTest : KotlinLightCodeInsightFixtureTest
performGenerateCommand(classOrObject, listOf(singleToOverride)) performGenerateCommand(classOrObject, listOf(singleToOverride))
} }
private fun doMultiOverrideImplement(handler: OverrideImplementMembersHandler) { private fun doMultiOverrideImplement(handler: GenerateMembersHandler) {
val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset) val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)
val classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, KtClassOrObject::class.java) val classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, KtClassOrObject::class.java)
?: error("Caret should be inside class or object") ?: error("Caret should be inside class or object")
@@ -167,7 +167,7 @@ abstract class AbstractOverrideImplementTest : KotlinLightCodeInsightFixtureTest
try { try {
val copyDoc = InTextDirectivesUtils.isDirectiveDefined(classOrObject.containingFile.text, "// COPY_DOC") val copyDoc = InTextDirectivesUtils.isDirectiveDefined(classOrObject.containingFile.text, "// COPY_DOC")
myFixture.project.executeWriteCommand("") { myFixture.project.executeWriteCommand("") {
OverrideImplementMembersHandler.generateMembers(myFixture.editor, classOrObject, selectedElements, copyDoc) GenerateMembersHandler.generateMembers(myFixture.editor, classOrObject, selectedElements, copyDoc)
} }
} catch (throwable: Throwable) { } catch (throwable: Throwable) {
throw rethrow(throwable) throw rethrow(throwable)