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:
committed by
TeamCityServer
parent
06ba143afe
commit
34387e228f
@@ -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()
|
||||||
|
}
|
||||||
+13
-73
@@ -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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-8
@@ -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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-20
@@ -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)) {
|
||||||
|
|||||||
+5
-5
@@ -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(
|
||||||
|
|||||||
+39
-62
@@ -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()
|
|
||||||
}
|
}
|
||||||
+95
@@ -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
|
||||||
|
}
|
||||||
+16
@@ -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()
|
||||||
|
}
|
||||||
+12
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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
-1
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
+2
-2
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -124,7 +124,7 @@ class KotlinGenerateSecondaryConstructorAction : KotlinGenerateMemberActionBase<
|
|||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMembersAfter(editor, targetClass, prototypes, findAnchor())
|
insertMembersAfterAndReformat(editor, targetClass, prototypes, findAnchor())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user