mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
Rewrite to Kotlin: rewrite methods for markers on overridden declarations
This commit is contained in:
@@ -8,4 +8,7 @@
|
||||
<item name='com.intellij.ide.util.PsiElementListCellRenderer java.lang.String getElementText(T) 0'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='com.intellij.ide.util.PsiElementListCellRenderer java.util.Comparator<T> getComparator()'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -18,41 +18,30 @@ package org.jetbrains.jet.plugin.highlighter;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import com.intellij.codeHighlighting.Pass;
|
||||
import com.intellij.codeInsight.daemon.DaemonBundle;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
||||
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper;
|
||||
import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator;
|
||||
import com.intellij.codeInsight.daemon.impl.MarkerType;
|
||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator;
|
||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
|
||||
import com.intellij.ide.util.MethodCellRenderer;
|
||||
import com.intellij.ide.util.PsiClassListCellRenderer;
|
||||
import com.intellij.ide.util.PsiElementListCellRenderer;
|
||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiElementProcessor;
|
||||
import com.intellij.psi.search.PsiElementProcessorAdapter;
|
||||
import com.intellij.psi.search.searches.AllOverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.Modality;
|
||||
@@ -101,7 +90,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
@Override
|
||||
public String fun(@Nullable PsiElement element) {
|
||||
PsiMethod psiMethod = getPsiMethod(element);
|
||||
return psiMethod != null ? getOverriddenMethodTooltip(psiMethod) : null;
|
||||
return psiMethod != null ? MarkersPackage.getOverriddenMethodTooltip(psiMethod) : null;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -110,7 +99,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
public void browse(@Nullable MouseEvent e, @Nullable PsiElement element) {
|
||||
PsiMethod psiMethod = getPsiMethod(element);
|
||||
if (psiMethod != null) {
|
||||
navigateToOverriddenMethod(e, psiMethod);
|
||||
MarkersPackage.navigateToOverriddenMethod(e, psiMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,7 +359,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
|
||||
Set<PsiClass> classes = collectContainingClasses(mappingToJava.keySet());
|
||||
|
||||
for (JetProperty property : getOverriddenDeclarations(mappingToJava, classes)) {
|
||||
for (JetProperty property : MarkersPackage.getOverriddenDeclarations(mappingToJava, classes)) {
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
PsiElement anchor = property.getNameIdentifier();
|
||||
@@ -400,7 +389,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
|
||||
Set<PsiClass> classes = collectContainingClasses(mappingToJava.keySet());
|
||||
|
||||
for (JetNamedFunction function : getOverriddenDeclarations(mappingToJava, classes)) {
|
||||
for (JetNamedFunction function : MarkersPackage.getOverriddenDeclarations(mappingToJava, classes)) {
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
PsiElement anchor = function.getNameIdentifier();
|
||||
@@ -428,128 +417,4 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
private static <T> Set<T> getOverriddenDeclarations(final Map<PsiMethod, T> mappingToJava, Set<PsiClass> classes) {
|
||||
final Set<T> overridden = Sets.newHashSet();
|
||||
for (PsiClass aClass : classes) {
|
||||
AllOverridingMethodsSearch.search(aClass).forEach(new Processor<Pair<PsiMethod, PsiMethod>>() {
|
||||
@Override
|
||||
public boolean process(Pair<PsiMethod, PsiMethod> pair) {
|
||||
ProgressManager.checkCanceled();
|
||||
|
||||
if (!(pair.getSecond() instanceof KotlinLightMethodFromTrait)) {
|
||||
PsiMethod superMethod = pair.getFirst();
|
||||
|
||||
T declaration = mappingToJava.get(superMethod);
|
||||
if (declaration != null) {
|
||||
mappingToJava.remove(superMethod);
|
||||
overridden.add(declaration);
|
||||
}
|
||||
}
|
||||
|
||||
return !mappingToJava.isEmpty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return overridden;
|
||||
}
|
||||
|
||||
public static String getOverriddenMethodTooltip(PsiMethod method) {
|
||||
PsiElementProcessor.CollectElementsWithLimit<PsiMethod> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(5);
|
||||
OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter<PsiMethod>(processor));
|
||||
|
||||
boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
|
||||
|
||||
if (processor.isOverflow()){
|
||||
return isAbstract ? DaemonBundle.message("method.is.implemented.too.many") : DaemonBundle.message("method.is.overridden.too.many");
|
||||
}
|
||||
|
||||
PsiMethod[] javaOverridings = processor.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
List<PsiMethod> filter = ContainerUtil.filter(javaOverridings, new Condition<PsiMethod>() {
|
||||
@Override
|
||||
public boolean value(PsiMethod method) {
|
||||
return !(method instanceof KotlinLightMethodFromTrait);
|
||||
}
|
||||
});
|
||||
PsiMethod[] overridings = filter.toArray(new PsiMethod[filter.size()]);
|
||||
|
||||
if (overridings.length == 0) return null;
|
||||
|
||||
Comparator<PsiMethod> comparator = new MethodCellRenderer(false).getComparator();
|
||||
Arrays.sort(overridings, comparator);
|
||||
|
||||
String start = isAbstract ? DaemonBundle.message("method.is.implemented.header") : DaemonBundle.message("method.is.overriden.header");
|
||||
@NonNls String pattern = " {1}";
|
||||
return GutterIconTooltipHelper.composeText(overridings, start, pattern);
|
||||
}
|
||||
|
||||
public static void navigateToOverriddenMethod(MouseEvent e, final PsiMethod method) {
|
||||
if (DumbService.isDumb(method.getProject())) {
|
||||
DumbService.getInstance(method.getProject()).showDumbModeNotification(
|
||||
"Navigation to overriding classes is not possible during index update");
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElementProcessor.CollectElementsWithLimit<PsiMethod> collectProcessor =
|
||||
new PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(2, new THashSet<PsiMethod>());
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter<PsiMethod>(collectProcessor));
|
||||
}
|
||||
}, "Searching for overriding methods", true, method.getProject(), (JComponent)e.getComponent())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiMethod[] javaOverridings = collectProcessor.toArray(PsiMethod.EMPTY_ARRAY);
|
||||
List<PsiMethod> filter = ContainerUtil.filter(javaOverridings, new Condition<PsiMethod>() {
|
||||
@Override
|
||||
public boolean value(PsiMethod method) {
|
||||
return !(method instanceof KotlinLightMethodFromTrait);
|
||||
}
|
||||
});
|
||||
PsiMethod[] overridings = filter.toArray(new PsiMethod[filter.size()]);
|
||||
|
||||
if (overridings.length == 0) return;
|
||||
boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridings);
|
||||
MethodCellRenderer renderer = new MethodCellRenderer(showMethodNames);
|
||||
Arrays.sort(overridings, renderer.getComparator());
|
||||
OverridingMethodsUpdater methodsUpdater = new OverridingMethodsUpdater(method, renderer);
|
||||
PsiElementListNavigator.openTargets(e, overridings, methodsUpdater.getCaption(overridings.length), "Overriding methods of " + method.getName(), renderer, methodsUpdater);
|
||||
}
|
||||
|
||||
private static class OverridingMethodsUpdater extends ListBackgroundUpdaterTask {
|
||||
private final PsiMethod myMethod;
|
||||
private final PsiElementListCellRenderer myRenderer;
|
||||
|
||||
public OverridingMethodsUpdater(PsiMethod method, PsiElementListCellRenderer renderer) {
|
||||
super(method.getProject(), "Searching for overriding methods");
|
||||
myMethod = method;
|
||||
myRenderer = renderer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCaption(int size) {
|
||||
return myMethod.hasModifierProperty(PsiModifier.ABSTRACT) ?
|
||||
DaemonBundle.message("navigation.title.implementation.method", myMethod.getName(), size) :
|
||||
DaemonBundle.message("navigation.title.overrider.method", myMethod.getName(), size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
super.run(indicator);
|
||||
OverridingMethodsSearch.search(myMethod, true).forEach(
|
||||
new CommonProcessors.CollectProcessor<PsiMethod>() {
|
||||
@Override
|
||||
public boolean process(PsiMethod psiMethod) {
|
||||
if (!updateComponent(psiMethod, myRenderer.getComparator())) {
|
||||
indicator.cancel();
|
||||
}
|
||||
indicator.checkCanceled();
|
||||
return super.process(psiMethod);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.plugin.highlighter.markers
|
||||
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.psi.search.PsiElementProcessor
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch
|
||||
import com.intellij.psi.PsiModifier
|
||||
import com.intellij.codeInsight.daemon.DaemonBundle
|
||||
import com.intellij.ide.util.MethodCellRenderer
|
||||
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper
|
||||
import java.awt.event.MouseEvent
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import javax.swing.JComponent
|
||||
import com.intellij.psi.util.PsiUtil
|
||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
|
||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask
|
||||
import com.intellij.ide.util.PsiElementListCellRenderer
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.util.CommonProcessors
|
||||
import com.intellij.psi.search.PsiElementProcessorAdapter
|
||||
import com.intellij.psi.PsiElement
|
||||
import gnu.trove.THashSet
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.search.searches.AllOverridingMethodsSearch
|
||||
import com.intellij.openapi.util.Pair
|
||||
import java.util.HashSet
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait
|
||||
|
||||
private fun <T> getOverriddenDeclarations(mappingToJava: MutableMap<PsiMethod, T>, classes: Set<PsiClass>): Set<T> {
|
||||
val overridden = HashSet<T>()
|
||||
for (aClass in classes) {
|
||||
AllOverridingMethodsSearch.search(aClass)!!.forEach(object : Processor<Pair<PsiMethod, PsiMethod>> {
|
||||
override fun process(pair: Pair<PsiMethod, PsiMethod>?): Boolean {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
if (pair!!.getSecond() !is KotlinLightMethodFromTrait) {
|
||||
val superMethod = pair.getFirst()
|
||||
|
||||
val declaration = mappingToJava.get(superMethod)
|
||||
if (declaration != null) {
|
||||
mappingToJava.remove(superMethod)
|
||||
overridden.add(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
return !mappingToJava.isEmpty()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return overridden
|
||||
}
|
||||
|
||||
public fun getOverriddenMethodTooltip(method: PsiMethod): String? {
|
||||
val processor = PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(5)
|
||||
OverridingMethodsSearch.search(method, true).forEach(PsiElementProcessorAdapter(processor))
|
||||
|
||||
val isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT)
|
||||
|
||||
if (processor.isOverflow()) {
|
||||
return if (isAbstract) DaemonBundle.message("method.is.implemented.too.many") else DaemonBundle.message("method.is.overridden.too.many")
|
||||
}
|
||||
|
||||
val comparator = MethodCellRenderer(false).getComparator()
|
||||
|
||||
val overridingJavaMethods = processor.getCollection().filter { it !is KotlinLightMethodFromTrait } sortBy(comparator)
|
||||
if (overridingJavaMethods.isEmpty()) return null
|
||||
|
||||
val start = if (isAbstract) DaemonBundle.message("method.is.implemented.header") else DaemonBundle.message("method.is.overriden.header")
|
||||
|
||||
return GutterIconTooltipHelper.composeText(overridingJavaMethods, start, " {1}")
|
||||
}
|
||||
|
||||
public fun navigateToOverriddenMethod(e: MouseEvent?, method: PsiMethod) {
|
||||
if (DumbService.isDumb(method.getProject())) {
|
||||
DumbService.getInstance(method.getProject())?.showDumbModeNotification("Navigation to overriding classes is not possible during index update")
|
||||
return
|
||||
}
|
||||
|
||||
val processor = PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(2, THashSet<PsiMethod>())
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
{
|
||||
OverridingMethodsSearch.search(method, true).forEach(PsiElementProcessorAdapter(processor))
|
||||
},
|
||||
"Searching for overriding declarations", true, method.getProject(), e?.getComponent() as JComponent?)) {
|
||||
return
|
||||
}
|
||||
|
||||
var overridingJavaMethods = processor.getCollection().filter { it !is KotlinLightMethodFromTrait }
|
||||
if (overridingJavaMethods.isEmpty()) return
|
||||
|
||||
val showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridingJavaMethods.copyToArray())
|
||||
|
||||
val renderer = MethodCellRenderer(showMethodNames)
|
||||
overridingJavaMethods = overridingJavaMethods.sortBy(renderer.getComparator())
|
||||
|
||||
val methodsUpdater = OverridingMethodsUpdater(method, renderer)
|
||||
PsiElementListNavigator.openTargets(
|
||||
e,
|
||||
overridingJavaMethods.copyToArray(),
|
||||
methodsUpdater.getCaption(overridingJavaMethods.size),
|
||||
"Overriding declarations of " + method.getName(),
|
||||
renderer,
|
||||
methodsUpdater)
|
||||
}
|
||||
|
||||
private class OverridingMethodsUpdater(
|
||||
private val myMethod: PsiMethod,
|
||||
private val myRenderer: PsiElementListCellRenderer<out PsiElement>) :
|
||||
ListBackgroundUpdaterTask(myMethod.getProject(), "Searching for overriding methods") {
|
||||
override fun getCaption(size: Int): String {
|
||||
return if (myMethod.hasModifierProperty(PsiModifier.ABSTRACT))
|
||||
DaemonBundle.message("navigation.title.implementation.method", myMethod.getName(), size)!!
|
||||
else
|
||||
DaemonBundle.message("navigation.title.overrider.method", myMethod.getName(), size)!!
|
||||
}
|
||||
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
super.run(indicator)
|
||||
OverridingMethodsSearch.search(myMethod, true).forEach(object : CommonProcessors.CollectProcessor<PsiMethod>() {
|
||||
override fun process(psiMethod: PsiMethod?): Boolean {
|
||||
if (!updateComponent(psiMethod, myRenderer.getComparator())) {
|
||||
indicator.cancel()
|
||||
}
|
||||
indicator.checkCanceled()
|
||||
return super.process(psiMethod)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user