Converted to Kotlin
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user