From 4abdc2887378b03b811dea9cffdaf48c7b90aed3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 10 Nov 2014 14:21:17 +0100 Subject: [PATCH] enable overriding marks for functional expressions --- .../daemon/impl/JavaLineMarkerProvider.java | 15 +++- .../codeInsight/daemon/impl/MarkerType.java | 89 +++++++++++++++---- ...hodOrFunctionalExpressionCellRenderer.java | 53 +++++++++++ ...rFunctionalExpressionListCellRenderer.java | 40 +++++++++ .../intellij/psi/PsiFunctionalExpression.java | 1 + 5 files changed, 181 insertions(+), 17 deletions(-) create mode 100644 java/java-impl/src/com/intellij/ide/util/MethodOrFunctionalExpressionCellRenderer.java create mode 100644 java/java-impl/src/com/intellij/ide/util/PsiClassOrFunctionalExpressionListCellRenderer.java 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 f017ad5c61b3..8c6a19b49a81 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 @@ -37,6 +37,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.searches.AllOverridingMethodsSearch; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.SuperMethodsSearch; import com.intellij.psi.util.MethodSignatureBackedByPsiMethod; import com.intellij.psi.util.PsiUtil; @@ -179,8 +180,7 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { } if (CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) return; // It's useless to have overridden markers for object. - PsiClass inheritor = ClassInheritorsSearch.search(aClass, false).findFirst(); - if (inheritor != null) { + if (ClassInheritorsSearch.search(aClass, false).findFirst() != null || FunctionalExpressionSearch.search(aClass).findFirst() != null) { final Icon icon = aClass.isInterface() ? AllIcons.Gutter.ImplementedMethod : AllIcons.Gutter.OverridenMethod; PsiElement range = aClass.getNameIdentifier(); if (range == null) range = aClass; @@ -219,6 +219,17 @@ public class JavaLineMarkerProvider implements LineMarkerProvider, DumbAware { }); } + if (!methods.isEmpty()) { + for (PsiClass aClass : classes) { + final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(aClass); + if (interfaceMethod != null) { + if (FunctionalExpressionSearch.search(aClass).findFirst() != null) { + overridden.add(interfaceMethod); + } + } + } + } + for (PsiMethod method : overridden) { ProgressManager.checkCanceled(); boolean overrides = !method.hasModifierProperty(PsiModifier.ABSTRACT); 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 72e8eca35fa6..0232be21919d 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 @@ -23,9 +23,7 @@ import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.daemon.DaemonBundle; import com.intellij.codeInsight.daemon.GutterIconNavigationHandler; import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask; -import com.intellij.ide.util.MethodCellRenderer; -import com.intellij.ide.util.PsiClassListCellRenderer; -import com.intellij.ide.util.PsiElementListCellRenderer; +import com.intellij.ide.util.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -36,6 +34,7 @@ import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.SearchScope; import com.intellij.psi.search.searches.ClassInheritorsSearch; +import com.intellij.psi.search.searches.FunctionalExpressionSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.util.PsiUtil; import com.intellij.util.*; @@ -136,7 +135,7 @@ public class MarkerType { } }); - public static String getOverriddenMethodTooltip(PsiMethod method) { + public static String getOverriddenMethodTooltip(final PsiMethod method) { PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(5); OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter(processor)); @@ -146,8 +145,14 @@ public class MarkerType { return isAbstract ? DaemonBundle.message("method.is.implemented.too.many") : DaemonBundle.message("method.is.overridden.too.many"); } - PsiMethod[] overridings = processor.toArray(new PsiMethod[processor.getCollection().size()]); - if (overridings.length == 0) return null; + PsiMethod[] overridings = processor.toArray(PsiMethod.EMPTY_ARRAY); + if (overridings.length == 0) { + final PsiClass aClass = method.getContainingClass(); + if (aClass != null && FunctionalExpressionSearch.search(aClass).findFirst() != null) { + return "Has functional implementations"; + } + return null; + } Comparator comparator = new MethodCellRenderer(false).getComparator(); Arrays.sort(overridings, comparator); @@ -166,19 +171,33 @@ public class MarkerType { final PsiElementProcessor.CollectElementsWithLimit collectProcessor = new PsiElementProcessor.CollectElementsWithLimit(2, new THashSet()); + final PsiElementProcessor.CollectElementsWithLimit collectExprProcessor = + new PsiElementProcessor.CollectElementsWithLimit(2, new THashSet()); if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { @Override public void run() { OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter(collectProcessor)); + if (collectProcessor.getCollection().isEmpty()) { + final PsiClass aClass = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiClass compute() { + return method.getContainingClass(); + } + }); + if (aClass != null) { + FunctionalExpressionSearch.search(aClass).forEach(new PsiElementProcessorAdapter(collectExprProcessor)); + } + } } }, SEARCHING_FOR_OVERRIDING_METHODS, true, method.getProject(), (JComponent)e.getComponent())) { return; } - PsiMethod[] overridings = collectProcessor.toArray(PsiMethod.EMPTY_ARRAY); + final PsiMethod[] methodOverriders = collectProcessor.toArray(PsiMethod.EMPTY_ARRAY); + NavigatablePsiElement[] overridings = ArrayUtil.mergeArrays(methodOverriders, collectExprProcessor.toArray(PsiFunctionalExpression.EMPTY_ARRAY)); if (overridings.length == 0) return; - boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridings); - MethodCellRenderer renderer = new MethodCellRenderer(showMethodNames); + boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(methodOverriders); + MethodOrFunctionalExpressionCellRenderer renderer = new MethodOrFunctionalExpressionCellRenderer(showMethodNames); Arrays.sort(overridings, renderer.getComparator()); final OverridingMethodsUpdater methodsUpdater = new OverridingMethodsUpdater(method, renderer); PsiElementListNavigator.openTargets(e, overridings, methodsUpdater.getCaption(overridings.length), "Overriding methods of " + method.getName(), renderer, methodsUpdater); @@ -214,8 +233,16 @@ public class MarkerType { : DaemonBundle.message("class.is.subclassed.too.many"); } - PsiClass[] subclasses = processor.toArray(new PsiClass[processor.getCollection().size()]); - if (subclasses.length == 0) return null; + PsiClass[] subclasses = processor.toArray(PsiClass.EMPTY_ARRAY); + if (subclasses.length == 0) { + final PsiElementProcessor.CollectElementsWithLimit functionalImplementations = + new PsiElementProcessor.CollectElementsWithLimit<>(2, new THashSet()); + FunctionalExpressionSearch.search(aClass).forEach(new PsiElementProcessorAdapter(functionalImplementations)); + if (!functionalImplementations.getCollection().isEmpty()) { + return "Has functional implementations"; + } + return null; + } Comparator comparator = new PsiClassListCellRenderer().getComparator(); Arrays.sort(subclasses, comparator); @@ -234,18 +261,23 @@ public class MarkerType { } final PsiElementProcessor.CollectElementsWithLimit collectProcessor = new PsiElementProcessor.CollectElementsWithLimit(2, new THashSet()); + final PsiElementProcessor.CollectElementsWithLimit collectExprProcessor = new PsiElementProcessor.CollectElementsWithLimit(2, new THashSet()); if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { @Override public void run() { ClassInheritorsSearch.search(aClass, true).forEach(new PsiElementProcessorAdapter(collectProcessor)); + if (collectProcessor.getCollection().isEmpty()) { + FunctionalExpressionSearch.search(aClass).forEach(new PsiElementProcessorAdapter(collectExprProcessor)); + } } }, SEARCHING_FOR_OVERRIDDEN_METHODS, true, aClass.getProject(), (JComponent)e.getComponent())) { return; } - PsiClass[] inheritors = collectProcessor.toArray(PsiClass.EMPTY_ARRAY); + NavigatablePsiElement[] inheritors = ArrayUtil.mergeArrays(collectProcessor.toArray(PsiClass.EMPTY_ARRAY), + collectExprProcessor.toArray(PsiFunctionalExpression.EMPTY_ARRAY)); if (inheritors.length == 0) return; - final PsiClassListCellRenderer renderer = new PsiClassListCellRenderer(); + final PsiClassOrFunctionalExpressionListCellRenderer renderer = new PsiClassOrFunctionalExpressionListCellRenderer(); final SubclassUpdater subclassUpdater = new SubclassUpdater(aClass, renderer); Arrays.sort(inheritors, renderer.getComparator()); PsiElementListNavigator.openTargets(e, inheritors, subclassUpdater.getCaption(inheritors.length), CodeInsightBundle.message("goto.implementation.findUsages.title", aClass.getName()), renderer, subclassUpdater); @@ -276,9 +308,9 @@ public class MarkerType { private static class SubclassUpdater extends ListBackgroundUpdaterTask { private final PsiClass myClass; - private final PsiClassListCellRenderer myRenderer; + private final PsiClassOrFunctionalExpressionListCellRenderer myRenderer; - public SubclassUpdater(PsiClass aClass, PsiClassListCellRenderer renderer) { + public SubclassUpdater(PsiClass aClass, PsiClassOrFunctionalExpressionListCellRenderer renderer) { super(aClass.getProject(), SEARCHING_FOR_OVERRIDDEN_METHODS); myClass = aClass; myRenderer = renderer; @@ -309,6 +341,17 @@ public class MarkerType { return super.process(o); } }); + + FunctionalExpressionSearch.search(myClass).forEach(new CommonProcessors.CollectProcessor() { + @Override + public boolean process(final PsiFunctionalExpression expr) { + if (!updateComponent(expr, myRenderer.getComparator())) { + indicator.cancel(); + } + indicator.checkCanceled(); + return super.process(expr); + } + }); } } @@ -344,6 +387,22 @@ public class MarkerType { return super.process(psiMethod); } }); + final PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable() { + @Override + public PsiClass compute() { + return myMethod.getContainingClass(); + } + }); + FunctionalExpressionSearch.search(psiClass).forEach(new CommonProcessors.CollectProcessor() { + @Override + public boolean process(final PsiFunctionalExpression expr) { + if (!updateComponent(expr, myRenderer.getComparator())) { + indicator.cancel(); + } + indicator.checkCanceled(); + return super.process(expr); + } + }); } } } diff --git a/java/java-impl/src/com/intellij/ide/util/MethodOrFunctionalExpressionCellRenderer.java b/java/java-impl/src/com/intellij/ide/util/MethodOrFunctionalExpressionCellRenderer.java new file mode 100644 index 000000000000..0e8a33a9b111 --- /dev/null +++ b/java/java-impl/src/com/intellij/ide/util/MethodOrFunctionalExpressionCellRenderer.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.util; + +import com.intellij.psi.*; +import com.intellij.psi.util.PsiExpressionTrimRenderer; +import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiFormatUtilBase; + +import javax.swing.*; + +public class MethodOrFunctionalExpressionCellRenderer extends PsiElementListCellRenderer { + private final PsiClassListCellRenderer myClassListCellRenderer = new PsiClassListCellRenderer(); + private final MethodCellRenderer myMethodCellRenderer; + + public MethodOrFunctionalExpressionCellRenderer(boolean showMethodNames) { + this(showMethodNames, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS); + } + public MethodOrFunctionalExpressionCellRenderer(boolean showMethodNames, @PsiFormatUtil.FormatMethodOptions int options) { + myMethodCellRenderer = new MethodCellRenderer(showMethodNames, options); + } + + public String getElementText(NavigatablePsiElement element) { + return element instanceof PsiMethod ? myMethodCellRenderer.getElementText((PsiMethod)element) + : PsiExpressionTrimRenderer.render((PsiExpression)element); + } + + protected Icon getIcon(PsiElement element) { + return element instanceof PsiMethod ? myMethodCellRenderer.getIcon(element) : null; + } + + public String getContainerText(final NavigatablePsiElement element, final String name) { + return element instanceof PsiMethod ? myMethodCellRenderer.getContainerText((PsiMethod)element, name) + : PsiClassListCellRenderer.getContainerTextStatic(element); + } + + public int getIconFlags() { + return myClassListCellRenderer.getIconFlags(); + } +} diff --git a/java/java-impl/src/com/intellij/ide/util/PsiClassOrFunctionalExpressionListCellRenderer.java b/java/java-impl/src/com/intellij/ide/util/PsiClassOrFunctionalExpressionListCellRenderer.java new file mode 100644 index 000000000000..eeea2efd734b --- /dev/null +++ b/java/java-impl/src/com/intellij/ide/util/PsiClassOrFunctionalExpressionListCellRenderer.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ide.util; + +import com.intellij.psi.NavigatablePsiElement; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiExpression; +import com.intellij.psi.presentation.java.ClassPresentationUtil; +import com.intellij.psi.util.PsiExpressionTrimRenderer; + +public class PsiClassOrFunctionalExpressionListCellRenderer extends PsiElementListCellRenderer { + @Override + public String getElementText(NavigatablePsiElement element) { + return element instanceof PsiClass ? ClassPresentationUtil.getNameForClass((PsiClass)element, false) + : PsiExpressionTrimRenderer.render((PsiExpression)element); + } + + @Override + protected String getContainerText(NavigatablePsiElement element, final String name) { + return PsiClassListCellRenderer.getContainerTextStatic(element); + } + + @Override + protected int getIconFlags() { + return 0; + } +} diff --git a/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java b/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java index 28290da31342..000848fc1faf 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiFunctionalExpression.java @@ -19,6 +19,7 @@ import com.intellij.openapi.util.Iconable; import org.jetbrains.annotations.Nullable; public interface PsiFunctionalExpression extends PsiExpression, Iconable, NavigatablePsiElement { + PsiFunctionalExpression[] EMPTY_ARRAY = new PsiFunctionalExpression[0]; /** * @return SAM type the lambda expression corresponds to * null when no SAM type could be found