Fix navigate to super declaration line marker tooltip

Don't show overridden function signature each time, show only where it's declared
This commit is contained in:
Nikolay Krasko
2014-07-25 02:40:36 +04:00
parent 6a714436f2
commit 6aa5e53a00
7 changed files with 57 additions and 55 deletions
@@ -42,27 +42,26 @@ import com.intellij.psi.search.searches.AllOverridingMethodsSearch;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.Modality;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.OverrideResolver;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.ProjectRootsUtil;
import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil;
import org.jetbrains.jet.plugin.codeInsight.JetFunctionPsiElementCellRenderer;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.plugin.search.ideaExtensions.KotlinDefinitionsSearcher;
import org.jetbrains.jet.renderer.DescriptorRenderer;
import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
import javax.swing.*;
import java.awt.event.MouseEvent;
@@ -239,27 +238,18 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
BindingContext bindingContext = AnalyzerFacadeWithCache.getContextForElement((JetElement) element);
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
if (!(descriptor instanceof CallableMemberDescriptor)) {
return null;
}
if (!(descriptor instanceof CallableMemberDescriptor)) return null;
Set<? extends CallableMemberDescriptor> overriddenMembers = OverrideResolver.getDirectlyOverriddenDeclarations(
(CallableMemberDescriptor) descriptor);
if (overriddenMembers.size() == 0) {
return null;
}
boolean allOverriddenAbstract = true;
for (CallableMemberDescriptor function : overriddenMembers) {
allOverriddenAbstract &= function.getModality() == Modality.ABSTRACT;
}
if (overriddenMembers.isEmpty()) return null;
// 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.
return new LineMarkerInfo<JetElement>(
(JetElement) element,
element.getTextOffset(),
allOverriddenAbstract ? IMPLEMENTING_MARK : OVERRIDING_MARK,
isImplementsAndNotOverrides((CallableMemberDescriptor) descriptor, overriddenMembers) ? IMPLEMENTING_MARK : OVERRIDING_MARK,
Pass.UPDATE_ALL,
new Function<JetElement, String>() {
@Override
@@ -271,45 +261,57 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
);
}
private static String calculateTooltipString(PsiElement element) {
JetFile file = (JetFile)element.getContainingFile();
if (file == null) return "";
BindingContext bindingContext = ResolvePackage.getBindingContext(file);
private static String calculateTooltipString(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.size() == 0) {
return "";
}
if (!(descriptor instanceof CallableMemberDescriptor)) return "";
CallableMemberDescriptor callableDescriptor = (CallableMemberDescriptor) descriptor;
Set<CallableMemberDescriptor> overriddenMembers = OverrideResolver.getDirectlyOverriddenDeclarations(callableDescriptor);
if (overriddenMembers.isEmpty()) return "";
final boolean isAbstract = callableDescriptor.getModality() == Modality.ABSTRACT;
final DescriptorRenderer renderer = new DescriptorRendererBuilder()
.setTextFormat(DescriptorRenderer.TextFormat.HTML)
.setWithDefinedIn(false)
.setStartFromName(true)
.setWithoutSuperTypes(true)
.build();
List<String> containingStrings = ContainerUtil.map(overriddenMembers, new Function<CallableMemberDescriptor, String>() {
@Override
public String fun(CallableMemberDescriptor overriddenDescriptor) {
DeclarationDescriptor declaration = overriddenDescriptor.getContainingDeclaration();
String memberKind =
overriddenDescriptor instanceof PropertyAccessorDescriptor || overriddenDescriptor instanceof PropertyDescriptor ?
"property" : "function";
boolean isBaseAbstract = overriddenDescriptor.getModality() == Modality.ABSTRACT;
return String.format("%s %s in '%s'",
!isAbstract && isBaseAbstract ? "Implements" : "Overrides",
memberKind, renderer.render(declaration));
}
});
Collections.sort(containingStrings);
return StringUtil.join(containingStrings, "<br/>");
}
private static boolean isImplementsAndNotOverrides(
CallableMemberDescriptor descriptor,
Collection<? extends CallableMemberDescriptor> overriddenMembers
) {
if (descriptor.getModality() == Modality.ABSTRACT) return false;
boolean allOverriddenAbstract = true;
for (CallableMemberDescriptor function : overriddenMembers) {
allOverriddenAbstract &= function.getModality() == Modality.ABSTRACT;
if (function.getModality() != Modality.ABSTRACT) return false;
}
String implementsOrOverrides = allOverriddenAbstract ? "implements" : "overrides";
String memberKind = element instanceof JetNamedFunction ? "function" : "property";
StringBuilder builder = new StringBuilder();
builder.append(DescriptorRenderer.HTML.render(descriptor));
int overrideCount = overriddenMembers.size();
if (overrideCount >= 1) {
builder.append("<br/>").append(implementsOrOverrides).append("<br/>");
builder.append(DescriptorRenderer.HTML.render(overriddenMembers.iterator().next()));
}
if (overrideCount > 1) {
int otherCount = overrideCount - 1;
builder.append("<br/>and ").append(otherCount).append(" other ").append(StringUtil.pluralize(memberKind, otherCount));
}
return builder.toString();
return true;
}
@Override
@@ -5,7 +5,7 @@ trait <lineMarker></lineMarker>TestTrait {
class A {
class B {
class object : TestTrait { // TODO: No line marker
override fun <lineMarker descr="<b>internal</b> <b>open</b> <b>fun</b> test(): kotlin.Unit <i>defined in</i> A.B.&lt;class-object-for-B&gt;<br/>implements<br/><b>internal</b> <b>abstract</b> <b>fun</b> test(): kotlin.Unit <i>defined in</i> TestTrait"></lineMarker>test() {
override fun <lineMarker descr="Implements function in 'TestTrait'"></lineMarker>test() {
}
}
}
@@ -9,5 +9,5 @@ open class <lineMarker></lineMarker>C(b : B) : B by b, A {
}
class D(b : B) : C(b) {
override fun <lineMarker descr="<b>internal</b> <b>open</b> <b>fun</b> f(): kotlin.Unit <i>defined in</i> D<br/>overrides<br/><b>internal</b> <b>open</b> <b>fun</b> f(): kotlin.Unit <i>defined in</i> A"></lineMarker>f() {}
override fun <lineMarker descr="Overrides function in 'A'"></lineMarker>f() {}
}
@@ -9,5 +9,5 @@ open class <lineMarker></lineMarker>C(b : B) : B by b, A {
}
class D(b : B) : C(b) {
override val <lineMarker descr="<b>internal</b> <b>open</b> <b>val</b> f: kotlin.Int <i>defined in</i> D<br/>overrides<br/><b>internal</b> <b>open</b> <b>val</b> f: kotlin.Int <i>defined in</i> A"></lineMarker>f: Int = 2
override val <lineMarker descr="Overrides property in 'A'"></lineMarker>f: Int = 2
}
@@ -7,5 +7,5 @@ trait <lineMarker></lineMarker>B : A
trait <lineMarker></lineMarker>C : B, A
class SomeClass() : C {
override fun <lineMarker descr="<b>internal</b> <b>open</b> <b>fun</b> f(): kotlin.Unit <i>defined in</i> SomeClass<br/>overrides<br/><b>internal</b> <b>open</b> <b>fun</b> f(): kotlin.Unit <i>defined in</i> A"></lineMarker>f() {}
override fun <lineMarker descr="Overrides function in 'A'"></lineMarker>f() {}
}
@@ -9,5 +9,5 @@ trait <lineMarker></lineMarker>B : A {
trait <lineMarker></lineMarker>C : B, A
class SomeClass() : C {
override fun <lineMarker descr="<b>internal</b> <b>open</b> <b>fun</b> f(): kotlin.Unit <i>defined in</i> SomeClass<br/>overrides<br/><b>internal</b> <b>open</b> <b>fun</b> f(): kotlin.Unit <i>defined in</i> B"></lineMarker>f() {}
override fun <lineMarker descr="Overrides function in 'B'"></lineMarker>f() {}
}
@@ -8,5 +8,5 @@ trait <lineMarker></lineMarker>B : A
trait <lineMarker></lineMarker>C : B, A
class SomeClass() : C {
override val <lineMarker descr="<b>internal</b> <b>open</b> <b>val</b> f: kotlin.Int <i>defined in</i> SomeClass<br/>overrides<br/><b>internal</b> <b>open</b> <b>val</b> f: kotlin.Int <i>defined in</i> A"></lineMarker>f: Int = 4
override val <lineMarker descr="Overrides property in 'A'"></lineMarker>f: Int = 4
}