IDEA-143820

This commit is contained in:
Alexey Kudravtsev
2015-09-02 14:10:13 +03:00
parent 4f22cc16f6
commit 00a08306e9
5 changed files with 63 additions and 13 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-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.
@@ -36,15 +36,15 @@ public class GutterIconTooltipHelper {
private GutterIconTooltipHelper() {
}
public static String composeText(@NotNull PsiElement[] elements, String start, final String pattern) {
public static String composeText(@NotNull PsiElement[] elements, @NotNull String start, @NotNull String pattern) {
return composeText(Arrays.asList(elements), start, pattern);
}
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, String start, final String pattern) {
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, @NotNull String start, @NotNull String pattern) {
return composeText(elements, start, pattern, "");
}
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, String start, final String pattern, String postfix) {
public static String composeText(@NotNull Iterable<? extends PsiElement> elements, @NotNull String start, @NotNull String pattern, @NotNull String postfix) {
@NonNls StringBuilder result = new StringBuilder();
result.append("<html><body>");
result.append(start);
@@ -15,6 +15,8 @@
*/
package com.intellij.psi.impl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.MethodSignature;
@@ -64,11 +66,12 @@ public class FindSuperElementsHelper {
}
public static PsiMethod getSiblingInheritedViaSubClass(@NotNull PsiMethod method) {
return getSiblingInheritedViaSubClass(method, createSubClassCache());
return Pair.getFirst(getSiblingInheritedViaSubClass(method, createSubClassCache()));
}
public static PsiMethod getSiblingInheritedViaSubClass(@NotNull final PsiMethod method,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
// returns super method, sub class
public static Pair<PsiMethod, PsiClass> getSiblingInheritedViaSubClass(@NotNull final PsiMethod method,
@NotNull Map<PsiClass, PsiClass> subClassCache) {
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return null;
if (method.hasModifierProperty(PsiModifier.STATIC)) return null;
final PsiClass containingClass = method.getContainingClass();
@@ -77,7 +80,7 @@ public class FindSuperElementsHelper {
return null;
}
final Collection<PsiAnchor> checkedInterfaces = new THashSet<PsiAnchor>();
final PsiMethod[] result = new PsiMethod[1];
final Ref<Pair<PsiMethod, PsiClass>> result = Ref.create();
ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false).forEach(new Processor<PsiClass>() {
@Override
public boolean process(PsiClass inheritor) {
@@ -107,14 +110,14 @@ public class FindSuperElementsHelper {
if (!isOverridden) {
continue;
}
result[0] = superMethod;
result.set(Pair.create(superMethod, inheritor));
return false;
}
}
return true;
}
});
return result[0];
return result.get();
}
@NotNull
@@ -184,12 +184,14 @@ public class JavaLineMarkerProvider implements LineMarkerProvider {
boolean canHaveSiblingSuper = !method.hasModifierProperty(PsiModifier.ABSTRACT) && !method.hasModifierProperty(PsiModifier.STATIC) && method.hasModifierProperty(PsiModifier.PUBLIC)&& !method.hasModifierProperty(PsiModifier.FINAL)&& !method.hasModifierProperty(PsiModifier.NATIVE);
if (!canHaveSiblingSuper) continue;
PsiMethod siblingInheritedViaSubClass = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache);
PsiMethod siblingInheritedViaSubClass = Pair.getFirst(FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, subClassCache));
if (siblingInheritedViaSubClass == null) {
continue;
}
PsiElement range = getMethodRange(method);
LineMarkerInfo info = createSuperMethodLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, Pass.UPDATE_OVERRIDEN_MARKERS);
ArrowUpLineMarkerInfo upInfo = new ArrowUpLineMarkerInfo(range, AllIcons.Gutter.ImplementingMethod, MarkerType.SIBLING_OVERRIDING_METHOD,
Pass.UPDATE_OVERRIDEN_MARKERS);
LineMarkerInfo info = NavigateAction.setNavigateAction(upInfo, "Go to super method", IdeActions.ACTION_GOTO_SUPER);
result.add(info);
}
}
@@ -33,8 +33,10 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.FindSuperElementsHelper;
import com.intellij.psi.presentation.java.ClassPresentationUtil;
import com.intellij.psi.search.PsiElementProcessor;
import com.intellij.psi.search.PsiElementProcessorAdapter;
import com.intellij.psi.search.SearchScope;
@@ -54,6 +56,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Comparator;
@@ -119,6 +122,24 @@ public class MarkerType {
navigateToOverridingMethod(e, method, method != element.getParent());
}
});
static final MarkerType SIBLING_OVERRIDING_METHOD = new MarkerType("SIBLING_OVERRIDING_METHOD", new NullableFunction<PsiElement, String>() {
@Override
public String fun(PsiElement element) {
PsiElement parent = getParentMethod(element);
if (!(parent instanceof PsiMethod)) return null;
PsiMethod method = (PsiMethod)parent;
return calculateOverridingSiblingMethodTooltip(method);
}
}, new LineMarkerNavigator() {
@Override
public void browse(MouseEvent e, PsiElement element) {
PsiElement parent = getParentMethod(element);
if (!(parent instanceof PsiMethod)) return;
PsiMethod method = (PsiMethod)parent;
navigateToSiblingOverridingMethod(e, method);
}
});
@Nullable
private static String calculateOverridingMethodTooltip(@NotNull PsiMethod method, boolean acceptSelf) {
@@ -139,6 +160,22 @@ public class MarkerType {
}
return composeText(superMethods, "", DaemonBundle.message(key), IdeActions.ACTION_GOTO_SUPER);
}
@Nullable
private static String calculateOverridingSiblingMethodTooltip(@NotNull PsiMethod method) {
Pair<PsiMethod, PsiClass> pair =
FindSuperElementsHelper.getSiblingInheritedViaSubClass(method, FindSuperElementsHelper.createSubClassCache());
if (pair == null) return null;
PsiMethod superMethod = pair.getFirst();
PsiClass subClass = pair.getSecond();
boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
boolean isSuperAbstract = superMethod.hasModifierProperty(PsiModifier.ABSTRACT);
String postfix = MessageFormat.format(" via sub-class <a href=\"#javaClass/{0}\">{0}</a>", ClassPresentationUtil.getNameForClass(subClass, false));
@NonNls String pattern = DaemonBundle.message(isSuperAbstract && !isAbstract ?
"method.implements" :
"method.overrides") + postfix;
return composeText(new PsiElement[]{superMethod}, "", pattern, IdeActions.ACTION_GOTO_SUPER);
}
@NotNull
private static String composeText(@NotNull PsiElement[] methods, @NotNull String start, @NotNull String pattern, @NotNull String actionId) {
@@ -159,6 +196,14 @@ public class MarkerType {
DaemonBundle.message("navigation.findUsages.title.super.method", method.getName()),
new MethodCellRenderer(showMethodNames));
}
private static void navigateToSiblingOverridingMethod(MouseEvent e, @NotNull PsiMethod method) {
PsiMethod superMethod = FindSuperElementsHelper.getSiblingInheritedViaSubClass(method);
if (superMethod == null) return;
PsiElementListNavigator.openTargets(e, new NavigatablePsiElement[]{superMethod},
DaemonBundle.message("navigation.title.super.method", method.getName()),
DaemonBundle.message("navigation.findUsages.title.super.method", method.getName()),
new MethodCellRenderer(false));
}
@NotNull
private static PsiMethod[] composeSuperMethods(@NotNull PsiMethod method, boolean acceptSelf) {
@@ -96,7 +96,7 @@ public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase {
assertSame(MarkerType.OVERRIDDEN_METHOD.getNavigationHandler(), iMarker.getNavigationHandler());
LineMarkerInfo aMarker = findMarkerWithElement(markers, aRun.getNameIdentifier());
assertSame(MarkerType.OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler());
assertSame(MarkerType.SIBLING_OVERRIDING_METHOD.getNavigationHandler(), aMarker.getNavigationHandler());
}
private static LineMarkerInfo findMarkerWithElement(List<LineMarkerInfo> markers, PsiElement psiMethod) {