Expect/actual markers: handle secondary constructors correctly

So #KT-20309 Fixed
This commit is contained in:
Mikhail Glukhikh
2017-10-06 17:27:13 +03:00
parent 26136cd0fe
commit ceab148b09
8 changed files with 59 additions and 25 deletions
@@ -44,8 +44,8 @@ fun ModuleDescriptor.actualsFor(descriptor: MemberDescriptor, checkCompatible: B
} }
} }
fun getPlatformActualTooltip(declaration: KtDeclaration): String? { fun getPlatformActualTooltip(declaration: KtDeclaration?): String? {
val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return null val descriptor = declaration?.toDescriptor() as? MemberDescriptor ?: return null
val commonModuleDescriptor = declaration.containingKtFile.findModuleDescriptor() val commonModuleDescriptor = declaration.containingKtFile.findModuleDescriptor()
val platformModulesWithActuals = commonModuleDescriptor.implementingDescriptors.filter { val platformModulesWithActuals = commonModuleDescriptor.implementingDescriptors.filter {
@@ -58,13 +58,13 @@ fun getPlatformActualTooltip(declaration: KtDeclaration): String? {
} }
} }
fun navigateToPlatformActual(e: MouseEvent?, declaration: KtDeclaration) { fun navigateToPlatformActual(e: MouseEvent?, declaration: KtDeclaration?) {
val actuals = declaration.actualsForExpected() val actualDeclarations = declaration?.actualsForExpected() ?: return
if (actuals.isEmpty()) return if (actualDeclarations.isEmpty()) return
val renderer = DefaultPsiElementCellRenderer() val renderer = DefaultPsiElementCellRenderer()
PsiElementListNavigator.openTargets(e, PsiElementListNavigator.openTargets(e,
actuals.toTypedArray(), actualDeclarations.toTypedArray(),
"Choose actual for ${declaration.name}", "Choose actual for ${declaration.name}",
"Actuals for ${declaration.name}", "Actuals for ${declaration.name}",
renderer) renderer)
@@ -58,8 +58,8 @@ private fun ModuleDescriptor.declarationOf(descriptor: MemberDescriptor): Declar
descriptor.findCompatibleExpectedForActual(this@declarationOf).firstOrNull() descriptor.findCompatibleExpectedForActual(this@declarationOf).firstOrNull()
} }
fun getExpectedDeclarationTooltip(declaration: KtDeclaration): String? { fun getExpectedDeclarationTooltip(declaration: KtDeclaration?): String? {
val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return null val descriptor = declaration?.toDescriptor() as? MemberDescriptor ?: return null
val platformModuleDescriptor = declaration.containingKtFile.findModuleDescriptor() val platformModuleDescriptor = declaration.containingKtFile.findModuleDescriptor()
val commonModuleDescriptor = platformModuleDescriptor.commonModuleOrNull() ?: return null val commonModuleDescriptor = platformModuleDescriptor.commonModuleOrNull() ?: return null
@@ -68,8 +68,8 @@ fun getExpectedDeclarationTooltip(declaration: KtDeclaration): String? {
return "Has declaration in common module" return "Has declaration in common module"
} }
fun navigateToExpectedDeclaration(declaration: KtDeclaration) { fun navigateToExpectedDeclaration(declaration: KtDeclaration?) {
declaration.expectedDeclarationIfAny()?.navigate(false) declaration?.expectedDeclarationIfAny()?.navigate(false)
} }
internal fun MemberDescriptor.expectedDescriptor() = module.commonModuleOrNull()?.declarationOf(this) internal fun MemberDescriptor.expectedDescriptor() = module.commonModuleOrNull()?.declarationOf(this)
@@ -182,22 +182,25 @@ private val OVERRIDDEN_PROPERTY = object : MarkerType(
} }
} }
private val PsiElement.markerDeclaration
get() = (this as? KtDeclaration) ?: (parent as? KtDeclaration)
private val PLATFORM_ACTUAL = MarkerType( private val PLATFORM_ACTUAL = MarkerType(
"PLATFORM_ACTUAL", "PLATFORM_ACTUAL",
{ it?.let { getPlatformActualTooltip(it.parent as KtDeclaration) } }, { it?.let { getPlatformActualTooltip(it.markerDeclaration) } },
object : LineMarkerNavigator() { object : LineMarkerNavigator() {
override fun browse(e: MouseEvent?, element: PsiElement?) { override fun browse(e: MouseEvent?, element: PsiElement?) {
element?.let { navigateToPlatformActual(e, it.parent as KtDeclaration) } element?.let { navigateToPlatformActual(e, it.markerDeclaration) }
} }
} }
) )
private val EXPECTED_DECLARATION = MarkerType( private val EXPECTED_DECLARATION = MarkerType(
"EXPECTED_DECLARATION", "EXPECTED_DECLARATION",
{ it?.let { getExpectedDeclarationTooltip(it.parent as KtDeclaration) } }, { it?.let { getExpectedDeclarationTooltip(it.markerDeclaration) } },
object : LineMarkerNavigator() { object : LineMarkerNavigator() {
override fun browse(e: MouseEvent?, element: PsiElement?) { override fun browse(e: MouseEvent?, element: PsiElement?) {
element?.let { navigateToExpectedDeclaration(it.parent as KtDeclaration) } element?.let { navigateToExpectedDeclaration(it.markerDeclaration) }
} }
} }
) )
@@ -286,6 +289,9 @@ private fun collectOverriddenPropertyAccessors(properties: Collection<KtNamedDec
} }
} }
private val KtNamedDeclaration.expectOrActualAnchor
get() = nameIdentifier ?: (this as? KtConstructor<*>)?.getConstructorKeyword() ?: this
private fun collectActualMarkers(declaration: KtNamedDeclaration, private fun collectActualMarkers(declaration: KtNamedDeclaration,
result: MutableCollection<LineMarkerInfo<*>>) { result: MutableCollection<LineMarkerInfo<*>>) {
@@ -294,7 +300,7 @@ private fun collectActualMarkers(declaration: KtNamedDeclaration,
if (commonModuleDescriptor.implementingDescriptors.none { it.hasActualsFor(descriptor) }) return if (commonModuleDescriptor.implementingDescriptors.none { it.hasActualsFor(descriptor) }) return
val anchor = declaration.nameIdentifier ?: declaration val anchor = declaration.expectOrActualAnchor
result.add(LineMarkerInfo( result.add(LineMarkerInfo(
anchor, anchor,
@@ -315,7 +321,7 @@ private fun collectExpectedMarkers(declaration: KtNamedDeclaration,
val commonModuleDescriptor = platformModuleDescriptor.commonModuleOrNull() ?: return val commonModuleDescriptor = platformModuleDescriptor.commonModuleOrNull() ?: return
if (!commonModuleDescriptor.hasDeclarationOf(descriptor)) return if (!commonModuleDescriptor.hasDeclarationOf(descriptor)) return
val anchor = declaration.nameIdentifier ?: declaration val anchor = declaration.expectOrActualAnchor
result.add(LineMarkerInfo( result.add(LineMarkerInfo(
anchor, anchor,
@@ -0,0 +1,5 @@
// !CHECK_HIGHLIGHTING
expect class SecondaryConstructor{
constructor(name: String, surname: String)
}
@@ -0,0 +1,5 @@
actual class <lineMarker>SecondaryConstructor</lineMarker> {
actual <lineMarker>constructor</lineMarker>(name: String, surname: String) {}
}
@@ -0,0 +1,3 @@
expect class <lineMarker>SecondaryConstructor</lineMarker>{
constructor(name: String, surname: String)
}
@@ -0,0 +1,7 @@
// !CHECK_HIGHLIGHTING
actual class SecondaryConstructor {
actual constructor(name: String, surname: String) {}
}
@@ -34,6 +34,14 @@ class MultiModuleLineMarkerTest : AbstractMultiModuleHighlightingTest() {
override fun doTestLineMarkers() = true override fun doTestLineMarkers() = true
fun testFromActualSecondaryConstructor() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
}
fun testFromClassToAlias() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
}
fun testFromCommonToJvmHeader() { fun testFromCommonToJvmHeader() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
} }
@@ -42,18 +50,10 @@ class MultiModuleLineMarkerTest : AbstractMultiModuleHighlightingTest() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
} }
fun testFromClassToAlias() { fun testFromExpectedSecondaryConstructor() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]) doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
} }
fun testWithOverloads() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
}
fun testSuspendImplInPlatformModules() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], TargetPlatformKind.JavaScript)
}
fun testKotlinTestAnnotations() { fun testKotlinTestAnnotations() {
doMultiPlatformTest(TargetPlatformKind.JavaScript, doMultiPlatformTest(TargetPlatformKind.JavaScript,
configureModule = { module, _ -> configureModule = { module, _ ->
@@ -66,6 +66,10 @@ class MultiModuleLineMarkerTest : AbstractMultiModuleHighlightingTest() {
}) })
} }
fun testSuspendImplInPlatformModules() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6], TargetPlatformKind.JavaScript)
}
fun testTransitive() { fun testTransitive() {
val commonModule = module("common", TestJdkKind.MOCK_JDK) val commonModule = module("common", TestJdkKind.MOCK_JDK)
commonModule.createFacet(TargetPlatformKind.Common, false) commonModule.createFacet(TargetPlatformKind.Common, false)
@@ -84,4 +88,8 @@ class MultiModuleLineMarkerTest : AbstractMultiModuleHighlightingTest() {
checkHighlightingInAllFiles() checkHighlightingInAllFiles()
} }
fun testWithOverloads() {
doMultiPlatformTest(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
}
} }