diff options
6 files changed, 189 insertions, 11 deletions
diff --git a/core/src/main/kotlin/model/aditionalExtras.kt b/core/src/main/kotlin/model/aditionalExtras.kt index f71852c4..055fc5a6 100644 --- a/core/src/main/kotlin/model/aditionalExtras.kt +++ b/core/src/main/kotlin/model/aditionalExtras.kt @@ -59,4 +59,15 @@ data class ActualTypealias(val underlyingType: SourceSetDependent<Bound>) : Extr } override val key: ExtraProperty.Key<DClasslike, ActualTypealias> = ActualTypealias +} + +data class ConstructorValues(val values: List<String>) : ExtraProperty<DEnumEntry>{ + companion object : ExtraProperty.Key<DEnumEntry, ConstructorValues> { + override fun mergeStrategyFor(left: ConstructorValues, right: ConstructorValues) = + MergeStrategy.Fail{ + throw IllegalArgumentException("Merging constructor parameters not applicable") + } + } + + override val key: ExtraProperty.Key<DEnumEntry, ConstructorValues> = ConstructorValues }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index 33c82458..367a7a95 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -33,8 +33,16 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog } private fun signature(e: DEnumEntry) = - contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)) { - link(e.name, e.dri) + contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace), sourceSets = e.sourceSets.toSet()) { + group(styles = setOf(TextStyle.Block)){ + annotationsBlock(e) + link(e.name, e.dri, styles = emptySet()) + e.extra[ConstructorValues]?.let { + list(it.values, prefix = "(", suffix = ")"){ + text(it) + } + } + } } private fun actualTypealiasedSignature(dri: DRI, name: String, aliasedTypes: SourceSetDependent<Bound>) = @@ -87,7 +95,7 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog +buildSignature(it) } } - if (c is DClass) { + if (c is WithConstructors) { val pConstructor = c.constructors.singleOrNull { it.extra[PrimaryConstructorExtra] != null } if (pConstructor?.annotations()?.isNotEmpty() == true) { text(nbsp.toString()) diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 60182ba9..a56eb454 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -24,8 +24,9 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies import org.jetbrains.kotlin.idea.kdoc.findKDoc import org.jetbrains.kotlin.load.kotlin.toSourceElement -import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.AnnotationValue as ConstantsAnnotationValue @@ -41,9 +42,12 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.source.KotlinSourceElement +import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.types.DynamicType import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjection +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.nio.file.Paths import kotlin.IllegalArgumentException @@ -212,7 +216,11 @@ private class DokkaDescriptorVisitor( properties = scope.properties(driWithPlatform), sourceSets = listOf(sourceSet), expectPresentInSet = sourceSet.takeIf { isExpect }, - extra = PropertyContainer.withAll(descriptor.additionalExtras(), descriptor.getAnnotations()) + extra = PropertyContainer.withAll( + descriptor.additionalExtras(), + descriptor.getAnnotations(), + ConstructorValues(descriptor.getAppliedConstructorParameters()) + ) ) } @@ -499,7 +507,6 @@ private class DokkaDescriptorVisitor( getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS, packageLevel) .filter { it is ClassDescriptor && it.kind != ClassKind.ENUM_ENTRY } .map { visitClassDescriptor(it as ClassDescriptor, parent) } - .mapNotNull { it as? DClasslike } private fun MemberScope.packages(parent: DRIWithPlatformInfo): List<DPackage> = getContributedDescriptors(DescriptorKindFilter.PACKAGES) { true } @@ -681,6 +688,19 @@ private class DokkaDescriptorVisitor( private fun ValueParameterDescriptor.getDefaultValue(): String? = (source as? KotlinSourceElement)?.psi?.children?.find { it is KtExpression }?.text + private fun ClassDescriptor.getAppliedConstructorParameters() = + (source as PsiSourceElement).psi?.children?.flatMap { + it.safeAs<KtInitializerList>()?.initializersAsText().orEmpty() + }.orEmpty() + + private fun KtInitializerList.initializersAsText() = + initializers.firstIsInstanceOrNull<KtCallElement>() + ?.getValueArgumentsInParentheses() + ?.flatMap { it.childrenAsText() } + .orEmpty() + + private fun ValueArgument.childrenAsText() = this.safeAs<KtValueArgument>()?.children?.map {it.text }.orEmpty() + private data class ClassInfo(val supertypes: List<DRI>, val docs: SourceSetDependent<DocumentationNode>) private fun Visibility.toDokkaVisibility(): org.jetbrains.dokka.model.Visibility = when (this) { diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index d9927046..d573b76c 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -172,7 +172,6 @@ padding: 8px 16px; box-sizing: border-box; font-weight: bold; - white-space: pre; flex-wrap: wrap; } diff --git a/plugins/base/src/test/kotlin/enums/EnumsTest.kt b/plugins/base/src/test/kotlin/enums/EnumsTest.kt index 5f8bf8c8..6c44dc35 100644 --- a/plugins/base/src/test/kotlin/enums/EnumsTest.kt +++ b/plugins/base/src/test/kotlin/enums/EnumsTest.kt @@ -1,11 +1,16 @@ package enums +import matchers.content.assertNode +import matchers.content.group +import matchers.content.header +import matchers.content.link +import org.jetbrains.dokka.model.ConstructorValues import org.jetbrains.dokka.model.DEnum -import org.jetbrains.dokka.pages.ClasslikePageNode -import org.jetbrains.dokka.pages.ModulePageNode -import org.junit.jupiter.api.Test +import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import utils.unwrapAnnotation class EnumsTest : AbstractCoreTest() { @@ -85,7 +90,142 @@ class EnumsTest : AbstractCoreTest() { } } + @Test + fun enumWithConstructor() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package enums + | + | + |enum class Test(name: String, index: Int, excluded: Boolean) { + | E1("e1", 1, true), + | E2("e2", 2, false); + |} + """.trimMargin(), + configuration + ) { + documentablesTransformationStage = { m -> + m.packages.let { p -> + p.first().classlikes.let { c -> + val enum = c.first() as DEnum + val (first, second) = enum.entries + + assertEquals(1, first.extra.allOfType<ConstructorValues>().size) + assertEquals(1, second.extra.allOfType<ConstructorValues>().size) + assertEquals(listOf("\"e1\"", "1", "true"), first.extra.allOfType<ConstructorValues>().first().values) + assertEquals(listOf("\"e2\"", "2", "false"), second.extra.allOfType<ConstructorValues>().first().values) + } + } + } + pagesGenerationStage = { module -> + val entryPage = module.dfs { it.name == "E1" } as ClasslikePageNode + val signaturePart = (entryPage.content.dfs { + it is ContentGroup && it.dci.toString() == "[enums/Test.E1///PointingToDeclaration/][Symbol]" + } as ContentGroup).children.first() as ContentGroup + assertEquals("(\"e1\", 1, true)", signaturePart.constructorSignature()) + } + } + } + + @Test + fun enumWithMethods() { + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package enums + | + | + |interface Sample { + | fun toBeImplemented(): String + |} + | + |enum class Test: 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() + + assertEquals(1, first.extra.allOfType<ConstructorValues>().size) + assertEquals(emptyList<String>(), first.extra.allOfType<ConstructorValues>().first().values) + assertNotNull(first.functions.find { it.name == "toBeImplemented" }) + } + } + } + } + } + + @Test + fun enumWithAnnotationsOnEntries(){ + val configuration = dokkaConfiguration { + passes { + pass { + sourceRoots = listOf("src/") + } + } + } + + testInline( + """ + |/src/main/kotlin/basic/Test.kt + |package enums + | + |enum class Test { + | @SinceKotlin("1.3") + | E1 + |} + """.trimMargin(), + configuration + ) { + pagesTransformationStage = { m -> + val entryNode = m.children.first { it.name == "enums" }.children.first { it.name == "Test" }.children.first() as ClasslikePageNode + val signature = (entryNode.content as ContentGroup).dfs { it is ContentGroup && it.dci.toString() == "[enums/Test.E1///PointingToDeclaration/][Cover]" } as ContentGroup + + signature.assertNode { + header(1) { +"E1" } + group { + mapOf("SinceKotlin" to setOf("version")).entries.forEach { + group { + group { + unwrapAnnotation(it) + } + link { +"E1" } + } + } + } + } + } + } + } + fun ModulePageNode.getClasslikeToMemberMap() = this.parentMap.filterValues { it is ClasslikePageNode }.entries.groupBy({ it.value }) { it.key } + + private fun ContentGroup.constructorSignature(): String = + children.drop(1).joinToString(separator = "") { (it as ContentText).text } }
\ No newline at end of file diff --git a/plugins/base/src/test/kotlin/utils/contentUtils.kt b/plugins/base/src/test/kotlin/utils/contentUtils.kt index 4aba3e9d..7e1b8bf4 100644 --- a/plugins/base/src/test/kotlin/utils/contentUtils.kt +++ b/plugins/base/src/test/kotlin/utils/contentUtils.kt @@ -184,7 +184,7 @@ fun ContentMatcherBuilder<*>.unnamedTag(tag: String, content: ContentMatcherBuil group { content() } } -private fun ContentMatcherBuilder<*>.unwrapAnnotation(elem: Map.Entry<String, Set<String>>) { +fun ContentMatcherBuilder<*>.unwrapAnnotation(elem: Map.Entry<String, Set<String>>) { +"@" link { +elem.key } +"(" |