Rewrite to Kotlin: overridden properties markers tooltip and navigation
This commit is contained in:
@@ -16,32 +16,23 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.highlighter;
|
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.codeHighlighting.Pass;
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
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.LineMarkerNavigator;
|
||||||
import com.intellij.codeInsight.daemon.impl.MarkerType;
|
import com.intellij.codeInsight.daemon.impl.MarkerType;
|
||||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator;
|
|
||||||
import com.intellij.icons.AllIcons;
|
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.editor.markup.GutterIconRenderer;
|
||||||
import com.intellij.openapi.progress.ProgressManager;
|
import com.intellij.openapi.progress.ProgressManager;
|
||||||
import com.intellij.openapi.project.DumbService;
|
import com.intellij.openapi.project.DumbService;
|
||||||
import com.intellij.psi.NavigatablePsiElement;
|
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiMethod;
|
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.ClassInheritorsSearch;
|
||||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
import com.intellij.util.NullableFunction;
|
||||||
import com.intellij.util.*;
|
|
||||||
import kotlin.KotlinPackage;
|
import kotlin.KotlinPackage;
|
||||||
import org.jetbrains.annotations.NonNls;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
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.descriptors.Modality;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
import org.jetbrains.jet.plugin.JetBundle;
|
|
||||||
import org.jetbrains.jet.plugin.ProjectRootsUtil;
|
import org.jetbrains.jet.plugin.ProjectRootsUtil;
|
||||||
import org.jetbrains.jet.plugin.highlighter.markers.MarkersPackage;
|
import org.jetbrains.jet.plugin.highlighter.markers.MarkersPackage;
|
||||||
import org.jetbrains.jet.plugin.highlighter.markers.ResolveWithParentsResult;
|
import org.jetbrains.jet.plugin.highlighter.markers.ResolveWithParentsResult;
|
||||||
import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerNavigationHandler;
|
import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerNavigationHandler;
|
||||||
import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerTooltip;
|
import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerTooltip;
|
||||||
import org.jetbrains.jet.plugin.search.ideaExtensions.KotlinDefinitionsSearcher;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.event.MouseEvent;
|
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 class JetLineMarkerProvider implements LineMarkerProvider {
|
||||||
public static final Icon OVERRIDING_MARK = AllIcons.Gutter.OverridingMethod;
|
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";
|
assert element.getParent() instanceof JetProperty : "This tooltip provider should be placed only on identifies in properties";
|
||||||
JetProperty property = (JetProperty) element.getParent();
|
JetProperty property = (JetProperty) element.getParent();
|
||||||
|
|
||||||
PsiElementProcessor.CollectElementsWithLimit<PsiClass> processor = new PsiElementProcessor.CollectElementsWithLimit<PsiClass>(5);
|
return MarkersPackage.getOverriddenPropertyTooltip(property);
|
||||||
Processor<PsiMethod> consumer = new AdapterProcessor<PsiMethod, PsiClass>(
|
|
||||||
new CommonProcessors.UniqueProcessor<PsiClass>(new PsiElementProcessorAdapter<PsiClass>(processor)),
|
|
||||||
new Function<PsiMethod, PsiClass>() {
|
|
||||||
@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<PsiClass> 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);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new LineMarkerNavigator() {
|
new LineMarkerNavigator() {
|
||||||
@Override
|
@Override
|
||||||
public void browse(@Nullable MouseEvent e, @Nullable final PsiElement element) {
|
public void browse(@Nullable MouseEvent e, @Nullable PsiElement element) {
|
||||||
if (element == null) return;
|
if (element == null) return;
|
||||||
|
|
||||||
assert element.getParent() instanceof JetProperty : "This marker navigator should be placed only on identifies in properties";
|
assert element.getParent() instanceof JetProperty : "This marker navigator should be placed only on identifies in properties";
|
||||||
JetProperty property = (JetProperty) element.getParent();
|
JetProperty property = (JetProperty) element.getParent();
|
||||||
|
|
||||||
if (DumbService.isDumb(element.getProject())) {
|
MarkersPackage.navigateToPropertyOverriddenDeclarations(e, property);
|
||||||
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<PsiElement> elementProcessor = new CommonProcessors.CollectUniquesProcessor<PsiElement>();
|
|
||||||
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<PsiElement> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -310,7 +236,7 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isImplemented(JetNamedDeclaration declaration) {
|
public static boolean isImplemented(JetNamedDeclaration declaration) {
|
||||||
if (declaration.hasModifier(JetTokens.ABSTRACT_KEYWORD)) return true;
|
if (declaration.hasModifier(JetTokens.ABSTRACT_KEYWORD)) return true;
|
||||||
|
|
||||||
PsiElement parent = declaration.getParent();
|
PsiElement parent = declaration.getParent();
|
||||||
@@ -344,7 +270,8 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
|||||||
anchor, anchor.getTextOffset(),
|
anchor, anchor.getTextOffset(),
|
||||||
isImplemented(property) ? IMPLEMENTED_MARK : OVERRIDDEN_MARK,
|
isImplemented(property) ? IMPLEMENTED_MARK : OVERRIDDEN_MARK,
|
||||||
Pass.UPDATE_OVERRIDEN_MARKERS,
|
Pass.UPDATE_OVERRIDEN_MARKERS,
|
||||||
OVERRIDDEN_PROPERTY.getTooltip(), OVERRIDDEN_PROPERTY.getNavigationHandler(),
|
OVERRIDDEN_PROPERTY.getTooltip(),
|
||||||
|
OVERRIDDEN_PROPERTY.getNavigationHandler(),
|
||||||
GutterIconRenderer.Alignment.RIGHT);
|
GutterIconRenderer.Alignment.RIGHT);
|
||||||
|
|
||||||
result.add(info);
|
result.add(info);
|
||||||
|
|||||||
@@ -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<PsiClass>(5)
|
||||||
|
|
||||||
|
val consumer = AdapterProcessor<PsiMethod, PsiClass>(
|
||||||
|
CommonProcessors.UniqueProcessor<PsiClass>(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<PsiElement>()
|
||||||
|
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<NavigatablePsiElement>())
|
||||||
|
|
||||||
|
PsiElementListNavigator.openTargets(e,
|
||||||
|
navigatingOverrides.copyToArray(),
|
||||||
|
JetBundle.message("navigation.title.overriding.property", property.getName()),
|
||||||
|
JetBundle.message("navigation.findUsages.title.overriding.property", property.getName()), renderer)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user