From 50e711d24b517bc93c37d89f258c9dafaa038ad1 Mon Sep 17 00:00:00 2001 From: Szymon Świstun Date: Mon, 20 Jan 2020 14:55:42 +0100 Subject: kotlin-as-java plugin --- plugins/kotlin-as-java/build.gradle.kts | 17 +++ ...linAsJavaDescriptorToDocumentationTranslator.kt | 75 ++++++++++ .../src/main/kotlin/KotlinAsJavaPageBuilder.kt | 68 ++++++++++ .../main/kotlin/KotlinAsJavaPageContentBuilder.kt | 65 +++++++++ .../src/main/kotlin/KotlinAsJavaPlugin.kt | 39 ++++++ .../src/main/kotlin/KotlinToJVMResolver.kt | 151 +++++++++++++++++++++ .../org.jetbrains.dokka.plugability.DokkaPlugin | 1 + .../src/test/kotlin/KotlinAsJavaPluginTest.kt | 98 +++++++++++++ 8 files changed, 514 insertions(+) create mode 100644 plugins/kotlin-as-java/build.gradle.kts create mode 100644 plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentationTranslator.kt create mode 100644 plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt create mode 100644 plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt create mode 100644 plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt create mode 100644 plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt create mode 100644 plugins/kotlin-as-java/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin create mode 100644 plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt (limited to 'plugins/kotlin-as-java') diff --git a/plugins/kotlin-as-java/build.gradle.kts b/plugins/kotlin-as-java/build.gradle.kts new file mode 100644 index 00000000..5d04060f --- /dev/null +++ b/plugins/kotlin-as-java/build.gradle.kts @@ -0,0 +1,17 @@ +publishing { + publications { + register("kotlin-as-java-plugin") { + artifactId = "kotlin-as-java-plugin" + from(components["java"]) + } + } +} + +dependencies { + implementation(kotlin("stdlib-jdk8")) + compileOnly(project(":coreDependencies", configuration = "shadow")) + testImplementation(project(":core")) + testImplementation(project(":coreDependencies", configuration = "shadow")) + testImplementation(project(":testApi")) + testImplementation("junit:junit:4.13") +} \ No newline at end of file diff --git a/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentationTranslator.kt b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentationTranslator.kt new file mode 100644 index 00000000..9c4ee9aa --- /dev/null +++ b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentationTranslator.kt @@ -0,0 +1,75 @@ +package org.jetbrains.dokka.kotlinAsJava + +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +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.DRIWithPlatformInfo +import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentationTranslator +import org.jetbrains.dokka.transformers.descriptors.DokkaDescriptorVisitor +import org.jetbrains.dokka.transformers.descriptors.withEmptyInfo +import org.jetbrains.kotlin.descriptors.* + +object KotlinAsJavaDescriptorToDocumentationTranslator : DescriptorToDocumentationTranslator { + override fun invoke( + moduleName: String, + packageFragments: Iterable, + platformData: PlatformData, + context: DokkaContext + ): 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 new file mode 100644 index 00000000..67a3ee86 --- /dev/null +++ b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt @@ -0,0 +1,68 @@ +package org.jetbrains.dokka.kotlinAsJava + +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.withClass +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.Enum +import org.jetbrains.dokka.model.doc.TagWrapper +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.transformers.descriptors.KotlinClassKindTypes +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 List.groupedByLocation(): Map> = + this.map { DescriptorCache[it.dri]?.sourceLocation() to it } + .filter { it.first != null }.groupBy({ (location, _) -> + location!!.let { it.split("/").last().split(".").first() + "Kt" } + }) { it.second } + +class KotlinAsJavaPageBuilder(rootContentGroup: RootContentBuilder) : DefaultPageBuilder(rootContentGroup) { + + data class FunsAndProps(val key: String, val funs: List, val props: List) + + 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) + 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 = emptyList(), + 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) = group(p) { + header(1) { text("Package ${p.name}") } + block("Types", 2, ContentKind.Properties, nClasses, p.platformData) { + link(it.name, it.dri) + text(it.briefDocTagString) + } + } + + private fun TagWrapper.toHeaderString() = this.javaClass.toGenericString().split('.').last() +} \ 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 new file mode 100644 index 00000000..65925fb2 --- /dev/null +++ b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt @@ -0,0 +1,65 @@ +package org.jetbrains.dokka.kotlinAsJava + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.TypeWrapper +import org.jetbrains.dokka.model.doc.DocTag +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.transformers.psi.JavaTypeWrapper +import org.jetbrains.dokka.utilities.DokkaLogger + +class KotlinAsJavaPageContentBuilder( + private val dri: Set, + private val platformData: Set, + private val kind: Kind, + private val commentsConverter: CommentsToContentConverter, + override val logger: DokkaLogger, + private val styles: Set