From 10cbc925c9d9930286e9cf72922bee4f44942424 Mon Sep 17 00:00:00 2001 From: Seggan Date: Thu, 25 Sep 2025 17:02:12 -0400 Subject: [PATCH 1/2] Fix docs not inherited to accessors --- .../converters/KotlinToJavaConverter.kt | 18 +++++-- .../kotlin/kotlinAsJavaPlugin/PropertyTest.kt | 51 +++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt diff --git a/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt b/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt index b565164511..58b32fe323 100644 --- a/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt +++ b/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt @@ -32,6 +32,16 @@ internal val DProperty.isJvmField: Boolean internal val DFunction.isJvmStatic: Boolean get() = jvmStatic() != null +internal val DProperty.documentedGetter: DFunction? + get() = getter?.let { getter -> + getter.copy(documentation = getter.documentation.takeIf { it.isNotEmpty() } ?: this.documentation) + } + +internal val DProperty.documentedSetter: DFunction? + get() = setter?.let { setter -> + setter.copy(documentation = setter.documentation.takeIf { it.isNotEmpty() } ?: this.documentation) + } + private fun DProperty.hasModifier(modifier: ExtraModifiers.KotlinOnlyModifiers): Boolean = extra[AdditionalModifiers] ?.content @@ -306,7 +316,7 @@ public class KotlinToJavaConverter( internal fun DClass.functionsInJava(): List = properties .filter { !it.isJvmField && !it.hasJvmSynthetic() } - .flatMap { property -> listOfNotNull(property.getter, property.setter) } + .flatMap { property -> listOfNotNull(property.documentedGetter, property.documentedSetter) } .plus(functions) .plus(companion.staticFunctionsForJava()) .filterNot { it.hasJvmSynthetic() } @@ -370,7 +380,7 @@ public class KotlinToJavaConverter( .plus( properties .filter { !it.isJvmField && !it.hasJvmSynthetic() } - .flatMap { listOf(it.getter, it.setter) } + .flatMap { listOf(it.documentedGetter, it.documentedSetter) } ) .filterNotNull() .filterNot { it.hasJvmSynthetic() } @@ -396,7 +406,7 @@ public class KotlinToJavaConverter( properties .filterNot { it in excludedProps } .filter { !it.isJvmField && !it.isConst && !it.isLateInit && !it.hasJvmSynthetic() } - .flatMap { listOf(it.getter, it.setter) } + .flatMap { listOf(it.documentedGetter, it.documentedSetter) } ) .filterNotNull() .filterNot { it in excludedFunctions } @@ -436,7 +446,7 @@ public class KotlinToJavaConverter( .plus( properties .filter { it.jvmField() == null && !it.hasJvmSynthetic() } - .flatMap { listOf(it.getter, it.setter) } + .flatMap { listOf(it.documentedGetter, it.documentedSetter) } ) .filterNotNull() .filterNot { it.hasJvmSynthetic() } diff --git a/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt b/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt new file mode 100644 index 0000000000..9bd33c824a --- /dev/null +++ b/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinAsJavaPlugin + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.doc.DocTag +import org.jetbrains.dokka.model.doc.Text +import kotlin.test.* + +class PropertyTest : BaseAbstractTest() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + classpath += jvmStdlibPath!! + } + } + } + + @Test + fun `property accessors should inherit doc`(){ + testInline( + """ + |/src/main/kotlin/kotlinAsJavaPlugin/sample.kt + |package kotlinAsJavaPlugin + |class MyClass { + | /** + | * Some doc + | */ + | var property: String = TODO() + |} + """.trimMargin(), + configuration, + ) { + documentablesTransformationStage = { module -> + val classLike = module.packages.flatMap { it.classlikes }.first() + val getter = classLike.functions.firstOrNull { it.name == "getProperty" } + val setter = classLike.functions.firstOrNull { it.name == "setProperty" } + assertNotNull(getter) + assertNotNull(setter) + + assertEquals("Some doc", getter.documentation.values.first().children.first().root.text) + } + } + } +} + +private val DocTag.text: String + get() = if (this is Text) body else children.joinToString("") { it.text } From 55e10c0d3bb53677a655b46868099866b9217db8 Mon Sep 17 00:00:00 2001 From: Seggan Date: Fri, 26 Sep 2025 11:18:31 -0400 Subject: [PATCH 2/2] Fix it in the case of top level `@property` --- .../converters/KotlinToJavaConverter.kt | 32 +++++++++++++---- .../kotlin/kotlinAsJavaPlugin/PropertyTest.kt | 35 ++++++++++++++++++- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt b/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt index 58b32fe323..b0241dc1dd 100644 --- a/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt +++ b/dokka-subprojects/plugin-kotlin-as-java/src/main/kotlin/org/jetbrains/dokka/kotlinAsJava/converters/KotlinToJavaConverter.kt @@ -16,6 +16,9 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin +import org.jetbrains.dokka.model.doc.Description +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Property public val jvmNameProvider: JvmNameProvider = JvmNameProvider() internal const val OBJECT_INSTANCE_NAME = "INSTANCE" @@ -32,15 +35,32 @@ internal val DProperty.isJvmField: Boolean internal val DFunction.isJvmStatic: Boolean get() = jvmStatic() != null -internal val DProperty.documentedGetter: DFunction? - get() = getter?.let { getter -> - getter.copy(documentation = getter.documentation.takeIf { it.isNotEmpty() } ?: this.documentation) +/** + * Converts any `@property` tags into descriptions for the Java accessors + */ +private fun transformAccessorDocs(docs: SourceSetDependent): SourceSetDependent { + return docs.mapValues { (_, node) -> + node.copy( + children = node.children.map { tag -> + if (tag is Property) { + Description(tag.root) + } else { + tag + } + } + ) } +} + +internal val DProperty.documentedGetter: DFunction? + get() = getter?.copy( + documentation = transformAccessorDocs(getter?.documentation?.takeIf { it.isNotEmpty() } ?: documentation) + ) internal val DProperty.documentedSetter: DFunction? - get() = setter?.let { setter -> - setter.copy(documentation = setter.documentation.takeIf { it.isNotEmpty() } ?: this.documentation) - } + get() = setter?.copy( + documentation = transformAccessorDocs(setter?.documentation?.takeIf { it.isNotEmpty() } ?: documentation) + ) private fun DProperty.hasModifier(modifier: ExtraModifiers.KotlinOnlyModifiers): Boolean = extra[AdditionalModifiers] diff --git a/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt b/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt index 9bd33c824a..50198c0004 100644 --- a/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt +++ b/dokka-subprojects/plugin-kotlin-as-java/src/test/kotlin/kotlinAsJavaPlugin/PropertyTest.kt @@ -5,6 +5,7 @@ package kotlinAsJavaPlugin import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.model.doc.DocTag import org.jetbrains.dokka.model.doc.Text import kotlin.test.* @@ -41,11 +42,43 @@ class PropertyTest : BaseAbstractTest() { assertNotNull(getter) assertNotNull(setter) - assertEquals("Some doc", getter.documentation.values.first().children.first().root.text) + assertEquals("Some doc", getter.docText) + assertEquals("Some doc", setter.docText) + } + } + + testInline( + """ + |/src/main/kotlin/kotlinAsJavaPlugin/sample.kt + |package kotlinAsJavaPlugin + |/** + |* @property property Some doc + |*/ + |class MyClass { + | var property: String = TODO() + |} + """.trimMargin(), + configuration, + ) { + documentablesTransformationStage = { module -> + val classLike = module.packages.flatMap { it.classlikes }.first() + val getter = classLike.functions.firstOrNull { it.name == "getProperty" } + val setter = classLike.functions.firstOrNull { it.name == "setProperty" } + assertNotNull(getter) + assertNotNull(setter) + + assertEquals("Some doc", getter.docText) + assertEquals("Some doc", setter.docText) } } } } +private val Documentable.docText: String + get() = this.documentation.values + .flatMap { it.children } + .map { it.root } + .joinToString("") { it.text } + private val DocTag.text: String get() = if (this is Text) body else children.joinToString("") { it.text }