Skip to content

Commit

Permalink
[K2] Fix nullable parameters in DRI and Javadoc links (#3501)
Browse files Browse the repository at this point in the history
  • Loading branch information
vmishenev committed Feb 26, 2024
1 parent 722d082 commit 1dec220
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ private fun KtAnalysisSession.getTypeReferenceFromPossiblyRecursive(
}

is KtClassErrorType -> TypeConstructor("$ERROR_CLASS_NAME $type", emptyList())
is KtFlexibleType -> getTypeReferenceFromPossiblyRecursive(
type.upperBound,
paramTrace
)

is KtDefinitelyNotNullType -> getTypeReferenceFromPossiblyRecursive(
type.original,
Expand All @@ -63,6 +59,17 @@ private fun KtAnalysisSession.getTypeReferenceFromPossiblyRecursive(

is KtDynamicType -> TypeConstructor("[dynamic]", emptyList())
is KtTypeErrorType -> TypeConstructor("$ERROR_CLASS_NAME $type", emptyList())
// Non-denotable types, see https://kotlinlang.org/spec/type-system.html#type-kinds

// By the definition [flexible types](https://kotlinlang.org/spec/type-system.html#flexible-types),
// we can take any type between lower and upper bounds
// In Dokka K1, a lower bound is taken
// For example, most Java types T in Kotlin are flexible (T..T?) or T!
// see https://github.com/JetBrains/kotlin/blob/master/spec-docs/flexible-java-types.md (warn: it is not official spec)
is KtFlexibleType -> getTypeReferenceFromPossiblyRecursive(
type.lowerBound,
paramTrace
)
is KtCapturedType -> throw NotImplementedError()
is KtIntegerLiteralType -> throw NotImplementedError()
is KtIntersectionType -> throw NotImplementedError()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ package org.jetbrains.dokka.base.resolvers.external.javadoc

import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider
import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation
import org.jetbrains.dokka.links.Callable
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.DRIExtraContainer
import org.jetbrains.dokka.links.EnumEntryDRIExtra
import org.jetbrains.dokka.links.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.utilities.htmlEscape

Expand Down Expand Up @@ -56,7 +53,21 @@ public open class JavadocExternalLocationProvider(
protected open fun anchorPart(callable: Callable): String {
return callable.name +
"${brackets.first()}" +
callable.params.joinToString(separator) +
callable.params.joinToString(separator) { it.toJavadocURL() } +
"${brackets.last()}"
}

private fun TypeReference.toJavadocURL(): String {
return when (this) {
is JavaClassReference -> name
is Nullable -> wrapped.toJavadocURL() // just ignore
is StarProjection -> "?"

// TODO #3502
is TypeConstructor -> fullyQualifiedName +
(if (params.isNotEmpty()) "[${params.joinToString(",") { it.toJavadocURL() }}]" else "")
is TypeParam -> toString()
is RecursiveType -> "^".repeat(rank + 1)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import org.jetbrains.dokka.base.resolvers.external.javadoc.JavadocExternalLocati
import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation
import org.jetbrains.dokka.base.resolvers.shared.PackageList
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.DRIExtraContainer
import org.jetbrains.dokka.links.EnumEntryDRIExtra
import org.jetbrains.dokka.links.PointingToDeclaration
import org.jetbrains.dokka.links.*
import org.jetbrains.dokka.plugability.DokkaContext
import java.net.URL
import kotlin.test.Test
Expand Down Expand Up @@ -82,4 +79,23 @@ class JavadocExternalLocationProviderTest : BaseAbstractTest() {
locationProvider.resolve(dri)
)
}

@Test
fun `link to function with nullable parameter`() {
val locationProvider = getTestLocationProvider()
val dri = DRI(
packageName = "java.applet",
classNames = "AppletContext",
callable = Callable(
name = "showDocument",
params = listOf(Nullable(TypeConstructor("java.net.URL", emptyList())))
),
target = PointingToDeclaration
)

assertEquals(
"https://docs.oracle.com/javase/8/docs/api/java/applet/AppletContext.html#showDocument-java.net.URL-",
locationProvider.resolve(dri)
)
}
}
56 changes: 56 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 @@ -493,6 +493,62 @@ class LinkTest : BaseAbstractTest() {
}
}

@Test
fun `link should lead to a function with a nullable parameter`() {
val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src/")
}
}
}

testInline(
"""
|/src/main/kotlin/Testing.kt
|package example
|
|/**
| * ref to [java.applet.AppletContext.showDocument]
| */
|fun x(){}
""".trimMargin(),
configuration
) {
documentablesMergingStage = { module ->
val functionDocs = module.packages.flatMap { it.functions }.first().documentation.values.first()
val expected = Description(
root = CustomDocTag(
children = listOf(
P(
children = listOf(
Text("ref to "),
DocumentationLink(
dri = DRI(
packageName = "java.applet",
classNames = "AppletContext",
callable = Callable(
name = "showDocument",
params = listOf(TypeConstructor("java.net.URL", emptyList()))
),
target = PointingToDeclaration
),
children = listOf(
Text("java.applet.AppletContext.showDocument")
),
params = mapOf("href" to "[java.applet.AppletContext.showDocument]")
),
)
)
),
name = "MARKDOWN_FILE"
)
)
assertEquals(expected, functionDocs.children.first())
}
}
}

@Test
fun `link should lead to function rather than property`() {
val configuration = dokkaConfiguration {
Expand Down

0 comments on commit 1dec220

Please sign in to comment.