diff --git a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt index 7b354484c8..561f7fae49 100644 --- a/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt +++ b/dokka-integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/kotlin/SerializationGradleIntegrationTest.kt @@ -45,7 +45,6 @@ class SerializationGradleIntegrationTest : AbstractGradleIntegrationTest(), Test copyAndApplyGitDiff(File("projects", "serialization/serialization.diff")) } - @OnlyDescriptors // failed due to https://github.com/Kotlin/dokka/issues/3207 @ParameterizedTest(name = "{0}") @ArgumentsSource(SerializationBuildVersionsArgumentsProvider::class) fun execute(buildVersions: BuildVersions) { diff --git a/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt b/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt index a2cb423aba..37914dd8d5 100644 --- a/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt +++ b/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DRIFactory.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.markers.KtNamedSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithTypeParameters -import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType +import org.jetbrains.kotlin.analysis.api.types.* import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -93,6 +93,28 @@ internal fun KtAnalysisSession.getDRIFromValueParameter(symbol: KtValueParameter return funDRI.copy(target = PointingToCallableParameters(index)) } +/** + * @return [DRI] to receiver type + */ +internal fun KtAnalysisSession.getDRIFromReceiverParameter(receiverParameterSymbol: KtReceiverParameterSymbol): DRI = + getDRIFromReceiverType(receiverParameterSymbol.type) + +private fun KtAnalysisSession.getDRIFromReceiverType(type: KtType): DRI { + return when(type) { + is KtNonErrorClassType -> getDRIFromNonErrorClassType(type) + is KtTypeParameterType -> getDRIFromTypeParameter(type.symbol) + is KtDefinitelyNotNullType -> getDRIFromReceiverType(type.original) + is KtTypeErrorType -> DRI(packageName = "", classNames = "$ERROR_CLASS_NAME $type") + is KtClassErrorType -> DRI(packageName = "", classNames = "$ERROR_CLASS_NAME $type") + is KtDynamicType -> DRI(packageName = "", classNames = "$ERROR_CLASS_NAME $type") // prohibited by a compiler, but it's a possible input + + is KtCapturedType -> throw IllegalStateException("Unexpected non-denotable type while creating DRI $type") + is KtFlexibleType -> throw IllegalStateException("Unexpected non-denotable type while creating DRI $type") + is KtIntegerLiteralType -> throw IllegalStateException("Unexpected non-denotable type while creating DRI $type") + is KtIntersectionType -> throw IllegalStateException("Unexpected non-denotable type while creating DRI $type") + } +} + internal fun KtAnalysisSession.getDRIFromSymbol(symbol: KtSymbol): DRI = when (symbol) { is KtEnumEntrySymbol -> getDRIFromEnumEntry(symbol) @@ -103,6 +125,7 @@ internal fun KtAnalysisSession.getDRIFromSymbol(symbol: KtSymbol): DRI = is KtFunctionLikeSymbol -> getDRIFromFunctionLike(symbol) is KtClassLikeSymbol -> getDRIFromClassLike(symbol) is KtPackageSymbol -> getDRIFromPackage(symbol) + is KtReceiverParameterSymbol -> getDRIFromReceiverParameter(symbol) else -> throw IllegalStateException("Unknown symbol while creating DRI $symbol") } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/markdown/LinkTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/markdown/LinkTest.kt index 97e027b8c0..0fe4983fee 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/markdown/LinkTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/markdown/LinkTest.kt @@ -7,12 +7,14 @@ package markdown import org.jetbrains.dokka.analysis.kotlin.markdown.MARKDOWN_ELEMENT_FILE_NAME import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.dokka.links.* +import org.jetbrains.dokka.model.DFunction import org.jetbrains.dokka.model.WithGenerics import org.jetbrains.dokka.model.dfs import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ContentDRILink import org.jetbrains.dokka.pages.MemberPageNode +import utils.OnlySymbols import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -121,6 +123,138 @@ class LinkTest : BaseAbstractTest() { } } + @Test + @OnlySymbols("#3207 - In Dokka K1 [this] has an incorrect link that leads to a page of containing package") + fun `link to this keyword with receiver to some class`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |/** + |* Link to [this] + |*/ + |fun String.stop() {} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val fn = module.dfs { it.name == "stop" } as DFunction + val link = fn.documentation.values.single() + .dfs { it is DocumentationLink } as DocumentationLink + + assertEquals(DRI("kotlin", "String"), link.dri) + } + } + } + + @Test + @OnlySymbols("#3207 In Dokka K1 [this] has an incorrect link that leads to a page of containing package") + fun `link to this keyword with receiver to type parameter`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |/** + |* Link to [this] + |*/ + |fun T.stop() {} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val fn = module.dfs { it.name == "stop" } as DFunction + val link = fn.documentation.values.single() + .dfs { it is DocumentationLink } as DocumentationLink + + assertEquals(fn.generics.first().dri, link.dri) + } + } + } + + @Test + @OnlySymbols("#3207 In Dokka K1 [this] has an incorrect link that leads to a page of containing package") + fun `link to this keyword with receiver of dynamic that is prohibited by compiler`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |/** + |* Link to [this] + |*/ + |fun dynamic.stop() {} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val fn = module.dfs { it.name == "stop" } as DFunction + val link = fn.documentation.values.single() + .dfs { it is DocumentationLink } as DocumentationLink + + assertEquals(DRI(packageName = "", classNames = " dynamic"), link.dri) + } + } + } + + @Test + @OnlySymbols("#3207 In Dokka K1 [this] has an incorrect link that leads to a page of containing package") + fun `link to this keyword with receiver of DNN-type`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/Test.kt + |package example + | + |/** + |* Link to [this] + |*/ + |fun (T&Any).stop() {} + """.trimMargin(), + configuration + ) { + documentablesMergingStage = { module -> + val fn = module.dfs { it.name == "stop" } as DFunction + val link = fn.documentation.values.single() + .dfs { it is DocumentationLink } as DocumentationLink + + assertEquals(fn.generics.first().dri, link.dri) + } + } + } + @Test fun `link with exclamation mark`() { val configuration = dokkaConfiguration {