diff options
Diffstat (limited to 'plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt')
-rw-r--r-- | plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt | 503 |
1 files changed, 0 insertions, 503 deletions
diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt deleted file mode 100644 index 2180e776..00000000 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. - */ - -package org.jetbrains.dokka.base.signatures - -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.dri -import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.driOrNull -import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter -import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder -import org.jetbrains.dokka.links.* -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.model.Nullable -import org.jetbrains.dokka.model.TypeConstructor -import org.jetbrains.dokka.model.properties.WithExtraProperties -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.utilities.DokkaLogger -import kotlin.text.Typography.nbsp - -public class KotlinSignatureProvider( - ctcc: CommentsToContentConverter, - logger: DokkaLogger -) : SignatureProvider, JvmSignatureUtils by KotlinSignatureUtils { - - public constructor(context: DokkaContext) : this( - context.plugin<DokkaBase>().querySingle { commentsToContentConverter }, - context.logger, - ) - - private val contentBuilder = PageContentBuilder(ctcc, this, logger) - - private val ignoredVisibilities = setOf(JavaVisibility.Public, KotlinVisibility.Public) - private val ignoredModifiers = setOf(JavaModifier.Final, KotlinModifier.Final) - private val ignoredExtraModifiers = setOf( - ExtraModifiers.KotlinOnlyModifiers.TailRec, - ExtraModifiers.KotlinOnlyModifiers.External - ) - private val platformSpecificModifiers: Map<ExtraModifiers, Set<Platform>> = mapOf( - ExtraModifiers.KotlinOnlyModifiers.External to setOf(Platform.js, Platform.wasm) - ) - - override fun signature(documentable: Documentable): List<ContentNode> = when (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) - else -> throw NotImplementedError( - "Cannot generate signature for ${documentable::class.qualifiedName} ${documentable.name}" - ) - } - - private fun <T> PageContentBuilder.DocumentableContentBuilder.processExtraModifiers(t: T) - where T : Documentable, T : WithExtraProperties<T> { - sourceSetDependentText( - t.modifiers() - .mapValues { entry -> - entry.value.filter { - it !in ignoredExtraModifiers || entry.key.analysisPlatform in (platformSpecificModifiers[it] - ?: emptySet()) - } - }, styles = mainStyles + TokenStyle.Keyword - ) { - it.toSignatureString() - } - } - - private fun signature(e: DEnumEntry): List<ContentNode> = - e.sourceSets.map { - contentBuilder.contentFor( - e, - ContentKind.Symbol, - setOf(TextStyle.Monospace), - sourceSets = setOf(it) - ) { - group(styles = setOf(TextStyle.Block)) { - annotationsBlock(e) - link(e.name, e.dri, styles = mainStyles + e.stylesIfDeprecated(it)) - } - } - } - - private fun classlikeSignature(c: DClasslike): List<ContentNode> { - @Suppress("UNCHECKED_CAST") - val typeAlias = (c as? WithExtraProperties<DClasslike>) - ?.extra - ?.get(ActualTypealias) - ?.typeAlias - - return c.sourceSets.map { sourceSetData -> - if (typeAlias != null && sourceSetData in typeAlias.sourceSets) { - regularSignature(typeAlias, sourceSetData) - } else { - regularSignature(c, sourceSetData) - } - } - } - - private fun <T : Documentable> PageContentBuilder.DocumentableContentBuilder.defaultValueAssign( - d: WithExtraProperties<T>, - sourceSet: DokkaSourceSet - ) { - // a default value of parameter can be got from expect source set - // but expect properties cannot have a default value - d.extra[DefaultValue]?.expression?.let { - it[sourceSet] ?: if (d is DParameter) it[d.expectPresentInSet] else null - }?.let { expr -> - operator(" = ") - highlightValue(expr) - } - } - - private fun regularSignature(c: DClasslike, sourceSet: DokkaSourceSet): ContentGroup { - @Suppress("UNCHECKED_CAST") - val deprecationStyles = (c as? WithExtraProperties<out Documentable>) - ?.stylesIfDeprecated(sourceSet) - ?: emptySet() - - return contentBuilder.contentFor( - c, - ContentKind.Symbol, - setOf(TextStyle.Monospace), - sourceSets = setOf(sourceSet) - ) { - annotationsBlock(c) - c.visibility[sourceSet]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") } - if (c.isExpectActual) keyword(if (sourceSet == c.expectPresentInSet) "expect " else "actual ") - if (c is DClass) { - val modifier = - if (c.modifier[sourceSet] !in ignoredModifiers) { - when { - c.extra[AdditionalModifiers]?.content?.get(sourceSet)?.contains(ExtraModifiers.KotlinOnlyModifiers.Data) == true -> "" - c.modifier[sourceSet] is JavaModifier.Empty -> "${KotlinModifier.Open.name} " - else -> c.modifier[sourceSet]?.name?.let { "$it " } - } - } else { - null - } - modifier?.takeIf { it.isNotEmpty() }?.let { keyword(it) } - } - when (c) { - is DClass -> { - processExtraModifiers(c) - keyword("class ") - } - is DInterface -> { - processExtraModifiers(c) - keyword("interface ") - } - is DEnum -> { - processExtraModifiers(c) - keyword("enum ") - } - is DObject -> { - processExtraModifiers(c) - keyword("object ") - } - is DAnnotation -> { - processExtraModifiers(c) - keyword("annotation class ") - } - } - link(c.name!!, c.dri, styles = mainStyles + deprecationStyles) - if (c is WithGenerics) { - list(c.generics, prefix = "<", suffix = ">", - separatorStyles = mainStyles + TokenStyle.Punctuation, - surroundingCharactersStyle = mainStyles + TokenStyle.Operator) { - annotationsInline(it) - +buildSignature(it) - } - } - if (c is WithConstructors) { - val pConstructor = c.constructors.singleOrNull { it.extra[PrimaryConstructorExtra] != null } - if (pConstructor?.sourceSets?.contains(sourceSet) == true) { - if (pConstructor.annotations().values.any { it.isNotEmpty() }) { - text(nbsp.toString()) - annotationsInline(pConstructor) - keyword("constructor") - } - - // for primary constructor, opening and closing parentheses - // should be present only if it has parameters. If there are - // no parameters, it should result in `class Example` - if (pConstructor.parameters.isNotEmpty()) { - val parameterPropertiesByName = c.properties - .filter { it.isAlsoParameter(sourceSet) } - .associateBy { it.name } - - punctuation("(") - parametersBlock(pConstructor) { param -> - annotationsInline(param) - parameterPropertiesByName[param.name]?.let { property -> - property.setter?.let { keyword("var ") } ?: keyword("val ") - } - text(param.name.orEmpty()) - operator(": ") - signatureForProjection(param.type) - defaultValueAssign(param, sourceSet) - } - punctuation(")") - } - } - } - if (c is WithSupertypes) { - c.supertypes.filter { it.key == sourceSet }.map { (s, typeConstructors) -> - list(typeConstructors, prefix = " : ", sourceSets = setOf(s)) { - link(it.typeConstructor.dri.sureClassNames, it.typeConstructor.dri, sourceSets = setOf(s)) - list(it.typeConstructor.projections, prefix = "<", suffix = "> ", - separatorStyles = mainStyles + TokenStyle.Punctuation, - surroundingCharactersStyle = mainStyles + TokenStyle.Operator) { - signatureForProjection(it) - } - } - } - } - } - } - - /** - * An example would be a primary constructor `class A(val s: String)`, - * where `s` is both a function parameter and a property - */ - private fun DProperty.isAlsoParameter(sourceSet: DokkaSourceSet): Boolean { - return this.extra[IsAlsoParameter] - ?.inSourceSets - ?.any { it.sourceSetID == sourceSet.sourceSetID } - ?: false - } - - private fun propertySignature(p: DProperty) = - p.sourceSets.map { sourceSet -> - contentBuilder.contentFor( - p, - ContentKind.Symbol, - setOf(TextStyle.Monospace), - sourceSets = setOf(sourceSet) - ) { - annotationsBlock(p) - p.visibility[sourceSet].takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") } - if (p.isExpectActual) keyword(if (sourceSet == p.expectPresentInSet) "expect " else "actual ") - p.modifier[sourceSet].takeIf { it !in ignoredModifiers }?.let { - if (it is JavaModifier.Empty) KotlinModifier.Open else it - }?.name?.let { keyword("$it ") } - p.modifiers()[sourceSet]?.toSignatureString()?.let { keyword(it) } - if (p.isMutable()) keyword("var ") else keyword("val ") - list(p.generics, prefix = "<", suffix = "> ", - separatorStyles = mainStyles + TokenStyle.Punctuation, - surroundingCharactersStyle = mainStyles + TokenStyle.Operator) { - annotationsInline(it) - +buildSignature(it) - } - p.receiver?.also { - signatureForProjection(it.type) - punctuation(".") - } - link(p.name, p.dri, styles = mainStyles + p.stylesIfDeprecated(sourceSet)) - operator(": ") - signatureForProjection(p.type) - - if (p.isNotMutable()) { - defaultValueAssign(p, sourceSet) - } - } - } - - private fun DProperty.isNotMutable(): Boolean = !isMutable() - - private fun DProperty.isMutable(): Boolean { - return this.extra[IsVar] != null || this.setter != null - } - - private fun PageContentBuilder.DocumentableContentBuilder.highlightValue(expr: Expression) = when (expr) { - is IntegerConstant -> constant(expr.value.toString()) - is FloatConstant -> constant(expr.value.toString() + "f") - is DoubleConstant -> constant(expr.value.toString()) - is BooleanConstant -> booleanLiteral(expr.value) - is StringConstant -> stringLiteral("\"${expr.value}\"") - is ComplexExpression -> text(expr.value) - else -> Unit - } - - private fun functionSignature(f: DFunction) = - f.sourceSets.map { sourceSet -> - contentBuilder.contentFor( - f, - ContentKind.Symbol, - setOf(TextStyle.Monospace), - sourceSets = setOf(sourceSet) - ) { - annotationsBlock(f) - f.visibility[sourceSet]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") } - if (f.isExpectActual) keyword(if (sourceSet == f.expectPresentInSet) "expect " else "actual ") - if (f.isConstructor) { - keyword("constructor") - } else { - f.modifier[sourceSet]?.takeIf { it !in ignoredModifiers }?.let { - if (it is JavaModifier.Empty) KotlinModifier.Open else it - }?.name?.let { keyword("$it ") } - f.modifiers()[sourceSet]?.toSignatureString()?.let { keyword(it) } - keyword("fun ") - list( - f.generics, prefix = "<", suffix = "> ", - separatorStyles = mainStyles + TokenStyle.Punctuation, - surroundingCharactersStyle = mainStyles + TokenStyle.Operator - ) { - annotationsInline(it) - +buildSignature(it) - } - f.receiver?.also { - signatureForProjection(it.type) - punctuation(".") - } - link(f.name, f.dri, styles = mainStyles + TokenStyle.Function + f.stylesIfDeprecated(sourceSet)) - } - // for a function, opening and closing parentheses must be present - // anyway, even if it has no parameters, resulting in `fun test(): R` - punctuation("(") - if (f.parameters.isNotEmpty()) { - parametersBlock(f) { param -> - annotationsInline(param) - processExtraModifiers(param) - text(param.name!!) - operator(": ") - signatureForProjection(param.type) - defaultValueAssign(param, sourceSet) - } - } - punctuation(")") - if (f.documentReturnType()) { - operator(": ") - signatureForProjection(f.type) - } - } - } - - private fun DFunction.documentReturnType() = when { - this.isConstructor -> false - this.type is TypeConstructor && (this.type as TypeConstructor).dri == DriOfUnit -> false - this.type is Void -> false - else -> true - } - - private fun signature(t: DTypeAlias) = - t.sourceSets.map { - regularSignature(t, it) - } - - private fun regularSignature( - t: DTypeAlias, - sourceSet: DokkaSourceSet - ) = contentBuilder.contentFor(t, sourceSets = setOf(sourceSet)) { - t.underlyingType.entries.groupBy({ it.value }, { it.key }).map { (type, platforms) -> - +contentBuilder.contentFor( - t, - ContentKind.Symbol, - setOf(TextStyle.Monospace), - sourceSets = platforms.toSet() - ) { - annotationsBlock(t) - t.visibility[sourceSet]?.takeIf { it !in ignoredVisibilities }?.name?.let { keyword("$it ") } - if (t.expectPresentInSet != null) keyword("actual ") - processExtraModifiers(t) - keyword("typealias ") - group(styles = mainStyles + t.stylesIfDeprecated(sourceSet)) { - signatureForProjection(t.type) - } - operator(" = ") - signatureForTypealiasTarget(t, type) - } - } - } - - private fun signature(t: DTypeParameter) = - t.sourceSets.map { - contentBuilder.contentFor(t, sourceSets = setOf(it)) { - group(styles = mainStyles + t.stylesIfDeprecated(it)) { - signatureForProjection(t.variantTypeParameter.withDri(t.dri.withTargetToDeclaration())) - } - list( - elements = t.nontrivialBounds, - prefix = " : ", - surroundingCharactersStyle = mainStyles + TokenStyle.Operator - ) { bound -> - signatureForProjection(bound) - } - } - } - - private fun PageContentBuilder.DocumentableContentBuilder.signatureForTypealiasTarget( - typeAlias: DTypeAlias, bound: Bound - ) { - signatureForProjection( - p = bound, - showFullyQualifiedName = bound.driOrNull?.classNames == typeAlias.dri.classNames - ) - } - - private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection( - p: Projection, showFullyQualifiedName: Boolean = false - ) { - return when (p) { - is TypeParameter -> { - if (p.presentableName != null) { - text(p.presentableName!!) - operator(": ") - } - annotationsInline(p) - link(p.name, p.dri) - } - is FunctionalTypeConstructor -> +funType(mainDRI.single(), mainSourcesetData, p) - is GenericTypeConstructor -> - group(styles = emptySet()) { - val linkText = if (showFullyQualifiedName && p.dri.packageName != null) { - "${p.dri.packageName}.${p.dri.classNames.orEmpty()}" - } else p.dri.classNames.orEmpty() - if (p.presentableName != null) { - text(p.presentableName!!) - operator(": ") - } - annotationsInline(p) - link(linkText, p.dri) - list(p.projections, prefix = "<", suffix = ">", - separatorStyles = mainStyles + TokenStyle.Punctuation, - surroundingCharactersStyle = mainStyles + TokenStyle.Operator) { - signatureForProjection(it, showFullyQualifiedName) - } - } - - is Variance<*> -> group(styles = emptySet()) { - keyword("$p ".takeIf { it.isNotBlank() } ?: "") - signatureForProjection(p.inner, showFullyQualifiedName) - } - - is Star -> operator("*") - - is Nullable -> group(styles = emptySet()) { - signatureForProjection(p.inner, showFullyQualifiedName) - operator("?") - } - is DefinitelyNonNullable -> group(styles = emptySet()) { - signatureForProjection(p.inner, showFullyQualifiedName) - operator(" & ") - link("Any", DriOfAny) - } - - is TypeAliased -> signatureForProjection(p.typeAlias) - is JavaObject -> { - annotationsInline(p) - link("Any", DriOfAny) - } - is Void -> link("Unit", DriOfUnit) - is PrimitiveJavaType -> signatureForProjection(p.translateToKotlin(), showFullyQualifiedName) - is Dynamic -> text("dynamic") - is UnresolvedBound -> text(p.name) - } - } - - private fun funType(dri: DRI, sourceSets: Set<DokkaSourceSet>, type: FunctionalTypeConstructor) = - contentBuilder.contentFor(dri, sourceSets, ContentKind.Main) { - - if (type.presentableName != null) { - text(type.presentableName!!) - operator(": ") - } - annotationsInline(type) - if (type.isSuspendable) keyword("suspend ") - - if (type.isExtensionFunction) { - signatureForProjection(type.projections.first()) - punctuation(".") - } - - val args = if (type.isExtensionFunction) - type.projections.drop(1) - else - type.projections - - punctuation("(") - args.subList(0, args.size - 1).forEachIndexed { i, arg -> - signatureForProjection(arg) - if (i < args.size - 2) punctuation(", ") - } - punctuation(")") - operator(" -> ") - signatureForProjection(args.last()) - } -} - -private fun PrimitiveJavaType.translateToKotlin() = GenericTypeConstructor( - dri = dri, - projections = emptyList(), - presentableName = null -) - -private val DTypeParameter.nontrivialBounds: List<Bound> - get() = bounds.filterNot { it is Nullable && it.inner.driOrNull == DriOfAny } |