Improve expect / actual markers on one line
Before this commit, only one-line enums and annotation classes were considered. Now we can have enum header on one line and some entries on another lines, and it still works. Same with primary constructor parameters. #KT-22637 Fixed
This commit is contained in:
@@ -63,7 +63,7 @@ fun getPlatformActualTooltip(declaration: KtDeclaration): String? {
|
||||
}
|
||||
|
||||
fun KtDeclaration.allNavigatableActualDeclarations(): Set<KtDeclaration> =
|
||||
actualsForExpected() + findMarkerBoundDeclarations().flatMap { it.actualsForExpected() }
|
||||
actualsForExpected() + findMarkerBoundDeclarations().flatMap { it.actualsForExpected().asSequence() }
|
||||
|
||||
class ActualExpectedPsiElementCellRenderer : DefaultPsiElementCellRenderer() {
|
||||
override fun getContainerText(element: PsiElement?, name: String?) = ""
|
||||
|
||||
@@ -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<KtNamedDeclaration> {
|
||||
if (this !is KtClass) return emptyList()
|
||||
val result = mutableListOf<KtNamedDeclaration>()
|
||||
internal fun KtDeclaration.findMarkerBoundDeclarations(): Sequence<KtNamedDeclaration> {
|
||||
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 <T : KtNamedDeclaration> Sequence<T>.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(
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package test
|
||||
|
||||
expect enum class <lineMarker descr="Has actuals in JVM">Enum</lineMarker> {
|
||||
<lineMarker descr="Has actuals in JVM">A</lineMarker>, 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
|
||||
*/
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// !CHECK_HIGHLIGHTING
|
||||
package test
|
||||
|
||||
actual enum class Enum {
|
||||
A, B, C, D
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
// !CHECK_HIGHLIGHTING
|
||||
|
||||
expect annotation class Ann(
|
||||
val x: Int, val y: String,
|
||||
val z: Double, val b: Boolean
|
||||
)
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
actual annotation class <lineMarker descr="Has declaration in common module">Ann</lineMarker>(
|
||||
actual val <lineMarker descr="Has declaration in common module">x</lineMarker>: Int, actual val y: String,
|
||||
actual val <lineMarker descr="Has declaration in common module">z</lineMarker>: 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
|
||||
*/
|
||||
|
||||
Generated
+10
@@ -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/");
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user