Fix override navigation from properties defined in primary constructor
EA-91185 - CCE: KotlinLineMarkerProviderKt$OVERRIDDEN_PROPERTY$.browse
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.idea.highlighter.markers
|
package org.jetbrains.kotlin.idea.highlighter.markers
|
||||||
|
|
||||||
import com.intellij.codeHighlighting.Pass
|
import com.intellij.codeHighlighting.Pass
|
||||||
|
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
import com.intellij.codeInsight.daemon.LineMarkerInfo
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerProvider
|
import com.intellij.codeInsight.daemon.LineMarkerProvider
|
||||||
import com.intellij.codeInsight.daemon.impl.LineMarkerNavigator
|
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",
|
"OVERRIDDEN_FUNCTION",
|
||||||
{ getPsiMethod(it)?.let(::getOverriddenMethodTooltip) },
|
{ getPsiMethod(it)?.let(::getOverriddenMethodTooltip) },
|
||||||
object : LineMarkerNavigator() {
|
object : LineMarkerNavigator() {
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
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",
|
"OVERRIDDEN_PROPERTY",
|
||||||
{ it?.let { getOverriddenPropertyTooltip(it.parent as KtNamedDeclaration) } },
|
{ it?.let { getOverriddenPropertyTooltip(it.parent as KtNamedDeclaration) } },
|
||||||
object : LineMarkerNavigator() {
|
object : LineMarkerNavigator() {
|
||||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
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(
|
private val PLATFORM_IMPLEMENTATION = MarkerType(
|
||||||
"PLATFORM_IMPLEMENTATION",
|
"PLATFORM_IMPLEMENTATION",
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.highlighter.markers
|
|||||||
|
|
||||||
import com.intellij.codeInsight.daemon.DaemonBundle
|
import com.intellij.codeInsight.daemon.DaemonBundle
|
||||||
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper
|
import com.intellij.codeInsight.daemon.impl.GutterIconTooltipHelper
|
||||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
|
|
||||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask
|
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask
|
||||||
import com.intellij.ide.util.MethodCellRenderer
|
import com.intellij.ide.util.MethodCellRenderer
|
||||||
import com.intellij.ide.util.PsiElementListCellRenderer
|
import com.intellij.ide.util.PsiElementListCellRenderer
|
||||||
@@ -93,10 +92,12 @@ fun getOverriddenMethodTooltip(method: PsiMethod): String? {
|
|||||||
return GutterIconTooltipHelper.composeText(overridingJavaMethods, start, " {1}")
|
return GutterIconTooltipHelper.composeText(overridingJavaMethods, start, " {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)) {
|
if (DumbService.isDumb(method.project)) {
|
||||||
DumbService.getInstance(method.project)?.showDumbModeNotification("Navigation to overriding classes is not possible during index update")
|
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>())
|
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))
|
OverridingMethodsSearch.search(method, true).forEach(PsiElementProcessorAdapter(processor))
|
||||||
},
|
},
|
||||||
"Searching for overriding declarations", true, method.project, e?.component as JComponent?)) {
|
"Searching for overriding declarations", true, method.project, e?.component as JComponent?)) {
|
||||||
return
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
var overridingJavaMethods = processor.collection.filter { !it.isMethodWithDeclarationInOtherClass() }
|
var overridingJavaMethods = processor.collection.filter { !it.isMethodWithDeclarationInOtherClass() }
|
||||||
if (overridingJavaMethods.isEmpty()) return
|
if (overridingJavaMethods.isEmpty()) return null
|
||||||
|
|
||||||
val showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridingJavaMethods.toTypedArray())
|
val showMethodNames = !PsiUtil.allMethodsHaveSameSignature(overridingJavaMethods.toTypedArray())
|
||||||
|
|
||||||
@@ -117,13 +118,11 @@ fun navigateToOverriddenMethod(e: MouseEvent?, method: PsiMethod) {
|
|||||||
overridingJavaMethods = overridingJavaMethods.sortedWith(renderer.comparator)
|
overridingJavaMethods = overridingJavaMethods.sortedWith(renderer.comparator)
|
||||||
|
|
||||||
val methodsUpdater = OverridingMethodsUpdater(method, renderer)
|
val methodsUpdater = OverridingMethodsUpdater(method, renderer)
|
||||||
PsiElementListNavigator.openTargets(
|
return NavigationPopupDescriptor(overridingJavaMethods,
|
||||||
e,
|
methodsUpdater.getCaption(overridingJavaMethods.size),
|
||||||
overridingJavaMethods.toTypedArray(),
|
"Overriding declarations of " + method.name,
|
||||||
methodsUpdater.getCaption(overridingJavaMethods.size),
|
renderer,
|
||||||
"Overriding declarations of " + method.name,
|
methodsUpdater)
|
||||||
renderer,
|
|
||||||
methodsUpdater)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OverridingMethodsUpdater(
|
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.GutterIconTooltipHelper
|
||||||
import com.intellij.codeInsight.daemon.impl.MarkerType
|
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.DefaultPsiElementCellRenderer
|
||||||
import com.intellij.ide.util.PsiClassListCellRenderer
|
import com.intellij.ide.util.PsiClassListCellRenderer
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
@@ -76,18 +75,22 @@ fun getOverriddenPropertyTooltip(property: KtNamedDeclaration): String? {
|
|||||||
return GutterIconTooltipHelper.composeText(collectedClasses.sortedWith(PsiClassListCellRenderer().comparator), start, pattern)
|
return GutterIconTooltipHelper.composeText(collectedClasses.sortedWith(PsiClassListCellRenderer().comparator), start, pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: KtProperty) {
|
fun buildNavigateToPropertyOverriddenDeclarationsPopup(e: MouseEvent?, element: PsiElement?): NavigationPopupDescriptor? {
|
||||||
val project = property.project
|
val propertyOrParameter = element?.parent as? KtNamedDeclaration ?: return null
|
||||||
|
val project = propertyOrParameter.project
|
||||||
|
|
||||||
if (DumbService.isDumb(project)) {
|
if (DumbService.isDumb(project)) {
|
||||||
DumbService.getInstance(project)?.showDumbModeNotification("Navigation to overriding classes is not possible during index update")
|
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 elementProcessor = CommonProcessors.CollectUniquesProcessor<PsiElement>()
|
||||||
val jetPsiMethodProcessor = Runnable {
|
val ktPsiMethodProcessor = Runnable {
|
||||||
KotlinDefinitionsSearcher.processPropertyImplementationsMethods(
|
KotlinDefinitionsSearcher.processPropertyImplementationsMethods(
|
||||||
psiPropertyMethods,
|
psiPropertyMethods,
|
||||||
GlobalSearchScope.allScope(project),
|
GlobalSearchScope.allScope(project),
|
||||||
@@ -95,12 +98,12 @@ fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: KtPropert
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||||
/* runnable */ jetPsiMethodProcessor,
|
/* runnable */ ktPsiMethodProcessor,
|
||||||
MarkerType.SEARCHING_FOR_OVERRIDING_METHODS,
|
MarkerType.SEARCHING_FOR_OVERRIDING_METHODS,
|
||||||
/* can be canceled */ true,
|
/* can be canceled */ true,
|
||||||
project,
|
project,
|
||||||
e?.component as JComponent?)) {
|
e?.component as JComponent?)) {
|
||||||
return
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val renderer = DefaultPsiElementCellRenderer()
|
val renderer = DefaultPsiElementCellRenderer()
|
||||||
@@ -108,10 +111,9 @@ fun navigateToPropertyOverriddenDeclarations(e: MouseEvent?, property: KtPropert
|
|||||||
.sortedWith(renderer.comparator)
|
.sortedWith(renderer.comparator)
|
||||||
.filterIsInstance<NavigatablePsiElement>()
|
.filterIsInstance<NavigatablePsiElement>()
|
||||||
|
|
||||||
PsiElementListNavigator.openTargets(e,
|
return NavigationPopupDescriptor(navigatingOverrides,
|
||||||
navigatingOverrides.toTypedArray(),
|
KotlinBundle.message("navigation.title.overriding.property", propertyOrParameter.name),
|
||||||
KotlinBundle.message("navigation.title.overriding.property", property.name),
|
KotlinBundle.message("navigation.findUsages.title.overriding.property", propertyOrParameter.name), renderer)
|
||||||
KotlinBundle.message("navigation.findUsages.title.overriding.property", property.name), renderer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
@@ -8,3 +8,10 @@ open class <lineMarker>C</lineMarker>(
|
|||||||
class D : C("") {
|
class D : C("") {
|
||||||
override val <lineMarker>s</lineMarker>: String get() = "q"
|
override val <lineMarker>s</lineMarker>: String get() = "q"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
LINEMARKER: <html><body>Is overridden in <br/> 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.KotlinLightCodeInsightFixtureTestCase
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import org.jetbrains.kotlin.test.ReferenceUtils
|
import org.jetbrains.kotlin.test.ReferenceUtils
|
||||||
@@ -115,9 +114,7 @@ abstract class AbstractLineMarkersTest : KotlinLightCodeInsightFixtureTestCase()
|
|||||||
|
|
||||||
val handler = navigateMarker.navigationHandler
|
val handler = navigateMarker.navigationHandler
|
||||||
if (handler is TestableLineMarkerNavigator) {
|
if (handler is TestableLineMarkerNavigator) {
|
||||||
val element = navigateMarker.element as KtDeclaration
|
val navigateElements = handler.getTargetsPopupDescriptor(navigateMarker.element)?.targets?.sortedBy { ReferenceUtils.renderAsGotoImplementation(it) }
|
||||||
|
|
||||||
val navigateElements = handler.getTargetsPopupDescriptor(element)?.targets?.sortedBy { ReferenceUtils.renderAsGotoImplementation(it) }
|
|
||||||
val actualNavigationData = NavigationTestUtils.getNavigateElementsText(myFixture.project, navigateElements)
|
val actualNavigationData = NavigationTestUtils.getNavigateElementsText(myFixture.project, navigateElements)
|
||||||
|
|
||||||
UsefulTestCase.assertSameLines(getExpectedNavigationText(navigationComment), actualNavigationData)
|
UsefulTestCase.assertSameLines(getExpectedNavigationText(navigationComment), actualNavigationData)
|
||||||
|
|||||||
Reference in New Issue
Block a user