Repository: Kotlin/dokka (kotlin)

Issue:
[K2] Filter out JVM mapped properties
 Related to https://github.com/Kotlin/dokka/issues/3542
 ```kt
 class Child: kotlin.RuntimeException()
 ```
 **K2:** 
![image](https://github.com/user-attachments/assets/40ef90a5-e435-44d5-ac62-bb64db4fe9d9)
**K1:** 
![image](https://github.com/user-attachments/assets/d28650fd-27d7-4949-b021-5baf038a46e5)

Pull request:
fixes #3939

Patch:
diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/documentables/JvmMappedMethodsDocumentableFilterTransformer.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/documentables/JvmMappedMethodsDocumentableFilterTransformer.kt
index 5f5f7a292f..3d66723e53 100644
--- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/documentables/JvmMappedMethodsDocumentableFilterTransformer.kt
+++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/documentables/JvmMappedMethodsDocumentableFilterTransformer.kt
@@ -8,12 +8,13 @@ import org.jetbrains.dokka.Platform
 import org.jetbrains.dokka.links.DRI
 import org.jetbrains.dokka.model.Annotations
 import org.jetbrains.dokka.model.DFunction
+import org.jetbrains.dokka.model.DProperty
 import org.jetbrains.dokka.model.Documentable
 import org.jetbrains.dokka.model.StringValue
 import org.jetbrains.dokka.plugability.DokkaContext
 
 /**
- *  Filter out methods  that come from [mapping to Java](https://kotlinlang.org/docs/java-interop.html#mapped-types)
+ *  Filter out methods and synthetic properties that come from [mapping to Java](https://kotlinlang.org/docs/java-interop.html#mapped-types)
  *  since they have no available doc
  *
  *  Currently, a list of such methods is supported manually based on the compiler source
@@ -23,7 +24,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
  * - HIDDEN
  * - VISIBLE
  * - DROP
- * - NOT_CONSIDERED in K1 / HIDDEN_IN_DECLARING_CLASS_ONLY in K2. See [DFunction.hasDeprecated]
+ * - NOT_CONSIDERED in K1 / HIDDEN_IN_DECLARING_CLASS_ONLY (KT-65438 WEAKLY_HIDDEN) in K2. See [DFunction.hasDeprecated]
  * We want co cover the HIDDEN, VISIBLE, HIDDEN_IN_DECLARING_CLASS_ONLY statuses here.
  *
  *  TODO https://youtrack.jetbrains.com/issue/KT-69796/Analysis-API-Provide-a-way-to-detect-mapped-methods-from-JVM
@@ -246,7 +247,7 @@ internal class JvmMappedMethodsDocumentableFilterTransformer(context: DokkaConte
     /**
      * KT-65438: In K1, such methods (e.g. translateEscapes, formatted... in java.lang.String) have the NOT_CONSIDERED status,
      * that means they are available and have a deprecation annotation.
-     * In K2, they are unavailable for final classes + [NOT_CONSIDER_METHOD_SIGNATURES]
+     * In K2, they are unavailable for final classes (KT-65438) + [NOT_CONSIDER_METHOD_SIGNATURES]
      * @see NOT_CONSIDER_METHOD_SIGNATURES
      */
     private fun DFunction.hasDeprecated(): Boolean = this.extra[Annotations]?.directAnnotations?.any {
@@ -256,15 +257,22 @@ internal class JvmMappedMethodsDocumentableFilterTransformer(context: DokkaConte
     } ?: false
 
     // user case: stdlib
-    private fun DFunction.isOnlyInJVM() = sourceSets.all { it.analysisPlatform == Platform.jvm }
+    private fun Documentable.isOnlyInJVM() = sourceSets.all { it.analysisPlatform == Platform.jvm }
+
+    private fun DFunction.shouldBeSuppressed() = if (this.hasDeprecated())
+        true
+    else {
+        val fqn = this.dri.let { it.packageName + "." + it.classNames + "." + it.callable?.name }
+        fqn in VISIBLE_METHOD_SIGNATURES || fqn in MUTABLE_METHOD_SIGNATURES || fqn in DEPRECATED_LIST_METHODS || fqn in HIDDEN_METHOD_SIGNATURES || fqn in NOT_CONSIDER_METHOD_SIGNATURES
+    }
 
     override fun shouldBeSuppressed(d: Documentable): Boolean =
-        if (d is DFunction && d.isOnlyInJVM()) {
-            if (d.hasDeprecated())
-                true
-            else {
-                val fqn = d.dri.let { it.packageName + "." + it.classNames + "." + it.callable?.name }
-                fqn in VISIBLE_METHOD_SIGNATURES || fqn in MUTABLE_METHOD_SIGNATURES || fqn in DEPRECATED_LIST_METHODS || fqn in HIDDEN_METHOD_SIGNATURES || fqn in NOT_CONSIDER_METHOD_SIGNATURES
+        if (d.isOnlyInJVM()) {
+            when (d) {
+                is DFunction -> d.shouldBeSuppressed()
+                // Note that, if the Java class only has a setter, it isn't visible as a property in Kotlin because Kotlin doesn't support set-only properties
+                is DProperty -> d.getter?.shouldBeSuppressed() ?: false
+                else -> false
             }
         } else false
 }
\ No newline at end of file


Test patch:
diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/transformers/JvmMappedMethodsFilterTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/transformers/JvmMappedMethodsFilterTest.kt
index 543bd57ab6..b455e4e48d 100644
--- a/dokka-subprojects/plugin-base/src/test/kotlin/transformers/JvmMappedMethodsFilterTest.kt
+++ b/dokka-subprojects/plugin-base/src/test/kotlin/transformers/JvmMappedMethodsFilterTest.kt
@@ -17,6 +17,7 @@ class JvmMappedMethodsFilterTest : BaseAbstractTest() {
             sourceSet {
                 sourceRoots = listOf("src")
                 analysisPlatform = "jvm"
+                classpath = listOfNotNull(jvmStdlibPath)
             }
         }
     }
@@ -26,6 +27,28 @@ class JvmMappedMethodsFilterTest : BaseAbstractTest() {
         return cl.functions.map { it.name }.toSet()
     }
 
+    fun List<DModule>.getPropertyNamesFrom(classname: String): Set<String> {
+        val cl = this.mapNotNull { it.dfs { it.name == classname && it is DClasslike } }.first() as DClasslike
+        return cl.properties.map { it.name }.toSet()
+    }
+
+    @Test
+    fun `should filter out JVM synthetic properties in RuntimeException`() {
+        testInline(
+            """
+            |/src/MyRuntimeException.kt
+            |class MyRuntimeException: RuntimeException()
+            """.trimIndent(), configuration
+        ) {
+            preMergeDocumentablesTransformationStage = { modules ->
+                assertEquals(
+                    setOf("cause", "message"),
+                    modules.getPropertyNamesFrom("MyRuntimeException")
+                )
+            }
+        }
+    }
+
     @Test
     fun `should filter out JVM mapped methods in CharSequence`() {
         testInline(