Skip to content

Commit

Permalink
[K2] Support [this] link for extensions (#3445)
Browse files Browse the repository at this point in the history
* [K2] Support `[this]` link for extensions

* Enable serialization test

* Refactor and add one more test

* Support dynamic receiver as a possible input
  • Loading branch information
vmishenev authored Jan 17, 2024
1 parent acb16bf commit 42ce2bd
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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")
}

Expand Down
134 changes: 134 additions & 0 deletions dokka-subprojects/plugin-base/src/test/kotlin/markdown/LinkTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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> 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 = "<ERROR CLASS> 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> (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 {
Expand Down

0 comments on commit 42ce2bd

Please sign in to comment.