diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java index e9ae9270e03..f4d865a535c 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java @@ -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 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) element, element.getTextOffset(), - allOverriddenAbstract ? IMPLEMENTING_MARK : OVERRIDING_MARK, + isImplementsAndNotOverrides((CallableMemberDescriptor) descriptor, overriddenMembers) ? IMPLEMENTING_MARK : OVERRIDING_MARK, Pass.UPDATE_ALL, new Function() { @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 overriddenMembers = OverrideResolver - .getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor); - if (overriddenMembers.size() == 0) { - return ""; - } + if (!(descriptor instanceof CallableMemberDescriptor)) return ""; + CallableMemberDescriptor callableDescriptor = (CallableMemberDescriptor) descriptor; + + Set 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 containingStrings = ContainerUtil.map(overriddenMembers, new Function() { + @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, "
"); + } + + private static boolean isImplementsAndNotOverrides( + CallableMemberDescriptor descriptor, + Collection 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("
").append(implementsOrOverrides).append("
"); - builder.append(DescriptorRenderer.HTML.render(overriddenMembers.iterator().next())); - } - if (overrideCount > 1) { - int otherCount = overrideCount - 1; - builder.append("
and ").append(otherCount).append(" other ").append(StringUtil.pluralize(memberKind, otherCount)); - } - - return builder.toString(); + return true; } @Override diff --git a/idea/testData/codeInsight/lineMarker/ClassObjectInStaticNestedClass.kt b/idea/testData/codeInsight/lineMarker/ClassObjectInStaticNestedClass.kt index 44ff3df7f77..4180151cf87 100644 --- a/idea/testData/codeInsight/lineMarker/ClassObjectInStaticNestedClass.kt +++ b/idea/testData/codeInsight/lineMarker/ClassObjectInStaticNestedClass.kt @@ -5,7 +5,7 @@ trait TestTrait { class A { class B { class object : TestTrait { // TODO: No line marker - override fun test() { + override fun test() { } } } diff --git a/idea/testData/codeInsight/lineMarker/DelegatedFun.kt b/idea/testData/codeInsight/lineMarker/DelegatedFun.kt index f047fc3e8ba..4364b2d0f9b 100644 --- a/idea/testData/codeInsight/lineMarker/DelegatedFun.kt +++ b/idea/testData/codeInsight/lineMarker/DelegatedFun.kt @@ -9,5 +9,5 @@ open class C(b : B) : B by b, A { } class D(b : B) : C(b) { - override fun f() {} + override fun f() {} } \ No newline at end of file diff --git a/idea/testData/codeInsight/lineMarker/DelegatedProperty.kt b/idea/testData/codeInsight/lineMarker/DelegatedProperty.kt index 1e201b51eec..6bf827d6b28 100644 --- a/idea/testData/codeInsight/lineMarker/DelegatedProperty.kt +++ b/idea/testData/codeInsight/lineMarker/DelegatedProperty.kt @@ -9,5 +9,5 @@ open class C(b : B) : B by b, A { } class D(b : B) : C(b) { - override val f: Int = 2 + override val f: Int = 2 } \ No newline at end of file diff --git a/idea/testData/codeInsight/lineMarker/FakeOverrideFun.kt b/idea/testData/codeInsight/lineMarker/FakeOverrideFun.kt index fdd6f0fcaea..1961703b7cc 100644 --- a/idea/testData/codeInsight/lineMarker/FakeOverrideFun.kt +++ b/idea/testData/codeInsight/lineMarker/FakeOverrideFun.kt @@ -7,5 +7,5 @@ trait B : A trait C : B, A class SomeClass() : C { - override fun f() {} + override fun f() {} } \ No newline at end of file diff --git a/idea/testData/codeInsight/lineMarker/FakeOverrideFunWithMostRelevantImplementation.kt b/idea/testData/codeInsight/lineMarker/FakeOverrideFunWithMostRelevantImplementation.kt index 9e3f4e1ceca..25eda5e73c4 100644 --- a/idea/testData/codeInsight/lineMarker/FakeOverrideFunWithMostRelevantImplementation.kt +++ b/idea/testData/codeInsight/lineMarker/FakeOverrideFunWithMostRelevantImplementation.kt @@ -9,5 +9,5 @@ trait B : A { trait C : B, A class SomeClass() : C { - override fun f() {} + override fun f() {} } \ No newline at end of file diff --git a/idea/testData/codeInsight/lineMarker/FakeOverrideProperty.kt b/idea/testData/codeInsight/lineMarker/FakeOverrideProperty.kt index de34ae5270a..ea81e0aaed1 100644 --- a/idea/testData/codeInsight/lineMarker/FakeOverrideProperty.kt +++ b/idea/testData/codeInsight/lineMarker/FakeOverrideProperty.kt @@ -8,5 +8,5 @@ trait B : A trait C : B, A class SomeClass() : C { - override val f: Int = 4 + override val f: Int = 4 } \ No newline at end of file