mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
lambda/method refs: provide super class navigation - ctrl-u/line markers (IDEA-120160)
This commit is contained in:
@@ -81,6 +81,13 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware {
|
||||
}
|
||||
}
|
||||
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(element);
|
||||
if (interfaceMethod != null) {
|
||||
final Icon icon = AllIcons.Gutter.ImplementingMethod;
|
||||
final MarkerType type = MarkerType.OVERRIDING_METHOD;
|
||||
return new ArrowUpLineMarkerInfo(element, icon, type);
|
||||
}
|
||||
|
||||
if (myDaemonSettings.SHOW_METHOD_SEPARATORS && element.getFirstChild() == null) {
|
||||
PsiElement element1 = element;
|
||||
boolean isMember = false;
|
||||
|
||||
@@ -53,27 +53,27 @@ public class MarkerType {
|
||||
public static final MarkerType OVERRIDING_METHOD = new MarkerType(new NullableFunction<PsiElement, String>() {
|
||||
@Override
|
||||
public String fun(PsiElement element) {
|
||||
PsiElement parent = element.getParent();
|
||||
PsiElement parent = getParentMethod(element);
|
||||
if (!(parent instanceof PsiMethod)) return null;
|
||||
PsiMethod method = (PsiMethod)parent;
|
||||
|
||||
return calculateOverridingMethodTooltip(method);
|
||||
return calculateOverridingMethodTooltip(method, method != element.getParent());
|
||||
}
|
||||
}, new LineMarkerNavigator(){
|
||||
@Override
|
||||
public void browse(MouseEvent e, PsiElement element) {
|
||||
PsiElement parent = element.getParent();
|
||||
PsiElement parent = getParentMethod(element);
|
||||
if (!(parent instanceof PsiMethod)) return;
|
||||
PsiMethod method = (PsiMethod)parent;
|
||||
navigateToOverridingMethod(e, method);
|
||||
navigateToOverridingMethod(e, method, method != element.getParent());
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@Nullable
|
||||
public static String calculateOverridingMethodTooltip(PsiMethod method) {
|
||||
PsiMethod[] superMethods = method.findSuperMethods(false);
|
||||
if (superMethods.length == 0) return null;
|
||||
public static String calculateOverridingMethodTooltip(PsiMethod method, boolean acceptSelf) {
|
||||
PsiMethod[] superMethods = composeSuperMethods(method, acceptSelf);
|
||||
if (superMethods == null) return null;
|
||||
|
||||
PsiMethod superMethod = superMethods[0];
|
||||
boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT);
|
||||
@@ -90,9 +90,9 @@ public class MarkerType {
|
||||
return GutterIconTooltipHelper.composeText(superMethods, "", DaemonBundle.message(key));
|
||||
}
|
||||
|
||||
public static void navigateToOverridingMethod(MouseEvent e, PsiMethod method) {
|
||||
PsiMethod[] superMethods = method.findSuperMethods(false);
|
||||
if (superMethods.length == 0) return;
|
||||
public static void navigateToOverridingMethod(MouseEvent e, PsiMethod method, boolean acceptSelf) {
|
||||
PsiMethod[] superMethods = composeSuperMethods(method, acceptSelf);
|
||||
if (superMethods == null) return;
|
||||
boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(superMethods);
|
||||
PsiElementListNavigator.openTargets(e, superMethods,
|
||||
DaemonBundle.message("navigation.title.super.method", method.getName()),
|
||||
@@ -100,6 +100,22 @@ public class MarkerType {
|
||||
new MethodCellRenderer(showMethodNames));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod[] composeSuperMethods(PsiMethod method, boolean acceptSelf) {
|
||||
PsiMethod[] superMethods = method.findSuperMethods(false);
|
||||
if (acceptSelf) {
|
||||
superMethods = ArrayUtil.prepend(method, superMethods);
|
||||
}
|
||||
if (superMethods.length == 0) return null;
|
||||
return superMethods;
|
||||
}
|
||||
|
||||
private static PsiElement getParentMethod(PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(element);
|
||||
return interfaceMethod != null ? interfaceMethod : parent;
|
||||
}
|
||||
|
||||
public static final String SEARCHING_FOR_OVERRIDING_METHODS = "Searching for overriding methods";
|
||||
public static final MarkerType OVERRIDEN_METHOD = new MarkerType(new NullableFunction<PsiElement, String>() {
|
||||
@Override
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.FindSuperElementsHelper;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -65,20 +66,27 @@ public class JavaGotoSuperHandler implements CodeInsightActionHandler {
|
||||
|
||||
@Nullable
|
||||
private PsiElement[] findSuperElements(PsiFile file, int offset) {
|
||||
PsiNameIdentifierOwner parent = getElement(file, offset);
|
||||
if (parent == null) return null;
|
||||
PsiElement element = getElement(file, offset);
|
||||
if (element == null) return null;
|
||||
|
||||
final PsiExpression expression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class, PsiMethodReferenceExpression.class);
|
||||
if (expression != null) {
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(expression);
|
||||
if (interfaceMethod != null) {
|
||||
return ArrayUtil.prepend(interfaceMethod, interfaceMethod.findSuperMethods(false));
|
||||
}
|
||||
}
|
||||
|
||||
final PsiNameIdentifierOwner parent = PsiTreeUtil.getNonStrictParentOfType(element, PsiMethod.class, PsiClass.class);
|
||||
if (parent == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return FindSuperElementsHelper.findSuperElements(parent);
|
||||
}
|
||||
|
||||
protected PsiNameIdentifierOwner getElement(PsiFile file, int offset) {
|
||||
PsiElement element = file.findElementAt(offset);
|
||||
if (element == null) return null;
|
||||
|
||||
PsiNameIdentifierOwner parent = PsiTreeUtil.getParentOfType(element, PsiMethod.class, PsiClass.class);
|
||||
if (parent == null)
|
||||
return null;
|
||||
return parent;
|
||||
protected PsiElement getElement(PsiFile file, int offset) {
|
||||
return file.findElementAt(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package com.intellij.spi;
|
||||
|
||||
import com.intellij.codeInsight.navigation.JavaGotoSuperHandler;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiNameIdentifierOwner;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.spi.psi.SPIClassProviderReferenceElement;
|
||||
|
||||
@@ -27,11 +26,11 @@ import com.intellij.spi.psi.SPIClassProviderReferenceElement;
|
||||
*/
|
||||
public class SPIGotoSuperHandler extends JavaGotoSuperHandler {
|
||||
@Override
|
||||
protected PsiNameIdentifierOwner getElement(PsiFile file, int offset) {
|
||||
protected PsiElement getElement(PsiFile file, int offset) {
|
||||
final SPIClassProviderReferenceElement
|
||||
providerElement = PsiTreeUtil.getParentOfType(file.findElementAt(offset), SPIClassProviderReferenceElement.class);
|
||||
providerElement = PsiTreeUtil.getParentOfType(super.getElement(file, offset), SPIClassProviderReferenceElement.class);
|
||||
if (providerElement != null) {
|
||||
return (PsiClass)providerElement.resolve();
|
||||
return providerElement.resolve();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -60,6 +60,16 @@ public class LambdaUtil {
|
||||
return getFunctionalInterfaceMethod(PsiUtil.resolveGenericsClassInType(functionalInterfaceType));
|
||||
}
|
||||
|
||||
public static PsiMethod getFunctionalInterfaceMethod(@Nullable PsiElement element) {
|
||||
if (element instanceof PsiLambdaExpression || element instanceof PsiMethodReferenceExpression) {
|
||||
final PsiType samType = element instanceof PsiLambdaExpression
|
||||
? ((PsiLambdaExpression)element).getFunctionalInterfaceType()
|
||||
: ((PsiMethodReferenceExpression)element).getFunctionalInterfaceType();
|
||||
return getFunctionalInterfaceMethod(samType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getFunctionalInterfaceMethod(PsiClassType.ClassResolveResult result) {
|
||||
final PsiClass psiClass = result.getElement();
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
interface I {
|
||||
void <caret>run();
|
||||
}
|
||||
|
||||
class Foo {
|
||||
{
|
||||
I i = () -> {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
interface I {
|
||||
void run();
|
||||
}
|
||||
|
||||
class Foo {
|
||||
{
|
||||
I i = ()<caret> -> {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
interface I {
|
||||
void run();
|
||||
}
|
||||
|
||||
class Foo {
|
||||
{
|
||||
I i = ()<caret> -> {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.intellij.codeInsight.navigation;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.CodeInsightActionHandler;
|
||||
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
|
||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
|
||||
import com.intellij.lang.CodeInsightActions;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JavaGotoSuperTest extends LightDaemonAnalyzerTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath();
|
||||
}
|
||||
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/gotosuper/";
|
||||
}
|
||||
|
||||
public void testLambda() throws Throwable {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLambdaMarker() throws Exception {
|
||||
configureByFile(getBasePath() + getTestName(false) + ".java");
|
||||
int offset = myEditor.getCaretModel().getOffset();
|
||||
|
||||
doHighlighting();
|
||||
Document document = getEditor().getDocument();
|
||||
List<LineMarkerInfo> markers = DaemonCodeAnalyzerImpl.getLineMarkers(document, getProject());
|
||||
for (LineMarkerInfo info : markers) {
|
||||
if (info.endOffset >= offset && info.startOffset <= offset) {
|
||||
assertEquals("<html><body>Overrides method in 'I'</body></html>", info.getLineMarkerTooltip());
|
||||
return;
|
||||
}
|
||||
}
|
||||
fail("Gutter expected");
|
||||
}
|
||||
|
||||
private void doTest() throws Throwable {
|
||||
configureByFile(getBasePath() + getTestName(false) + ".java");
|
||||
final CodeInsightActionHandler handler = CodeInsightActions.GOTO_SUPER.forLanguage(JavaLanguage.INSTANCE);
|
||||
handler.invoke(getProject(), getEditor(), getFile());
|
||||
checkResultByFile(getBasePath() + getTestName(false) + ".after.java");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user