From f76025710ebf7a5d1c180a0b0a8d76917aab8a9f Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Wed, 1 Oct 2014 14:32:40 +0400 Subject: [PATCH] Rewrite to Kotlin: overridden properties markers tooltip and navigation --- .../highlighter/JetLineMarkerProvider.java | 99 ++------------- .../markers/OverridenPropertyMarker.kt | 115 ++++++++++++++++++ 2 files changed, 128 insertions(+), 86 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenPropertyMarker.kt diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java index 77bf00ee81c..57f5c9e8ed3 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java @@ -16,32 +16,23 @@ package org.jetbrains.jet.plugin.highlighter; -import com.google.common.collect.*; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.intellij.codeHighlighting.Pass; import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.codeInsight.daemon.LineMarkerProvider; -import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper; import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator; import com.intellij.codeInsight.daemon.impl.MarkerType; -import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator; import com.intellij.icons.AllIcons; -import com.intellij.ide.util.DefaultPsiElementCellRenderer; -import com.intellij.ide.util.PsiClassListCellRenderer; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; -import com.intellij.psi.NavigatablePsiElement; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiElementProcessor; -import com.intellij.psi.search.PsiElementProcessorAdapter; import com.intellij.psi.search.searches.ClassInheritorsSearch; -import com.intellij.psi.search.searches.OverridingMethodsSearch; -import com.intellij.util.*; +import com.intellij.util.NullableFunction; import kotlin.KotlinPackage; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.asJava.LightClassUtil; @@ -49,17 +40,18 @@ import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.Modality; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.plugin.JetBundle; import org.jetbrains.jet.plugin.ProjectRootsUtil; import org.jetbrains.jet.plugin.highlighter.markers.MarkersPackage; import org.jetbrains.jet.plugin.highlighter.markers.ResolveWithParentsResult; import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerNavigationHandler; import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerTooltip; -import org.jetbrains.jet.plugin.search.ideaExtensions.KotlinDefinitionsSearcher; import javax.swing.*; import java.awt.event.MouseEvent; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; public class JetLineMarkerProvider implements LineMarkerProvider { public static final Icon OVERRIDING_MARK = AllIcons.Gutter.OverridingMethod; @@ -116,85 +108,19 @@ public class JetLineMarkerProvider implements LineMarkerProvider { assert element.getParent() instanceof JetProperty : "This tooltip provider should be placed only on identifies in properties"; JetProperty property = (JetProperty) element.getParent(); - PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(5); - Processor consumer = new AdapterProcessor( - new CommonProcessors.UniqueProcessor(new PsiElementProcessorAdapter(processor)), - new Function() { - @Override - public PsiClass fun(PsiMethod method) { - return method.getContainingClass(); - } - }); - - for (PsiMethod method : LightClassUtil.getLightClassPropertyMethods(property)) { - if (!processor.isOverflow()) { - OverridingMethodsSearch.search(method, true).forEach(consumer); - } - } - - boolean isImplemented = isImplemented(property); - if (processor.isOverflow()) { - return isImplemented ? - JetBundle.message("property.is.implemented.too.many") : - JetBundle.message("property.is.overridden.too.many"); - } - - List collectedClasses = Lists.newArrayList(processor.getCollection()); - if (collectedClasses.isEmpty()) return null; - - Collections.sort(collectedClasses, new PsiClassListCellRenderer().getComparator()); - - String start = isImplemented ? - JetBundle.message("property.is.implemented.header") : - JetBundle.message("property.is.overridden.header"); - - @NonNls String pattern = "    {0}"; - return GutterIconTooltipHelper.composeText(collectedClasses, start, pattern); + return MarkersPackage.getOverriddenPropertyTooltip(property); } }, new LineMarkerNavigator() { @Override - public void browse(@Nullable MouseEvent e, @Nullable final PsiElement element) { + public void browse(@Nullable MouseEvent e, @Nullable PsiElement element) { if (element == null) return; assert element.getParent() instanceof JetProperty : "This marker navigator should be placed only on identifies in properties"; JetProperty property = (JetProperty) element.getParent(); - if (DumbService.isDumb(element.getProject())) { - DumbService.getInstance(element.getProject()).showDumbModeNotification("Navigation to overriding classes is not possible during index update"); - return; - } - - final LightClassUtil.PropertyAccessorsPsiMethods psiPropertyMethods = - LightClassUtil.getLightClassPropertyMethods((JetProperty) element.getParent()); - - final CommonProcessors.CollectUniquesProcessor elementProcessor = new CommonProcessors.CollectUniquesProcessor(); - Runnable jetPsiMethodProcessor = new Runnable() { - @Override - public void run() { - KotlinDefinitionsSearcher.processPropertyImplementationsMethods(psiPropertyMethods, GlobalSearchScope.allScope(element.getProject()), elementProcessor); - } - }; - - if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( - jetPsiMethodProcessor, - MarkerType.SEARCHING_FOR_OVERRIDING_METHODS, true, - element.getProject(), - e != null ? (JComponent) e.getComponent() : null)) { - return; - } - - DefaultPsiElementCellRenderer renderer = new DefaultPsiElementCellRenderer(); - List elements = Ordering.from(renderer.getComparator()).sortedCopy(elementProcessor.getResults()); - - NavigatablePsiElement[] navigatableElements = Iterables.toArray( - Iterables.filter(elements, NavigatablePsiElement.class), NavigatablePsiElement.class); - - PsiElementListNavigator.openTargets(e, navigatableElements, - JetBundle.message("navigation.title.overriding.property", property.getName()), - JetBundle.message("navigation.findUsages.title.overriding.property", property.getName()), - renderer); + MarkersPackage.navigateToPropertyOverriddenDeclarations(e, property); } } ); @@ -310,7 +236,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { return false; } - private static boolean isImplemented(JetNamedDeclaration declaration) { + public static boolean isImplemented(JetNamedDeclaration declaration) { if (declaration.hasModifier(JetTokens.ABSTRACT_KEYWORD)) return true; PsiElement parent = declaration.getParent(); @@ -344,7 +270,8 @@ public class JetLineMarkerProvider implements LineMarkerProvider { anchor, anchor.getTextOffset(), isImplemented(property) ? IMPLEMENTED_MARK : OVERRIDDEN_MARK, Pass.UPDATE_OVERRIDEN_MARKERS, - OVERRIDDEN_PROPERTY.getTooltip(), OVERRIDDEN_PROPERTY.getNavigationHandler(), + OVERRIDDEN_PROPERTY.getTooltip(), + OVERRIDDEN_PROPERTY.getNavigationHandler(), GutterIconRenderer.Alignment.RIGHT); result.add(info); diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenPropertyMarker.kt b/idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenPropertyMarker.kt new file mode 100644 index 00000000000..ea6388557f0 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenPropertyMarker.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2010-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 org.jetbrains.jet.plugin.highlighter.markers + +import org.jetbrains.jet.lang.psi.JetProperty +import com.intellij.psi.search.PsiElementProcessor +import com.intellij.psi.PsiClass +import org.jetbrains.jet.plugin.JetBundle +import com.intellij.psi.search.searches.OverridingMethodsSearch +import org.jetbrains.jet.asJava.LightClassUtil +import com.intellij.psi.PsiMethod +import com.intellij.util.AdapterProcessor +import com.intellij.util.CommonProcessors +import com.intellij.psi.search.PsiElementProcessorAdapter +import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper +import com.intellij.psi.PsiElement +import java.awt.event.MouseEvent +import com.intellij.openapi.project.DumbService +import org.jetbrains.jet.plugin.search.ideaExtensions.KotlinDefinitionsSearcher +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.openapi.progress.ProgressManager +import com.intellij.codeInsight.daemon.impl.MarkerType +import com.intellij.ide.util.DefaultPsiElementCellRenderer +import com.intellij.ide.util.PsiClassListCellRenderer +import javax.swing.JComponent +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator +import com.intellij.psi.NavigatablePsiElement +import com.intellij.util.Function +import org.jetbrains.jet.plugin.highlighter.JetLineMarkerProvider + +fun getOverriddenPropertyTooltip(property: JetProperty): String? { + val overriddenInClassesProcessor = PsiElementProcessor.CollectElementsWithLimit(5) + + val consumer = AdapterProcessor( + CommonProcessors.UniqueProcessor(PsiElementProcessorAdapter(overriddenInClassesProcessor)), + Function { (method: PsiMethod?): PsiClass? -> method?.getContainingClass() } + ) + + for (method in LightClassUtil.getLightClassPropertyMethods(property)) { + if (!overriddenInClassesProcessor.isOverflow()) { + OverridingMethodsSearch.search(method, true).forEach(consumer) + } + } + + val isImplemented = JetLineMarkerProvider.isImplemented(property) + if (overriddenInClassesProcessor.isOverflow()) { + return if (isImplemented) + JetBundle.message("property.is.implemented.too.many") + else + JetBundle.message("property.is.overridden.too.many") + } + + val collectedClasses = overriddenInClassesProcessor.getCollection() + if (collectedClasses.isEmpty()) return null + + val start = if (isImplemented) + JetBundle.message("property.is.implemented.header") + else + JetBundle.message("property.is.overridden.header") + + val pattern = "    {0}" + return GutterIconTooltipHelper.composeText(collectedClasses.sortBy(PsiClassListCellRenderer().getComparator()), start, pattern) +} + +fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: JetProperty) { + val project = property.getProject() + + if (DumbService.isDumb(project)) { + DumbService.getInstance(project)?.showDumbModeNotification("Navigation to overriding classes is not possible during index update") + return + } + + val psiPropertyMethods = LightClassUtil.getLightClassPropertyMethods(property) + + val elementProcessor = CommonProcessors.CollectUniquesProcessor() + val jetPsiMethodProcessor = Runnable { + KotlinDefinitionsSearcher.processPropertyImplementationsMethods( + psiPropertyMethods, + GlobalSearchScope.allScope(project), + elementProcessor) + } + + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( + /* runnable */ jetPsiMethodProcessor, + MarkerType.SEARCHING_FOR_OVERRIDING_METHODS, + /* can be canceled */ true, + project, + e?.getComponent() as JComponent?)) { + return + } + + val renderer = DefaultPsiElementCellRenderer() + val navigatingOverrides = elementProcessor.getResults() + .sortBy(renderer.getComparator()) + .filterIsInstance(javaClass()) + + PsiElementListNavigator.openTargets(e, + navigatingOverrides.copyToArray(), + JetBundle.message("navigation.title.overriding.property", property.getName()), + JetBundle.message("navigation.findUsages.title.overriding.property", property.getName()), renderer) +}