Drop bunch code by introduction wrapper for PopupChooserBuilder

This commit is contained in:
Nikolay Krasko
2019-01-09 20:11:30 +03:00
parent 3707812fc2
commit 4e9c8cee70
9 changed files with 33 additions and 1559 deletions
+1
View File
@@ -115,6 +115,7 @@
<Problem reference="com.intellij.openapi.extensions.ExtensionPointName#extensions(com.intellij.openapi.extensions.AreaInstance)" reason="Absent in 182." />
<Problem reference="com.intellij.openapi.extensions.ExtensionPointName#getPoint" reason="Absent in 182." />
<Problem reference="com.intellij.openapi.extensions.ExtensionPointName#findExtensionOrFail" reason="Absent in 182." />
<Problem reference="com.intellij.openapi.ui.popup.PopupChooserBuilder#PopupChooserBuilder(javax.swing.JList)" reason="Generified in 182. Use PopupChooserBuilderWrapper instead." />
</list>
</option>
</inspection_tool>
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.generateUnsupportedOrSup
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.setupEditorSelection
import org.jetbrains.kotlin.idea.refactoring.j2k
import org.jetbrains.kotlin.idea.testIntegration.findSuitableFrameworks
import org.jetbrains.kotlin.idea.util.PopupChooserBuilderWrapper
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
@@ -74,7 +75,7 @@ abstract class KotlinGenerateTestSupportActionBase(
val list = JBList<TestFramework>(*frameworks.toTypedArray())
list.cellRenderer = TestFrameworkListCellRenderer()
PopupChooserBuilder<TestFramework>(list)
PopupChooserBuilderWrapper<TestFramework>(list)
.setFilteringEnabled { (it as TestFramework).name }
.setTitle("Choose Framework")
.setItemChoosenCallback { consumer(list.selectedValue as TestFramework) }
@@ -1,261 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.actions.generate
import com.intellij.codeInsight.generation.actions.GenerateActionPopupTemplateInjector
import com.intellij.codeInsight.hint.HintManager
import com.intellij.ide.fileTemplates.FileTemplateManager
import com.intellij.ide.fileTemplates.impl.AllFileTemplatesConfigurable
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.InputValidator
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.popup.PopupChooserBuilder
import com.intellij.openapi.util.io.FileUtil
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiFile
import com.intellij.testIntegration.JavaTestFramework
import com.intellij.testIntegration.TestFramework
import com.intellij.testIntegration.TestIntegrationUtils.MethodKind
import com.intellij.ui.components.JBList
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.core.insertMember
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject.BodyType
import org.jetbrains.kotlin.idea.core.overrideImplement.generateUnsupportedOrSuperCall
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.setupEditorSelection
import org.jetbrains.kotlin.idea.refactoring.j2k
import org.jetbrains.kotlin.idea.testIntegration.findSuitableFrameworks
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
import org.jetbrains.kotlin.utils.ifEmpty
abstract class KotlinGenerateTestSupportActionBase(
private val methodKind : MethodKind
) : KotlinGenerateActionBase(), GenerateActionPopupTemplateInjector {
companion object {
private fun findTargetClass(editor: Editor, file: PsiFile): KtClassOrObject? {
val elementAtCaret = file.findElementAt(editor.caretModel.offset) ?: return null
return elementAtCaret.parentsWithSelf.filterIsInstance<KtClassOrObject>().firstOrNull { !it.isLocal }
}
private fun chooseAndPerform(editor: Editor, frameworks: List<TestFramework>, consumer: (TestFramework) -> Unit) {
frameworks.ifEmpty { return }
frameworks.singleOrNull()?.let { return consumer(it) }
if (ApplicationManager.getApplication().isUnitTestMode) return consumer(frameworks.first())
val list = JBList<TestFramework>(*frameworks.toTypedArray())
list.cellRenderer = TestFrameworkListCellRenderer()
PopupChooserBuilder(list)
.setFilteringEnabled { (it as TestFramework).name }
.setTitle("Choose Framework")
.setItemChoosenCallback { consumer(list.selectedValue as TestFramework) }
.setMovable(true)
.createPopup()
.showInBestPositionFor(editor)
}
private val BODY_VAR = "\${BODY}"
private val NAME_VAR = "\${NAME}"
private val NAME_VALIDATOR = object : InputValidator {
override fun checkInput(inputString: String) = inputString.quoteIfNeeded().isIdentifier()
override fun canClose(inputString: String) = true
}
}
class SetUp : KotlinGenerateTestSupportActionBase(MethodKind.SET_UP) {
override fun isApplicableTo(framework: TestFramework, targetClass: KtClassOrObject): Boolean {
return framework.findSetUpMethod(targetClass.toLightClass()!!) == null
}
}
class Test : KotlinGenerateTestSupportActionBase(MethodKind.TEST) {
override fun isApplicableTo(framework: TestFramework, targetClass: KtClassOrObject) = true
}
class Data : KotlinGenerateTestSupportActionBase(MethodKind.DATA) {
override fun isApplicableTo(framework: TestFramework, targetClass: KtClassOrObject): Boolean {
if (framework !is JavaTestFramework) return false
return framework.findParametersMethod(targetClass.toLightClass()) == null
}
}
class TearDown : KotlinGenerateTestSupportActionBase(MethodKind.TEAR_DOWN) {
override fun isApplicableTo(framework: TestFramework, targetClass: KtClassOrObject): Boolean {
return framework.findTearDownMethod(targetClass.toLightClass()!!) == null
}
}
override fun getTargetClass(editor: Editor, file: PsiFile): KtClassOrObject? {
return findTargetClass(editor, file)
}
override fun isValidForClass(targetClass: KtClassOrObject): Boolean {
return findSuitableFrameworks(targetClass).any { isApplicableTo(it, targetClass) }
}
protected abstract fun isApplicableTo(framework: TestFramework, targetClass: KtClassOrObject): Boolean
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
val klass = findTargetClass(editor, file) ?: return
if (testFrameworkToUse != null) {
val frameworkToUse = findSuitableFrameworks(klass).first { it.name == testFrameworkToUse }
if (isApplicableTo(frameworkToUse, klass)) {
doGenerate(editor, file, klass, frameworkToUse)
}
}
else {
val frameworks = findSuitableFrameworks(klass)
.filter { methodKind.getFileTemplateDescriptor(it) != null && isApplicableTo(it, klass) }
chooseAndPerform(editor, frameworks) { doGenerate(editor, file, klass, it) }
}
}
var testFrameworkToUse: String? = null
private val DUMMY_NAME = "__KOTLIN_RULEZZZ__"
private fun doGenerate(editor: Editor, file: PsiFile, klass: KtClassOrObject, framework: TestFramework) {
val project = file.project
val commandName = "Generate test function"
val fileTemplateDescriptor = methodKind.getFileTemplateDescriptor(framework)
val fileTemplate = FileTemplateManager.getInstance(project).getCodeTemplate(fileTemplateDescriptor.fileName)
var templateText = fileTemplate.text.replace(BODY_VAR, "")
var name: String? = null
if (templateText.contains(NAME_VAR)) {
name = if (templateText.contains("test$NAME_VAR")) "Name" else "name"
if (!ApplicationManager.getApplication().isUnitTestMode) {
name = Messages.showInputDialog("Choose test name: ", commandName, null, name, NAME_VALIDATOR)
?: return
}
templateText = fileTemplate.text.replace(NAME_VAR, DUMMY_NAME)
}
try {
var errorHint: String? = null
project.executeWriteCommand(commandName) {
PsiDocumentManager.getInstance(project).commitAllDocuments()
val factory = PsiElementFactory.SERVICE.getInstance(project)
val psiMethod = factory.createMethodFromText(templateText, null)
psiMethod.throwsList.referenceElements.forEach { it.delete() }
var function = psiMethod.j2k() as? KtNamedFunction ?: run {
errorHint = "Couldn't convert Java template to Kotlin"
return@executeWriteCommand
}
name?.let {
function = substituteNewName(function, it)
}
val functionInPlace = insertMember(editor, klass, function)
val functionDescriptor = functionInPlace.unsafeResolveToDescriptor() as FunctionDescriptor
val overriddenDescriptors = functionDescriptor.overriddenDescriptors
val bodyText = when (overriddenDescriptors.size) {
0 -> generateUnsupportedOrSuperCall(project, functionDescriptor, BodyType.FROM_TEMPLATE)
1 -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.single(), BodyType.SUPER)
else -> generateUnsupportedOrSuperCall(project, overriddenDescriptors.first(), BodyType.QUALIFIED_SUPER)
}
functionInPlace.bodyExpression?.delete()
functionInPlace.add(KtPsiFactory(project).createBlock(bodyText))
if (overriddenDescriptors.isNotEmpty()) {
functionInPlace.addModifier(KtTokens.OVERRIDE_KEYWORD)
}
setupEditorSelection(editor, functionInPlace)
}
errorHint?.let { HintManager.getInstance().showErrorHint(editor, it) }
}
catch (e: IncorrectOperationException) {
HintManager.getInstance().showErrorHint(editor, "Cannot generate method: " + e.message)
}
}
private fun substituteNewName(function: KtNamedFunction, name: String): KtNamedFunction {
val psiFactory = KtPsiFactory(function)
// First replace all DUMMY_NAME occurrences in names as they need special treatment due to quotation
var function1 = function
function1.accept(
object : KtTreeVisitorVoid() {
private fun getNewId(currentId: String): String? {
if (!currentId.contains(DUMMY_NAME)) return null
return currentId.replace(DUMMY_NAME, name).quoteIfNeeded()
}
override fun visitNamedDeclaration(declaration: KtNamedDeclaration) {
val nameIdentifier = declaration.nameIdentifier ?: return
val newId = getNewId(nameIdentifier.text) ?: return
declaration.setName(newId)
}
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val newId = getNewId(expression.text) ?: return
expression.replace(psiFactory.createSimpleName(newId))
}
}
)
// Then text-replace remaining occurrences (if any)
val functionText = function1.text
if (functionText.contains(DUMMY_NAME)) {
function1 = psiFactory.createFunction(function1.text.replace(DUMMY_NAME, name))
}
return function1
}
override fun createEditTemplateAction(dataContext: DataContext): AnAction? {
val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return null
val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return null
val file = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return null
val targetClass = getTargetClass(editor, file) ?: return null
val frameworks = findSuitableFrameworks(targetClass).ifEmpty { return null }
return object : AnAction("Edit Template") {
override fun actionPerformed(e: AnActionEvent) {
chooseAndPerform(editor, frameworks) {
val descriptor = methodKind.getFileTemplateDescriptor(it)
if (descriptor == null) {
HintManager.getInstance().showErrorHint(editor, "No template found for ${it.name}:${templatePresentation.text}")
return@chooseAndPerform
}
AllFileTemplatesConfigurable.editCodeTemplate(FileUtil.getNameWithoutExtension(descriptor.fileName), project)
}
}
}
}
}
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.refactoring.isAbstract
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.util.PopupChooserBuilderWrapper
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
@@ -213,7 +214,7 @@ abstract class ImplementAbstractMemberIntentionBase :
selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
cellRenderer = renderer
}
val builder = PopupChooserBuilder<PsiElement>(list)
val builder = PopupChooserBuilderWrapper<PsiElement>(list)
renderer.installSpeedSearch(builder)
builder
.setTitle(CodeInsightBundle.message("intention.implement.abstract.method.class.chooser.title"))
@@ -1,268 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.FileModificationService
import com.intellij.codeInsight.generation.OverrideImplementUtil
import com.intellij.ide.util.PsiClassListCellRenderer
import com.intellij.ide.util.PsiElementListCellRenderer
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.ui.popup.PopupChooserBuilder
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.ui.components.JBList
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.refactoring.isAbstract
import org.jetbrains.kotlin.idea.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import java.util.*
import javax.swing.ListSelectionModel
abstract class ImplementAbstractMemberIntentionBase :
SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java, "", "Implement abstract member") {
companion object {
private val LOG = Logger.getInstance("#${ImplementAbstractMemberIntentionBase::class.java.canonicalName}")
}
protected fun findExistingImplementation(
subClass: ClassDescriptor,
superMember: CallableMemberDescriptor
): CallableMemberDescriptor? {
val superClass = superMember.containingDeclaration as? ClassDescriptor ?: return null
val substitutor = getTypeSubstitutor(superClass.defaultType, subClass.defaultType) ?: TypeSubstitutor.EMPTY
val signatureInSubClass = superMember.substitute(substitutor) as? CallableMemberDescriptor ?: return null
val subMember = subClass.findCallableMemberBySignature(signatureInSubClass)
return if (subMember?.kind?.isReal == true) subMember else null
}
protected abstract fun acceptSubClass(subClassDescriptor: ClassDescriptor, memberDescriptor: CallableMemberDescriptor): Boolean
private fun findClassesToProcess(member: KtNamedDeclaration): Sequence<PsiElement> {
val baseClass = member.containingClassOrObject as? KtClass ?: return emptySequence()
val memberDescriptor = member.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return emptySequence()
fun acceptSubClass(subClass: PsiElement): Boolean {
val classDescriptor = when (subClass) {
is KtLightClass -> subClass.kotlinOrigin?.resolveToDescriptorIfAny()
is KtEnumEntry -> subClass.resolveToDescriptorIfAny()
is PsiClass -> subClass.getJavaClassDescriptor()
else -> null
} ?: return false
return acceptSubClass(classDescriptor, memberDescriptor)
}
if (baseClass.isEnum()) {
return baseClass.declarations
.asSequence()
.filterIsInstance<KtEnumEntry>()
.filter(::acceptSubClass)
}
return HierarchySearchRequest(baseClass, baseClass.useScope, false)
.searchInheritors()
.asSequence()
.filter(::acceptSubClass)
}
protected abstract fun computeText(element: KtNamedDeclaration): String?
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
if (!element.isAbstract()) return null
text = computeText(element) ?: return null
if (!findClassesToProcess(element).any()) return null
return element.nameIdentifier?.textRange
}
protected abstract val preferConstructorParameters: Boolean
private fun implementInKotlinClass(editor: Editor?, member: KtNamedDeclaration, targetClass: KtClassOrObject) {
val subClassDescriptor = targetClass.resolveToDescriptorIfAny() ?: return
val superMemberDescriptor = member.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return
val superClassDescriptor = superMemberDescriptor.containingDeclaration as? ClassDescriptor ?: return
val substitutor = getTypeSubstitutor(superClassDescriptor.defaultType, subClassDescriptor.defaultType)
?: TypeSubstitutor.EMPTY
val descriptorToImplement = superMemberDescriptor.substitute(substitutor) as CallableMemberDescriptor
val chooserObject = OverrideMemberChooserObject.create(member.project,
descriptorToImplement,
descriptorToImplement,
OverrideMemberChooserObject.BodyType.FROM_TEMPLATE,
preferConstructorParameters)
OverrideImplementMembersHandler.generateMembers(editor, targetClass, listOf(chooserObject), false)
}
private fun implementInJavaClass(member: KtNamedDeclaration, targetClass: PsiClass) {
member.toLightMethods().forEach { OverrideImplementUtil.overrideOrImplement(targetClass, it) }
}
private fun implementInClass(member: KtNamedDeclaration, targetClasses: List<PsiElement>) {
val project = member.project
project.executeCommand(CodeInsightBundle.message("intention.implement.abstract.method.command.name")) {
if (!FileModificationService.getInstance().preparePsiElementsForWrite(targetClasses)) return@executeCommand
runWriteAction {
for (targetClass in targetClasses) {
try {
val descriptor = OpenFileDescriptor(project, targetClass.containingFile.virtualFile)
val targetEditor = FileEditorManager.getInstance(project).openTextEditor(descriptor, true)!!
when (targetClass) {
is KtLightClass -> targetClass.kotlinOrigin?.let { implementInKotlinClass(targetEditor, member, it) }
is KtEnumEntry -> implementInKotlinClass(targetEditor, member, targetClass)
is PsiClass -> implementInJavaClass(member, targetClass)
}
}
catch(e: IncorrectOperationException) {
LOG.error(e)
}
}
}
}
}
private class ClassRenderer : PsiElementListCellRenderer<PsiElement>() {
private val psiClassRenderer = PsiClassListCellRenderer()
override fun getComparator(): Comparator<PsiElement> {
val baseComparator = psiClassRenderer.comparator
return Comparator { o1, o2 ->
when {
o1 is KtEnumEntry && o2 is KtEnumEntry -> o1.name!!.compareTo(o2.name!!)
o1 is KtEnumEntry -> -1
o2 is KtEnumEntry -> 1
o1 is PsiClass && o2 is PsiClass -> baseComparator.compare(o1, o2)
else -> 0
}
}
}
override fun getIconFlags() = 0
override fun getElementText(element: PsiElement?): String? {
return when (element) {
is KtEnumEntry -> element.name
is PsiClass -> psiClassRenderer.getElementText(element)
else -> null
}
}
override fun getContainerText(element: PsiElement?, name: String?): String? {
return when (element) {
is KtEnumEntry -> element.containingClassOrObject?.fqName?.asString()
is PsiClass -> PsiClassListCellRenderer.getContainerTextStatic(element)
else -> null
}
}
}
override fun applyTo(element: KtNamedDeclaration, editor: Editor?) {
if (editor == null) throw IllegalArgumentException("This intention requires an editor")
val project = element.project
val classesToProcess = project.runSynchronouslyWithProgress(
CodeInsightBundle.message("intention.implement.abstract.method.searching.for.descendants.progress"),
true
) { findClassesToProcess(element).toList() } ?: return
if (classesToProcess.isEmpty()) return
classesToProcess.singleOrNull()?.let { return implementInClass(element, listOf(it)) }
val renderer = ClassRenderer()
val sortedClasses = classesToProcess.sortedWith(renderer.comparator)
if (ApplicationManager.getApplication().isUnitTestMode) return implementInClass(element, sortedClasses)
val list = JBList(sortedClasses).apply {
selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
cellRenderer = renderer
}
val builder = PopupChooserBuilder(list)
renderer.installSpeedSearch(builder)
builder
.setTitle(CodeInsightBundle.message("intention.implement.abstract.method.class.chooser.title"))
.setItemChoosenCallback {
val index = list.selectedIndex
if (index < 0) return@setItemChoosenCallback
@Suppress("UNCHECKED_CAST")
implementInClass(element, list.selectedValues.toList() as List<KtClassOrObject>)
}
.createPopup()
.showInBestPositionFor(editor)
}
}
class ImplementAbstractMemberIntention : ImplementAbstractMemberIntentionBase() {
override fun computeText(element: KtNamedDeclaration): String? {
return when(element) {
is KtProperty -> "Implement abstract property"
is KtNamedFunction -> "Implement abstract function"
else -> null
}
}
override fun acceptSubClass(subClassDescriptor: ClassDescriptor, memberDescriptor: CallableMemberDescriptor): Boolean {
return subClassDescriptor.kind != ClassKind.INTERFACE && findExistingImplementation(subClassDescriptor, memberDescriptor) == null
}
override val preferConstructorParameters: Boolean
get() = false
}
class ImplementAbstractMemberAsConstructorParameterIntention : ImplementAbstractMemberIntentionBase() {
override fun computeText(element: KtNamedDeclaration): String? {
if (element !is KtProperty) return null
return "Implement as constructor parameter"
}
override fun acceptSubClass(subClassDescriptor: ClassDescriptor, memberDescriptor: CallableMemberDescriptor): Boolean {
val kind = subClassDescriptor.kind
return (kind == ClassKind.CLASS || kind == ClassKind.ENUM_CLASS)
&& subClassDescriptor !is JavaClassDescriptor
&& findExistingImplementation(subClassDescriptor, memberDescriptor) == null
}
override val preferConstructorParameters: Boolean
get() = true
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
if (element !is KtProperty) return null
return super.applicabilityRange(element)
}
}
@@ -74,10 +74,7 @@ import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinValVar
import org.jetbrains.kotlin.idea.refactoring.changeSignature.toValVar
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KtPsiClassWrapper
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.idea.util.actualsForExpected
import org.jetbrains.kotlin.idea.util.liftToExpected
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.idea.util.string.collapseSpaces
import org.jetbrains.kotlin.j2k.ConverterSettings
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
@@ -263,7 +260,7 @@ fun <T, E : PsiElement> getPsiElementPopup(
}
}
return with(PopupChooserBuilder<E>(list)) {
return with(PopupChooserBuilderWrapper<E>(list)) {
title?.let { setTitle(it) }
renderer.installSpeedSearch(this, true)
setItemChoosenCallback {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.util
import com.intellij.openapi.ui.popup.PopupChooserBuilder
import javax.swing.JList
// BUNCH: 181
@Suppress("IncompatibleAPI")
class PopupChooserBuilderWrapper<T>(list: JList<T>): PopupChooserBuilder<T>(list)
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.util
import com.intellij.openapi.ui.popup.PopupChooserBuilder
import javax.swing.JList
// BUNCH: 181
@Suppress("IncompatibleAPI")
class PopupChooserBuilderWrapper<T>(list: JList<T>) : PopupChooserBuilder(list)