aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/kotlin/links/DRI.kt4
-rw-r--r--kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt28
-rw-r--r--plugins/base/src/test/kotlin/basic/DRITest.kt35
3 files changed, 50 insertions, 17 deletions
diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt
index e73c2faa..8dfac80c 100644
--- a/core/src/main/kotlin/links/DRI.kt
+++ b/core/src/main/kotlin/links/DRI.kt
@@ -68,8 +68,8 @@ data class TypeConstructor(
(if (params.isNotEmpty()) "[${params.joinToString(",")}]" else "")
}
-object SelfType : TypeReference() {
- override fun toString() = "^"
+data class RecursiveType(val rank: Int): TypeReference() {
+ override fun toString() = "^".repeat(rank + 1)
}
data class Nullable(val wrapped: TypeReference) : TypeReference() {
diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt
index e07672d4..aae1f189 100644
--- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt
+++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/TypeReferenceFactory.kt
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.types.TypeProjection
fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference? =
when (d.value) {
- is ExtensionReceiver -> fromPossiblyNullable(d.type)
+ is ExtensionReceiver -> fromPossiblyNullable(d.type, emptyList())
else -> run {
println("Unknown value type for $d")
null
@@ -20,31 +20,35 @@ fun TypeReference.Companion.from(d: ReceiverParameterDescriptor): TypeReference?
}
fun TypeReference.Companion.from(d: ValueParameterDescriptor): TypeReference? =
- fromPossiblyNullable(d.type)
+ fromPossiblyNullable(d.type, emptyList())
fun TypeReference.Companion.from(p: PsiClass) = TypeReference
-private fun TypeReference.Companion.fromPossiblyNullable(t: KotlinType, self: KotlinType? = null): TypeReference =
- from(t, self).let { if (t.isMarkedNullable) Nullable(it) else it }
+private fun TypeReference.Companion.fromPossiblyNullable(t: KotlinType, paramTrace: List<KotlinType>): TypeReference =
+ fromPossiblyRecursive(t, paramTrace).let { if (t.isMarkedNullable) Nullable(it) else it }
-private fun TypeReference.Companion.from(t: KotlinType, self: KotlinType? = null): TypeReference =
- if (self is KotlinType && self.constructor == t.constructor && self.arguments == t.arguments)
- SelfType
- else when (val d = t.constructor.declarationDescriptor) {
+private fun TypeReference.Companion.fromPossiblyRecursive(t: KotlinType, paramTrace: List<KotlinType>): TypeReference =
+ paramTrace.indexOfFirst { it.constructor == t.constructor && it.arguments == t.arguments }
+ .takeIf { it >= 0 }
+ ?.let(::RecursiveType)
+ ?: from(t, paramTrace)
+
+private fun TypeReference.Companion.from(t: KotlinType, paramTrace: List<KotlinType>): TypeReference =
+ when (val d = t.constructor.declarationDescriptor) {
is TypeParameterDescriptor -> TypeParam(
- d.upperBounds.map { fromPossiblyNullable(it, self ?: t) }
+ d.upperBounds.map { fromPossiblyNullable(it, paramTrace + t) }
)
else -> TypeConstructor(
t.constructorName.orEmpty(),
- t.arguments.map { fromProjection(it, self) }
+ t.arguments.map { fromProjection(it, paramTrace) }
)
}
-private fun TypeReference.Companion.fromProjection(t: TypeProjection, r: KotlinType? = null): TypeReference =
+private fun TypeReference.Companion.fromProjection(t: TypeProjection, paramTrace: List<KotlinType>): TypeReference =
if (t.isStarProjection) {
StarProjection
} else {
- fromPossiblyNullable(t.type, r)
+ fromPossiblyNullable(t.type, paramTrace)
}
private val KotlinType.constructorName
diff --git a/plugins/base/src/test/kotlin/basic/DRITest.kt b/plugins/base/src/test/kotlin/basic/DRITest.kt
index 7083609a..4e805f48 100644
--- a/plugins/base/src/test/kotlin/basic/DRITest.kt
+++ b/plugins/base/src/test/kotlin/basic/DRITest.kt
@@ -38,7 +38,7 @@ class DRITest : AbstractCoreTest() {
val expected = TypeConstructor(
"kotlin.Function1", listOf(
TypeParam(listOf(Nullable(TypeConstructor("kotlin.Any", emptyList())))),
- Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(SelfType)))))
+ Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0))))))
)
)
val actual = module.packages.single()
@@ -70,7 +70,7 @@ class DRITest : AbstractCoreTest() {
configuration
) {
documentablesMergingStage = { module ->
- val expected = Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(SelfType)))))
+ val expected = Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0))))))
val actual = module.packages.single()
.functions.single()
.dri.callable?.params?.single()
@@ -100,7 +100,7 @@ class DRITest : AbstractCoreTest() {
configuration
) {
documentablesMergingStage = { module ->
- val expected = Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(SelfType)))))
+ val expected = Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0))))))
val actual = module.packages.single()
.functions.single()
.dri.callable?.receiver
@@ -314,4 +314,33 @@ class DRITest : AbstractCoreTest() {
}
}
}
+
+ @Test
+ fun `deep recursive typebound #1342`() {
+ val configuration = dokkaConfiguration {
+ sourceSets {
+ sourceSet {
+ sourceRoots = listOf("src/")
+ }
+ }
+ }
+ testInline(
+ """
+ |/src/main/kotlin/Test.kt
+ |package example
+ |
+ | fun <T, S, R> recursiveBound(t: T, s: S, r: R) where T: List<S>, S: List<R>, R: List<S> = Unit
+ |
+ """.trimMargin(),
+ configuration
+ ) {
+ documentablesMergingStage = { module ->
+ val function = module.dfs { it.name == "recursiveBound" }
+ assertEquals(
+ "example//recursiveBound/#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^^]])]])]])#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^]])]])#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^]])]])/PointingToDeclaration/",
+ function?.dri?.toString(),
+ )
+ }
+ }
+ }
}