From 623b0e729c805e2ec019b1f56f67c5a2cf7eb327 Mon Sep 17 00:00:00 2001 From: Ignat Beresnev Date: Thu, 30 Jun 2022 16:01:31 +0200 Subject: Add enum synthetic functions to documentable model (#2553) --- .../DefaultDescriptorToDocumentableTranslator.kt | 33 +- plugins/base/src/test/kotlin/enums/EnumsTest.kt | 369 ------------------- .../base/src/test/kotlin/enums/KotlinEnumTest.kt | 408 +++++++++++++++++++++ 3 files changed, 432 insertions(+), 378 deletions(-) delete mode 100644 plugins/base/src/test/kotlin/enums/EnumsTest.kt create mode 100644 plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt (limited to 'plugins/base') diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index c4a8253a..43b8c544 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -59,6 +59,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.resolve.descriptorUtil.parents import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinEnum import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.resolve.source.PsiSourceFile @@ -261,13 +262,12 @@ private class DokkaDescriptorVisitor( private suspend fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnum { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() - val scope = descriptor.unsubstitutedMemberScope val isExpect = descriptor.isExpect val isActual = descriptor.isActual val info = descriptor.resolveClassDescriptionData() return coroutineScope { - val descriptorsWithKind = scope.getDescriptorsWithKind() + val descriptorsWithKind = descriptor.getEnumDescriptorsWithKind() val functions = async { descriptorsWithKind.functions.visitFunctions(driWithPlatform) } val properties = async { descriptorsWithKind.properties.visitProperties(driWithPlatform) } @@ -301,6 +301,16 @@ private class DokkaDescriptorVisitor( } } + private fun ClassDescriptor.getEnumDescriptorsWithKind(): DescriptorsWithKind { + val descriptorsWithKind = this.unsubstitutedMemberScope.getDescriptorsWithKind() + val staticScopeForKotlinEnum = (this.staticScope as? StaticScopeForKotlinEnum) ?: return descriptorsWithKind + + // synthetic values() and valueOf() functions are not present among average class functions + val enumSyntheticFunctions = staticScopeForKotlinEnum.getContributedDescriptors { true } + + return descriptorsWithKind.copy(functions = descriptorsWithKind.functions + enumSyntheticFunctions) + } + private suspend fun visitEnumEntryDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): DEnumEntry { val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() val scope = descriptor.unsubstitutedMemberScope @@ -578,7 +588,7 @@ private class DokkaDescriptorVisitor( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), (descriptor.getAnnotations() + descriptor.fileLevelAnnotations()).toSourceSetDependent() .toAnnotations(), - ObviousMember.takeIf { descriptor.isObvious }, + ObviousMember.takeIf { descriptor.isObvious() }, ) ) } @@ -597,6 +607,17 @@ private class DokkaDescriptorVisitor( .takeIf { parent.dri.classNames != this.classNames || parent.dri.packageName != this.packageName } } + private fun FunctionDescriptor.isObvious(): Boolean { + return kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE + || kind == CallableMemberDescriptor.Kind.SYNTHESIZED + || containingDeclaration.fqNameOrNull()?.isObvious() == true + } + + private fun FqName.isObvious(): Boolean = with(this.asString()) { + return this == "kotlin.Any" || this == "kotlin.Enum" + || this == "java.lang.Object" || this == "java.lang.Enum" + } + suspend fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): DFunction { val name = descriptor.constructedClass.name.toString() val dri = parent.dri.copy(callable = Callable.from(descriptor, name)) @@ -1204,12 +1225,6 @@ private class DokkaDescriptorVisitor( ?.parallelMap { it.toAnnotation(scope = Annotations.AnnotationScope.FILE) } .orEmpty() - private val FunctionDescriptor.isObvious: Boolean - get() = kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE || - kind == CallableMemberDescriptor.Kind.SYNTHESIZED || - containingDeclaration.fqNameOrNull()?.asString() - ?.let { it == "kotlin.Any" || it == "kotlin.Enum" || it == "java.lang.Enum" || it == "java.lang.Object" } == true - private fun AncestryNode.exceptionInSupertypesOrNull(): ExceptionInSupertypes? = typeConstructorsBeingExceptions().takeIf { it.isNotEmpty() }?.let { ExceptionInSupertypes(it.toSourceSetDependent()) } } diff --git a/plugins/base/src/test/kotlin/enums/EnumsTest.kt b/plugins/base/src/test/kotlin/enums/EnumsTest.kt deleted file mode 100644 index 8cb9f654..00000000 --- a/plugins/base/src/test/kotlin/enums/EnumsTest.kt +++ /dev/null @@ -1,369 +0,0 @@ -package enums - -import matchers.content.* -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest -import org.jetbrains.dokka.model.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance -import org.jsoup.Jsoup -import org.jsoup.nodes.Element -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.Test -import signatures.renderedContent -import utils.TestOutputWriter -import utils.TestOutputWriterPlugin - -class EnumsTest : BaseAbstractTest() { - - @Test - fun `should preserve enum source ordering for documentables`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - documentablesTransformationStage = { module -> - val testPackage = module.packages[0] - assertEquals("testpackage", testPackage.name) - - val testEnum = testPackage.classlikes[0] as DEnum - assertEquals("TestEnum", testEnum.name) - - val enumEntries = testEnum.entries - assertEquals(10, enumEntries.count()) - - assertEquals("ZERO", enumEntries[0].name) - assertEquals("ONE", enumEntries[1].name) - assertEquals("TWO", enumEntries[2].name) - assertEquals("THREE", enumEntries[3].name) - assertEquals("FOUR", enumEntries[4].name) - assertEquals("FIVE", enumEntries[5].name) - assertEquals("SIX", enumEntries[6].name) - assertEquals("SEVEN", enumEntries[7].name) - assertEquals("EIGHT", enumEntries[8].name) - assertEquals("NINE", enumEntries[9].name) - } - } - } - - @Test - fun `should preserve enum source ordering for generated pages`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - pagesGenerationStage = { rootPage -> - val packagePage = rootPage.children[0] - assertEquals("testpackage", packagePage.name) - - val testEnumNode = packagePage.children[0] - assertEquals("TestEnum", testEnumNode.name) - - val enumEntries = testEnumNode.children - assertEquals(10, enumEntries.size) - - assertEquals("ZERO", enumEntries[0].name) - assertEquals("ONE", enumEntries[1].name) - assertEquals("TWO", enumEntries[2].name) - assertEquals("THREE", enumEntries[3].name) - assertEquals("FOUR", enumEntries[4].name) - assertEquals("FIVE", enumEntries[5].name) - assertEquals("SIX", enumEntries[6].name) - assertEquals("SEVEN", enumEntries[7].name) - assertEquals("EIGHT", enumEntries[8].name) - assertEquals("NINE", enumEntries[9].name) - } - } - } - - @Test - fun `should preserve enum source ordering for rendered entries`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - renderingStage = { _, _ -> - val enumEntriesOnPage = writerPlugin.writer.renderedContent("root/testpackage/-test-enum/index.html") - .select("div.table[data-togglable=Entries]") - .select("div.table-row") - .select("div.keyValue") - .select("div.title") - .select("a") - - val enumEntries = enumEntriesOnPage.map { it.text() } - assertEquals(10, enumEntries.size) - - assertEquals("ZERO", enumEntries[0]) - assertEquals("ONE", enumEntries[1]) - assertEquals("TWO", enumEntries[2]) - assertEquals("THREE", enumEntries[3]) - assertEquals("FOUR", enumEntries[4]) - assertEquals("FIVE", enumEntries[5]) - assertEquals("SIX", enumEntries[6]) - assertEquals("SEVEN", enumEntries[7]) - assertEquals("EIGHT", enumEntries[8]) - assertEquals("NINE", enumEntries[9]) - } - } - } - - @Test - fun `should preserve enum source ordering for navigation menu`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - val writerPlugin = TestOutputWriterPlugin() - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | ZERO, - | ONE, - | TWO, - | THREE, - | FOUR, - | FIVE, - | SIX, - | SEVEN, - | EIGHT, - | NINE - |} - """.trimMargin(), - configuration, - pluginOverrides = listOf(writerPlugin) - ) { - renderingStage = { _, _ -> - val sideMenu = writerPlugin.writer.navigationHtml().select("div.sideMenuPart") - - assertEquals("ZERO", sideMenu.select("#root-nav-submenu-0-0-0").text()) - assertEquals("ONE", sideMenu.select("#root-nav-submenu-0-0-1").text()) - assertEquals("TWO", sideMenu.select("#root-nav-submenu-0-0-2").text()) - assertEquals("THREE", sideMenu.select("#root-nav-submenu-0-0-3").text()) - assertEquals("FOUR", sideMenu.select("#root-nav-submenu-0-0-4").text()) - assertEquals("FIVE", sideMenu.select("#root-nav-submenu-0-0-5").text()) - assertEquals("SIX", sideMenu.select("#root-nav-submenu-0-0-6").text()) - assertEquals("SEVEN", sideMenu.select("#root-nav-submenu-0-0-7").text()) - assertEquals("EIGHT", sideMenu.select("#root-nav-submenu-0-0-8").text()) - assertEquals("NINE", sideMenu.select("#root-nav-submenu-0-0-9").text()) - } - } - } - - fun TestOutputWriter.navigationHtml(): Element = contents.getValue("navigation.html").let { Jsoup.parse(it) } - - @Test - fun `should handle companion object within enum`() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/Test.kt - |package testpackage - | - |enum class TestEnum { - | E1, - | E2; - | companion object {} - |} - """.trimMargin(), - configuration - ) { - documentablesTransformationStage = { m -> - m.packages.let { p -> - assertTrue(p.isNotEmpty(), "Package list cannot be empty") - p.first().classlikes.let { c -> - assertTrue(c.isNotEmpty(), "Classlikes list cannot be empty") - - val enum = c.first() as DEnum - assertNotNull(enum.companion) - } - } - } - } - } - - @Test - fun enumWithMethods() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/TestEnum.kt - |package testpackage - | - | - |interface Sample { - | fun toBeImplemented(): String - |} - | - |enum class TestEnum: Sample { - | E1 { - | override fun toBeImplemented(): String = "e1" - | } - |} - """.trimMargin(), - configuration - ) { - documentablesTransformationStage = { m -> - m.packages.let { p -> - p.first().classlikes.let { c -> - val enum = c.first { it is DEnum } as DEnum - val first = enum.entries.first() - - assertNotNull(first.functions.find { it.name == "toBeImplemented" }) - } - } - } - } - } - - @Test - fun enumWithAnnotationsOnEntries() { - val configuration = dokkaConfiguration { - sourceSets { - sourceSet { - sourceRoots = listOf("src/") - } - } - } - - testInline( - """ - |/src/main/kotlin/basic/TestEnum.kt - |package testpackage - | - |enum class TestEnum { - | /** - | Sample docs for E1 - | **/ - | @SinceKotlin("1.3") // This annotation is transparent due to lack of @MustBeDocumented annotation - | E1 - |} - """.trimMargin(), - configuration - ) { - pagesTransformationStage = { m -> - val entryNode = m.children.first { it.name == "testpackage" }.children.first { it.name == "TestEnum" }.children.firstIsInstance() - val signature = (entryNode.content as ContentGroup).dfs { it is ContentGroup && it.dci.toString() == "[testpackage/TestEnum.E1///PointingToDeclaration/{\"org.jetbrains.dokka.links.EnumEntryDRIExtra\":{\"key\":\"org.jetbrains.dokka.links.EnumEntryDRIExtra\"}}][Cover]" } as ContentGroup - - signature.assertNode { - header(1) { +"E1" } - platformHinted { - group { - group { - link { +"E1" } - } - } - group { - group { - group { - +"Sample docs for E1" - } - } - } - } - } - } - } - } -} diff --git a/plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt b/plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt new file mode 100644 index 00000000..83430869 --- /dev/null +++ b/plugins/base/src/test/kotlin/enums/KotlinEnumTest.kt @@ -0,0 +1,408 @@ +package enums + +import matchers.content.* +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.* +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.jsoup.Jsoup +import org.jsoup.nodes.Element +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import signatures.renderedContent +import utils.TestOutputWriter +import utils.TestOutputWriterPlugin + +class KotlinEnumTest : BaseAbstractTest() { + + @Test + fun `should preserve enum source ordering for documentables`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package testpackage + | + |enum class TestEnum { + | ZERO, + | ONE, + | TWO, + | THREE, + | FOUR, + | FIVE, + | SIX, + | SEVEN, + | EIGHT, + | NINE + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + documentablesTransformationStage = { module -> + val testPackage = module.packages[0] + assertEquals("testpackage", testPackage.name) + + val testEnum = testPackage.classlikes[0] as DEnum + assertEquals("TestEnum", testEnum.name) + + val enumEntries = testEnum.entries + assertEquals(10, enumEntries.count()) + + assertEquals("ZERO", enumEntries[0].name) + assertEquals("ONE", enumEntries[1].name) + assertEquals("TWO", enumEntries[2].name) + assertEquals("THREE", enumEntries[3].name) + assertEquals("FOUR", enumEntries[4].name) + assertEquals("FIVE", enumEntries[5].name) + assertEquals("SIX", enumEntries[6].name) + assertEquals("SEVEN", enumEntries[7].name) + assertEquals("EIGHT", enumEntries[8].name) + assertEquals("NINE", enumEntries[9].name) + } + } + } + + @Test + fun `should preserve enum source ordering for generated pages`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package testpackage + | + |enum class TestEnum { + | ZERO, + | ONE, + | TWO, + | THREE, + | FOUR, + | FIVE, + | SIX, + | SEVEN, + | EIGHT, + | NINE + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + pagesGenerationStage = { rootPage -> + val packagePage = rootPage.children[0] + assertEquals("testpackage", packagePage.name) + + val testEnumNode = packagePage.children[0] + assertEquals("TestEnum", testEnumNode.name) + + val enumEntries = testEnumNode.children + assertEquals(10, enumEntries.size) + + assertEquals("ZERO", enumEntries[0].name) + assertEquals("ONE", enumEntries[1].name) + assertEquals("TWO", enumEntries[2].name) + assertEquals("THREE", enumEntries[3].name) + assertEquals("FOUR", enumEntries[4].name) + assertEquals("FIVE", enumEntries[5].name) + assertEquals("SIX", enumEntries[6].name) + assertEquals("SEVEN", enumEntries[7].name) + assertEquals("EIGHT", enumEntries[8].name) + assertEquals("NINE", enumEntries[9].name) + } + } + } + + @Test + fun `should preserve enum source ordering for rendered entries`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package testpackage + | + |enum class TestEnum { + | ZERO, + | ONE, + | TWO, + | THREE, + | FOUR, + | FIVE, + | SIX, + | SEVEN, + | EIGHT, + | NINE + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val enumEntriesOnPage = writerPlugin.writer.renderedContent("root/testpackage/-test-enum/index.html") + .select("div.table[data-togglable=Entries]") + .select("div.table-row") + .select("div.keyValue") + .select("div.title") + .select("a") + + val enumEntries = enumEntriesOnPage.map { it.text() } + assertEquals(10, enumEntries.size) + + assertEquals("ZERO", enumEntries[0]) + assertEquals("ONE", enumEntries[1]) + assertEquals("TWO", enumEntries[2]) + assertEquals("THREE", enumEntries[3]) + assertEquals("FOUR", enumEntries[4]) + assertEquals("FIVE", enumEntries[5]) + assertEquals("SIX", enumEntries[6]) + assertEquals("SEVEN", enumEntries[7]) + assertEquals("EIGHT", enumEntries[8]) + assertEquals("NINE", enumEntries[9]) + } + } + } + + @Test + fun `should preserve enum source ordering for navigation menu`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + val writerPlugin = TestOutputWriterPlugin() + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package testpackage + | + |enum class TestEnum { + | ZERO, + | ONE, + | TWO, + | THREE, + | FOUR, + | FIVE, + | SIX, + | SEVEN, + | EIGHT, + | NINE + |} + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val sideMenu = writerPlugin.writer.navigationHtml().select("div.sideMenuPart") + + assertEquals("ZERO", sideMenu.select("#root-nav-submenu-0-0-0").text()) + assertEquals("ONE", sideMenu.select("#root-nav-submenu-0-0-1").text()) + assertEquals("TWO", sideMenu.select("#root-nav-submenu-0-0-2").text()) + assertEquals("THREE", sideMenu.select("#root-nav-submenu-0-0-3").text()) + assertEquals("FOUR", sideMenu.select("#root-nav-submenu-0-0-4").text()) + assertEquals("FIVE", sideMenu.select("#root-nav-submenu-0-0-5").text()) + assertEquals("SIX", sideMenu.select("#root-nav-submenu-0-0-6").text()) + assertEquals("SEVEN", sideMenu.select("#root-nav-submenu-0-0-7").text()) + assertEquals("EIGHT", sideMenu.select("#root-nav-submenu-0-0-8").text()) + assertEquals("NINE", sideMenu.select("#root-nav-submenu-0-0-9").text()) + } + } + } + + fun TestOutputWriter.navigationHtml(): Element = contents.getValue("navigation.html").let { Jsoup.parse(it) } + + @Test + fun `should handle companion object within enum`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package testpackage + | + |enum class TestEnum { + | E1, + | E2; + | companion object {} + |} + """.trimMargin(), + configuration + ) { + documentablesTransformationStage = { m -> + m.packages.let { p -> + assertTrue(p.isNotEmpty(), "Package list cannot be empty") + p.first().classlikes.let { c -> + assertTrue(c.isNotEmpty(), "Classlikes list cannot be empty") + + val enum = c.first() as DEnum + assertNotNull(enum.companion) + } + } + } + } + } + + + @Test + fun `should contain synthetic values and valueOf functions`() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package testpackage + | + |enum class TestEnum { + | E1, + | E2; + |} + """.trimMargin(), + configuration + ) { + // stage is important because they will get filtered out later on + documentablesCreationStage = { modules -> + val pckg = modules.flatMap { it.packages }.single { it.packageName == "testpackage" } + val enum = pckg.children.single { it is DEnum } as DEnum + + val valueOf = enum.functions.single { it.name == "valueOf" } + assertEquals("testpackage/TestEnum/valueOf/#kotlin.String/PointingToDeclaration/", valueOf.dri.toString()) + assertNotNull(valueOf.extra[ObviousMember]) + + val values = enum.functions.single { it.name == "values" } + assertEquals("testpackage/TestEnum/values/#/PointingToDeclaration/", values.dri.toString()) + assertNotNull(values.extra[ObviousMember]) + } + } + } + + @Test + fun enumWithMethods() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/TestEnum.kt + |package testpackage + | + | + |interface Sample { + | fun toBeImplemented(): String + |} + | + |enum class TestEnum: Sample { + | E1 { + | override fun toBeImplemented(): String = "e1" + | } + |} + """.trimMargin(), + configuration + ) { + documentablesTransformationStage = { m -> + m.packages.let { p -> + p.first().classlikes.let { c -> + val enum = c.first { it is DEnum } as DEnum + val first = enum.entries.first() + + assertNotNull(first.functions.find { it.name == "toBeImplemented" }) + } + } + } + } + } + + @Test + fun enumWithAnnotationsOnEntries() { + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/TestEnum.kt + |package testpackage + | + |enum class TestEnum { + | /** + | Sample docs for E1 + | **/ + | @SinceKotlin("1.3") // This annotation is transparent due to lack of @MustBeDocumented annotation + | E1 + |} + """.trimMargin(), + configuration + ) { + pagesTransformationStage = { m -> + val entryNode = m.children.first { it.name == "testpackage" }.children.first { it.name == "TestEnum" }.children.firstIsInstance() + val signature = (entryNode.content as ContentGroup).dfs { it is ContentGroup && it.dci.toString() == "[testpackage/TestEnum.E1///PointingToDeclaration/{\"org.jetbrains.dokka.links.EnumEntryDRIExtra\":{\"key\":\"org.jetbrains.dokka.links.EnumEntryDRIExtra\"}}][Cover]" } as ContentGroup + + signature.assertNode { + header(1) { +"E1" } + platformHinted { + group { + group { + link { +"E1" } + } + } + group { + group { + group { + +"Sample docs for E1" + } + } + } + } + } + } + } + } +} -- cgit