diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java
index de09c0840340..780fd5886003 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/GutterIconTooltipHelper.java
@@ -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("
");
result.append(start);
diff --git a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java
index e9039aba119b..7d5bfda6dfec 100644
--- a/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java
+++ b/java/java-analysis-impl/src/com/intellij/psi/impl/FindSuperElementsHelper.java
@@ -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 subClassCache) {
+ // returns super method, sub class
+ public static Pair getSiblingInheritedViaSubClass(@NotNull final PsiMethod method,
+ @NotNull Map 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 checkedInterfaces = new THashSet();
- final PsiMethod[] result = new PsiMethod[1];
+ final Ref> result = Ref.create();
ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true, true, false).forEach(new Processor() {
@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
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java
index f60ba833b1f6..21847f82799c 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/JavaLineMarkerProvider.java
@@ -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);
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java
index 5de455903a00..604e4db19817 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/MarkerType.java
@@ -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() {
+ @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 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 {0}", 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) {
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java
index 5fc8d7b07da2..f39d316b5bd1 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/JavaGotoSuperTest.java
@@ -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 markers, PsiElement psiMethod) {