diff options
author | Kamil Doległo <kamilok1965@interia.pl> | 2020-04-02 18:20:34 +0200 |
---|---|---|
committer | Paweł Marks <Kordyjan@users.noreply.github.com> | 2020-04-07 11:43:41 +0200 |
commit | af1ea32aa3f1e71cd47851a4a06344431801c8fd (patch) | |
tree | 906f1d7751780ba82dee91a4dbd7c29c585c52f9 /plugins/base/src/main | |
parent | fe24837fb51d5004ec3d7d728ce4c325a192e426 (diff) | |
download | dokka-af1ea32aa3f1e71cd47851a4a06344431801c8fd.tar.gz dokka-af1ea32aa3f1e71cd47851a4a06344431801c8fd.tar.bz2 dokka-af1ea32aa3f1e71cd47851a4a06344431801c8fd.zip |
Add Typealiases rendering and merging
Diffstat (limited to 'plugins/base/src/main')
7 files changed, 233 insertions, 110 deletions
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 548bcb93..77028d53 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -10,6 +10,7 @@ import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.resolvers.external.* import org.jetbrains.dokka.base.resolvers.local.DefaultLocationProviderFactory import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory +import org.jetbrains.dokka.base.transformers.documentables.ActualTypealiasAdder import org.jetbrains.dokka.base.transformers.documentables.DefaultDocumentableMerger import org.jetbrains.dokka.base.transformers.documentables.InheritorsExtractorTransformer import org.jetbrains.dokka.base.transformers.pages.annotations.DeprecatedStrikethroughTransformer @@ -51,6 +52,10 @@ class DokkaBase : DokkaPlugin() { CoreExtensions.preMergeDocumentableTransformer with DocumentableVisibilityFilter } + val actualTypealiasAdder by extending { + CoreExtensions.preMergeDocumentableTransformer with ActualTypealiasAdder() + } + val kotlinSignatureProvider by extending(isFallback = true) { signatureProvider providing { ctx -> KotlinSignatureProvider(ctx.single(commentsToContentConverter), ctx.logger) diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index a30e1b72..ef557eaf 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -7,9 +7,7 @@ import org.jetbrains.dokka.links.DriOfAny import org.jetbrains.dokka.links.DriOfUnit import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.DAnnotation -import org.jetbrains.dokka.model.DEnum -import org.jetbrains.dokka.model.DFunction +import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.pages.ContentKind import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.pages.PlatformData @@ -22,9 +20,9 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog private val ignoredVisibilities = setOf(JavaVisibility.Default, KotlinVisibility.Public) override fun signature(documentable: Documentable): ContentNode = when (documentable) { - is DFunction -> signature(documentable) - is DProperty -> signature(documentable) - is DClasslike -> signature(documentable) + is DFunction -> functionSignature(documentable) + is DProperty -> propertySignature(documentable) + is DClasslike -> classlikeSignature(documentable) is DTypeParameter -> signature(documentable) is DEnumEntry -> signature(documentable) is DTypeAlias -> signature(documentable) @@ -33,71 +31,94 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog ) } - private fun signature(e: DEnumEntry)= contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)) + private fun signature(e: DEnumEntry) = contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)) - private fun signature(c: DClasslike) = contentBuilder.contentFor(c, ContentKind.Symbol, setOf(TextStyle.Monospace)) { - platformText(c.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } - if (c is DClass) { - platformText(c.modifier){ - if (c.extra[AdditionalModifiers]?.content?.contains(ExtraModifiers.DATA) == true && it.name == "final") "data " - else it.name + " " + private fun actualTypealiasedSignature(dri: DRI, name: String, aliasedTypes: PlatformDependent<Bound>) = + aliasedTypes.entries.groupBy({ it.value }, { it.key }).map { (bound, platforms) -> + contentBuilder.contentFor(dri, platforms.toSet(), ContentKind.Symbol, setOf(TextStyle.Monospace)) { + text("actual typealias ") + link(name, dri) + text(" = ") + signatureForProjection(bound) } } - when (c) { - is DClass -> text("class ") - is DInterface -> text("interface ") - is DEnum -> text("enum ") - is DObject -> text("object ") - is DAnnotation -> text("annotation class ") - } - link(c.name!!, c.dri) - if(c is DClass){ - val pConstructor = c.constructors.singleOrNull() { it.extra[PrimaryConstructorExtra] != null } - list(pConstructor?.parameters.orEmpty(), "(", ")", ",", pConstructor?.platformData.orEmpty().toSet()){ - breakLine() - text(it.name ?: "", styles = mainStyles.plus(TextStyle.Bold).plus(TextStyle.Indented)) - text(": ") - signatureForProjection(it.type) + + private fun <T : DClasslike> classlikeSignature(c: T) = + (c as? WithExtraProperties<out DClasslike>)?.let { + c.extra[ActualTypealias]?.let { + contentBuilder.contentFor(c) { + +regularSignature(c, platformData = c.platformData.toSet() - it.underlyingType.keys) + +actualTypealiasedSignature(c.dri, c.name.orEmpty(), it.underlyingType) + } + } ?: regularSignature(c) + } ?: regularSignature(c) + + private fun regularSignature(c: DClasslike, platformData: Set<PlatformData> = c.platformData.toSet()) = + contentBuilder.contentFor(c, ContentKind.Symbol, setOf(TextStyle.Monospace), platformData = platformData) { + platformText(c.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } + if (c is DClass) { + platformText(c.modifier) { + if (c.extra[AdditionalModifiers]?.content?.contains(ExtraModifiers.DATA) == true && it.name == "final") "data " + else it.name + " " + } } - } - if (c is WithSupertypes) { - c.supertypes.map { (p, dris) -> - list(dris, prefix = " : ", platformData = setOf(p)) { - link(it.sureClassNames, it, platformData = setOf(p)) + when (c) { + is DClass -> text("class ") + is DInterface -> text("interface ") + is DEnum -> text("enum ") + is DObject -> text("object ") + is DAnnotation -> text("annotation class ") + } + link(c.name!!, c.dri) + if (c is DClass) { + val pConstructor = c.constructors.singleOrNull() { it.extra[PrimaryConstructorExtra] != null } + list(pConstructor?.parameters.orEmpty(), "(", ")", ",", pConstructor?.platformData.orEmpty().toSet()) { + breakLine() + text(it.name ?: "", styles = mainStyles.plus(TextStyle.Bold).plus(TextStyle.Indented)) + text(": ") + signatureForProjection(it.type) + } + } + if (c is WithSupertypes) { + c.supertypes.map { (p, dris) -> + list(dris, prefix = " : ", platformData = setOf(p)) { + link(it.sureClassNames, it, platformData = setOf(p)) + } } } } - } - - private fun signature(p: DProperty) = contentBuilder.contentFor(p, ContentKind.Symbol, setOf(TextStyle.Monospace)) { - signatureForProjection(p.type) - } - private fun signature(f: DFunction) = contentBuilder.contentFor(f, ContentKind.Symbol, setOf(TextStyle.Monospace)) { - platformText(f.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } - platformText(f.modifier) { it.name + " " } - text("fun ") - list(f.generics, prefix = "<", suffix = "> ") { - +buildSignature(it) + private fun propertySignature(p: DProperty, platformData: Set<PlatformData> = p.platformData.toSet()) = + contentBuilder.contentFor(p, ContentKind.Symbol, setOf(TextStyle.Monospace), platformData = platformData) { + signatureForProjection(p.type) } - f.receiver?.also { - signatureForProjection(it.type) - text(".") - } - link(f.name, f.dri) - text("(") - list(f.parameters) { - text(it.name!!) - text(": ") - signatureForProjection(it.type) - } - text(")") - if (f.documentReturnType()) { - text(": ") - signatureForProjection(f.type) + private fun functionSignature(f: DFunction, platformData: Set<PlatformData> = f.platformData.toSet()) = + contentBuilder.contentFor(f, ContentKind.Symbol, setOf(TextStyle.Monospace), platformData = platformData) { + platformText(f.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } + platformText(f.modifier) { it.name + " " } + text("fun ") + list(f.generics, prefix = "<", suffix = "> ") { + +buildSignature(it) + } + f.receiver?.also { + signatureForProjection(it.type) + text(".") + } + link(f.name, f.dri) + text("(") + list(f.parameters) { + text(it.name!!) + text(": ") + + signatureForProjection(it.type) + } + text(")") + if (f.documentReturnType()) { + text(": ") + signatureForProjection(f.type) + } } - } private fun DFunction.documentReturnType() = when { this.isConstructor -> false @@ -106,12 +127,23 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog else -> true } - private fun signature(t: DTypeAlias) = contentBuilder.contentFor(t, ContentKind.Symbol, setOf(TextStyle.Monospace)) { - text("typealias ") - signatureForProjection(t.type) - text(" = ") - signatureForProjection(t.underlyingType) - } + private fun signature(t: DTypeAlias) = + contentBuilder.contentFor(t, ContentKind.Symbol, setOf(TextStyle.Monospace)) { + t.underlyingType.entries.groupBy({ it.value }, { it.key }).map { (type, platforms) -> + +contentBuilder.contentFor( + t, + ContentKind.Symbol, + setOf(TextStyle.Monospace), + platformData = platforms.toSet() + ) { + platformText(t.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } + text("typealias ") + signatureForProjection(t.type) + text(" = ") + signatureForProjection(type) + } + } + } private fun signature(t: DTypeParameter) = contentBuilder.contentFor(t) { link(t.name, t.dri) @@ -120,37 +152,38 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog } } - private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection(p: Projection): Unit = when (p) { - is OtherParameter -> text(p.name) + private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection(p: Projection): Unit = + when (p) { + is OtherParameter -> text(p.name) - is TypeConstructor -> if (p.function) - +funType(this.mainDRI, this.mainPlatformData, p) - else - group { - link(p.dri.classNames.orEmpty(), p.dri) - list(p.projections, prefix = "<", suffix = ">") { - signatureForProjection(it) + is TypeConstructor -> if (p.function) + +funType(this.mainDRI, this.mainPlatformData, p) + else + group { + link(p.dri.classNames.orEmpty(), p.dri) + list(p.projections, prefix = "<", suffix = ">") { + signatureForProjection(it) + } } + + is Variance -> group { + text(p.kind.toString() + " ") + signatureForProjection(p.inner) } - is Variance -> group { - text(p.kind.toString() + " ") - signatureForProjection(p.inner) - } + is Star -> text("*") - is Star -> text("*") + is Nullable -> group { + signatureForProjection(p.inner) + text("?") + } - is Nullable -> group { - signatureForProjection(p.inner) - text("?") + is JavaObject -> link("Any", DriOfAny) + is Void -> link("Unit", DriOfUnit) + is PrimitiveJavaType -> signatureForProjection(p.translateToKotlin()) } - is JavaObject -> link("Any", DriOfAny) - is Void -> link("Unit", DriOfUnit) - is PrimitiveJavaType -> signatureForProjection(p.translateToKotlin()) - } - - fun funType(dri: DRI, platformData: Set<PlatformData>, type: TypeConstructor) = + private fun funType(dri: DRI, platformData: Set<PlatformData>, type: TypeConstructor) = contentBuilder.contentFor(dri, platformData, ContentKind.Symbol, setOf(TextStyle.Monospace)) { if (type.extension) { signatureForProjection(type.projections.first()) diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ActualTypealiasAdder.kt b/plugins/base/src/main/kotlin/transformers/documentables/ActualTypealiasAdder.kt new file mode 100644 index 00000000..b3282b03 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/ActualTypealiasAdder.kt @@ -0,0 +1,73 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.properties.WithExtraProperties +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer + +class ActualTypealiasAdder : PreMergeDocumentableTransformer { + override fun invoke(modules: List<DModule>, context: DokkaContext) = modules.map { it.mergeTypealiases() } + + private fun DModule.mergeTypealiases(): DModule = copy(packages = packages.map { pkg -> + if (pkg.typealiases.isEmpty()) { + pkg + } else { + val typealiases = pkg.typealiases.map { it.dri to it }.toMap() + pkg.copy( + classlikes = addActualTypeAliasToClasslikes(pkg.classlikes, typealiases) + ) + } + }) + + private fun addActualTypeAliasToClasslikes( + elements: Iterable<DClasslike>, + typealiases: Map<DRI, DTypeAlias> + ): List<DClasslike> = elements.flatMap { + when (it) { + is DClass -> addActualTypeAlias( + it.copy( + classlikes = addActualTypeAliasToClasslikes(it.classlikes, typealiases) + ).let(::listOf), + typealiases + ) + is DEnum -> addActualTypeAlias( + it.copy( + classlikes = addActualTypeAliasToClasslikes(it.classlikes, typealiases) + ).let(::listOf), + typealiases + ) + is DInterface -> addActualTypeAlias( + it.copy( + classlikes = addActualTypeAliasToClasslikes(it.classlikes, typealiases) + ).let(::listOf), + typealiases + ) + is DObject -> addActualTypeAlias( + it.copy( + classlikes = addActualTypeAliasToClasslikes(it.classlikes, typealiases) + ).let(::listOf), + typealiases + ) + else -> throw IllegalStateException("${it::class.qualifiedName} ${it.name} cannot have extra added") + } as List<DClasslike> + } + + private fun <T> addActualTypeAlias( + elements: Iterable<T>, + typealiases: Map<DRI, DTypeAlias> + ): List<T> where T : DClasslike, T : WithExtraProperties<T>, T : WithExpectActual = + elements.map { element -> + if (element.sources.expect != null) { + typealiases[element.dri]?.let { ta -> + element.withNewExtras( + element.extra + ActualTypealias( + PlatformDependent.from(ta.platformData.single(), ta.underlyingType.values.single()) + ) + ) + } ?: element + } else { + element + } + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt index c87b5de3..ddb5903b 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt @@ -1,10 +1,6 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.DEnum -import org.jetbrains.dokka.model.DFunction -import org.jetbrains.dokka.model.DPackage -import org.jetbrains.dokka.model.DAnnotation import org.jetbrains.dokka.model.properties.mergeExtras import org.jetbrains.dokka.pages.PlatformData import org.jetbrains.dokka.plugability.DokkaContext @@ -16,7 +12,8 @@ internal object DefaultDocumentableMerger : DocumentableMerger { override fun invoke(modules: Collection<DModule>, context: DokkaContext): DModule { val projectName = - modules.fold(modules.first().name) { acc, module -> acc.commonPrefixWith(module.name) }.takeIf { it.isNotEmpty() } + modules.fold(modules.first().name) { acc, module -> acc.commonPrefixWith(module.name) } + .takeIf { it.isNotEmpty() } ?: "project" return modules.reduce { left, right -> @@ -111,6 +108,7 @@ fun DPackage.mergeWith(other: DPackage): DPackage = copy( properties = mergeExpectActual(properties + other.properties, DProperty::mergeWith) { copy(platformData = it) }, classlikes = mergeExpectActual(classlikes + other.classlikes, DClasslike::mergeWith, DClasslike::setPlatformData), documentation = documentation.mergeWith(other.documentation), + typealiases = merge(typealiases + other.typealiases, DTypeAlias::mergeWith), platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other) @@ -243,4 +241,11 @@ fun DParameter.mergeWith(other: DParameter): DParameter = copy( fun DTypeParameter.mergeWith(other: DTypeParameter): DTypeParameter = copy( documentation = documentation.mergeWith(other.documentation), platformData = (platformData + other.platformData).distinct() +).mergeExtras(this, other) + +fun DTypeAlias.mergeWith(other: DTypeAlias): DTypeAlias = copy( + documentation = documentation.mergeWith(other.documentation), + underlyingType = underlyingType.mergeWith(other.underlyingType), + visibility = visibility.mergeWith(other.visibility), + platformData = (platformData + other.platformData).distinct() ).mergeExtras(this, other)
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index ceb4d0bd..b7dfccd2 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -405,14 +405,18 @@ private class DokkaDescriptorVisitor( } override fun visitTypeAliasDescriptor(descriptor: TypeAliasDescriptor, parent: DRIWithPlatformInfo?) = - DTypeAlias( - dri = DRI.from(descriptor), - name = descriptor.name.asString(), - type = descriptor.defaultType.toBound(), - underlyingType = descriptor.underlyingType.toBound(), - documentation = descriptor.resolveDescriptorData(platformData), - platformData = listOf(platformData) - ) + with(descriptor) { + DTypeAlias( + dri = DRI.from(this), + name = name.asString(), + type = defaultType.toBound(), + underlyingType = PlatformDependent.from(platformData, underlyingType.toBound()), + visibility = if (isExpect) PlatformDependent.expectFrom(visibility.toDokkaVisibility()) + else PlatformDependent.from(platformData, visibility.toDokkaVisibility()), + documentation = resolveDescriptorData(platformData), + platformData = listOf(platformData) + ) + } private fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) = DParameter( diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt index 5ed44e18..3fcd07b3 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt @@ -72,14 +72,16 @@ open class DefaultPageCreator( } protected open fun contentForPackage(p: DPackage) = contentBuilder.contentFor(p) { - group(p.dri, p.platformData.toSet(), ContentKind.Packages){ + group(p.dri, p.platformData.toSet(), ContentKind.Packages) { header(1) { text("Package ${p.name}") } } +contentForScope(p, p.dri, p.platformData) - block("Type aliases", 2, ContentKind.Classlikes, p.typealiases, p.platformData.toSet()) { + block("Type aliases", 2, ContentKind.TypeAliases, p.typealiases, p.platformData.toSet()) { link(it.name, it.dri) group { - +buildSignature(it) + platformDependentHint(it.dri, it.platformData.toSet()) { + +buildSignature(it) + } group(kind = ContentKind.BriefComment) { text(it.briefDocumentation()) } @@ -147,7 +149,7 @@ open class DefaultPageCreator( } protected open fun contentForClasslike(c: DClasslike) = contentBuilder.contentFor(c) { - group(c.dri, c.platformData.toSet(), ContentKind.Classlikes){ + group(c.dri, c.platformData.toSet(), ContentKind.Classlikes) { header(1) { text(c.name.orEmpty()) } platformDependentHint(c.dri, c.platformData.toSet()) { +buildSignature(c) @@ -179,7 +181,7 @@ open class DefaultPageCreator( block("Entries", 2, ContentKind.Classlikes, c.entries, c.platformData.toSet()) { link(it.name.orEmpty(), it.dri) group { - platformDependentHint(it.dri, it.platformData.toSet()){ + platformDependentHint(it.dri, it.platformData.toSet()) { +buildSignature(it) } group(kind = ContentKind.BriefComment) { @@ -193,12 +195,12 @@ open class DefaultPageCreator( } @Suppress("UNCHECKED_CAST") - private inline fun <reified T: TagWrapper> GroupedTags.withTypeUnnamed(): PlatformDependent<T> = + private inline fun <reified T : TagWrapper> GroupedTags.withTypeUnnamed(): PlatformDependent<T> = (this[T::class] as List<Pair<PlatformData, T>>?) ?.let { PlatformDependent.from(it) }.orEmpty() @Suppress("UNCHECKED_CAST") - private inline fun <reified T: NamedTagWrapper> GroupedTags.withTypeNamed(): Map<String, PlatformDependent<T>> = + private inline fun <reified T : NamedTagWrapper> GroupedTags.withTypeNamed(): Map<String, PlatformDependent<T>> = (this[T::class] as List<Pair<PlatformData, T>>?) ?.groupBy { it.second.name } ?.mapValues { (_, v) -> PlatformDependent.from(v) } diff --git a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt index f77b4592..74d0011f 100644 --- a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt +++ b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt @@ -34,9 +34,10 @@ open class PageContentBuilder( kind: Kind = ContentKind.Main, styles: Set<Style> = emptySet(), extra: PropertyContainer<ContentNode> = PropertyContainer.empty(), + platformData: Set<PlatformData> = d.platformData.toSet(), block: DocumentableContentBuilder.() -> Unit = {} ): ContentGroup = - DocumentableContentBuilder(d.dri, d.platformData.toSet(), styles, extra) + DocumentableContentBuilder(d.dri, platformData, styles, extra) .apply(block) .build(d.platformData.toSet(), kind, styles, extra) |