From 7a83e4665cceeec448212ea97194caeadb7e4a9f Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Wed, 12 Jan 2022 13:21:54 +0100 Subject: [PATCH] Fix resolving DRIs of Enum Entries --- .../dokka/analysis/CallableFactory.kt | 14 ++++ .../jetbrains/dokka/analysis/DRIFactory.kt | 18 +++-- .../translators/psi/parsers/JavadocParser.kt | 2 +- .../test/kotlin/linking/EnumValuesLinking.kt | 70 +++++++++++++++++++ .../kotlin/linking/source/JavaEnum.java | 5 ++ .../kotlin/linking/source/JavaLinker.java | 8 +++ .../kotlin/linking/source/KotlinEnum.kt | 5 ++ .../kotlin/linking/source/KotlinLinker.kt | 8 +++ 8 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 plugins/base/src/test/kotlin/linking/EnumValuesLinking.kt create mode 100644 plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaEnum.java create mode 100644 plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaLinker.java create mode 100644 plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinEnum.kt create mode 100644 plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinLinker.kt diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt index de48cfae16..c71034e910 100644 --- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/CallableFactory.kt @@ -6,6 +6,8 @@ import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.JavaClassReference import org.jetbrains.dokka.links.TypeReference import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor +import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor fun Callable.Companion.from(descriptor: CallableDescriptor, name: String? = null) = with(descriptor) { Callable( @@ -15,6 +17,18 @@ fun Callable.Companion.from(descriptor: CallableDescriptor, name: String? = null ) } +fun Callable.Companion.from(descriptor: LazyClassDescriptor) = Callable( + descriptor.name.asString(), + null, + emptyList() +) + +fun Callable.Companion.from(descriptor: EnumEntrySyntheticClassDescriptor) = Callable( + descriptor.name.asString(), + null, + emptyList() +) + fun Callable.Companion.from(psi: PsiMethod) = with(psi) { Callable( name, diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt index 5f74c42991..2a358531a8 100644 --- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt @@ -6,19 +6,29 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf +import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWithSelf.run { val parameter = firstIsInstanceOrNull() val callable = parameter?.containingDeclaration ?: firstIsInstanceOrNull() - DRI( packageName = firstIsInstanceOrNull()?.fqName?.asString() ?: "", - classNames = (filterIsInstance() + filterIsInstance()).toList() + classNames = (filterIsInstance().map { + if (it.kind == ClassKind.ENUM_ENTRY) + it.name.asString().split(".").dropLast(1).joinToString(".") + else + it.name.asString() + } + filterIsInstance().map { it.name.asString() } + ).toList() + .filter { it.isNotBlank() } .takeIf { it.isNotEmpty() } ?.asReversed() - ?.joinToString(separator = ".") { it.name.asString() }, - callable = callable?.let { Callable.from(it) }, + ?.joinToString(separator = "."), + callable = callable?.let { Callable.from(it) } + ?: descriptor.safeAs().takeIf { it?.kind == ClassKind.ENUM_ENTRY }?.let { Callable.from(it) } + ?: descriptor.safeAs()?.let { Callable.from(it) }, target = DriTarget.from(parameter ?: descriptor), extra = if (descriptor is EnumEntrySyntheticClassDescriptor) DRIExtraContainer().also { it[EnumEntryDRIExtra] = EnumEntryDRIExtra }.encode() diff --git a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt index f9f591b2de..a501ae55ca 100644 --- a/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt +++ b/plugins/base/src/main/kotlin/translators/psi/parsers/JavadocParser.kt @@ -326,7 +326,7 @@ class JavadocParser( dri.toString() } ?: UNRESOLVED_PSI_ELEMENT - return """${label.ifBlank{ defaultLabel().text }}""" + return """${label.ifBlank{ defaultLabel().text }}""" } private fun convertInlineDocTag( diff --git a/plugins/base/src/test/kotlin/linking/EnumValuesLinking.kt b/plugins/base/src/test/kotlin/linking/EnumValuesLinking.kt new file mode 100644 index 0000000000..f690dfbdae --- /dev/null +++ b/plugins/base/src/test/kotlin/linking/EnumValuesLinking.kt @@ -0,0 +1,70 @@ +package linking + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.doc.DocumentationLink +import org.junit.jupiter.api.Test +import java.nio.file.Paths +import org.junit.jupiter.api.Assertions.assertEquals +import java.lang.AssertionError + +class EnumValuesLinking : BaseAbstractTest() { + + @Test + fun `check if enum values are correctly linked`() { + val testDataDir = getTestDataDir("linking").toAbsolutePath() + testFromData( + dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf(Paths.get("$testDataDir/jvmMain/kotlin").toString()) + analysisPlatform = "jvm" + name = "jvm" + } + } + } + ) { + documentablesTransformationStage = { + val classlikes = it.packages.single().children + assertEquals(4, classlikes.size) + + val javaLinker = classlikes.single { it.name == "JavaLinker" } + javaLinker.documentation.values.single().children.run { + when (val kotlinLink = this[0].children[1].children[1]) { + is DocumentationLink -> kotlinLink.dri.run { + assertEquals("KotlinEnum", this.classNames) + assertEquals("ON_CREATE", this.callable?.name) + } + else -> throw AssertionError("Link node is not DocumentationLink type") + } + + when (val javaLink = this[0].children[2].children[1]) { + is DocumentationLink -> javaLink.dri.run { + assertEquals("JavaEnum", this.classNames) + assertEquals("ON_DECEIT", this.callable?.name) + } + else -> throw AssertionError("Link node is not DocumentationLink type") + } + } + + val kotlinLinker = classlikes.single { it.name == "KotlinLinker" } + kotlinLinker.documentation.values.single().children.run { + when (val kotlinLink = this[0].children[0].children[5]) { + is DocumentationLink -> kotlinLink.dri.run { + assertEquals("KotlinEnum", this.classNames) + assertEquals("ON_CREATE", this.callable?.name) + } + else -> throw AssertionError("Link node is not DocumentationLink type") + } + + when (val javaLink = this[0].children[0].children[9]) { + is DocumentationLink -> javaLink.dri.run { + assertEquals("JavaEnum", this.classNames) + assertEquals("ON_DECEIT", this.callable?.name) + } + else -> throw AssertionError("Link node is not DocumentationLink type") + } + } + } + } + } +} diff --git a/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaEnum.java b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaEnum.java new file mode 100644 index 0000000000..016365a723 --- /dev/null +++ b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaEnum.java @@ -0,0 +1,5 @@ +package linking.source; + +public enum JavaEnum { + ON_DECEIT, ON_DESTROY; +} diff --git a/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaLinker.java b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaLinker.java new file mode 100644 index 0000000000..ac416530be --- /dev/null +++ b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/JavaLinker.java @@ -0,0 +1,8 @@ +package linking.source; + +/** + * Reference link {@link linking.source.KotlinEnum} should resolve

+ * sjuff sjuff {@link linking.source.KotlinEnum#ON_CREATE} should resolve

+ * sjujj sjujj {@link linking.source.JavaEnum#ON_DECEIT} should resolve + */ +public class JavaLinker {} diff --git a/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinEnum.kt b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinEnum.kt new file mode 100644 index 0000000000..a03316b125 --- /dev/null +++ b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinEnum.kt @@ -0,0 +1,5 @@ +package linking.source + +enum class KotlinEnum { + ON_CREATE, ON_CATASTROPHE +} diff --git a/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinLinker.kt b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinLinker.kt new file mode 100644 index 0000000000..45afc3d5b1 --- /dev/null +++ b/plugins/base/src/test/resources/linking/jvmMain/kotlin/linking/source/KotlinLinker.kt @@ -0,0 +1,8 @@ +package linking.source + +/** + * Reference link [KotlinEnum] should resolve

+ * stuff stuff [KotlinEnum.ON_CREATE] should resolve

+ * stuff stuff [JavaEnum.ON_DECEIT] should resolve + */ +class KotlinLinker {}