diff options
Diffstat (limited to 'plugins/kotlin-as-java/src/main/kotlin')
-rw-r--r-- | plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt | 88 | ||||
-rw-r--r-- | plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt | 81 |
2 files changed, 105 insertions, 64 deletions
diff --git a/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt index 2e3ec152..8e2c783e 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt @@ -3,7 +3,6 @@ package org.jetbrains.dokka.kotlinAsJava import org.jetbrains.dokka.base.signatures.SignatureProvider import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder -import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.Annotation @@ -17,48 +16,50 @@ import org.jetbrains.dokka.utilities.DokkaLogger class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider { private val contentBuilder = PageContentBuilder(ctcc, this, logger) - override fun signature(documentable: Documentable): List<ContentNode> = when (documentable) { + private val ignoredVisibilities = setOf(JavaVisibility.Default, KotlinVisibility.Public) + private val ignoredModifiers = + setOf(WithAbstraction.Modifier.Open, WithAbstraction.Modifier.Empty, WithAbstraction.Modifier.Sealed) + + + override fun signature(documentable: Documentable): ContentNode = when (documentable) { is Function -> signature(documentable) is Classlike -> signature(documentable) + is TypeParameter -> signature(documentable) else -> throw NotImplementedError( "Cannot generate signature for ${documentable::class.qualifiedName} ${documentable.name}" ) } - private fun signature(f: Function) = f.platformData.map { signature(f, it) }.distinct() - - private fun signature(c: Classlike) = c.platformData.map { signature(c, it) }.distinct() + private fun signature(c: Classlike) = contentBuilder.contentFor(c, ContentKind.Symbol) { + platformText(c.visibility) { (it.takeIf { it !in ignoredVisibilities }?.name ?: "") + " " } - private fun signature(c: Classlike, platform: PlatformData) = contentBuilder.contentFor(c, ContentKind.Symbol) { if (c is Class) { - text(c.modifier.takeIf { it != WithAbstraction.Modifier.Empty }?.toString()?.toLowerCase().orEmpty()) + text(c.modifier.takeIf { it !in ignoredModifiers }?.toString()?.toLowerCase().orEmpty() + " ") } + when (c) { - is Class -> text(" class ") - is Interface -> text(" interface ") - is Enum -> text(" enum ") - is Object -> text(" class ") - is Annotation -> text(" @interface ") + is Class -> text("class ") + is Interface -> text("interface ") + is Enum -> text("enum ") + is Object -> text("class ") + is Annotation -> text("@interface ") } text(c.name!!) if (c is WithGenerics) { - val generics = c.generics.filterOnPlatform(platform) - if (generics.isNotEmpty()) { - text("<") - list(generics) { - +this@JavaSignatureProvider.signature(it) - } - text(">") + list(c.generics, prefix = "<", suffix = ">") { + +buildSignature(it) } } - if (c is WithSupertypes && c.supertypes.containsKey(platform)) { - list(c.supertypes.getValue(platform), prefix = " extends ") { - link(it.sureClassNames, it) + if (c is WithSupertypes) { + c.supertypes.map { (p, dris) -> + list(dris, prefix = " extends ", platformData = setOf(p)) { + link(it.sureClassNames, it, platformData = setOf(p)) + } } } } - private fun signature(f: Function, platform: PlatformData) = contentBuilder.contentFor(f, ContentKind.Symbol) { + private fun signature(f: Function) = contentBuilder.contentFor(f, ContentKind.Symbol) { text(f.modifier.takeIf { it != WithAbstraction.Modifier.Empty }?.toString()?.toLowerCase().orEmpty() + " ") val returnType = f.type if (!f.isConstructor && returnType.constructorFqName != Unit::class.qualifiedName) { @@ -66,16 +67,11 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge } text(" ") link(f.name, f.dri) - val generics = f.generics.filterOnPlatform(platform) - if (generics.isNotEmpty()) { - text("<") - generics.forEach { - this@JavaSignatureProvider.signature(it) - } - text(">") + list(f.generics, prefix = "<", suffix = ">") { + +buildSignature(it) } text("(") - list(f.parameters.filterOnPlatform(platform)) { + list(f.parameters) { type(it.type) text(" ") link(it.name!!, it.dri) @@ -85,34 +81,30 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge private fun signature(t: TypeParameter) = contentBuilder.contentFor(t, ContentKind.Symbol) { text(t.name.substringAfterLast(".")) - if (t.bounds.isNotEmpty()) { - text(" extends ") - t.bounds.forEach { - +signature(it, t.dri, t.platformData) - } + list(t.bounds, prefix = " extends ") { + signatureForProjection(it) } } - private fun signature(p: Projection, dri: DRI, platforms: List<PlatformData>): List<ContentNode> = when (p) { - is OtherParameter -> contentBuilder.contentFor(dri, platforms.toSet()) { text(p.name) }.children - is TypeConstructor -> contentBuilder.contentFor(dri, platforms.toSet()) { + private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection(p: Projection): Unit = when (p) { + is OtherParameter -> text(p.name) + + is TypeConstructor -> group { link(p.dri.classNames.orEmpty(), p.dri) list(p.projections, prefix = "<", suffix = ">") { - +signature(it, dri, platforms) + signatureForProjection(it) } - }.children + } - is Variance -> contentBuilder.contentFor(dri, platforms.toSet()) { + is Variance -> group { text(p.kind.toString() + " ") - }.children + signature(p.inner, dri, platforms) + signatureForProjection(p.inner) + } - is Star -> contentBuilder.contentFor(dri, platforms.toSet()) { text("?") }.children + is Star -> text("?") - is Nullable -> signature(p.inner, dri, platforms) + contentBuilder.contentFor( - dri, - platforms.toSet() - ) { text("?") }.children + is Nullable -> signatureForProjection(p.inner) } private fun <T : Documentable> Collection<T>.filterOnPlatform(platformData: PlatformData) = diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt index f7fc57ff..a8b45db0 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt @@ -16,7 +16,9 @@ import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType private fun <T : WithExpectActual> List<T>.groupedByLocation() = map { it.sources to it } .groupBy({ (location, _) -> - location.let { it.map.entries.first().value.path.split("/").last().split(".").first() + "Kt" } // TODO: first() does not look reasonable + location.let { + it.map.entries.first().value.path.split("/").last().split(".").first() + "Kt" + } // TODO: first() does not look reasonable }) { it.second } internal fun Package.asJava(): Package { @@ -61,16 +63,19 @@ internal fun Property.asJava(isTopLevel: Boolean = false, relocateToClass: Strin } else { dri.withClass(relocateToClass) }, -// name = name.o, modifier = if (setter == null) { WithAbstraction.Modifier.Final } else { WithAbstraction.Modifier.Empty }, - type = type.asJava(isTopLevel), // TODO: check, + visibility = visibility.copy( + map = visibility.mapValues { JavaVisibility.Private } + ), + type = type.asJava(isTopLevel), // TODO: check setter = null, - getter = null // Removing getters and setters as they will be available as functions - ) // TODO: visibility -> always private; if (isTopLevel) -> static + getter = null, // Removing getters and setters as they will be available as functions + extra = if (isTopLevel) extra.plus(extra.mergeAdditionalModifiers(listOf(ExtraModifiers.STATIC))) else extra + ) internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass: String? = null): List<Function> = listOfNotNull( @@ -86,7 +91,11 @@ internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass } else { WithAbstraction.Modifier.Empty }, - type = type.asJava(isTopLevel) // TODO: check, + visibility = visibility.copy( + map = visibility.mapValues { JavaVisibility.Public } + ), + type = type.asJava(isTopLevel), // TODO: check + extra = if (isTopLevel) getter!!.extra.plus(getter!!.extra.mergeAdditionalModifiers(listOf(ExtraModifiers.STATIC))) else getter!!.extra ), setter?.copy( dri = if (relocateToClass.isNullOrBlank()) { @@ -100,9 +109,13 @@ internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass } else { WithAbstraction.Modifier.Empty }, - type = type.asJava(isTopLevel) // TODO: check, + visibility = visibility.copy( + map = visibility.mapValues { JavaVisibility.Public } + ), + type = type.asJava(isTopLevel), // TODO: check + extra = if (isTopLevel) setter!!.extra.plus(setter!!.extra.mergeAdditionalModifiers(listOf(ExtraModifiers.STATIC))) else setter!!.extra ) - ) // TODO: if (isTopLevel) -> static; visibility -> always? public + ) internal fun Function.asJava(containingClassName: String): Function { @@ -134,18 +147,38 @@ internal fun Class.asJava(): Class = copy( it.asJava(name) }, properties = properties.map { it.asJava() }, - classlikes = classlikes.map { it.asJava() } + classlikes = classlikes.map { it.asJava() }, + generics = generics.map { it.asJava() }, + supertypes = supertypes.copy( + map = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + ) ) // TODO: if modifier is from Kotlin, then Empty -> Final I think, Java ones stay the same +private fun TypeParameter.asJava(): TypeParameter = copy( + dri = dri.possiblyAsJava(), + bounds = bounds.map { it.asJava() } +) + +private fun Bound.asJava(): Bound = when (this) { + is TypeConstructor -> copy( + dri = dri.possiblyAsJava() + ) + is Nullable -> copy( + inner = inner.asJava() + ) + else -> this +} + internal fun Enum.asJava(): Enum = copy( constructors = constructors.map { it.asJava(name) }, functions = (functions + properties.map { it.getter } + properties.map { it.setter }).filterNotNull().map { - it.asJava( - name - ) + it.asJava(name) }, properties = properties.map { it.asJava() }, - classlikes = classlikes.map { it.asJava() } + classlikes = classlikes.map { it.asJava() }, + supertypes = supertypes.copy( + map = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + ) // , entries = entries.map { it.asJava() } ) // TODO: if modifier is from Kotlin, then Empty -> Final I think, Java ones stay the same @@ -173,7 +206,10 @@ internal fun Object.asJava(): Object = copy( platformData = platformData, receiver = null ), - classlikes = classlikes.map { it.asJava() } + classlikes = classlikes.map { it.asJava() }, + supertypes = supertypes.copy( + map = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + ) ) internal fun Interface.asJava(): Interface = copy( @@ -181,7 +217,11 @@ internal fun Interface.asJava(): Interface = copy( .filterNotNull() .map { it.asJava(name) }, properties = emptyList(), - classlikes = classlikes.map { it.asJava() } // TODO: public static final class DefaultImpls with impls for methods (killme please) + classlikes = classlikes.map { it.asJava() }, // TODO: public static final class DefaultImpls with impls for methods + generics = generics.map { it.asJava() }, + supertypes = supertypes.copy( + map = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + ) ) internal fun Annotation.asJava(): Annotation = copy( @@ -215,8 +255,11 @@ internal fun TypeWrapper.getAsType(classId: ClassId, fqName: String, top: Boolea ) } +private fun DRI.partialFqName() = packageName?.let { "$it." } + classNames +private fun DRI.possiblyAsJava() = this.partialFqName().mapToJava()?.toDRI(this) ?: this + internal fun TypeWrapper.asJava(top: Boolean = true): TypeWrapper = constructorFqName - ?.takeUnless { it.endsWith(".Unit") } // TODO: ??? +// ?.takeUnless { it.endsWith(".Unit") } // TODO: ??? ?.let { fqName -> fqName.mapToJava()?.let { getAsType(it, fqName, top) } } ?: this @@ -231,6 +274,12 @@ internal fun ClassId.toDRI(dri: DRI?): DRI = DRI( target = null ) +private fun PropertyContainer<out Documentable>.mergeAdditionalModifiers(second: List<ExtraModifiers>) = + this[AdditionalModifiers.AdditionalKey]?.squash(AdditionalModifiers(second)) ?: AdditionalModifiers(second) + +private fun AdditionalModifiers.squash(second: AdditionalModifiers) = + AdditionalModifiers((content + second.content).distinct()) + internal fun ClassId.classNames(): String = shortClassName.identifier + (outerClassId?.classNames()?.let { ".$it" } ?: "") |