Code simplifications

This commit is contained in:
Valentin Kipyatkov
2015-10-15 22:25:55 +03:00
parent 1a13ec0b00
commit ff13bcce1f
3 changed files with 50 additions and 97 deletions
@@ -16,9 +16,6 @@
package org.jetbrains.kotlin.idea.actions package org.jetbrains.kotlin.idea.actions
import com.intellij.codeInsight.hint.QuestionAction
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
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.popup.JBPopupFactory import com.intellij.openapi.ui.popup.JBPopupFactory
@@ -36,10 +33,10 @@ import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.JetClass import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetNamedFunction import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.psi.JetPsiFactory import org.jetbrains.kotlin.psi.JetPsiFactory
import java.util.*
/** /**
* Changes method signature to one of provided signatures. * Changes method signature to one of provided signatures.
@@ -48,14 +45,8 @@ import java.util.*
class JetAddFunctionToClassifierAction( class JetAddFunctionToClassifierAction(
private val project: Project, private val project: Project,
private val editor: Editor?, private val editor: Editor?,
functionsToAdd: List<FunctionDescriptor> private val functionsToAdd: List<FunctionDescriptor>
) : QuestionAction { ) {
private val functionsToAdd: List<FunctionDescriptor>
init {
this.functionsToAdd = ArrayList(functionsToAdd)
}
private fun addFunction( private fun addFunction(
project: Project, project: Project,
typeDescriptor: ClassDescriptor, typeDescriptor: ClassDescriptor,
@@ -66,57 +57,40 @@ class JetAddFunctionToClassifierAction(
PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(project).commitAllDocuments()
val classifierDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, typeDescriptor) as JetClass val classifierDeclaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, typeDescriptor) as JetClass
CommandProcessor.getInstance().executeCommand(project, object : Runnable {
override fun run() {
ApplicationManager.getApplication().runWriteAction(object : Runnable {
override fun run() {
val psiFactory = JetPsiFactory(classifierDeclaration)
val body = classifierDeclaration.getOrCreateBody()
var functionBody = "" project.executeWriteCommand(JetBundle.message("add.function.to.type.action")) {
if (typeDescriptor.kind != ClassKind.INTERFACE && functionDescriptor.modality != Modality.ABSTRACT) { val body = classifierDeclaration.getOrCreateBody()
functionBody = "{}"
val returnType = functionDescriptor.returnType
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) {
functionBody = "{ throw UnsupportedOperationException() }"
}
}
val functionElement = psiFactory.createFunction(signatureString + functionBody)
val anchor = body.rBrace
val insertedFunctionElement = body.addBefore(functionElement, anchor) as JetNamedFunction
ShortenReferences.DEFAULT.process(insertedFunctionElement) var functionBody = ""
} if (typeDescriptor.kind != ClassKind.INTERFACE && functionDescriptor.modality != Modality.ABSTRACT) {
}) functionBody = "{}"
val returnType = functionDescriptor.returnType
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) {
functionBody = "{ throw UnsupportedOperationException() }"
}
} }
}, JetBundle.message("add.function.to.type.action"), null) val functionElement = JetPsiFactory(project).createFunction(signatureString + functionBody)
val insertedFunctionElement = body.addBefore(functionElement, body.rBrace) as JetNamedFunction
ShortenReferences.DEFAULT.process(insertedFunctionElement)
}
} }
override fun execute(): Boolean { fun execute() {
if (functionsToAdd.isEmpty()) { if (functionsToAdd.isEmpty()) return
return false
}
if (functionsToAdd.size == 1 || editor == null || !editor.component.isShowing) { if (functionsToAdd.size == 1 || editor == null || !editor.component.isShowing) {
addFunction(functionsToAdd.get(0)) addFunction(functionsToAdd.get(0))
} }
else { else {
chooseFunctionAndAdd() JBPopupFactory.getInstance().createListPopup(functionPopup).showInBestPositionFor(editor)
} }
return true
}
private fun chooseFunctionAndAdd() {
JBPopupFactory.getInstance().createListPopup(functionPopup).showInBestPositionFor(editor!!)
} }
private val functionPopup: ListPopupStep<*> private val functionPopup: ListPopupStep<*>
get() { get() {
return object : BaseListPopupStep<FunctionDescriptor>(JetBundle.message("add.function.to.type.action.type.chooser"), functionsToAdd) { return object : BaseListPopupStep<FunctionDescriptor>(JetBundle.message("add.function.to.type.action.type.chooser"), functionsToAdd) {
override fun isAutoSelectionEnabled(): Boolean { override fun isAutoSelectionEnabled() = false
return false
}
override fun onChosen(selectedValue: FunctionDescriptor, finalChoice: Boolean): PopupStep<Any>? { override fun onChosen(selectedValue: FunctionDescriptor, finalChoice: Boolean): PopupStep<Any>? {
if (finalChoice) { if (finalChoice) {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.idea.quickfix package org.jetbrains.kotlin.idea.quickfix
import com.google.common.collect.Lists
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
@@ -34,12 +33,12 @@ import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetNamedFunction import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.types.typeUtil.supertypes
import java.util.* import java.util.*
class AddFunctionToSupertypeFix(element: JetNamedFunction) : JetHintAction<JetNamedFunction>(element) { class AddFunctionToSupertypeFix(element: JetNamedFunction) : JetHintAction<JetNamedFunction>(element) {
private val functionsToAdd: List<FunctionDescriptor> = generateFunctionsToAdd(element) private val functionsToAdd = generateFunctionsToAdd(element)
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean { override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
return super.isAvailable(project, editor, file) && !functionsToAdd.isEmpty() return super.isAvailable(project, editor, file) && !functionsToAdd.isEmpty()
@@ -48,11 +47,11 @@ class AddFunctionToSupertypeFix(element: JetNamedFunction) : JetHintAction<JetNa
override fun showHint(editor: Editor) = false override fun showHint(editor: Editor) = false
override fun getText(): String { override fun getText(): String {
if (functionsToAdd.size == 1) { val single = functionsToAdd.singleOrNull()
val newFunction = functionsToAdd.get(0) if (single != null) {
val supertype = newFunction.containingDeclaration as ClassDescriptor val supertype = single.containingDeclaration as ClassDescriptor
return JetBundle.message("add.function.to.type.action.single", return JetBundle.message("add.function.to.type.action.single",
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(newFunction), IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(single),
supertype.name.toString()) supertype.name.toString())
} }
else { else {
@@ -70,57 +69,46 @@ class AddFunctionToSupertypeFix(element: JetNamedFunction) : JetHintAction<JetNa
}) })
} }
private fun createAction(project: Project, editor: Editor?): JetAddFunctionToClassifierAction { private fun createAction(project: Project, editor: Editor?)
return JetAddFunctionToClassifierAction(project, editor, functionsToAdd) = JetAddFunctionToClassifierAction(project, editor, functionsToAdd)
}
companion object { companion object: JetSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val function = QuickFixUtil.getParentElementOfType(diagnostic, JetNamedFunction::class.java)
return if (function == null) null else AddFunctionToSupertypeFix(function)
}
private fun generateFunctionsToAdd(functionElement: JetNamedFunction): List<FunctionDescriptor> { private fun generateFunctionsToAdd(functionElement: JetNamedFunction): List<FunctionDescriptor> {
val functionDescriptor = functionElement.resolveToDescriptor() as FunctionDescriptor val functionDescriptor = functionElement.resolveToDescriptor() as FunctionDescriptor
val containingClass = functionDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList() val containingClass = functionDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList()
val functions = ArrayList<FunctionDescriptor>()
// TODO: filter out impossible supertypes (for example when argument's type isn't visible in a superclass). // TODO: filter out impossible supertypes (for example when argument's type isn't visible in a superclass).
for (supertypeDescriptor in getSupertypes(containingClass)) { return getSupertypes(containingClass)
if (KotlinBuiltIns.isAnyOrNullableAny(supertypeDescriptor.defaultType)) continue .filterNot { KotlinBuiltIns.isAnyOrNullableAny(it.defaultType) }
functions.add(generateFunctionSignatureForType(functionDescriptor, supertypeDescriptor)) .map { generateFunctionSignatureForType(functionDescriptor, it) }
}
return functions
} }
private fun getSupertypes(classDescriptor: ClassDescriptor): List<ClassDescriptor> { private fun getSupertypes(classDescriptor: ClassDescriptor): List<ClassDescriptor> {
val supertypes = Lists.newArrayList(TypeUtils.getAllSupertypes(classDescriptor.defaultType)) val supertypes = classDescriptor.defaultType.supertypes().sortedWith(object : Comparator<JetType> {
Collections.sort(supertypes, object : Comparator<JetType> {
override fun compare(o1: JetType, o2: JetType): Int { override fun compare(o1: JetType, o2: JetType): Int {
if (o1 == o2) { return when {
return 0 o1 == o2 -> 0
JetTypeChecker.DEFAULT.isSubtypeOf(o1, o2) -> -1
JetTypeChecker.DEFAULT.isSubtypeOf(o2, o1) -> 1
else -> o1.toString().compareTo(o2.toString())
} }
if (JetTypeChecker.DEFAULT.isSubtypeOf(o1, o2)) {
return -1
}
if (JetTypeChecker.DEFAULT.isSubtypeOf(o2, o1)) {
return 1
}
return o1.toString().compareTo(o2.toString())
} }
}) })
val supertypesDescriptors = Lists.newArrayList<ClassDescriptor>()
for (supertype in supertypes) { return supertypes.map { DescriptorUtils.getClassDescriptorForType(it) }
supertypesDescriptors.add(DescriptorUtils.getClassDescriptorForType(supertype))
}
return supertypesDescriptors
} }
private fun generateFunctionSignatureForType( private fun generateFunctionSignatureForType(functionDescriptor: FunctionDescriptor, typeDescriptor: ClassDescriptor): FunctionDescriptor {
functionDescriptor: FunctionDescriptor,
typeDescriptor: ClassDescriptor): FunctionDescriptor {
// TODO: support for generics. // TODO: support for generics.
var modality = typeDescriptor.modality
if (typeDescriptor.kind == ClassKind.INTERFACE) { val modality = if (typeDescriptor.kind == ClassKind.INTERFACE) Modality.OPEN else typeDescriptor.modality
modality = Modality.OPEN
}
return functionDescriptor.copy( return functionDescriptor.copy(
typeDescriptor, typeDescriptor,
modality, modality,
@@ -128,14 +116,5 @@ class AddFunctionToSupertypeFix(element: JetNamedFunction) : JetHintAction<JetNa
CallableMemberDescriptor.Kind.DECLARATION, CallableMemberDescriptor.Kind.DECLARATION,
/* copyOverrides = */ false) /* copyOverrides = */ false)
} }
fun createFactory(): JetIntentionActionsFactory {
return object : JetSingleIntentionActionFactory() {
public override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val function = QuickFixUtil.getParentElementOfType(diagnostic, JetNamedFunction::class.java)
return if (function == null) null else AddFunctionToSupertypeFix(function)
}
}
}
} }
} }
@@ -91,7 +91,7 @@ public class QuickFixRegistrar : QuickFixContributor {
NOTHING_TO_OVERRIDE.registerFactory( RemoveModifierFix.createRemoveModifierFromListOwnerFactory(OVERRIDE_KEYWORD), NOTHING_TO_OVERRIDE.registerFactory( RemoveModifierFix.createRemoveModifierFromListOwnerFactory(OVERRIDE_KEYWORD),
ChangeMemberFunctionSignatureFix, ChangeMemberFunctionSignatureFix,
AddFunctionToSupertypeFix.createFactory()) AddFunctionToSupertypeFix)
VIRTUAL_MEMBER_HIDDEN.registerFactory(AddModifierFix.createFactory(OVERRIDE_KEYWORD)) VIRTUAL_MEMBER_HIDDEN.registerFactory(AddModifierFix.createFactory(OVERRIDE_KEYWORD))
USELESS_CAST.registerFactory(RemoveRightPartOfBinaryExpressionFix.createRemoveTypeFromBinaryExpressionFactory("Remove cast")) USELESS_CAST.registerFactory(RemoveRightPartOfBinaryExpressionFix.createRemoveTypeFromBinaryExpressionFactory("Remove cast"))