diff --git a/annotations/com/intellij/ide/util/annotations.xml b/annotations/com/intellij/ide/util/annotations.xml index 1f6acdd9f8e..aa29d33dc5b 100644 --- a/annotations/com/intellij/ide/util/annotations.xml +++ b/annotations/com/intellij/ide/util/annotations.xml @@ -8,4 +8,7 @@ + + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java index 58fdda6bf80..4f3bcb78232 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java @@ -18,41 +18,30 @@ package org.jetbrains.jet.plugin.highlighter; import com.google.common.collect.*; import com.intellij.codeHighlighting.Pass; -import com.intellij.codeInsight.daemon.DaemonBundle; 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.codeInsight.navigation.ListBackgroundUpdaterTask; import com.intellij.icons.AllIcons; import com.intellij.ide.util.DefaultPsiElementCellRenderer; -import com.intellij.ide.util.MethodCellRenderer; import com.intellij.ide.util.PsiClassListCellRenderer; -import com.intellij.ide.util.PsiElementListCellRenderer; import com.intellij.openapi.editor.markup.GutterIconRenderer; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiElementProcessor; import com.intellij.psi.search.PsiElementProcessorAdapter; -import com.intellij.psi.search.searches.AllOverridingMethodsSearch; import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.psi.search.searches.OverridingMethodsSearch; -import com.intellij.psi.util.PsiUtil; import com.intellij.util.*; -import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import kotlin.KotlinPackage; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait; import org.jetbrains.jet.asJava.LightClassUtil; import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.Modality; @@ -101,7 +90,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { @Override public String fun(@Nullable PsiElement element) { PsiMethod psiMethod = getPsiMethod(element); - return psiMethod != null ? getOverriddenMethodTooltip(psiMethod) : null; + return psiMethod != null ? MarkersPackage.getOverriddenMethodTooltip(psiMethod) : null; } }, @@ -110,7 +99,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { public void browse(@Nullable MouseEvent e, @Nullable PsiElement element) { PsiMethod psiMethod = getPsiMethod(element); if (psiMethod != null) { - navigateToOverriddenMethod(e, psiMethod); + MarkersPackage.navigateToOverriddenMethod(e, psiMethod); } } } @@ -370,7 +359,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { Set classes = collectContainingClasses(mappingToJava.keySet()); - for (JetProperty property : getOverriddenDeclarations(mappingToJava, classes)) { + for (JetProperty property : MarkersPackage.getOverriddenDeclarations(mappingToJava, classes)) { ProgressManager.checkCanceled(); PsiElement anchor = property.getNameIdentifier(); @@ -400,7 +389,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider { Set classes = collectContainingClasses(mappingToJava.keySet()); - for (JetNamedFunction function : getOverriddenDeclarations(mappingToJava, classes)) { + for (JetNamedFunction function : MarkersPackage.getOverriddenDeclarations(mappingToJava, classes)) { ProgressManager.checkCanceled(); PsiElement anchor = function.getNameIdentifier(); @@ -428,128 +417,4 @@ public class JetLineMarkerProvider implements LineMarkerProvider { } return classes; } - - private static Set getOverriddenDeclarations(final Map mappingToJava, Set classes) { - final Set overridden = Sets.newHashSet(); - for (PsiClass aClass : classes) { - AllOverridingMethodsSearch.search(aClass).forEach(new Processor>() { - @Override - public boolean process(Pair pair) { - ProgressManager.checkCanceled(); - - if (!(pair.getSecond() instanceof KotlinLightMethodFromTrait)) { - PsiMethod superMethod = pair.getFirst(); - - T declaration = mappingToJava.get(superMethod); - if (declaration != null) { - mappingToJava.remove(superMethod); - overridden.add(declaration); - } - } - - return !mappingToJava.isEmpty(); - } - }); - } - - return overridden; - } - - public static String getOverriddenMethodTooltip(PsiMethod method) { - PsiElementProcessor.CollectElementsWithLimit processor = new PsiElementProcessor.CollectElementsWithLimit(5); - OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter(processor)); - - boolean isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT); - - if (processor.isOverflow()){ - return isAbstract ? DaemonBundle.message("method.is.implemented.too.many") : DaemonBundle.message("method.is.overridden.too.many"); - } - - PsiMethod[] javaOverridings = processor.toArray(PsiMethod.EMPTY_ARRAY); - List filter = ContainerUtil.filter(javaOverridings, new Condition() { - @Override - public boolean value(PsiMethod method) { - return !(method instanceof KotlinLightMethodFromTrait); - } - }); - PsiMethod[] overridings = filter.toArray(new PsiMethod[filter.size()]); - - if (overridings.length == 0) return null; - - Comparator comparator = new MethodCellRenderer(false).getComparator(); - Arrays.sort(overridings, comparator); - - String start = isAbstract ? DaemonBundle.message("method.is.implemented.header") : DaemonBundle.message("method.is.overriden.header"); - @NonNls String pattern = "    {1}"; - return GutterIconTooltipHelper.composeText(overridings, start, pattern); - } - - public static void navigateToOverriddenMethod(MouseEvent e, final PsiMethod method) { - if (DumbService.isDumb(method.getProject())) { - DumbService.getInstance(method.getProject()).showDumbModeNotification( - "Navigation to overriding classes is not possible during index update"); - return; - } - - final PsiElementProcessor.CollectElementsWithLimit collectProcessor = - new PsiElementProcessor.CollectElementsWithLimit(2, new THashSet()); - if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { - @Override - public void run() { - OverridingMethodsSearch.search(method, true).forEach(new PsiElementProcessorAdapter(collectProcessor)); - } - }, "Searching for overriding methods", true, method.getProject(), (JComponent)e.getComponent())) { - return; - } - - PsiMethod[] javaOverridings = collectProcessor.toArray(PsiMethod.EMPTY_ARRAY); - List filter = ContainerUtil.filter(javaOverridings, new Condition() { - @Override - public boolean value(PsiMethod method) { - return !(method instanceof KotlinLightMethodFromTrait); - } - }); - PsiMethod[] overridings = filter.toArray(new PsiMethod[filter.size()]); - - if (overridings.length == 0) return; - boolean showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridings); - MethodCellRenderer renderer = new MethodCellRenderer(showMethodNames); - Arrays.sort(overridings, renderer.getComparator()); - OverridingMethodsUpdater methodsUpdater = new OverridingMethodsUpdater(method, renderer); - PsiElementListNavigator.openTargets(e, overridings, methodsUpdater.getCaption(overridings.length), "Overriding methods of " + method.getName(), renderer, methodsUpdater); - } - - private static class OverridingMethodsUpdater extends ListBackgroundUpdaterTask { - private final PsiMethod myMethod; - private final PsiElementListCellRenderer myRenderer; - - public OverridingMethodsUpdater(PsiMethod method, PsiElementListCellRenderer renderer) { - super(method.getProject(), "Searching for overriding methods"); - myMethod = method; - myRenderer = renderer; - } - - @Override - public String getCaption(int size) { - return myMethod.hasModifierProperty(PsiModifier.ABSTRACT) ? - DaemonBundle.message("navigation.title.implementation.method", myMethod.getName(), size) : - DaemonBundle.message("navigation.title.overrider.method", myMethod.getName(), size); - } - - @Override - public void run(@NotNull final ProgressIndicator indicator) { - super.run(indicator); - OverridingMethodsSearch.search(myMethod, true).forEach( - new CommonProcessors.CollectProcessor() { - @Override - public boolean process(PsiMethod psiMethod) { - if (!updateComponent(psiMethod, myRenderer.getComparator())) { - indicator.cancel(); - } - indicator.checkCanceled(); - return super.process(psiMethod); - } - }); - } - } } diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenDeclarationMarker.kt b/idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenDeclarationMarker.kt new file mode 100644 index 00000000000..6b1018fbb7b --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/markers/OverridenDeclarationMarker.kt @@ -0,0 +1,147 @@ +/* + * 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 com.intellij.psi.PsiMethod +import com.intellij.psi.search.PsiElementProcessor +import com.intellij.psi.search.searches.OverridingMethodsSearch +import com.intellij.psi.PsiModifier +import com.intellij.codeInsight.daemon.DaemonBundle +import com.intellij.ide.util.MethodCellRenderer +import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper +import java.awt.event.MouseEvent +import com.intellij.openapi.project.DumbService +import com.intellij.openapi.progress.ProgressManager +import javax.swing.JComponent +import com.intellij.psi.util.PsiUtil +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator +import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask +import com.intellij.ide.util.PsiElementListCellRenderer +import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.util.CommonProcessors +import com.intellij.psi.search.PsiElementProcessorAdapter +import com.intellij.psi.PsiElement +import gnu.trove.THashSet +import com.intellij.psi.PsiClass +import com.intellij.psi.search.searches.AllOverridingMethodsSearch +import com.intellij.openapi.util.Pair +import java.util.HashSet +import com.intellij.util.Processor +import org.jetbrains.jet.asJava.KotlinLightMethodFromTrait + +private fun getOverriddenDeclarations(mappingToJava: MutableMap, classes: Set): Set { + val overridden = HashSet() + for (aClass in classes) { + AllOverridingMethodsSearch.search(aClass)!!.forEach(object : Processor> { + override fun process(pair: Pair?): Boolean { + ProgressManager.checkCanceled() + + if (pair!!.getSecond() !is KotlinLightMethodFromTrait) { + val superMethod = pair.getFirst() + + val declaration = mappingToJava.get(superMethod) + if (declaration != null) { + mappingToJava.remove(superMethod) + overridden.add(declaration) + } + } + + return !mappingToJava.isEmpty() + } + }) + } + + return overridden +} + +public fun getOverriddenMethodTooltip(method: PsiMethod): String? { + val processor = PsiElementProcessor.CollectElementsWithLimit(5) + OverridingMethodsSearch.search(method, true).forEach(PsiElementProcessorAdapter(processor)) + + val isAbstract = method.hasModifierProperty(PsiModifier.ABSTRACT) + + if (processor.isOverflow()) { + return if (isAbstract) DaemonBundle.message("method.is.implemented.too.many") else DaemonBundle.message("method.is.overridden.too.many") + } + + val comparator = MethodCellRenderer(false).getComparator() + + val overridingJavaMethods = processor.getCollection().filter { it !is KotlinLightMethodFromTrait } sortBy(comparator) + if (overridingJavaMethods.isEmpty()) return null + + val start = if (isAbstract) DaemonBundle.message("method.is.implemented.header") else DaemonBundle.message("method.is.overriden.header") + + return GutterIconTooltipHelper.composeText(overridingJavaMethods, start, "    {1}") +} + +public fun navigateToOverriddenMethod(e: MouseEvent?, method: PsiMethod) { + if (DumbService.isDumb(method.getProject())) { + DumbService.getInstance(method.getProject())?.showDumbModeNotification("Navigation to overriding classes is not possible during index update") + return + } + + val processor = PsiElementProcessor.CollectElementsWithLimit(2, THashSet()) + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( + { + OverridingMethodsSearch.search(method, true).forEach(PsiElementProcessorAdapter(processor)) + }, + "Searching for overriding declarations", true, method.getProject(), e?.getComponent() as JComponent?)) { + return + } + + var overridingJavaMethods = processor.getCollection().filter { it !is KotlinLightMethodFromTrait } + if (overridingJavaMethods.isEmpty()) return + + val showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridingJavaMethods.copyToArray()) + + val renderer = MethodCellRenderer(showMethodNames) + overridingJavaMethods = overridingJavaMethods.sortBy(renderer.getComparator()) + + val methodsUpdater = OverridingMethodsUpdater(method, renderer) + PsiElementListNavigator.openTargets( + e, + overridingJavaMethods.copyToArray(), + methodsUpdater.getCaption(overridingJavaMethods.size), + "Overriding declarations of " + method.getName(), + renderer, + methodsUpdater) +} + +private class OverridingMethodsUpdater( + private val myMethod: PsiMethod, + private val myRenderer: PsiElementListCellRenderer) : + ListBackgroundUpdaterTask(myMethod.getProject(), "Searching for overriding methods") { + override fun getCaption(size: Int): String { + return if (myMethod.hasModifierProperty(PsiModifier.ABSTRACT)) + DaemonBundle.message("navigation.title.implementation.method", myMethod.getName(), size)!! + else + DaemonBundle.message("navigation.title.overrider.method", myMethod.getName(), size)!! + } + + override fun run(indicator: ProgressIndicator) { + super.run(indicator) + OverridingMethodsSearch.search(myMethod, true).forEach(object : CommonProcessors.CollectProcessor() { + override fun process(psiMethod: PsiMethod?): Boolean { + if (!updateComponent(psiMethod, myRenderer.getComparator())) { + indicator.cancel() + } + indicator.checkCanceled() + return super.process(psiMethod) + } + }) + } +} \ No newline at end of file