From d050629589b8115021318e23d8a0a140d42dd311 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 2 Oct 2018 18:58:55 +0300 Subject: [PATCH] Show expect / actual for parameters & enum entries in drop-box #KT-26957 Fixed --- .../org/jetbrains/kotlin/psi/KtClassBody.kt | 3 +++ .../highlighter/markers/HasActualMarker.kt | 3 ++- .../highlighter/markers/HasExpectedMarker.kt | 22 +++++++++++++++-- .../markers/KotlinLineMarkerProvider.kt | 24 ++++++++++++++----- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassBody.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassBody.kt index b10d93c28fe..fe7cf69b56e 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassBody.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtClassBody.kt @@ -46,6 +46,9 @@ class KtClassBody : KtElementImplStub>, KtDec val properties: List get() = getStubOrPsiChildrenAsList(KtStubElementTypes.PROPERTY) + val enumEntries: List + get() = getStubOrPsiChildrenAsList(KtStubElementTypes.ENUM_ENTRY).filterIsInstance() + val allCompanionObjects: List get() = getStubOrPsiChildrenAsList(KtStubElementTypes.OBJECT_DECLARATION).filter { it.isCompanion() } diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasActualMarker.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasActualMarker.kt index 004dc62b6d2..f0de41025bf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasActualMarker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasActualMarker.kt @@ -65,7 +65,8 @@ fun getPlatformActualTooltip(declaration: KtDeclaration): String? { } fun navigateToPlatformActual(e: MouseEvent?, declaration: KtDeclaration) { - val actualDeclarations = declaration.actualsForExpected() + val actualDeclarations = + declaration.actualsForExpected() + declaration.findMarkerBoundDeclarations().flatMap { it.actualsForExpected() } if (actualDeclarations.isEmpty()) return val renderer = object : DefaultPsiElementCellRenderer() { diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasExpectedMarker.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasExpectedMarker.kt index e690ee8d904..7351d752f76 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasExpectedMarker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasExpectedMarker.kt @@ -16,6 +16,9 @@ package org.jetbrains.kotlin.idea.highlighter.markers +import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator +import com.intellij.ide.util.DefaultPsiElementCellRenderer +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.MemberDescriptor import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor @@ -23,6 +26,7 @@ import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.util.expectedDeclarationIfAny import org.jetbrains.kotlin.idea.util.hasDeclarationOf import org.jetbrains.kotlin.psi.KtDeclaration +import java.awt.event.MouseEvent fun getExpectedDeclarationTooltip(declaration: KtDeclaration): String? { val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return null @@ -34,6 +38,20 @@ fun getExpectedDeclarationTooltip(declaration: KtDeclaration): String? { return "Has declaration in common module" } -fun navigateToExpectedDeclaration(declaration: KtDeclaration) { - declaration.expectedDeclarationIfAny()?.navigate(/* request focus = */true) +fun navigateToExpectedDeclaration(e: MouseEvent?, declaration: KtDeclaration) { + val expectedDeclarations = + listOfNotNull(declaration.expectedDeclarationIfAny()) + + declaration.findMarkerBoundDeclarations().mapNotNull { it.expectedDeclarationIfAny() } + if (expectedDeclarations.isEmpty()) return + + val renderer = object : DefaultPsiElementCellRenderer() { + override fun getContainerText(element: PsiElement?, name: String?) = "" + } + PsiElementListNavigator.openTargets( + e, + expectedDeclarations.toTypedArray(), + "Choose expected for ${declaration.name}", + "Expected for ${declaration.name}", + renderer + ) } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt index d910ef7804b..cfa1e5e385c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt @@ -216,7 +216,7 @@ private val EXPECTED_DECLARATION = MarkerType( { element -> element?.markerDeclaration?.let { getExpectedDeclarationTooltip(it) } }, object : LineMarkerNavigator() { override fun browse(e: MouseEvent?, element: PsiElement?) { - element?.markerDeclaration?.let { navigateToExpectedDeclaration(it) } + element?.markerDeclaration?.let { navigateToExpectedDeclaration(e, it) } } } ) @@ -343,30 +343,42 @@ private fun collectMultiplatformMarkers( } } -private fun Document?.areAnchorsOnOneLine( +private fun Document.areAnchorsOnOneLine( first: KtNamedDeclaration, second: KtNamedDeclaration? ): Boolean { - if (this == null || second == null) return false + if (second == null) return false val firstAnchor = first.expectOrActualAnchor val secondAnchor = second.expectOrActualAnchor return firstAnchor.startLine(this) == secondAnchor.startLine(this) } -private fun KtNamedDeclaration.requiresNoMarkers(): Boolean { - val document = PsiDocumentManager.getInstance(project).getDocument(containingFile) +private fun KtNamedDeclaration.requiresNoMarkers( + document: Document? = PsiDocumentManager.getInstance(project).getDocument(containingFile) +): Boolean { when (this) { is KtPrimaryConstructor -> { return true } is KtParameter, - is KtEnumEntry -> if (document.areAnchorsOnOneLine(this, containingClassOrObject)) { + is KtEnumEntry -> if (document?.areAnchorsOnOneLine(this, containingClassOrObject) == true) { return true } } return false } +internal fun KtDeclaration.findMarkerBoundDeclarations(): List { + if (this !is KtClass) return emptyList() + val result = mutableListOf() + val document = PsiDocumentManager.getInstance(project).getDocument(containingFile) + result += primaryConstructor?.valueParameters?.filter { it.hasValOrVar() && it.requiresNoMarkers(document) }.orEmpty() + if (this.isEnum()) { + result += this.body?.enumEntries?.filter { it.requiresNoMarkers(document) }.orEmpty() + } + return result +} + private fun collectActualMarkers( declaration: KtNamedDeclaration, result: MutableCollection>