From 7bf622dd262962fa74fb82967f680b2457720031 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Mon, 25 Aug 2014 03:00:00 +0400 Subject: [PATCH] Rewrite to Kotlin: super navigation markers methods --- .../renderer/DescriptorRendererBuilder.java | 7 + .../highlighter/JetLineMarkerProvider.java | 128 ++---------------- .../markers/SuperDeclarationMarker.kt | 126 +++++++++++++++++ .../codeInsight/AbstractLineMarkersTest.java | 8 +- 4 files changed, 150 insertions(+), 119 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/highlighter/markers/SuperDeclarationMarker.kt diff --git a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererBuilder.java b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererBuilder.java index 4fb1d86fdaf..266848db7fd 100644 --- a/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererBuilder.java +++ b/core/descriptors/src/org/jetbrains/jet/renderer/DescriptorRendererBuilder.java @@ -159,36 +159,43 @@ public class DescriptorRendererBuilder { return this; } + @NotNull public DescriptorRendererBuilder setIncludePropertyConstant(boolean includePropertyConstant) { this.includePropertyConstant = includePropertyConstant; return this; } + @NotNull public DescriptorRendererBuilder setIncludeSynthesizedParameterNames(boolean includeSynthesizedParameterNames) { this.includeSynthesizedParameterNames = includeSynthesizedParameterNames; return this; } + @NotNull public DescriptorRendererBuilder setWithoutTypeParameters(boolean withoutTypeParameters) { this.withoutTypeParameters = withoutTypeParameters; return this; } + @NotNull public DescriptorRendererBuilder setWithoutFunctionParameterNames(boolean withoutFunctionParameterNames) { this.withoutFunctionParameterNames = withoutFunctionParameterNames; return this; } + @NotNull public DescriptorRendererBuilder setReceiverAfterName(boolean receiverAfterName) { this.receiverAfterName = receiverAfterName; return this; } + @NotNull public DescriptorRendererBuilder setRenderClassObjectName(boolean renderClassObjectName) { this.renderClassObjectName = renderClassObjectName; return this; } + @NotNull public DescriptorRendererBuilder setWithoutSuperTypes(boolean withoutSuperTypes) { this.withoutSuperTypes = withoutSuperTypes; return this; diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java index f9a1ebc4f4e..58fdda6bf80 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/JetLineMarkerProvider.java @@ -19,7 +19,6 @@ 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.GutterIconNavigationHandler; import com.intellij.codeInsight.daemon.LineMarkerInfo; import com.intellij.codeInsight.daemon.LineMarkerProvider; import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper; @@ -32,14 +31,12 @@ 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.application.ApplicationManager; 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.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiElementProcessor; @@ -55,29 +52,24 @@ import kotlin.KotlinPackage; 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.KotlinLightMethodFromTrait; import org.jetbrains.jet.asJava.LightClassUtil; -import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; +import org.jetbrains.jet.lang.descriptors.Modality; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingContext; 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.highlighter.markers.MarkersPackage; +import org.jetbrains.jet.plugin.highlighter.markers.ResolveWithParentsResult; +import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerNavigationHandler; +import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerTooltip; 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; import java.util.*; -import static org.jetbrains.jet.lang.resolve.OverrideResolver.getDirectlyOverriddenDeclarations; - public class JetLineMarkerProvider implements LineMarkerProvider { public static final Icon OVERRIDING_MARK = AllIcons.Gutter.OverridingMethod; public static final Icon IMPLEMENTING_MARK = AllIcons.Gutter.ImplementingMethod; @@ -245,46 +237,6 @@ public class JetLineMarkerProvider implements LineMarkerProvider { return null; } - 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 ""; - CallableMemberDescriptor callableDescriptor = (CallableMemberDescriptor) descriptor; - - Set overriddenMembers = 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 @@ -340,28 +292,20 @@ public class JetLineMarkerProvider implements LineMarkerProvider { if (!declaration.hasModifier(JetTokens.OVERRIDE_KEYWORD)) return; - DeclarationDescriptor descriptor = - ResolvePackage.getLazyResolveSession(declaration).resolveToDescriptor(declaration); - - if (!(descriptor instanceof CallableMemberDescriptor)) return; - - Set overriddenMembers = getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor); - if (overriddenMembers.isEmpty()) return; + ResolveWithParentsResult resolveWithParents = MarkersPackage.resolveDeclarationWithParents(declaration); + if (resolveWithParents.getOverriddenDescriptors().isEmpty()) return; // 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. LineMarkerInfo marker = new LineMarkerInfo( declaration, declaration.getTextOffset(), - isImplementsAndNotOverrides((CallableMemberDescriptor) descriptor, overriddenMembers) ? IMPLEMENTING_MARK : OVERRIDING_MARK, + isImplementsAndNotOverrides(resolveWithParents.getDescriptor(), resolveWithParents.getOverriddenDescriptors()) ? + IMPLEMENTING_MARK : + OVERRIDING_MARK, Pass.UPDATE_OVERRIDEN_MARKERS, - new Function() { - @Override - public String fun(JetElement element) { - return calculateTooltipString(element); - } - }, - new KotlinSuperNavigationHandler() + SuperDeclarationMarkerTooltip.INSTANCE$, + new SuperDeclarationMarkerNavigationHandler() ); result.add(marker); @@ -608,50 +552,4 @@ public class JetLineMarkerProvider implements LineMarkerProvider { }); } } - - public static class KotlinSuperNavigationHandler implements GutterIconNavigationHandler { - private List testNavigableElements; - - @TestOnly - @NotNull - public List getNavigationElements() { - List 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 overriddenMembers = - getDirectlyOverriddenDeclarations((CallableMemberDescriptor) descriptor); - if (overriddenMembers.isEmpty()) return; - - List superDeclarations = Lists.newArrayList(); - for (CallableMemberDescriptor overriddenMember : overriddenMembers) { - Collection 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; - } - } - } } diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/markers/SuperDeclarationMarker.kt b/idea/src/org/jetbrains/jet/plugin/highlighter/markers/SuperDeclarationMarker.kt new file mode 100644 index 00000000000..11cc4fca7ab --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/markers/SuperDeclarationMarker.kt @@ -0,0 +1,126 @@ +/* + * 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.JetElement +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor +import org.jetbrains.jet.lang.resolve.OverrideResolver +import org.jetbrains.jet.lang.descriptors.Modality +import org.jetbrains.jet.renderer.DescriptorRenderer +import org.jetbrains.jet.renderer.DescriptorRendererBuilder +import org.jetbrains.jet.lang.descriptors.PropertyAccessorDescriptor +import org.jetbrains.jet.lang.descriptors.PropertyDescriptor +import com.intellij.psi.NavigatablePsiElement +import java.awt.event.MouseEvent +import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil +import com.intellij.openapi.application.ApplicationManager +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator +import org.jetbrains.jet.plugin.JetBundle +import org.jetbrains.jet.plugin.codeInsight.JetFunctionPsiElementCellRenderer +import org.jetbrains.annotations.TestOnly +import com.intellij.codeInsight.daemon.GutterIconNavigationHandler +import java.util.ArrayList +import com.intellij.util.Function + +object SuperDeclarationMarkerTooltip: Function { + override fun `fun`(param: JetElement?): String? { + val element = param!! + + [suppress("UNUSED_VARIABLE")] + val (elementDescriptor, _, overriddenDescriptors) = resolveDeclarationWithParents(element) + if (overriddenDescriptors.isEmpty()) return "" + + val isAbstract = elementDescriptor!!.getModality() == Modality.ABSTRACT + + val renderer = DescriptorRendererBuilder() + .setTextFormat(DescriptorRenderer.TextFormat.HTML) + .setWithDefinedIn(false) + .setStartFromName(true) + .setWithoutSuperTypes(true) + .build() + + val containingStrings = overriddenDescriptors.map { + val declaration = it.getContainingDeclaration() + val memberKind = if (it is PropertyAccessorDescriptor || it is PropertyDescriptor) "property" else "function" + + val isBaseAbstract = it.getModality() == Modality.ABSTRACT + "${if (!isAbstract && isBaseAbstract) "Implements" else "Overrides"} $memberKind in '${renderer.render(declaration)}'" + } + + return containingStrings.sort().join(separator = "
") + } +} + +public class SuperDeclarationMarkerNavigationHandler : GutterIconNavigationHandler { + private var testNavigableElements: List? = null + + TestOnly + public fun getNavigationElements(): List { + val navigationResult = testNavigableElements!! + testNavigableElements = null + return navigationResult + } + + override fun navigate(e: MouseEvent?, element: JetElement?) { + if (element == null) return + + val (elementDescriptor, bindingContext, overriddenDescriptors) = resolveDeclarationWithParents(element) + if (overriddenDescriptors.isEmpty()) return + + val superDeclarations = ArrayList() + for (overriddenMember in overriddenDescriptors) { + val declarations = DescriptorToDeclarationUtil.resolveToPsiElements(element.getProject(), overriddenMember) + for (declaration in declarations) { + if (declaration is NavigatablePsiElement) { + superDeclarations.add(declaration as NavigatablePsiElement) + } + } + } + + if (!ApplicationManager.getApplication()!!.isUnitTestMode()) { + val elementName = elementDescriptor!!.getName() + + PsiElementListNavigator.openTargets( + e, + superDeclarations.copyToArray(), + JetBundle.message("navigation.title.super.declaration", elementName), + JetBundle.message("navigation.findUsages.title.super.declaration", elementName), + JetFunctionPsiElementCellRenderer(bindingContext)) + } + else { + // Only store elements for retrieve in test + testNavigableElements = superDeclarations + } + } +} + +public data class ResolveWithParentsResult( + val descriptor: CallableMemberDescriptor?, + val bindingContext: BindingContext, + val overriddenDescriptors: Collection) + +public fun resolveDeclarationWithParents(element: JetElement): ResolveWithParentsResult { + val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element) + val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) + + if (descriptor !is CallableMemberDescriptor) return ResolveWithParentsResult(null, bindingContext, listOf()) + + val overriddenMembers = OverrideResolver.getDirectlyOverriddenDeclarations(descriptor) + return ResolveWithParentsResult(descriptor, bindingContext, overriddenMembers) +} diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/AbstractLineMarkersTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/AbstractLineMarkersTest.java index b0007e11041..3bcf6646c60 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/AbstractLineMarkersTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/AbstractLineMarkersTest.java @@ -33,7 +33,7 @@ import org.jetbrains.jet.JetTestUtils; import org.jetbrains.jet.lang.psi.JetFile; import org.jetbrains.jet.plugin.JetLightCodeInsightFixtureTestCase; import org.jetbrains.jet.plugin.PluginTestCaseBase; -import org.jetbrains.jet.plugin.highlighter.JetLineMarkerProvider; +import org.jetbrains.jet.plugin.highlighter.markers.SuperDeclarationMarkerNavigationHandler; import org.jetbrains.jet.plugin.navigation.NavigationTestUtils; import org.jetbrains.jet.testing.HighlightTestDataUtil; import org.jetbrains.jet.testing.ReferenceUtils; @@ -113,13 +113,13 @@ public abstract class AbstractLineMarkersTest extends JetLightCodeInsightFixture navigateMarker); GutterIconNavigationHandler handler = navigateMarker.getNavigationHandler(); - if (handler instanceof JetLineMarkerProvider.KotlinSuperNavigationHandler) { + if (handler instanceof SuperDeclarationMarkerNavigationHandler) { PsiElement element = navigateMarker.getElement(); //noinspection unchecked handler.navigate(null, element); List navigateElements = - ((JetLineMarkerProvider.KotlinSuperNavigationHandler) handler).getNavigationElements(); + ((SuperDeclarationMarkerNavigationHandler) handler).getNavigationElements(); Collections.sort(navigateElements, new Comparator() { @Override @@ -137,7 +137,7 @@ public abstract class AbstractLineMarkersTest extends JetLightCodeInsightFixture assertSameLines(getExpectedNavigationText(navigationComment), actualNavigationData); } else { - Assert.fail("Only JetLineMarkerProvider.KotlinSuperNavigationHandler are supported in navigate check"); + Assert.fail("Only SuperDeclarationMarkerNavigationHandler are supported in navigate check"); } } }