Show expect / actual for parameters & enum entries in drop-box

#KT-26957 Fixed
This commit is contained in:
Mikhail Glukhikh
2018-10-02 18:58:55 +03:00
parent bb19d4c598
commit d050629589
4 changed files with 43 additions and 9 deletions
@@ -46,6 +46,9 @@ class KtClassBody : KtElementImplStub<KotlinPlaceHolderStub<KtClassBody>>, KtDec
val properties: List<KtProperty>
get() = getStubOrPsiChildrenAsList(KtStubElementTypes.PROPERTY)
val enumEntries: List<KtEnumEntry>
get() = getStubOrPsiChildrenAsList(KtStubElementTypes.ENUM_ENTRY).filterIsInstance<KtEnumEntry>()
val allCompanionObjects: List<KtObjectDeclaration>
get() = getStubOrPsiChildrenAsList(KtStubElementTypes.OBJECT_DECLARATION).filter { it.isCompanion() }
@@ -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() {
@@ -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
)
}
@@ -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<KtNamedDeclaration> {
if (this !is KtClass) return emptyList()
val result = mutableListOf<KtNamedDeclaration>()
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<LineMarkerInfo<*>>