aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Doległo <kamilok1965@interia.pl>2020-03-01 21:26:13 +0100
committerKamil Doległo <kamilok1965@users.noreply.github.com>2020-03-04 18:00:19 +0100
commite4044ec67ad90041b02bb84c4b966ffeac537617 (patch)
treea06e82ad218737771b7a6381537a98ba00c94eaf
parentcf0c5043887b1dd38808b0fc12bd8700c9f3b6ba (diff)
downloaddokka-e4044ec67ad90041b02bb84c4b966ffeac537617.tar.gz
dokka-e4044ec67ad90041b02bb84c4b966ffeac537617.tar.bz2
dokka-e4044ec67ad90041b02bb84c4b966ffeac537617.zip
Add initial version of Kotlin as Java plugin
-rw-r--r--plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt2
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt112
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentableTranslator.kt76
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt81
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt73
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt47
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt150
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt246
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt11
-rw-r--r--settings.gradle.kts2
10 files changed, 380 insertions, 420 deletions
diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
index 117dd552..f30ffa00 100644
--- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt
@@ -58,7 +58,7 @@ data class DRIWithPlatformInfo(
fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, PlatformDependent.empty())
-open class DokkaDescriptorVisitor( // TODO: close this class and make it private together with DRIWithPlatformInfo
+private class DokkaDescriptorVisitor( // TODO: close this class and make it private together with DRIWithPlatformInfo
private val platformData: PlatformData,
private val resolutionFacade: DokkaResolutionFacade
) : DeclarationDescriptorVisitorEmptyBodies<Documentable, DRIWithPlatformInfo>() {
diff --git a/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt
new file mode 100644
index 00000000..526546f2
--- /dev/null
+++ b/plugins/kotlin-as-java/src/main/kotlin/JavaSignatureProvider.kt
@@ -0,0 +1,112 @@
+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
+import org.jetbrains.dokka.model.Enum
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.pages.ContentKind
+import org.jetbrains.dokka.pages.ContentNode
+import org.jetbrains.dokka.pages.PlatformData
+import org.jetbrains.dokka.utilities.DokkaLogger
+
+class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider {
+ private val contentBuilder = PageContentBuilder(ctcc, logger)
+
+ override fun signature(documentable: Documentable): List<ContentNode> = when (documentable) {
+ is Function -> signature(documentable)
+ is Classlike -> 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, platform: PlatformData) = contentBuilder.contentFor(c, ContentKind.Symbol) {
+ text(c.visibility[platform]?.externalDisplayName ?: "")
+ if (c is Class) {
+ text(c.modifier.toString())
+ }
+ when (c) {
+ 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 WithSupertypes) {
+ list(c.supertypes.getValue(platform), prefix = " : ") {
+ link(it.sureClassNames, it)
+ }
+ }
+ }
+
+ private fun signature(f: Function, platform: PlatformData) = contentBuilder.contentFor(f, ContentKind.Symbol) {
+ text(f.visibility[platform]?.externalDisplayName ?: "")
+ text(f.modifier.toString())
+ val returnType = f.type
+ if (!f.isConstructor && returnType.constructorFqName != Unit::class.qualifiedName) {
+ text(": ")
+ type(returnType)
+ }
+ text(" ")
+ link(f.name, f.dri)
+ val generics = f.generics.filterOnPlatform(platform)
+ if (generics.isNotEmpty()) {
+ text("<")
+ generics.forEach {
+ signature(it)
+ }
+ text(">")
+ }
+ text("(")
+ list(listOfNotNull(f.receiver) + f.parameters.filterOnPlatform(platform)) {
+ type(it.type)
+ text(" ")
+ link(it.name!!, it.dri)
+ text(", ")
+ }
+ text(")")
+ }
+
+ private fun signature(t: TypeParameter) = contentBuilder.contentFor(t, ContentKind.Symbol) {
+ link(t.name, t.dri)
+ if (t.bounds.isNotEmpty()) {
+ text("<")
+ t.bounds.forEach {
+ signature(it, t.dri, t.platformData)
+ }
+ text(">")
+ }
+ }
+
+ 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()) {
+ link(p.dri.classNames.orEmpty(), p.dri)
+ }.children + p.projections.flatMap { signature(it, dri, platforms) }
+
+ is Variance -> contentBuilder.contentFor(dri, platforms.toSet()) {
+ text(p.kind.toString() + " ")
+ }.children + signature(p.inner, dri, platforms)
+
+ is Star -> contentBuilder.contentFor(dri, platforms.toSet()) { text("*") }.children
+
+ is Nullable -> signature(p.inner, dri, platforms) + contentBuilder.contentFor(
+ dri,
+ platforms.toSet()
+ ) { text("?") }.children
+ }
+
+ private fun <T : Documentable> Collection<T>.filterOnPlatform(platformData: PlatformData) =
+ this.filter { it.platformData.contains(platformData) }
+} \ No newline at end of file
diff --git a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentableTranslator.kt b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentableTranslator.kt
deleted file mode 100644
index 3b615dcb..00000000
--- a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentableTranslator.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-package org.jetbrains.dokka.kotlinAsJava
-
-import org.jetbrains.dokka.analysis.DokkaResolutionFacade
-import org.jetbrains.dokka.base.translators.descriptors.DRIWithPlatformInfo
-import org.jetbrains.dokka.base.translators.descriptors.DokkaDescriptorVisitor
-import org.jetbrains.dokka.base.translators.descriptors.withEmptyInfo
-import org.jetbrains.dokka.links.Callable
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.links.withClass
-import org.jetbrains.dokka.model.*
-import org.jetbrains.dokka.model.Function
-import org.jetbrains.dokka.pages.PlatformData
-import org.jetbrains.dokka.plugability.DokkaContext
-import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentableTranslator
-import org.jetbrains.kotlin.descriptors.*
-
-class KotlinAsJavaDescriptorToDocumentableTranslator(
- private val context: DokkaContext
-) : DescriptorToDocumentableTranslator {
- override fun invoke(
- moduleName: String,
- packageFragments: Iterable<PackageFragmentDescriptor>,
- platformData: PlatformData
- ): Module =
- KotlinAsJavaDokkaDescriptorVisitor(platformData, context.platforms[platformData]?.facade!!).run {
- packageFragments.map { visitPackageFragmentDescriptor(it, DRI.topLevel.withEmptyInfo()) }
- }.let { Module(moduleName, it) }
-}
-
-class KotlinAsJavaDokkaDescriptorVisitor(
- platformData: PlatformData,
- resolutionFacade: DokkaResolutionFacade
-) : DokkaDescriptorVisitor(platformData, resolutionFacade) {
- override fun visitPackageFragmentDescriptor(
- descriptor: PackageFragmentDescriptor,
- parent: DRIWithPlatformInfo
- ): Package {
- val dri = DRI(packageName = descriptor.fqName.asString())
- DescriptorCache.add(dri, descriptor)
- return super.visitPackageFragmentDescriptor(descriptor, parent)
- }
-
- override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Classlike {
- val dri = parent.dri.withClass(descriptor.name.asString())
- DescriptorCache.add(dri, descriptor)
- return super.visitClassDescriptor(descriptor, parent)
- }
-
- override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): Property {
- val dri = parent.dri.copy(callable = Callable.from(descriptor))
- DescriptorCache.add(dri, descriptor)
- return super.visitPropertyDescriptor(descriptor, parent)
- }
-
- override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): Function {
- val dri = parent.dri.copy(callable = Callable.from(descriptor))
- DescriptorCache.add(dri, descriptor)
- return super.visitFunctionDescriptor(descriptor, parent)
- }
-
- override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): Function {
- val dri = parent.dri.copy(callable = Callable.from(descriptor))
- DescriptorCache.add(dri, descriptor)
- return super.visitConstructorDescriptor(descriptor, parent)
- }
-
- override fun visitPropertyAccessorDescriptor(
- descriptor: PropertyAccessorDescriptor,
- propertyDescriptor: PropertyDescriptor,
- parent: DRI
- ): Function {
- val dri = parent.copy(callable = Callable.from(descriptor))
- DescriptorCache.add(dri, descriptor)
- return super.visitPropertyAccessorDescriptor(descriptor, propertyDescriptor, parent)
- }
-} \ No newline at end of file
diff --git a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt
deleted file mode 100644
index ef6f9c33..00000000
--- a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.jetbrains.dokka.kotlinAsJava
-
-import org.jetbrains.dokka.base.translators.documentables.DefaultPageBuilder
-import org.jetbrains.dokka.base.translators.documentables.RootContentBuilder
-import org.jetbrains.dokka.kotlinAsJava.conversions.asJava
-import org.jetbrains.dokka.kotlinAsJava.conversions.asStatic
-import org.jetbrains.dokka.kotlinAsJava.conversions.withClass
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.links.withClass
-import org.jetbrains.dokka.model.*
-import org.jetbrains.dokka.model.Enum
-import org.jetbrains.dokka.model.Function
-import org.jetbrains.dokka.pages.*
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.Visibilities
-import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
-
-fun DeclarationDescriptor.sourceLocation(): String? = this.findPsi()?.containingFile?.virtualFile?.path
-fun <T : Documentable> List<T>.groupedByLocation(): Map<String, List<T>> =
- this.map { DescriptorCache[it.dri]?.sourceLocation() to it }
- .filter { it.first != null }.groupBy({ (location, _) ->
- location!!.let { it.split("/").last().split(".").first() + "Kt" }
- }) { it.second }
-
-fun PlatformInfo.toClassPlatformInfo(inherited: List<DRI> = emptyList()) =
- ClassPlatformInfo(this, emptyList())
-
-class KotlinAsJavaPageBuilder(rootContentGroup: RootContentBuilder) : DefaultPageBuilder(rootContentGroup) {
-
- override fun pageForModule(m: Module): ModulePageNode =
- ModulePageNode(m.name.ifEmpty { "root" }, contentForModule(m), m, m.packages.map { pageForPackage(it) })
-
- data class FunsAndProps(val key: String, val funs: List<Function>, val props: List<Property>)
-
- override fun pageForPackage(p: Package): PackagePageNode {
-
- val funs = p.functions.groupedByLocation()
-
- val props = p.properties.groupedByLocation()
-
- val zipped = (funs.keys + props.keys)
- .map { k -> FunsAndProps(k, funs[k].orEmpty(), props[k].orEmpty()) }
-
- val classes = (p.classlikes + zipped.map { (key, funs, props) ->
- val dri = p.dri.withClass(key)
- val actual =
- (funs.flatMap { it.actual } + props.flatMap { it.actual }).distinct().map { it.toClassPlatformInfo() }
- Class(
- dri = dri,
- name = key,
- kind = KotlinClassKindTypes.CLASS,
- constructors = emptyList(),
- functions = funs.map { it.withClass(key, dri).asStatic() },
- properties = props.map { it.withClass(key, dri) },
- classlikes = emptyList(),
- actual = actual,
- expected = null,
- visibility = p.platformData.map { it to Visibilities.PUBLIC }.toMap()
- )
- }).map { it.asJava() }
-
- return PackagePageNode(
- p.name, contentForPackage(p, classes), setOf(p.dri), p,
- classes.map(::pageForClasslike)
- )
- }
-
- private fun contentForPackage(p: Package, nClasses: List<Classlike>) = group(p) {
- header(1) { text("Package ${p.name}") }
- block("Types", 2, ContentKind.Properties, nClasses, p.platformData) {
- link(it.name, it.dri)
- text(it.briefDocTagString)
- }
- }
-
- override fun contentForClasslike(c: Classlike): ContentGroup = when (c) {
- is Class -> contentForClass(c)
- is Enum -> contentForEnum(c)
- else -> throw IllegalStateException("$c should not be present here")
- }
-} \ No newline at end of file
diff --git a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt
deleted file mode 100644
index a8ec7126..00000000
--- a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.jetbrains.dokka.kotlinAsJava
-
-import org.jetbrains.dokka.base.translators.documentables.DefaultPageContentBuilder
-import org.jetbrains.dokka.base.translators.documentables.PageContentBuilderFunction
-import org.jetbrains.dokka.base.translators.documentables.type
-import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.Function
-import org.jetbrains.dokka.model.JavaTypeWrapper
-import org.jetbrains.dokka.pages.*
-import org.jetbrains.dokka.utilities.DokkaLogger
-
-class KotlinAsJavaPageContentBuilder(
- dri: Set<DRI>,
- platformData: Set<PlatformData>,
- kind: Kind,
- commentsConverter: CommentsToContentConverter,
- logger: DokkaLogger,
- styles: Set<Style> = emptySet(),
- extras: Set<Extra> = emptySet()
-) : DefaultPageContentBuilder(dri, platformData, kind, commentsConverter, logger, styles, extras) {
-
- override fun signature(f: Function) = signature(f) {
-
- // DokkaConsoleLogger.info("KotlinAsJavaSignature")
- val returnType = f.returnType
- if (!f.isConstructor) {
- if (returnType != null &&
- returnType.constructorFqName != Unit::class.qualifiedName
- ) {
- if ((returnType as? JavaTypeWrapper)?.isPrimitive == true)
- text(returnType.constructorFqName ?: "")
- else
- type(returnType)
- text(" ")
- } else text("void ")
-
- }
-
- link(f.name, f.dri)
- text("(")
- val params = listOfNotNull(f.receiver) + f.parameters
- list(params) {
- if ((it.type as? JavaTypeWrapper)?.isPrimitive == true)
- text(it.type.constructorFqName ?: "")
- else
- type(it.type)
-
- text(" ")
- link(it.name ?: "receiver", it.dri)
- }
- text(")")
- }
-
- override fun group(
- dri: Set<DRI>,
- platformData: Set<PlatformData>,
- kind: Kind,
- block: PageContentBuilderFunction
- ): ContentGroup = group(dri, platformData, kind, commentsConverter, logger, block)
-
- companion object {
- fun group(
- dri: Set<DRI>,
- platformData: Set<PlatformData>,
- kind: Kind,
- commentsConverter: CommentsToContentConverter,
- logger: DokkaLogger,
- block: PageContentBuilderFunction
- ): ContentGroup =
- KotlinAsJavaPageContentBuilder(dri, platformData, kind, commentsConverter, logger).apply(block).build()
- }
-} \ No newline at end of file
diff --git a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt
index 1a6bc0db..0ca278ce 100644
--- a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt
+++ b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt
@@ -1,47 +1,18 @@
-package org.jetbrains.dokka.kotlinAsJava
-
+package org.jetbrains.dokka.kotlinAsJava
import org.jetbrains.dokka.CoreExtensions
import org.jetbrains.dokka.base.DokkaBase
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.Module
-import org.jetbrains.dokka.pages.ModulePageNode
-import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.kotlinAsJava.transformers.KotlinAsJavaDocumentableTransformer
import org.jetbrains.dokka.plugability.DokkaPlugin
-import org.jetbrains.dokka.plugability.plugin
-import org.jetbrains.dokka.plugability.querySingle
-import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
class KotlinAsJavaPlugin : DokkaPlugin() {
- val kotlinAsJavaDescriptorToDocumentableTranslator by extending {
- CoreExtensions.descriptorToDocumentableTranslator providing ::KotlinAsJavaDescriptorToDocumentableTranslator
- }
val kotlinAsJavaDocumentableToPageTranslator by extending {
- CoreExtensions.documentableToPageTranslator providing ::KotlinAsJavaDocumentationToPageTranslator
+ CoreExtensions.documentableTransformer with KotlinAsJavaDocumentableTransformer()
+ }
+ val javaSignatureProvider by extending {
+ val dokkaBasePlugin = plugin<DokkaBase>()
+ dokkaBasePlugin.signatureProvider providing { ctx ->
+ JavaSignatureProvider(ctx.single(dokkaBasePlugin.commentsToContentConverter), ctx.logger)
+ }
}
-}
-
-object DescriptorCache {
- private val cache: HashMap<DRI, DeclarationDescriptor> = HashMap()
-
- fun add(dri: DRI, descriptor: DeclarationDescriptor): Boolean = cache.putIfAbsent(dri, descriptor) == null
- operator fun get(dri: DRI): DeclarationDescriptor? = cache[dri]
-}
-
-class KotlinAsJavaDocumentationToPageTranslator(
- private val context: DokkaContext
-) : DocumentableToPageTranslator {
- override fun invoke(module: Module): ModulePageNode =
- KotlinAsJavaPageBuilder { node, kind, operation ->
- KotlinAsJavaPageContentBuilder.group(
- setOf(node.dri),
- node.platformData,
- kind,
- context.plugin<DokkaBase>().querySingle { commentsToContentConverter },
- context.logger,
- operation
- )
- }.pageForModule(module)
-
} \ No newline at end of file
diff --git a/plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt b/plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt
deleted file mode 100644
index 7b0495e9..00000000
--- a/plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt
+++ /dev/null
@@ -1,150 +0,0 @@
-package org.jetbrains.dokka.kotlinAsJava.conversions
-
-import org.jetbrains.dokka.kotlinAsJava.DescriptorCache
-import org.jetbrains.dokka.links.*
-import org.jetbrains.dokka.model.*
-import org.jetbrains.dokka.model.Function
-import org.jetbrains.dokka.model.Enum
-import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
-import org.jetbrains.kotlin.descriptors.FunctionDescriptor
-import org.jetbrains.kotlin.descriptors.PropertyDescriptor
-import org.jetbrains.kotlin.name.ClassId
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
-
-fun String.getAsPrimitive(): JvmPrimitiveType? = org.jetbrains.kotlin.builtins.PrimitiveType.values()
- .find { it.typeFqName.asString() == this }
- ?.let { JvmPrimitiveType.get(it) }
-
-fun TypeWrapper.getAsType(classId: ClassId, fqName: String, top: Boolean): TypeWrapper {
- val fqNameSplitted = fqName.takeIf { top }?.getAsPrimitive()?.name?.toLowerCase()
- ?.let { listOf(it) } ?: classId.asString().split("/")
- return JavaTypeWrapper(
- fqNameSplitted,
- arguments.mapNotNull { it.asJava(false) },
- classId.toDRI(dri),
- fqNameSplitted.last()[0].isLowerCase()
- )
-}
-
-fun TypeWrapper?.asJava(top: Boolean = true): TypeWrapper? = this?.constructorFqName
- ?.takeUnless { it.endsWith(".Unit") }
- ?.let { fqName ->
- fqName.mapToJava()
- ?.let { getAsType(it, fqName, top) } ?: this
- }
-
-fun Classlike.asJava(): Classlike = when {
- this is Class -> this.asJava()
- this is Enum -> this.asJava()
- this is EnumEntry -> this
- else -> throw IllegalArgumentException("$this shouldn't be here")
-}
-
-fun Class.asJava(): Class = Class(
- dri, name, kind,
- constructors.map { it.asJava() },
- (functions + properties.flatMap { it.accessors }).map { it.asJava() },
- properties, classlikes.mapNotNull { (it as? Class)?.asJava() }, expected, actual, extra, visibility
-)
-
-fun Enum.asJava(): Enum = Enum(
- dri = dri,
- name = name,
- entries = entries.mapNotNull { it.asJava() as? EnumEntry },
- constructors = constructors.map(Function::asJava),
- functions = (functions + properties.flatMap { it.accessors }).map(Function::asJava),
- properties = properties,
- classlikes = classlikes.map(Classlike::asJava),
- expected = expected,
- actual = actual,
- extra = extra,
- visibility = visibility
-)
-
-fun tcAsJava(tc: TypeConstructor): TypeReference =
- tc.fullyQualifiedName.mapToJava()
- ?.let {
- tc.copy(
- fullyQualifiedName = it.asString(),
- params = tc.params.map { it.asJava() }
- )
- } ?: tc
-
-fun tpAsJava(tp: TypeParam): TypeReference =
- tp.copy(bounds = tp.bounds.map { it.asJava() })
-
-fun TypeReference.asJava(): TypeReference = when (this) {
- is TypeConstructor -> tcAsJava(this)
- is TypeParam -> tpAsJava(this)
- else -> this
-}
-
-fun Callable.asJava(): Callable = copy(params = params.mapNotNull { (it as? TypeConstructor)?.asJava() })
-
-
-fun Parameter.asJava(): Parameter = Parameter(
- dri.copy(callable = dri.callable?.asJava()),
- name,
- type.asJava()!!,
- expected,
- actual,
- extra
-)
-
-fun Function.asJava(): Function {
- val newName = when {
- isConstructor -> "init"
- else -> name
- }
- return Function(
- dri.copy(callable = dri.callable?.asJava()),
- newName,
- returnType.asJava(),
- isConstructor,
- receiver,
- parameters.map { it.asJava() },
- expected,
- actual,
- extra,
- visibility
- )
-}
-
-private fun String.mapToJava(): ClassId? =
- JavaToKotlinClassMap.mapKotlinToJava(FqName(this).toUnsafe())
-
-fun ClassId.toDRI(dri: DRI?): DRI = DRI(
- packageName = packageFqName.asString(),
- classNames = classNames(),
- callable = dri?.callable?.asJava(),
- extra = null,
- target = null
-)
-
-fun ClassId.classNames(): String =
- shortClassName.identifier + (outerClassId?.classNames()?.let { ".$it" } ?: "")
-
-fun Function.asStatic(): Function = also { it.extra.add(STATIC) }
-
-fun Property.withClass(className: String, dri: DRI): Property {
- val nDri = dri.withClass(className).copy(
- callable = getDescriptor()?.let { Callable.from(it) }
- )
- return Property(
- nDri, name, receiver, expected, actual, extra, accessors, visibility
- )
-}
-
-fun Function.withClass(className: String, dri: DRI): Function {
- val nDri = dri.withClass(className).copy(
- callable = getDescriptor()?.let { Callable.from(it) }
- )
- return Function(
- nDri, name, returnType, isConstructor, receiver, parameters, expected, actual, extra, visibility
- )
-}
-
-fun Function.getDescriptor(): FunctionDescriptor? = DescriptorCache[dri].let { it as? FunctionDescriptor }
-
-fun Property.getDescriptor(): PropertyDescriptor? = DescriptorCache[dri].let { it as? PropertyDescriptor }
diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt
new file mode 100644
index 00000000..19c4ef19
--- /dev/null
+++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt
@@ -0,0 +1,246 @@
+package org.jetbrains.dokka.kotlinAsJava.converters
+
+import org.jetbrains.dokka.links.Callable
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.links.withClass
+import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.Annotation
+import org.jetbrains.dokka.model.Enum
+import org.jetbrains.dokka.model.Function
+import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
+import org.jetbrains.kotlin.name.ClassId
+import org.jetbrains.kotlin.name.FqName
+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
+ }) { it.second }
+
+internal fun Package.asJava(): Package {
+ @Suppress("UNCHECKED_CAST")
+ val syntheticClasses = ((properties + functions) as List<WithExpectActual>)
+ .groupedByLocation()
+ .map { (syntheticClassName, nodes) ->
+ Class(
+ dri = dri.withClass(syntheticClassName),
+ name = syntheticClassName,
+ properties = nodes.filterIsInstance<Property>().map { it.asJava() },
+ constructors = emptyList(),
+ functions = (
+ nodes.filterIsInstance<Property>().map { it.javaAccessors() } +
+ nodes.filterIsInstance<Function>().map { it.asJava(syntheticClassName) }
+ ) as List<Function>, // TODO: methods are static and receiver is a param
+ classlikes = emptyList(),
+ sources = PlatformDependent.empty(),
+ visibility = PlatformDependent.empty(), // TODO: fix this with the new visibility model -> public
+ companion = null,
+ generics = emptyList(),
+ supertypes = PlatformDependent.empty(),
+ documentation = PlatformDependent.empty(),
+ modifier = WithAbstraction.Modifier.Final,
+ platformData = platformData,
+ extra = PropertyContainer.empty()
+ )
+ }
+
+ return copy(
+ functions = emptyList(),
+ properties = emptyList(),
+ classlikes = classlikes.map { it.asJava() } + syntheticClasses,
+ packages = packages.map { it.asJava() }
+ )
+}
+
+internal fun Property.asJava(isTopLevel: Boolean = false, relocateToClass: String? = null) =
+ copy(
+ dri = if (relocateToClass.isNullOrBlank()) {
+ dri
+ } else {
+ dri.withClass(relocateToClass)
+ },
+ modifier = if (setter == null) {
+ WithAbstraction.Modifier.Final
+ } else {
+ WithAbstraction.Modifier.Empty
+ },
+ 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
+
+internal fun Property.javaAccessors(isTopLevel: Boolean = false, relocateToClass: String? = null): List<Function> =
+ listOfNotNull(
+ getter?.copy(
+ dri = if (relocateToClass.isNullOrBlank()) {
+ dri
+ } else {
+ dri.withClass(relocateToClass)
+ },
+ name = "get" + name.capitalize(),
+ modifier = if (setter == null) {
+ WithAbstraction.Modifier.Final
+ } else {
+ WithAbstraction.Modifier.Empty
+ },
+ type = type.asJava(isTopLevel) // TODO: check,
+ ),
+ setter?.copy(
+ dri = if (relocateToClass.isNullOrBlank()) {
+ dri
+ } else {
+ dri.withClass(relocateToClass)
+ },
+ name = "set" + name.capitalize(),
+ modifier = if (setter == null) {
+ WithAbstraction.Modifier.Final
+ } else {
+ WithAbstraction.Modifier.Empty
+ },
+ type = type.asJava(isTopLevel) // TODO: check,
+ )
+ ) // TODO: if (isTopLevel) -> static; visibility -> always? public
+
+
+internal fun Function.asJava(containingClassName: String): Function {
+ val newName = when {
+ isConstructor -> containingClassName
+ else -> name
+ }
+ return copy(
+// dri = dri.copy(callable = dri.callable?.asJava()),
+ name = newName,
+ type = type.asJava(),
+ parameters = parameters.map { it.asJava() }
+ ) // TODO: should receiver be the first param?
+}
+
+internal fun Classlike.asJava(): Classlike = when (this) {
+ is Class -> asJava()
+ is Enum -> asJava()
+ is Annotation -> asJava()
+ is Object -> asJava()
+ is Interface -> asJava()
+ else -> throw IllegalArgumentException("$this shouldn't be here")
+}
+
+internal fun Class.asJava(): Class = copy(
+ constructors = constructors.map { it.asJava(name) },
+ functions = (functions + properties.map { it.getter } + properties.map { it.setter }).filterNotNull().map {
+ it.asJava(
+ name
+ )
+ },
+ properties = properties.map { it.asJava() },
+ classlikes = classlikes.map { it.asJava() }
+) // TODO: if modifier is from Kotlin, then Empty -> Final I think, Java ones stay the same
+
+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
+ )
+ },
+ properties = properties.map { it.asJava() },
+ classlikes = classlikes.map { it.asJava() }
+// , entries = entries.map { it.asJava() }
+) // TODO: if modifier is from Kotlin, then Empty -> Final I think, Java ones stay the same
+
+internal fun Object.asJava(): Object = copy(
+ functions = (functions + properties.map { it.getter } + properties.map { it.setter })
+ .filterNotNull()
+ .map { it.asJava(name.orEmpty()) },
+ properties = properties.map { it.asJava() } +
+ Property(
+ name = "INSTANCE",
+ modifier = WithAbstraction.Modifier.Final,
+ dri = dri.copy(callable = Callable("INSTANCE", null, emptyList())),
+ documentation = PlatformDependent.empty(),
+ sources = PlatformDependent.empty(),
+ visibility = PlatformDependent.empty(), // TODO: public and static
+ type = JavaTypeWrapper(
+ dri.packageName?.split(".").orEmpty() +
+ dri.classNames?.split(".").orEmpty(),
+ emptyList(),
+ dri,
+ false
+ ),
+ setter = null,
+ getter = null,
+ platformData = platformData,
+ receiver = null
+ ),
+ classlikes = classlikes.map { it.asJava() }
+)
+
+internal fun Interface.asJava(): Interface = copy(
+ functions = (functions + properties.map { it.getter } + properties.map { it.setter })
+ .filterNotNull()
+ .map { it.asJava(name) },
+ properties = emptyList(),
+ classlikes = classlikes.map { it.asJava() } // TODO: public static final class DefaultImpls with impls for methods (killme please)
+)
+
+internal fun Annotation.asJava(): Annotation = copy(
+ properties = properties.map { it.asJava() },
+ constructors = emptyList(),
+ classlikes = classlikes.map { it.asJava() }
+) // TODO investigate if annotation class can have methods and properties not from constructor
+
+internal fun Parameter.asJava(): Parameter = copy(
+ type = type.asJava()
+)
+
+internal fun String.getAsPrimitive(): JvmPrimitiveType? = org.jetbrains.kotlin.builtins.PrimitiveType.values()
+ .find { it.typeFqName.asString() == this }
+ ?.let { JvmPrimitiveType.get(it) }
+
+internal fun TypeWrapper.getAsType(classId: ClassId, fqName: String, top: Boolean): TypeWrapper {
+ val fqNameSplit = fqName
+ .takeIf { top }
+ ?.getAsPrimitive()
+ ?.name?.toLowerCase()
+ ?.let(::listOf)
+ ?: classId.asString().split("/")
+
+ return JavaTypeWrapper(
+ fqNameSplit,
+ arguments.map { it.asJava(false) },
+ classId.toDRI(dri),
+ fqNameSplit.last()[0].isLowerCase()
+ )
+}
+
+internal fun TypeWrapper.asJava(top: Boolean = true): TypeWrapper = constructorFqName
+ ?.takeUnless { it.endsWith(".Unit") } // TODO: ???
+ ?.let { fqName -> fqName.mapToJava()?.let { getAsType(it, fqName, top) } } ?: this
+
+
+private fun String.mapToJava(): ClassId? =
+ JavaToKotlinClassMap.mapKotlinToJava(FqName(this).toUnsafe())
+
+internal fun ClassId.toDRI(dri: DRI?): DRI = DRI(
+ packageName = packageFqName.asString(),
+ classNames = classNames(),
+ callable = dri?.callable,//?.asJava(), TODO: ????
+ extra = null,
+ target = null
+)
+
+internal fun ClassId.classNames(): String =
+ shortClassName.identifier + (outerClassId?.classNames()?.let { ".$it" } ?: "")
+
+//fun TypeConstructor.asJava(): TypeReference =
+// fullyQualifiedName.mapToJava()
+// ?.let { tc.copy(fullyQualifiedName = it.asString(), params = tc.params.map { it.asJava() }) } ?: tc
+
+//fun TypeParam.asJava(): TypeReference = copy(bounds = bounds.map { it.asJava() })
+
+//fun TypeReference.asJava(): TypeReference = when (this) {
+// is TypeConstructor -> asJava()
+// is TypeParam -> asJava()
+// else -> this
+//} \ No newline at end of file
diff --git a/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt b/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt
new file mode 100644
index 00000000..8f51e105
--- /dev/null
+++ b/plugins/kotlin-as-java/src/main/kotlin/transformers/KotlinAsJavaDocumentableTransformer.kt
@@ -0,0 +1,11 @@
+package org.jetbrains.dokka.kotlinAsJava.transformers
+
+import org.jetbrains.dokka.kotlinAsJava.converters.asJava
+import org.jetbrains.dokka.model.Module
+import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer
+
+class KotlinAsJavaDocumentableTransformer : DocumentableTransformer {
+ override fun invoke(original: Module, context: DokkaContext): Module =
+ original.copy(packages = original.packages.map { it.asJava() })
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 04ce2baf..263a1b09 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -8,7 +8,7 @@ include("runners:cli")
include("runners:maven-plugin")
include("plugins:base")
include("plugins:mathjax")
-//include("plugins:kotlin-as-java")
+include("plugins:kotlin-as-java")
include("integration-tests:gradle-integration-tests")
pluginManagement {