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 elements, String start, final String pattern) { + public static String composeText(@NotNull Iterable elements, @NotNull String start, @NotNull String pattern) { return composeText(elements, start, pattern, ""); } - public static String composeText(@NotNull Iterable elements, String start, final String pattern, String postfix) { + public static String composeText(@NotNull Iterable 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) {