Skip to content

Commit f0abfa9

Browse files
authored
Add 'name' property to TypeParam and use it in TypeReference.toJavadocURL (#4344)
* Add 'name' property to `TypeParam` and use it in `TypeReference.toJavadocURL` * Update API * Update TypeParam to keep binary compatibility * Update test data
1 parent f98203a commit f0abfa9

File tree

9 files changed

+188
-47
lines changed

9 files changed

+188
-47
lines changed

dokka-subprojects/analysis-kotlin-descriptors-compiler/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/descriptors/compiler/configuration/TypeReferenceFactory.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ private fun TypeReference.Companion.from(t: KotlinType, paramTrace: List<KotlinT
5656
}
5757
return when (val d = t.constructor.declarationDescriptor) {
5858
is TypeParameterDescriptor -> TypeParam(
59-
d.upperBounds.map { fromPossiblyNullable(it, paramTrace + t) }
59+
bounds = d.upperBounds.map { fromPossiblyNullable(it, paramTrace + t) },
60+
name = d.name.asString()
6061
)
6162

6263
else -> TypeConstructor(

dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/TypeReferenceFactory.kt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,15 @@ private fun KaSession.getTypeReferenceFromPossiblyRecursive(
4444
val upperBoundsOrNullableAny =
4545
type.symbol.upperBounds.takeIf { it.isNotEmpty() } ?: listOf(this.builtinTypes.nullableAny)
4646

47-
TypeParam(bounds = upperBoundsOrNullableAny.map {
48-
getTypeReferenceFromPossiblyRecursive(
49-
it,
50-
paramTrace + type
51-
)
52-
})
47+
TypeParam(
48+
name = type.name.asString(),
49+
bounds = upperBoundsOrNullableAny.map {
50+
getTypeReferenceFromPossiblyRecursive(
51+
it,
52+
paramTrace + type
53+
)
54+
}
55+
)
5356
}
5457

5558
is KaClassErrorType -> TypeConstructor("$ERROR_CLASS_NAME $type", emptyList())
@@ -72,6 +75,7 @@ private fun KaSession.getTypeReferenceFromPossiblyRecursive(
7275
type.lowerBound,
7376
paramTrace
7477
)
78+
7579
is KaCapturedType -> throw NotImplementedError()
7680
is KaIntersectionType -> throw NotImplementedError()
7781
else -> throw NotImplementedError()

dokka-subprojects/core/api/dokka-core.api

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -648,12 +648,16 @@ public final class org/jetbrains/dokka/links/TypeConstructor : org/jetbrains/dok
648648
}
649649

650650
public final class org/jetbrains/dokka/links/TypeParam : org/jetbrains/dokka/links/TypeReference {
651-
public fun <init> (Ljava/util/List;)V
651+
public synthetic fun <init> (Ljava/util/List;)V
652+
public fun <init> (Ljava/util/List;Ljava/lang/String;)V
652653
public final fun component1 ()Ljava/util/List;
653-
public final fun copy (Ljava/util/List;)Lorg/jetbrains/dokka/links/TypeParam;
654-
public static synthetic fun copy$default (Lorg/jetbrains/dokka/links/TypeParam;Ljava/util/List;ILjava/lang/Object;)Lorg/jetbrains/dokka/links/TypeParam;
654+
public final fun component2 ()Ljava/lang/String;
655+
public final synthetic fun copy (Ljava/util/List;)Lorg/jetbrains/dokka/links/TypeParam;
656+
public final fun copy (Ljava/util/List;Ljava/lang/String;)Lorg/jetbrains/dokka/links/TypeParam;
657+
public static synthetic fun copy$default (Lorg/jetbrains/dokka/links/TypeParam;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/links/TypeParam;
655658
public fun equals (Ljava/lang/Object;)Z
656659
public final fun getBounds ()Ljava/util/List;
660+
public final fun getName ()Ljava/lang/String;
657661
public fun hashCode ()I
658662
public fun toString ()Ljava/lang/String;
659663
}

dokka-subprojects/core/src/main/kotlin/org/jetbrains/dokka/links/DRI.kt

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,29 @@ public data class JavaClassReference(val name: String) : TypeReference() {
128128
override fun toString(): String = name
129129
}
130130

131-
public data class TypeParam(val bounds: List<TypeReference>) : TypeReference()
131+
public data class TypeParam(
132+
val bounds: List<TypeReference>,
133+
val name: String,
134+
) : TypeReference() {
135+
136+
@Deprecated("Binary compatibility", level = DeprecationLevel.HIDDEN)
137+
public constructor(
138+
bounds: List<TypeReference>,
139+
) : this(bounds, "")
140+
141+
142+
@Deprecated("Binary compatibility", level = DeprecationLevel.HIDDEN)
143+
public fun copy(
144+
bounds: List<TypeReference>
145+
): TypeParam = copy(bounds = bounds, name = name)
146+
147+
/**
148+
* Custom `toString` with no `name` parameter to keep compatibility of
149+
* `DRI.toString` calls used in package-lists and HTML rendering
150+
*/
151+
override fun toString(): String = "TypeParam(bounds=${bounds})"
152+
}
153+
132154

133155
public data class TypeConstructor(
134156
val fullyQualifiedName: String,

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/resolvers/external/javadoc/JavadocExternalLocationProvider.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,8 @@ public open class JavadocExternalLocationProvider(
6363
is Nullable -> wrapped.toJavadocURL() // just ignore
6464
is StarProjection -> "?"
6565

66-
// TODO #3502
6766
is TypeConstructor -> fullyQualifiedName
68-
is TypeParam -> toString()
67+
is TypeParam -> name
6968
is RecursiveType -> "^".repeat(rank + 1)
7069
is Vararg -> "${elementType.toJavadocURL()}..."
7170
}

dokka-subprojects/plugin-base/src/test/kotlin/basic/DRITest.kt

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,16 @@ class DRITest : BaseAbstractTest() {
4242
documentablesMergingStage = { module ->
4343
val expected = TypeConstructor(
4444
"kotlin.Function1", listOf(
45-
TypeParam(listOf(Nullable(TypeConstructor("kotlin.Any", emptyList())))),
46-
Nullable(TypeParam(listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0))))))
45+
TypeParam(
46+
name = "T",
47+
bounds = listOf(Nullable(TypeConstructor("kotlin.Any", emptyList())))
48+
),
49+
Nullable(
50+
TypeParam(
51+
name = "R",
52+
bounds = listOf(TypeConstructor("kotlin.Comparable", listOf(RecursiveType(0))))
53+
)
54+
)
4755
)
4856
)
4957
val actual = module.packages.single()
@@ -69,7 +77,8 @@ class DRITest : BaseAbstractTest() {
6977
documentablesMergingStage = { module ->
7078
val expected = Nullable(
7179
TypeParam(
72-
listOf(
80+
name = "T",
81+
bounds = listOf(
7382
TypeConstructor(
7483
"kotlin.Comparable",
7584
listOf(RecursiveType(0))
@@ -100,7 +109,8 @@ class DRITest : BaseAbstractTest() {
100109
documentablesMergingStage = { module ->
101110
val expected = Nullable(
102111
TypeParam(
103-
listOf(
112+
name = "T",
113+
bounds = listOf(
104114
TypeConstructor(
105115
"kotlin.Comparable",
106116
listOf(RecursiveType(0))
@@ -150,7 +160,8 @@ class DRITest : BaseAbstractTest() {
150160
"qux", TypeConstructor(
151161
"Foo", listOf(
152162
TypeParam(
153-
listOf(
163+
name = "T",
164+
bounds = listOf(
154165
TypeConstructor(
155166
"kotlin.Comparable", listOf(
156167
Nullable(TypeConstructor("kotlin.Any", emptyList()))
@@ -310,6 +321,26 @@ class DRITest : BaseAbstractTest() {
310321
"example//extensionFunction/kotlin.collections.List[TypeParam(bounds=[kotlin.Any?])]#/PointingToDeclaration/",
311322
extensionFunction.dri.first().toString()
312323
)
324+
assertEquals(
325+
DRI(
326+
packageName = "example",
327+
classNames = null,
328+
callable = Callable(
329+
name = "extensionFunction",
330+
receiver = TypeConstructor(
331+
"kotlin.collections.List",
332+
listOf(
333+
TypeParam(
334+
name = "T",
335+
bounds = listOf(Nullable(TypeConstructor("kotlin.Any", emptyList())))
336+
)
337+
)
338+
),
339+
params = emptyList()
340+
)
341+
),
342+
extensionFunction.dri.first()
343+
)
313344
assertEquals(1, documentable.generics.size)
314345
assertEquals("T", documentable.generics.first().name)
315346
assertEquals(
@@ -336,7 +367,9 @@ class DRITest : BaseAbstractTest() {
336367
documentablesMergingStage = { module ->
337368
val function = module.dfs { it.name == "recursiveBound" }
338369
assertEquals(
339-
"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/",
370+
"example//recursiveBound/#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^^]])]])]])" +
371+
"#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^]])]])" +
372+
"#TypeParam(bounds=[kotlin.collections.List[TypeParam(bounds=[kotlin.collections.List[^]])]])/PointingToDeclaration/",
340373
function?.dri?.toString(),
341374
)
342375
}

dokka-subprojects/plugin-base/src/test/kotlin/locationProvider/JavadocExternalLocationProviderTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,25 @@ class JavadocExternalLocationProviderTest : BaseAbstractTest() {
120120
locationProvider.resolve(dri)
121121
)
122122
}
123+
124+
@Test
125+
fun `#3502 link to Java function with type parameters`() {
126+
val locationProvider = getTestLocationProvider()
127+
val dri = DRI(
128+
packageName = "java.util",
129+
classNames = "Arrays",
130+
callable = Callable(
131+
name = "asList",
132+
params = listOf(
133+
Nullable(Vararg(TypeParam(name = "T", bounds = listOf(TypeConstructor("kotlin.Any", emptyList())))))
134+
),
135+
),
136+
target = PointingToDeclaration
137+
)
138+
139+
assertEquals(
140+
"https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList-T...-",
141+
locationProvider.resolve(dri)
142+
)
143+
}
123144
}

dokka-subprojects/plugin-base/src/test/kotlin/markdown/LinkTest.kt

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class LinkTest : BaseAbstractTest() {
3131
}
3232
}
3333
}
34+
3435
@Test
3536
fun linkToClassLoader() {
3637
val configuration = dokkaConfiguration {
@@ -54,12 +55,13 @@ class LinkTest : BaseAbstractTest() {
5455
configuration
5556
) {
5657
renderingStage = { rootPageNode, _ ->
57-
assertNotNull((rootPageNode.children.single().children.single() as MemberPageNode)
58-
.content
59-
.dfs { node ->
60-
node is ContentDRILink &&
61-
node.address.toString() == "parser//test/#java.lang.ClassLoader/PointingToDeclaration/"
62-
}
58+
assertNotNull(
59+
(rootPageNode.children.single().children.single() as MemberPageNode)
60+
.content
61+
.dfs { node ->
62+
node is ContentDRILink &&
63+
node.address.toString() == "parser//test/#java.lang.ClassLoader/PointingToDeclaration/"
64+
}
6365
)
6466
}
6567
}
@@ -343,7 +345,8 @@ class LinkTest : BaseAbstractTest() {
343345
configuration
344346
) {
345347
documentablesMergingStage = { module ->
346-
val functionDocs = (module.packages.flatMap { it.classlikes }.first() as DClass).constructors.first().documentation.values.first()
348+
val functionDocs = (module.packages.flatMap { it.classlikes }
349+
.first() as DClass).constructors.first().documentation.values.first()
347350
val expected = Description(
348351
root = CustomDocTag(
349352
children = listOf(
@@ -776,6 +779,7 @@ class LinkTest : BaseAbstractTest() {
776779
}
777780
}
778781
}
782+
779783
@Test
780784
fun `link should be stable for overloads in different files`() {
781785
testInline(
@@ -851,7 +855,17 @@ class LinkTest : BaseAbstractTest() {
851855
configuration
852856
) {
853857
documentablesMergingStage = { module ->
854-
assertEquals(DRI("example", null, callable = Callable("bar", receiver = TypeConstructor("example.Bar", params = emptyList()), params = emptyList())), module.getLinkDRIFrom("usage"))
858+
assertEquals(
859+
DRI(
860+
"example",
861+
null,
862+
callable = Callable(
863+
"bar",
864+
receiver = TypeConstructor("example.Bar", params = emptyList()),
865+
params = emptyList()
866+
)
867+
), module.getLinkDRIFrom("usage")
868+
)
855869
}
856870
}
857871
}
@@ -888,7 +902,15 @@ class LinkTest : BaseAbstractTest() {
888902
null,
889903
callable = Callable(
890904
"foo",
891-
receiver = TypeConstructor("kotlin.collections.List", params = listOf(TypeParam(listOf(TypeConstructor("kotlin.Number", emptyList()))))),
905+
receiver = TypeConstructor(
906+
"kotlin.collections.List",
907+
params = listOf(
908+
TypeParam(
909+
name = "T",
910+
bounds = listOf(TypeConstructor("kotlin.Number", emptyList()))
911+
)
912+
)
913+
),
892914
params = emptyList()
893915
)
894916
)
@@ -946,7 +968,15 @@ class LinkTest : BaseAbstractTest() {
946968
null,
947969
callable = Callable(
948970
"foo",
949-
receiver = TypeConstructor("kotlin.collections.List", params = listOf(TypeParam(listOf(TypeConstructor("kotlin.Number", emptyList()))))),
971+
receiver = TypeConstructor(
972+
"kotlin.collections.List",
973+
params = listOf(
974+
TypeParam(
975+
name = "T",
976+
bounds = listOf(TypeConstructor("kotlin.Number", emptyList()))
977+
)
978+
)
979+
),
950980
params = emptyList()
951981
)
952982
)
@@ -996,7 +1026,10 @@ class LinkTest : BaseAbstractTest() {
9961026
assertEquals("kotlin.collections", dri.packageName)
9971027
assertEquals(null, dri.classNames)
9981028
assertEquals(functionName, dri.callable?.name)
999-
assertEquals("kotlin.collections.Iterable", (dri.callable?.receiver as? TypeConstructor)?.fullyQualifiedName)
1029+
assertEquals(
1030+
"kotlin.collections.Iterable",
1031+
(dri.callable?.receiver as? TypeConstructor)?.fullyQualifiedName
1032+
)
10001033
assertEquals(PointingToDeclaration, dri.target)
10011034
assertEquals(null, dri.extra)
10021035
}
@@ -1116,7 +1149,10 @@ class LinkTest : BaseAbstractTest() {
11161149
configuration
11171150
) {
11181151
documentablesMergingStage = { module ->
1119-
assertEquals(DRI("example", "Storage", Callable("value", null, emptyList())), module.getLinkDRIFrom("usage"))
1152+
assertEquals(
1153+
DRI("example", "Storage", Callable("value", null, emptyList())),
1154+
module.getLinkDRIFrom("usage")
1155+
)
11201156
}
11211157
}
11221158
}
@@ -1147,10 +1183,15 @@ class LinkTest : BaseAbstractTest() {
11471183
documentablesMergingStage = { module ->
11481184
assertEquals(
11491185
listOf(
1150-
"Storage.setValue" to DRI("example", "Storage", Callable("setValue", null, listOf(TypeConstructor("kotlin.String", emptyList())))),
1186+
"Storage.setValue" to DRI(
1187+
"example",
1188+
"Storage",
1189+
Callable("setValue", null, listOf(TypeConstructor("kotlin.String", emptyList())))
1190+
),
11511191
"Storage.prop" to DRI("example", "Storage", Callable("getProp", null, emptyList()))
11521192
),
1153-
module.getAllLinkDRIFrom("usage"))
1193+
module.getAllLinkDRIFrom("usage")
1194+
)
11541195
}
11551196
}
11561197
}

0 commit comments

Comments
 (0)