From cc96426756e6cf5d606b04f6dfc3831a74558983 Mon Sep 17 00:00:00 2001 From: Vadim Mishenev Date: Mon, 15 Apr 2024 16:19:00 +0300 Subject: [PATCH] [K2] Fix DRI for override symbols (#3560) Due to KT-63741 https://github.com/JetBrains/kotlin/commit/7056ad5325324bb8162db4cef2b5bcf02b3c5483 --- .../test/documentable/ObviousFunctionsTest.kt | 6 +-- .../DefaultSymbolToDocumentableTranslator.kt | 37 +++++++++---- .../src/test/kotlin/enums/KotlinEnumsTest.kt | 1 - .../src/test/kotlin/model/InheritorsTest.kt | 54 +++++++++++++++++++ ...nheritedFunctionsDocumentableFilterTest.kt | 3 +- 5 files changed, 84 insertions(+), 17 deletions(-) diff --git a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ObviousFunctionsTest.kt b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ObviousFunctionsTest.kt index c064da83ee..b3ae63c7fd 100644 --- a/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ObviousFunctionsTest.kt +++ b/dokka-subprojects/analysis-kotlin-api/src/test/kotlin/org/jetbrains/dokka/analysis/test/documentable/ObviousFunctionsTest.kt @@ -71,8 +71,8 @@ class ObviousFunctionsTest { } } - // when running with K2 - inherited from java enum functions available: "clone", "finalize", "getDeclaringClass" - @OnlyDescriptors("#3196") + // when running with K2 - kotlin package is skipped + @OnlyDescriptors("#3354") @Test fun `kotlin_Enum should not have obvious members`() { val project = kotlinJvmTestProject { @@ -103,8 +103,6 @@ class ObviousFunctionsTest { ) } - // when running with K2 there is no equals, hashCode, toString present - @OnlyDescriptors("#3196") @Test fun `kotlin_Enum should not have obvious members via external documentable provider`() { val project = kotlinJvmTestProject { diff --git a/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt b/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt index 1363d3a2bf..a85c0e031f 100644 --- a/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt +++ b/dokka-subprojects/analysis-kotlin-symbols/src/main/kotlin/org/jetbrains/dokka/analysis/kotlin/symbols/translators/DefaultSymbolToDocumentableTranslator.kt @@ -834,18 +834,33 @@ internal class DokkaSymbolVisitor( callableSymbol: KtCallableSymbol, wasOverriddenBy: DRI? = null ): DRIWithOverridden { - if (callableSymbol is KtPropertySymbol && callableSymbol.isOverride - || callableSymbol is KtFunctionSymbol && callableSymbol.isOverride - ) { + /** + * `open class A { fun x() = 0 }` is given + * + * There are two cases: + * 1. The callable `B.x` [DRI] should lead to itself - `B.x`. + * Dokka will create a separate page for the declaration. + * This case should be actual for cases when a callable is explicitly declared in a class. + * E.g. for override - `class B : A() { override fun x() = 1 }` + * 2. The `B.x` [DRI] should be lead to the parent `A.x` + * For the case `class B : A() {}` the compiler returns the `A.x` symbol itself. + * But in some cases, it creates and returns the `B.x` symbol: + * - fake overrides + * K2 distinguishes two kinds of fake overrides: [KtSymbolOrigin.INTERSECTION_OVERRIDE] and [KtSymbolOrigin.SUBSTITUTION_OVERRIDE] + * - synthetic members, e.g. `hashCode`/`equals` for data classes + * - delegating members + */ + val isDeclaration = callableSymbol.origin == KtSymbolOrigin.SOURCE || callableSymbol.origin == KtSymbolOrigin.LIBRARY + if (isDeclaration) { return DRIWithOverridden(getDRIFromSymbol(callableSymbol), wasOverriddenBy) - } - val overriddenSymbols = callableSymbol.getAllOverriddenSymbols() - // For already - return if (overriddenSymbols.isEmpty()) { - DRIWithOverridden(getDRIFromSymbol(callableSymbol), wasOverriddenBy) - } else { - createDRIWithOverridden(overriddenSymbols.first()) + } else { // fake, synthetic, delegating + val overriddenSymbols = callableSymbol.getAllOverriddenSymbols() + return if (overriddenSymbols.isEmpty()) { + DRIWithOverridden(getDRIFromSymbol(callableSymbol), wasOverriddenBy) + } else { + createDRIWithOverridden(overriddenSymbols.first()) + } } } @@ -858,7 +873,7 @@ internal class DokkaSymbolVisitor( private fun KtAnalysisSession.isObvious(functionSymbol: KtFunctionSymbol, inheritedFrom: DRI?): Boolean { return functionSymbol.origin == KtSymbolOrigin.SOURCE_MEMBER_GENERATED && !hasGeneratedKDocDocumentation(functionSymbol) || - !functionSymbol.isOverride && inheritedFrom?.isObvious() == true + inheritedFrom?.isObvious() == true } private fun DRI.isObvious(): Boolean = when (packageName) { diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/enums/KotlinEnumsTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/enums/KotlinEnumsTest.kt index 4b6de9c419..27899ff3aa 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/enums/KotlinEnumsTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/enums/KotlinEnumsTest.kt @@ -328,7 +328,6 @@ class KotlinEnumsTest : BaseAbstractTest() { } @Test - @OnlyDescriptors("K2 has `compareTo`, that should be suppressed, due to #3196") fun `enum should have functions on page`() { val configuration = dokkaConfiguration { sourceSets { diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/model/InheritorsTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/model/InheritorsTest.kt index 17d02bbb80..cc3e82296a 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/model/InheritorsTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/model/InheritorsTest.kt @@ -512,4 +512,58 @@ class InheritorsTest : AbstractModelTest("/src/main/kotlin/inheritors/Test.kt", } } + @Test + fun `DRI of generic inherited members (fake override) should lead to super member`() { + inlineModelTest( + """ + |interface A { fun x(): T } + |interface B : A { } + """ + ) { + with((this / "inheritors" / "A" / "x").cast()) { + dri.classNames equals "A" + dri.packageName equals "inheritors" + } + with((this / "inheritors" / "B" / "x").cast()) { + dri.classNames equals "A" + dri.packageName equals "inheritors" + } + } + } + @Test + fun `DRI of inherited members should lead to super member`() { + inlineModelTest( + """ + |interface A { fun x() = 0 } + |interface B : A { } + """ + ) { + with((this / "inheritors" / "A" / "x").cast()) { + dri.classNames equals "A" + dri.packageName equals "inheritors" + } + with((this / "inheritors" / "B" / "x").cast()) { + dri.classNames equals "A" + dri.packageName equals "inheritors" + } + } + } + @Test + fun `DRI of generic override members should lead to themself`() { + inlineModelTest( + """ + |open class A { open fun x(p: T):T { return p } } + |class B : A() { override fun x(p: Int): Int = 0 } + """ + ) { + with((this / "inheritors" / "A" / "x").cast()) { + dri.classNames equals "A" + dri.packageName equals "inheritors" + } + with((this / "inheritors" / "B" / "x").cast()) { + dri.classNames equals "B" + dri.packageName equals "inheritors" + } + } + } } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/transformers/ObviousAndInheritedFunctionsDocumentableFilterTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/transformers/ObviousAndInheritedFunctionsDocumentableFilterTest.kt index bdd63176ac..bf39a16e89 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/transformers/ObviousAndInheritedFunctionsDocumentableFilterTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/transformers/ObviousAndInheritedFunctionsDocumentableFilterTest.kt @@ -275,7 +275,8 @@ class ObviousAndInheritedFunctionsDocumentableFilterTest : BaseAbstractTest() { } } - @OnlyDescriptors("#3196") + // when running with K2 - kotlin package is skipped + @OnlyDescriptors("#3354") @ParameterizedTest @MethodSource(value = ["suppressingObviousConfiguration"]) fun `should not suppress toString, equals and hashcode of kotlin Enum`(suppressingConfiguration: DokkaConfigurationImpl) {