Fix override navigation from properties defined in primary constructor

EA-91185 - CCE: KotlinLineMarkerProviderKt$OVERRIDDEN_PROPERTY$.browse
This commit is contained in:
Dmitry Jemerov
2017-04-27 15:49:25 +02:00
parent c22e0d88f0
commit d49e9d7064
5 changed files with 65 additions and 35 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.highlighter.markers
import com.intellij.codeHighlighting.Pass
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler
import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator
@@ -132,23 +133,47 @@ private val SUBCLASSED_CLASS = MarkerType(
}
})
private val OVERRIDDEN_FUNCTION = MarkerType(
private val OVERRIDDEN_FUNCTION = object : MarkerType(
"OVERRIDDEN_FUNCTION",
{ getPsiMethod(it)?.let(::getOverriddenMethodTooltip) },
object : LineMarkerNavigator() {
override fun browse(e: MouseEvent?, element: PsiElement?) {
getPsiMethod(element)?.let { navigateToOverriddenMethod(e, it) }
buildNavigateToOverriddenMethodPopup(e, element)?.showPopup(e)
}
})
}) {
private val OVERRIDDEN_PROPERTY = MarkerType(
override fun getNavigationHandler(): GutterIconNavigationHandler<PsiElement> {
val superHandler = super.getNavigationHandler()
return object : GutterIconNavigationHandler<PsiElement>, TestableLineMarkerNavigator {
override fun navigate(e: MouseEvent?, elt: PsiElement?) {
superHandler.navigate(e, elt)
}
override fun getTargetsPopupDescriptor(element: PsiElement?) = buildNavigateToOverriddenMethodPopup(null, element)
}
}
}
private val OVERRIDDEN_PROPERTY = object : MarkerType(
"OVERRIDDEN_PROPERTY",
{ it?.let { getOverriddenPropertyTooltip(it.parent as KtNamedDeclaration) } },
object : LineMarkerNavigator() {
override fun browse(e: MouseEvent?, element: PsiElement?) {
element?.let { navigateToPropertyOverriddenDeclarations(e, it.parent as KtProperty) }
buildNavigateToPropertyOverriddenDeclarationsPopup(e, element)?.showPopup(e)
}
})
}) {
override fun getNavigationHandler(): GutterIconNavigationHandler<PsiElement> {
val superHandler = super.getNavigationHandler()
return object : GutterIconNavigationHandler<PsiElement>, TestableLineMarkerNavigator {
override fun navigate(e: MouseEvent?, elt: PsiElement?) {
superHandler.navigate(e, elt)
}
override fun getTargetsPopupDescriptor(element: PsiElement?) = buildNavigateToPropertyOverriddenDeclarationsPopup(null, element)
}
}
}
private val PLATFORM_IMPLEMENTATION = MarkerType(
"PLATFORM_IMPLEMENTATION",
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.highlighter.markers
import com.intellij.codeInsight.daemon.DaemonBundle
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask
import com.intellij.ide.util.MethodCellRenderer
import com.intellij.ide.util.PsiElementListCellRenderer
@@ -93,10 +92,12 @@ fun getOverriddenMethodTooltip(method: PsiMethod): String? {
return GutterIconTooltipHelper.composeText(overridingJavaMethods, start, "&nbsp;&nbsp;&nbsp;&nbsp;{1}")
}
fun navigateToOverriddenMethod(e: MouseEvent?, method: PsiMethod) {
fun buildNavigateToOverriddenMethodPopup(e: MouseEvent?, element: PsiElement?): NavigationPopupDescriptor? {
val method = getPsiMethod(element) ?: return null
if (DumbService.isDumb(method.project)) {
DumbService.getInstance(method.project)?.showDumbModeNotification("Navigation to overriding classes is not possible during index update")
return
return null
}
val processor = PsiElementProcessor.CollectElementsWithLimit<PsiMethod>(2, THashSet<PsiMethod>())
@@ -105,11 +106,11 @@ fun navigateToOverriddenMethod(e: MouseEvent?, method: PsiMethod) {
OverridingMethodsSearch.search(method, true).forEach(PsiElementProcessorAdapter(processor))
},
"Searching for overriding declarations", true, method.project, e?.component as JComponent?)) {
return
return null
}
var overridingJavaMethods = processor.collection.filter { !it.isMethodWithDeclarationInOtherClass() }
if (overridingJavaMethods.isEmpty()) return
if (overridingJavaMethods.isEmpty()) return null
val showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridingJavaMethods.toTypedArray())
@@ -117,13 +118,11 @@ fun navigateToOverriddenMethod(e: MouseEvent?, method: PsiMethod) {
overridingJavaMethods = overridingJavaMethods.sortedWith(renderer.comparator)
val methodsUpdater = OverridingMethodsUpdater(method, renderer)
PsiElementListNavigator.openTargets(
e,
overridingJavaMethods.toTypedArray(),
methodsUpdater.getCaption(overridingJavaMethods.size),
"Overriding declarations of " + method.name,
renderer,
methodsUpdater)
return NavigationPopupDescriptor(overridingJavaMethods,
methodsUpdater.getCaption(overridingJavaMethods.size),
"Overriding declarations of " + method.name,
renderer,
methodsUpdater)
}
private class OverridingMethodsUpdater(
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.highlighter.markers
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper
import com.intellij.codeInsight.daemon.impl.MarkerType
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
import com.intellij.ide.util.DefaultPsiElementCellRenderer
import com.intellij.ide.util.PsiClassListCellRenderer
import com.intellij.openapi.progress.ProgressManager
@@ -76,18 +75,22 @@ fun getOverriddenPropertyTooltip(property: KtNamedDeclaration): String? {
return GutterIconTooltipHelper.composeText(collectedClasses.sortedWith(PsiClassListCellRenderer().comparator), start, pattern)
}
fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: KtProperty) {
val project = property.project
fun buildNavigateToPropertyOverriddenDeclarationsPopup(e: MouseEvent?, element: PsiElement?): NavigationPopupDescriptor? {
val propertyOrParameter = element?.parent as? KtNamedDeclaration ?: return null
val project = propertyOrParameter.project
if (DumbService.isDumb(project)) {
DumbService.getInstance(project)?.showDumbModeNotification("Navigation to overriding classes is not possible during index update")
return
return null
}
val psiPropertyMethods = LightClassUtil.getLightClassPropertyMethods(property)
val psiPropertyMethods = when(propertyOrParameter) {
is KtProperty -> LightClassUtil.getLightClassPropertyMethods(propertyOrParameter)
is KtParameter -> LightClassUtil.getLightClassPropertyMethods(propertyOrParameter)
else -> return null
}
val elementProcessor = CommonProcessors.CollectUniquesProcessor<PsiElement>()
val jetPsiMethodProcessor = Runnable {
val ktPsiMethodProcessor = Runnable {
KotlinDefinitionsSearcher.processPropertyImplementationsMethods(
psiPropertyMethods,
GlobalSearchScope.allScope(project),
@@ -95,12 +98,12 @@ fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: KtPropert
}
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
/* runnable */ jetPsiMethodProcessor,
/* runnable */ ktPsiMethodProcessor,
MarkerType.SEARCHING_FOR_OVERRIDING_METHODS,
/* can be canceled */ true,
project,
e?.component as JComponent?)) {
return
return null
}
val renderer = DefaultPsiElementCellRenderer()
@@ -108,10 +111,9 @@ fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: KtPropert
.sortedWith(renderer.comparator)
.filterIsInstance<NavigatablePsiElement>()
PsiElementListNavigator.openTargets(e,
navigatingOverrides.toTypedArray(),
KotlinBundle.message("navigation.title.overriding.property", property.name),
KotlinBundle.message("navigation.findUsages.title.overriding.property", property.name), renderer)
return NavigationPopupDescriptor(navigatingOverrides,
KotlinBundle.message("navigation.title.overriding.property", propertyOrParameter.name),
KotlinBundle.message("navigation.findUsages.title.overriding.property", propertyOrParameter.name), renderer)
}
@@ -8,3 +8,10 @@ open class <lineMarker>C</lineMarker>(
class D : C("") {
override val <lineMarker>s</lineMarker>: String get() = "q"
}
/*
LINEMARKER: <html><body>Is overridden in <br/>&nbsp;&nbsp;&nbsp;&nbsp;D</body></html>
TARGETS:
PrimaryConstructorOpen.kt
override val <1>s: String get() = "q"
*/
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.ReferenceUtils
@@ -115,9 +114,7 @@ abstract class AbstractLineMarkersTest : KotlinLightCodeInsightFixtureTestCase()
val handler = navigateMarker.navigationHandler
if (handler is TestableLineMarkerNavigator) {
val element = navigateMarker.element as KtDeclaration
val navigateElements = handler.getTargetsPopupDescriptor(element)?.targets?.sortedBy { ReferenceUtils.renderAsGotoImplementation(it) }
val navigateElements = handler.getTargetsPopupDescriptor(navigateMarker.element)?.targets?.sortedBy { ReferenceUtils.renderAsGotoImplementation(it) }
val actualNavigationData = NavigationTestUtils.getNavigateElementsText(myFixture.project, navigateElements)
UsefulTestCase.assertSameLines(getExpectedNavigationText(navigationComment), actualNavigationData)