Converted to Kotlin

This commit is contained in:
Valentin Kipyatkov
2015-10-15 22:12:41 +03:00
parent 41775bf8a0
commit 1a13ec0b00
4 changed files with 283 additions and 327 deletions
@@ -1,160 +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;
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.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopupStep;
import com.intellij.openapi.ui.popup.PopupStep;
import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ClassKind;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.Modality;
import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.idea.util.ShortenReferences;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.types.JetType;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
/**
* Changes method signature to one of provided signatures.
* Based on {@link KotlinAddImportAction}
*/
public class JetAddFunctionToClassifierAction implements QuestionAction {
private final List<FunctionDescriptor> functionsToAdd;
private final Project project;
private final Editor editor;
public JetAddFunctionToClassifierAction(
@NotNull Project project,
@NotNull Editor editor,
@NotNull List<FunctionDescriptor> functionsToAdd
) {
this.project = project;
this.editor = editor;
this.functionsToAdd = new ArrayList<FunctionDescriptor>(functionsToAdd);
}
private static void addFunction(
@NotNull Project project,
@NotNull final ClassDescriptor typeDescriptor,
@NotNull final FunctionDescriptor functionDescriptor
) {
final String signatureString = IdeDescriptorRenderers.SOURCE_CODE.render(functionDescriptor);
PsiDocumentManager.getInstance(project).commitAllDocuments();
final JetClass classifierDeclaration = (JetClass) DescriptorToSourceUtilsIde.INSTANCE$.getAnyDeclaration(project, typeDescriptor);
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
JetPsiFactory psiFactory = JetPsiFactoryKt.JetPsiFactory(classifierDeclaration);
JetClassBody body = classifierDeclaration.getOrCreateBody();
String functionBody = "";
if (typeDescriptor.getKind() != ClassKind.INTERFACE && functionDescriptor.getModality() != Modality.ABSTRACT) {
functionBody = "{}";
JetType returnType = functionDescriptor.getReturnType();
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) {
functionBody = "{ throw UnsupportedOperationException() }";
}
}
JetNamedFunction functionElement = psiFactory.createFunction(signatureString + functionBody);
PsiElement anchor = body.getRBrace();
JetNamedFunction insertedFunctionElement = (JetNamedFunction) body.addBefore(functionElement, anchor);
ShortenReferences.DEFAULT.process(insertedFunctionElement);
}
});
}
}, JetBundle.message("add.function.to.type.action"), null);
}
@Override
public boolean execute() {
if (functionsToAdd.isEmpty()) {
return false;
}
if (functionsToAdd.size() == 1 || !editor.getComponent().isShowing()) {
addFunction(functionsToAdd.get(0));
}
else {
chooseFunctionAndAdd();
}
return true;
}
private void chooseFunctionAndAdd() {
JBPopupFactory.getInstance().createListPopup(getFunctionPopup()).showInBestPositionFor(editor);
}
private ListPopupStep getFunctionPopup() {
return new BaseListPopupStep<FunctionDescriptor>(
JetBundle.message("add.function.to.type.action.type.chooser"), functionsToAdd) {
@Override
public boolean isAutoSelectionEnabled() {
return false;
}
@Override
public PopupStep onChosen(FunctionDescriptor selectedValue, boolean finalChoice) {
if (finalChoice) {
addFunction(selectedValue);
}
return FINAL_CHOICE;
}
@Override
public Icon getIconFor(FunctionDescriptor aValue) {
return PlatformIcons.FUNCTION_ICON;
}
@NotNull
@Override
public String getTextFor(FunctionDescriptor functionDescriptor) {
ClassDescriptor type = (ClassDescriptor) functionDescriptor.getContainingDeclaration();
return JetBundle.message("add.function.to.type.action.single",
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(functionDescriptor),
type.getName().toString());
}
};
}
private void addFunction(FunctionDescriptor functionToAdd) {
addFunction(project, (ClassDescriptor) functionToAdd.getContainingDeclaration(), functionToAdd);
}
}
@@ -0,0 +1,142 @@
/*
* 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
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.project.Project
import com.intellij.openapi.ui.popup.JBPopupFactory
import com.intellij.openapi.ui.popup.ListPopupStep
import com.intellij.openapi.ui.popup.PopupStep
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
import com.intellij.psi.PsiDocumentManager
import com.intellij.util.PlatformIcons
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.psi.JetPsiFactory
import java.util.*
/**
* Changes method signature to one of provided signatures.
* Based on [KotlinAddImportAction]
*/
class JetAddFunctionToClassifierAction(
private val project: Project,
private val editor: Editor?,
functionsToAdd: List<FunctionDescriptor>
) : QuestionAction {
private val functionsToAdd: List<FunctionDescriptor>
init {
this.functionsToAdd = ArrayList(functionsToAdd)
}
private fun addFunction(
project: Project,
typeDescriptor: ClassDescriptor,
functionDescriptor: FunctionDescriptor
) {
val signatureString = IdeDescriptorRenderers.SOURCE_CODE.render(functionDescriptor)
PsiDocumentManager.getInstance(project).commitAllDocuments()
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 = ""
if (typeDescriptor.kind != ClassKind.INTERFACE && functionDescriptor.modality != Modality.ABSTRACT) {
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)
}
})
}
}, JetBundle.message("add.function.to.type.action"), null)
}
override fun execute(): Boolean {
if (functionsToAdd.isEmpty()) {
return false
}
if (functionsToAdd.size == 1 || editor == null || !editor.component.isShowing) {
addFunction(functionsToAdd.get(0))
}
else {
chooseFunctionAndAdd()
}
return true
}
private fun chooseFunctionAndAdd() {
JBPopupFactory.getInstance().createListPopup(functionPopup).showInBestPositionFor(editor!!)
}
private val functionPopup: ListPopupStep<*>
get() {
return object : BaseListPopupStep<FunctionDescriptor>(JetBundle.message("add.function.to.type.action.type.chooser"), functionsToAdd) {
override fun isAutoSelectionEnabled(): Boolean {
return false
}
override fun onChosen(selectedValue: FunctionDescriptor, finalChoice: Boolean): PopupStep<Any>? {
if (finalChoice) {
addFunction(selectedValue)
}
return PopupStep.FINAL_CHOICE
}
override fun getIconFor(aValue: FunctionDescriptor) = PlatformIcons.FUNCTION_ICON
override fun getTextFor(functionDescriptor: FunctionDescriptor): String {
val type = functionDescriptor.containingDeclaration as ClassDescriptor
return JetBundle.message("add.function.to.type.action.single",
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(functionDescriptor),
type.name.toString())
}
}
}
private fun addFunction(functionToAdd: FunctionDescriptor) {
addFunction(project, functionToAdd.containingDeclaration as ClassDescriptor, functionToAdd)
}
}
@@ -1,167 +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.quickfix;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.JetBundle;
import org.jetbrains.kotlin.idea.actions.JetAddFunctionToClassifierAction;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.psi.JetFile;
import org.jetbrains.kotlin.psi.JetNamedFunction;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class AddFunctionToSupertypeFix extends JetHintAction<JetNamedFunction> {
private final List<FunctionDescriptor> functionsToAdd;
public AddFunctionToSupertypeFix(JetNamedFunction element) {
super(element);
functionsToAdd = generateFunctionsToAdd(element);
}
private static List<FunctionDescriptor> generateFunctionsToAdd(JetNamedFunction functionElement) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) ResolutionUtils.resolveToDescriptor(functionElement);
DeclarationDescriptor containingDeclaration = functionDescriptor.getContainingDeclaration();
if (!(containingDeclaration instanceof ClassDescriptor)) return Collections.emptyList();
List<FunctionDescriptor> functions = Lists.newArrayList();
ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
// TODO: filter out impossible supertypes (for example when argument's type isn't visible in a superclass).
for (ClassDescriptor supertypeDescriptor : getSupertypes(classDescriptor)) {
if (KotlinBuiltIns.isAnyOrNullableAny(supertypeDescriptor.getDefaultType())) continue;
functions.add(generateFunctionSignatureForType(functionDescriptor, supertypeDescriptor));
}
return functions;
}
private static List<ClassDescriptor> getSupertypes(ClassDescriptor classDescriptor) {
List<JetType> supertypes = Lists.newArrayList(TypeUtils.getAllSupertypes(classDescriptor.getDefaultType()));
Collections.sort(supertypes, new Comparator<JetType>() {
@Override
public int compare(JetType o1, JetType o2) {
if (o1.equals(o2)) {
return 0;
}
if (JetTypeChecker.DEFAULT.isSubtypeOf(o1, o2)) {
return -1;
}
if (JetTypeChecker.DEFAULT.isSubtypeOf(o2, o1)) {
return 1;
}
return o1.toString().compareTo(o2.toString());
}
});
List<ClassDescriptor> supertypesDescriptors = Lists.newArrayList();
for (JetType supertype : supertypes) {
supertypesDescriptors.add(DescriptorUtils.getClassDescriptorForType(supertype));
}
return supertypesDescriptors;
}
private static FunctionDescriptor generateFunctionSignatureForType(
FunctionDescriptor functionDescriptor,
ClassDescriptor typeDescriptor
) {
// TODO: support for generics.
Modality modality = typeDescriptor.getModality();
if (typeDescriptor.getKind() == ClassKind.INTERFACE) {
modality = Modality.OPEN;
}
return functionDescriptor.copy(
typeDescriptor,
modality,
functionDescriptor.getVisibility(),
CallableMemberDescriptor.Kind.DECLARATION,
/* copyOverrides = */ false);
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return super.isAvailable(project, editor, file) && !functionsToAdd.isEmpty();
}
@Override
public boolean showHint(Editor editor) {
return false;
}
@NotNull
@Override
public String getText() {
if (functionsToAdd.size() == 1) {
FunctionDescriptor newFunction = functionsToAdd.get(0);
ClassDescriptor supertype = (ClassDescriptor) newFunction.getContainingDeclaration();
return JetBundle.message("add.function.to.type.action.single",
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(newFunction),
supertype.getName().toString());
}
else {
return JetBundle.message("add.function.to.supertype.action.multiple");
}
}
@NotNull
@Override
public String getFamilyName() {
return JetBundle.message("add.function.to.supertype.family");
}
@Override
protected void invoke(@NotNull final Project project, final Editor editor, final JetFile file) {
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
@Override
public void run() {
createAction(project, editor, file).execute();
}
});
}
@NotNull
private JetAddFunctionToClassifierAction createAction(Project project, Editor editor, JetFile file) {
return new JetAddFunctionToClassifierAction(project, editor, functionsToAdd);
}
public static JetIntentionActionsFactory createFactory() {
return new JetSingleIntentionActionFactory() {
@Nullable
@Override
public IntentionAction createAction(Diagnostic diagnostic) {
JetNamedFunction function = QuickFixUtil.getParentElementOfType(diagnostic, JetNamedFunction.class);
return function == null ? null : new AddFunctionToSupertypeFix(function);
}
};
}
}
@@ -0,0 +1,141 @@
/*
* 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.quickfix
import com.google.common.collect.Lists
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.idea.actions.JetAddFunctionToClassifierAction
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import java.util.*
class AddFunctionToSupertypeFix(element: JetNamedFunction) : JetHintAction<JetNamedFunction>(element) {
private val functionsToAdd: List<FunctionDescriptor> = generateFunctionsToAdd(element)
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
return super.isAvailable(project, editor, file) && !functionsToAdd.isEmpty()
}
override fun showHint(editor: Editor) = false
override fun getText(): String {
if (functionsToAdd.size == 1) {
val newFunction = functionsToAdd.get(0)
val supertype = newFunction.containingDeclaration as ClassDescriptor
return JetBundle.message("add.function.to.type.action.single",
IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(newFunction),
supertype.name.toString())
}
else {
return JetBundle.message("add.function.to.supertype.action.multiple")
}
}
override fun getFamilyName() = JetBundle.message("add.function.to.supertype.family")
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
CommandProcessor.getInstance().runUndoTransparentAction(object : Runnable {
override fun run() {
createAction(project, editor).execute()
}
})
}
private fun createAction(project: Project, editor: Editor?): JetAddFunctionToClassifierAction {
return JetAddFunctionToClassifierAction(project, editor, functionsToAdd)
}
companion object {
private fun generateFunctionsToAdd(functionElement: JetNamedFunction): List<FunctionDescriptor> {
val functionDescriptor = functionElement.resolveToDescriptor() as FunctionDescriptor
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).
for (supertypeDescriptor in getSupertypes(containingClass)) {
if (KotlinBuiltIns.isAnyOrNullableAny(supertypeDescriptor.defaultType)) continue
functions.add(generateFunctionSignatureForType(functionDescriptor, supertypeDescriptor))
}
return functions
}
private fun getSupertypes(classDescriptor: ClassDescriptor): List<ClassDescriptor> {
val supertypes = Lists.newArrayList(TypeUtils.getAllSupertypes(classDescriptor.defaultType))
Collections.sort(supertypes, object : Comparator<JetType> {
override fun compare(o1: JetType, o2: JetType): Int {
if (o1 == o2) {
return 0
}
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) {
supertypesDescriptors.add(DescriptorUtils.getClassDescriptorForType(supertype))
}
return supertypesDescriptors
}
private fun generateFunctionSignatureForType(
functionDescriptor: FunctionDescriptor,
typeDescriptor: ClassDescriptor): FunctionDescriptor {
// TODO: support for generics.
var modality = typeDescriptor.modality
if (typeDescriptor.kind == ClassKind.INTERFACE) {
modality = Modality.OPEN
}
return functionDescriptor.copy(
typeDescriptor,
modality,
functionDescriptor.visibility,
CallableMemberDescriptor.Kind.DECLARATION,
/* 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)
}
}
}
}
}