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 252264db1f7..739aab682ce 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasActualMarker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/HasActualMarker.kt @@ -63,7 +63,7 @@ fun getPlatformActualTooltip(declaration: KtDeclaration): String? { } fun KtDeclaration.allNavigatableActualDeclarations(): Set = - actualsForExpected() + findMarkerBoundDeclarations().flatMap { it.actualsForExpected() } + actualsForExpected() + findMarkerBoundDeclarations().flatMap { it.actualsForExpected().asSequence() } class ActualExpectedPsiElementCellRenderer : DefaultPsiElementCellRenderer() { override fun getContainerText(element: PsiElement?, name: String?) = "" 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 0bcd843569c..d49322963f0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/highlighter/markers/KotlinLineMarkerProvider.kt @@ -385,22 +385,59 @@ private fun KtNamedDeclaration.requiresNoMarkers( return true } is KtParameter, - is KtEnumEntry -> if (document?.areAnchorsOnOneLine(this, containingClassOrObject) == true) { - return true + is KtEnumEntry -> { + if (document?.areAnchorsOnOneLine(this, containingClassOrObject) == true) { + return true + } + if (this is KtEnumEntry) { + val enumEntries = containingClassOrObject?.body?.enumEntries.orEmpty() + val previousEnumEntry = enumEntries.getOrNull(enumEntries.indexOf(this) - 1) + if (document?.areAnchorsOnOneLine(this, previousEnumEntry) == true) { + return true + } + } + if (this is KtParameter && hasValOrVar()) { + val parameters = containingClassOrObject?.primaryConstructorParameters.orEmpty() + val previousParameter = parameters.getOrNull(parameters.indexOf(this) - 1) + if (document?.areAnchorsOnOneLine(this, previousParameter) == true) { + return true + } + } } } return false } -internal fun KtDeclaration.findMarkerBoundDeclarations(): List { - if (this !is KtClass) return emptyList() - val result = mutableListOf() +internal fun KtDeclaration.findMarkerBoundDeclarations(): Sequence { + if (this !is KtClass && this !is KtParameter) return emptySequence() 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() + + fun Sequence.takeBound(bound: KtNamedDeclaration) = takeWhile { + document?.areAnchorsOnOneLine(bound, it) == true + } + + return when (this) { + is KtParameter -> { + val propertyParameters = takeIf { hasValOrVar() }?.containingClassOrObject?.primaryConstructorParameters + ?: return emptySequence() + propertyParameters.asSequence().dropWhile { + it !== this + }.drop(1).takeBound(this).filter { it.hasValOrVar() } + } + is KtEnumEntry -> { + val enumEntries = containingClassOrObject?.body?.enumEntries ?: return emptySequence() + enumEntries.asSequence().dropWhile { + it !== this + }.drop(1).takeBound(this) + } + is KtClass -> { + val boundParameters = + primaryConstructor?.valueParameters?.asSequence()?.takeBound(this)?.filter { it.hasValOrVar() }.orEmpty() + val boundEnumEntries = this.takeIf { isEnum() }?.body?.enumEntries?.asSequence()?.takeBound(this).orEmpty() + boundParameters + boundEnumEntries + } + else -> emptySequence() } - return result } private fun collectActualMarkers( diff --git a/idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/common/common.kt b/idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/common/common.kt new file mode 100644 index 00000000000..6c0f30ab284 --- /dev/null +++ b/idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/common/common.kt @@ -0,0 +1,17 @@ +package test + +expect enum class Enum { + A, B, C, D +} + +/* +LINEMARKER: Has actuals in JVM +TARGETS: +jvm.kt +actual enum class <1>Enum { +*//* +LINEMARKER: Has actuals in JVM +TARGETS: +jvm.kt + <1>A, <2>B, <3>C, <4>D +*/ diff --git a/idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/jvm/jvm.kt b/idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/jvm/jvm.kt new file mode 100644 index 00000000000..b8819e16464 --- /dev/null +++ b/idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/jvm/jvm.kt @@ -0,0 +1,6 @@ +// !CHECK_HIGHLIGHTING +package test + +actual enum class Enum { + A, B, C, D +} \ No newline at end of file diff --git a/idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/common/common.kt b/idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/common/common.kt new file mode 100644 index 00000000000..df4754e0c91 --- /dev/null +++ b/idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/common/common.kt @@ -0,0 +1,6 @@ +// !CHECK_HIGHLIGHTING + +expect annotation class Ann( + val x: Int, val y: String, + val z: Double, val b: Boolean +) \ No newline at end of file diff --git a/idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/jvm/jvm.kt b/idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/jvm/jvm.kt new file mode 100644 index 00000000000..e54dfb4587d --- /dev/null +++ b/idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/jvm/jvm.kt @@ -0,0 +1,31 @@ +actual annotation class Ann( + actual val x: Int, actual val y: String, + actual val z: Double, actual val b: Boolean +) + +// TODO: first marker on 'Ann' is generated twice here, see collectSlowLineMarkers main loop. +// Since it's fragile place, I don't want to fix it right now + + +/* +LINEMARKER: Has declaration in common module +TARGETS: +common.kt +expect annotation class <1>Ann( +*//* +LINEMARKER: Has declaration in common module +TARGETS: +common.kt +expect annotation class <1>Ann( +*//* +LINEMARKER: Has declaration in common module +TARGETS: +common.kt + val <1>x: Int, val <2>y: String, +*//* +LINEMARKER: Has declaration in common module +TARGETS: +common.kt + val <2>z: Double, val <1>b: Boolean +*/ + diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTestGenerated.java index 5320d8757bd..5402f9773c4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/MultiModuleLineMarkerTestGenerated.java @@ -69,6 +69,11 @@ public class MultiModuleLineMarkerTestGenerated extends AbstractMultiModuleLineM runTest("idea/testData/multiModuleLineMarker/expectEnumEntriesInOneLine/"); } + @TestMetadata("expectEnumWithEnumEntriesInOneLine") + public void testExpectEnumWithEnumEntriesInOneLine() throws Exception { + runTest("idea/testData/multiModuleLineMarker/expectEnumWithEnumEntriesInOneLine/"); + } + @TestMetadata("expectWithOverload") public void testExpectWithOverload() throws Exception { runTest("idea/testData/multiModuleLineMarker/expectWithOverload/"); @@ -79,6 +84,11 @@ public class MultiModuleLineMarkerTestGenerated extends AbstractMultiModuleLineM runTest("idea/testData/multiModuleLineMarker/fromActualAnnotation/"); } + @TestMetadata("fromActualAnnotationWithParametersInOneLine") + public void testFromActualAnnotationWithParametersInOneLine() throws Exception { + runTest("idea/testData/multiModuleLineMarker/fromActualAnnotationWithParametersInOneLine/"); + } + @TestMetadata("fromActualCompanion") public void testFromActualCompanion() throws Exception { runTest("idea/testData/multiModuleLineMarker/fromActualCompanion/"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt index 5eda3ce7b8b..18d828f6ce4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractLineMarkersTest.kt @@ -117,16 +117,17 @@ abstract class AbstractLineMarkersTest : KotlinLightCodeInsightFixtureTestCase() ) if (navigationDataComments.isEmpty()) return - for (navigationComment in navigationDataComments) { + for ((navigationCommentIndex, navigationComment) in navigationDataComments.reversed().withIndex()) { val description = getLineMarkerDescription(navigationComment) - val navigateMarker = markers.find { it.lineMarkerTooltip?.startsWith(description) == true }!! + val navigateMarkers = markers.filter { it.lineMarkerTooltip?.startsWith(description) == true } + val navigateMarker = navigateMarkers.singleOrNull() ?: navigateMarkers.getOrNull(navigationCommentIndex) TestCase.assertNotNull( String.format("Can't find marker for navigation check with description \"%s\"", description), navigateMarker ) - val handler = navigateMarker.navigationHandler + val handler = navigateMarker!!.navigationHandler if (handler is TestableLineMarkerNavigator) { val navigateElements = handler.getTargetsPopupDescriptor(navigateMarker.element)?.targets?.sortedBy { it.renderAsGotoImplementation()