Make testable navigation from line markers for super declarations
This commit is contained in:
@@ -28,6 +28,7 @@ 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.DefaultPsiElementCellRenderer;
|
||||||
import com.intellij.ide.util.PsiClassListCellRenderer;
|
import com.intellij.ide.util.PsiClassListCellRenderer;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
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;
|
||||||
@@ -45,6 +46,7 @@ import gnu.trove.THashSet;
|
|||||||
import org.jetbrains.annotations.NonNls;
|
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.annotations.TestOnly;
|
||||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
@@ -254,53 +256,21 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
|||||||
|
|
||||||
// NOTE: Don't store descriptors in line markers because line markers are not deleted while editing other files and this can prevent
|
// NOTE: Don't store descriptors in line markers because line markers are not deleted while editing other files and this can prevent
|
||||||
// clearing the whole BindingTrace.
|
// clearing the whole BindingTrace.
|
||||||
return new LineMarkerInfo<PsiElement>(
|
return new LineMarkerInfo<JetElement>(
|
||||||
element,
|
(JetElement) element,
|
||||||
element.getTextOffset(),
|
element.getTextOffset(),
|
||||||
allOverriddenAbstract ? IMPLEMENTING_MARK : OVERRIDING_MARK,
|
allOverriddenAbstract ? IMPLEMENTING_MARK : OVERRIDING_MARK,
|
||||||
Pass.UPDATE_ALL,
|
Pass.UPDATE_ALL,
|
||||||
new Function<PsiElement, String>() {
|
new Function<JetElement, String>() {
|
||||||
@Override
|
@Override
|
||||||
public String fun(PsiElement element) {
|
public String fun(JetElement element) {
|
||||||
return calculateTooltipString(element);
|
return calculateTooltipString(element);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new GutterIconNavigationHandler<PsiElement>() {
|
new KotlinSuperNavigationHandler()
|
||||||
@Override
|
|
||||||
public void navigate(MouseEvent event, PsiElement elt) {
|
|
||||||
iconNavigatorHandler(event, elt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void iconNavigatorHandler(MouseEvent event, PsiElement elt) {
|
|
||||||
BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement((JetElement) elt);
|
|
||||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, elt);
|
|
||||||
if (!(descriptor instanceof CallableMemberDescriptor)) return;
|
|
||||||
|
|
||||||
Set<CallableMemberDescriptor> overriddenMembers =
|
|
||||||
OverrideResolver.getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor);
|
|
||||||
if (overriddenMembers.isEmpty()) return;
|
|
||||||
|
|
||||||
List<NavigatablePsiElement> list = Lists.newArrayList();
|
|
||||||
for (CallableMemberDescriptor overriddenMember : overriddenMembers) {
|
|
||||||
Collection<PsiElement> declarations = DescriptorToDeclarationUtil.INSTANCE$.resolveToPsiElements(elt.getProject(), overriddenMember);
|
|
||||||
for (PsiElement declaration : declarations) {
|
|
||||||
if (declaration instanceof NavigatablePsiElement) {
|
|
||||||
list.add((NavigatablePsiElement) declaration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiElementListNavigator.openTargets(
|
|
||||||
event,
|
|
||||||
ArrayUtil.toObjectArray(list, NavigatablePsiElement.class),
|
|
||||||
JetBundle.message("navigation.title.super.declaration", descriptor.getName()),
|
|
||||||
JetBundle.message("navigation.findUsages.title.super.declaration", descriptor.getName()),
|
|
||||||
new JetFunctionPsiElementCellRenderer(bindingContext));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String calculateTooltipString(PsiElement element) {
|
private static String calculateTooltipString(PsiElement element) {
|
||||||
JetFile file = (JetFile)element.getContainingFile();
|
JetFile file = (JetFile)element.getContainingFile();
|
||||||
if (file == null) return "";
|
if (file == null) return "";
|
||||||
@@ -512,4 +482,50 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
|
|||||||
|
|
||||||
return overridden;
|
return overridden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class KotlinSuperNavigationHandler implements GutterIconNavigationHandler<JetElement> {
|
||||||
|
private List<NavigatablePsiElement> testNavigableElements;
|
||||||
|
|
||||||
|
@TestOnly
|
||||||
|
@NotNull
|
||||||
|
public Collection<NavigatablePsiElement> getNavigationElements() {
|
||||||
|
Collection<NavigatablePsiElement> navigationResult = testNavigableElements;
|
||||||
|
testNavigableElements = null;
|
||||||
|
return navigationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void navigate(MouseEvent e, JetElement element) {
|
||||||
|
BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement(element);
|
||||||
|
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||||
|
if (!(descriptor instanceof CallableMemberDescriptor)) return;
|
||||||
|
|
||||||
|
Set<CallableMemberDescriptor> overriddenMembers =
|
||||||
|
OverrideResolver.getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor);
|
||||||
|
if (overriddenMembers.isEmpty()) return;
|
||||||
|
|
||||||
|
List<NavigatablePsiElement> superDeclarations = Lists.newArrayList();
|
||||||
|
for (CallableMemberDescriptor overriddenMember : overriddenMembers) {
|
||||||
|
Collection<PsiElement> declarations =
|
||||||
|
DescriptorToDeclarationUtil.INSTANCE$.resolveToPsiElements(element.getProject(), overriddenMember);
|
||||||
|
for (PsiElement declaration : declarations) {
|
||||||
|
if (declaration instanceof NavigatablePsiElement) {
|
||||||
|
superDeclarations.add((NavigatablePsiElement) declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||||
|
PsiElementListNavigator.openTargets(
|
||||||
|
e,
|
||||||
|
ArrayUtil.toObjectArray(superDeclarations, NavigatablePsiElement.class),
|
||||||
|
JetBundle.message("navigation.title.super.declaration", descriptor.getName()),
|
||||||
|
JetBundle.message("navigation.findUsages.title.super.declaration", descriptor.getName()),
|
||||||
|
new JetFunctionPsiElementCellRenderer(bindingContext));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
testNavigableElements = superDeclarations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user