Add special class for getting methods from traits

This commit is contained in:
Nikolay Krasko
2014-08-25 22:25:50 +04:00
parent 35c67734d3
commit 8ada9b68b0
4 changed files with 179 additions and 12 deletions
@@ -18,6 +18,7 @@ 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.GutterIconNavigationHandler;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
@@ -25,13 +26,18 @@ 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.application.ApplicationManager;
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.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -41,6 +47,7 @@ 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;
@@ -48,6 +55,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
@@ -98,7 +106,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
@Override
public String fun(@Nullable PsiElement element) {
PsiMethod psiMethod = getPsiMethod(element);
return psiMethod != null ? MarkerType.getOverriddenMethodTooltip(psiMethod) : null;
return psiMethod != null ? getOverriddenMethodTooltip(psiMethod) : null;
}
},
@@ -107,7 +115,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
public void browse(@Nullable MouseEvent e, @Nullable PsiElement element) {
PsiMethod psiMethod = getPsiMethod(element);
if (psiMethod != null) {
MarkerType.navigateToOverriddenMethod(e, psiMethod);
navigateToOverriddenMethod(e, psiMethod);
}
}
}
@@ -485,13 +493,111 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
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 = "&nbsp;&nbsp;&nbsp;&nbsp;{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);
}
});
}
}
public static class KotlinSuperNavigationHandler implements GutterIconNavigationHandler<JetElement> {
private List<NavigatablePsiElement> testNavigableElements;
@TestOnly
@NotNull
public Collection<NavigatablePsiElement> getNavigationElements() {
Collection<NavigatablePsiElement> navigationResult = testNavigableElements;
public List<NavigatablePsiElement> getNavigationElements() {
List<NavigatablePsiElement> navigationResult = testNavigableElements;
testNavigableElements = null;
return navigationResult;
}