aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.idea/compiler.xml2
-rw-r--r--core/src/main/kotlin/model/Documentable.kt52
-rw-r--r--core/src/main/kotlin/pages/PageBuilder.kt12
-rw-r--r--core/src/main/kotlin/pages/PageContentBuilder.kt12
-rw-r--r--core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt192
-rw-r--r--core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt13
-rw-r--r--core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt46
-rw-r--r--gradle/wrapper/gradle-wrapper.properties5
-rw-r--r--plugins/kotlin-as-java/build.gradle.kts17
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaDescriptorToDocumentationTranslator.kt75
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageBuilder.kt68
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPageContentBuilder.kt65
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt39
-rw-r--r--plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt151
-rw-r--r--plugins/kotlin-as-java/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin1
-rw-r--r--plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt98
-rw-r--r--settings.gradle.kts2
17 files changed, 751 insertions, 99 deletions
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 797b1d01..e9bdb9c1 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -38,6 +38,8 @@
<module name="dokka.integration.test" target="1.8" />
<module name="dokka.plugins.javadoc8.main" target="1.8" />
<module name="dokka.plugins.javadoc8.test" target="1.8" />
+ <module name="dokka.plugins.kotlin-as-java.main" target="1.8" />
+ <module name="dokka.plugins.kotlin-as-java.test" target="1.8" />
<module name="dokka.plugins.ma.main" target="1.8" />
<module name="dokka.plugins.ma.test" target="1.8" />
<module name="dokka.plugins.main" target="1.8" />
diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt
index 86ba24b7..1744e27f 100644
--- a/core/src/main/kotlin/model/Documentable.kt
+++ b/core/src/main/kotlin/model/Documentable.kt
@@ -4,7 +4,9 @@ import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.doc.DocumentationNode
import org.jetbrains.dokka.pages.PlatformData
import org.jetbrains.dokka.transformers.descriptors.KotlinClassKindTypes
-import org.jetbrains.dokka.transformers.descriptors.KotlinTypeWrapper
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.Visibilities
+import org.jetbrains.kotlin.descriptors.Visibility
class Module(override val name: String, val packages: List<Package>) : Documentable() {
override val dri: DRI = DRI.topLevel
@@ -32,7 +34,8 @@ class Class(
override val classlikes: List<Classlike>,
override val expected: ClassPlatformInfo?,
override val actual: List<ClassPlatformInfo>,
- override val extra: MutableSet<Extra> = mutableSetOf()
+ override val extra: MutableSet<Extra> = mutableSetOf(),
+ override val visibility: Map<PlatformData, Visibility>
) : Classlike(
name = name,
dri = dri,
@@ -43,7 +46,7 @@ class Class(
expected = expected,
actual = actual,
extra = extra
-)
+), WithVisibility
class Enum(
override val dri: DRI,
@@ -55,8 +58,9 @@ class Enum(
override val classlikes: List<Classlike> = emptyList(),
override val expected: ClassPlatformInfo? = null,
override val actual: List<ClassPlatformInfo>,
- override val extra: MutableSet<Extra> = mutableSetOf()
-) : Classlike(dri = dri, name = name, kind = KotlinClassKindTypes.ENUM_CLASS, actual = actual) {
+ override val extra: MutableSet<Extra> = mutableSetOf(),
+ override val visibility: Map<PlatformData, Visibility>
+) : Classlike(dri = dri, name = name, kind = KotlinClassKindTypes.ENUM_CLASS, actual = actual), WithVisibility {
constructor(c: Classlike, entries: List<EnumEntry>, ctors: List<Function>) : this(
dri = c.dri,
name = c.name,
@@ -67,7 +71,8 @@ class Enum(
classlikes = c.classlikes,
expected = c.expected,
actual = c.actual,
- extra = c.extra
+ extra = c.extra,
+ visibility = c.visibility
)
override val children: List<Documentable>
@@ -79,7 +84,8 @@ class EnumEntry(
override val name: String,
override val expected: ClassPlatformInfo? = null,
override val actual: List<ClassPlatformInfo>,
- override val extra: MutableSet<Extra> = mutableSetOf()
+ override val extra: MutableSet<Extra> = mutableSetOf(),
+ override val visibility: Map<PlatformData, Visibility>
) : Classlike(
dri = dri,
name = name,
@@ -93,7 +99,8 @@ class EnumEntry(
name = c.name,
actual = c.actual,
expected = c.expected,
- extra = c.extra
+ extra = c.extra,
+ visibility = c.visibility
)
override val children: List<Parameter>
@@ -109,8 +116,9 @@ class Function(
val parameters: List<Parameter>,
override val expected: PlatformInfo?,
override val actual: List<PlatformInfo>,
- override val extra: MutableSet<Extra> = mutableSetOf()
-) : CallableNode() {
+ override val extra: MutableSet<Extra> = mutableSetOf(),
+ override val visibility: Map<PlatformData, Visibility>
+) : CallableNode(), WithVisibility {
override val children: List<Parameter>
get() = listOfNotNull(receiver) + parameters
}
@@ -121,8 +129,10 @@ class Property(
override val receiver: Parameter?,
override val expected: PlatformInfo?,
override val actual: List<PlatformInfo>,
- override val extra: MutableSet<Extra> = mutableSetOf()
-) : CallableNode() {
+ override val extra: MutableSet<Extra> = mutableSetOf(),
+ val accessors: List<Function>,
+ override val visibility: Map<PlatformData, Visibility>
+) : CallableNode(), WithVisibility {
override val children: List<Parameter>
get() = listOfNotNull(receiver)
}
@@ -208,7 +218,7 @@ abstract class Classlike(
override val expected: ClassPlatformInfo? = null,
override val actual: List<ClassPlatformInfo>,
override val extra: MutableSet<Extra> = mutableSetOf()
-) : ScopeNode() {
+) : ScopeNode(), WithVisibility {
val inherited by lazy { platformInfo.mapNotNull { (it as? ClassPlatformInfo)?.inherited }.flatten() }
}
@@ -217,8 +227,12 @@ abstract class ScopeNode : Documentable() {
abstract val properties: List<Property>
abstract val classlikes: List<Classlike>
- override val children: List<Documentable>
- get() = functions + properties + classlikes
+ override val children: List<Documentable> // It is written so awkwardly because of type inference being lost here
+ get() = mutableListOf<Documentable>().apply {
+ addAll(functions)
+ addAll(properties)
+ addAll(classlikes)
+ }
}
abstract class CallableNode : Documentable() {
@@ -235,6 +249,7 @@ interface TypeWrapper {
val arguments: List<TypeWrapper>
val dri: DRI?
}
+
interface ClassKind
fun Documentable.dfs(predicate: (Documentable) -> Boolean): Documentable? =
@@ -244,4 +259,9 @@ fun Documentable.dfs(predicate: (Documentable) -> Boolean): Documentable? =
this.children.asSequence().mapNotNull { it.dfs(predicate) }.firstOrNull()
}
-interface Extra \ No newline at end of file
+interface Extra
+object STATIC : Extra
+
+interface WithVisibility {
+ val visibility: Map<PlatformData, Visibility>
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/pages/PageBuilder.kt b/core/src/main/kotlin/pages/PageBuilder.kt
index 7fe07ae4..df0c12c2 100644
--- a/core/src/main/kotlin/pages/PageBuilder.kt
+++ b/core/src/main/kotlin/pages/PageBuilder.kt
@@ -5,7 +5,7 @@ import org.jetbrains.dokka.model.Enum
import org.jetbrains.dokka.model.Function
import org.jetbrains.dokka.model.doc.TagWrapper
-class DefaultPageBuilder(
+open class DefaultPageBuilder(
override val rootContentGroup: RootContentBuilder
) : PageBuilder {
@@ -37,10 +37,10 @@ class DefaultPageBuilder(
else -> throw IllegalStateException("$m should not be present here")
}
- private fun group(node: Documentable, content: PageContentBuilderFunction) =
+ protected open fun group(node: Documentable, content: PageContentBuilderFunction) =
rootContentGroup(node, ContentKind.Main, content)
- private fun contentForModule(m: Module) = group(m) {
+ protected open fun contentForModule(m: Module) = group(m) {
header(1) { text("root") }
block("Packages", 2, ContentKind.Packages, m.packages, m.platformData) {
link(it.name, it.dri)
@@ -49,7 +49,7 @@ class DefaultPageBuilder(
text("Link to allpage here")
}
- private fun contentForPackage(p: Package) = group(p) {
+ protected open fun contentForPackage(p: Package) = group(p) {
header(1) { text("Package ${p.name}") }
block("Types", 2, ContentKind.Properties, p.classlikes, p.platformData) {
link(it.name, it.dri)
@@ -62,13 +62,13 @@ class DefaultPageBuilder(
}
}
- private fun contentForClasslike(c: Classlike): ContentGroup = when (c) {
+ fun contentForClasslike(c: Classlike): ContentGroup = when (c) {
is Class -> contentForClass(c)
is Enum -> contentForEnum(c)
else -> throw IllegalStateException("$c should not be present here")
}
- private fun contentForClass(c: Class) = group(c) {
+ protected fun contentForClass(c: Class) = group(c) {
header(1) { text(c.name) }
c.inherited.takeIf { it.isNotEmpty() }?.let {
diff --git a/core/src/main/kotlin/pages/PageContentBuilder.kt b/core/src/main/kotlin/pages/PageContentBuilder.kt
index d5ffe27a..bc01b03e 100644
--- a/core/src/main/kotlin/pages/PageContentBuilder.kt
+++ b/core/src/main/kotlin/pages/PageContentBuilder.kt
@@ -8,21 +8,21 @@ import org.jetbrains.dokka.model.TypeWrapper
import org.jetbrains.dokka.model.doc.DocTag
import org.jetbrains.dokka.utilities.DokkaLogger
-class DefaultPageContentBuilder(
+open class DefaultPageContentBuilder(
private val dri: Set<DRI>,
private val platformData: Set<PlatformData>,
private val kind: Kind,
private val commentsConverter: CommentsToContentConverter,
- val logger: DokkaLogger,
+ open val logger: DokkaLogger,
private val styles: Set<Style> = emptySet(),
private val extras: Set<Extra> = emptySet()
) : PageContentBuilder {
private val contents = mutableListOf<ContentNode>()
- private fun createText(text: String, kind: Kind = ContentKind.Symbol) =
+ protected fun createText(text: String, kind: Kind = ContentKind.Symbol) =
ContentText(text, DCI(dri, kind), platformData, styles, extras)
- private fun build() = ContentGroup(
+ protected fun build() = ContentGroup(
contents.toList(),
DCI(dri, kind),
platformData,
@@ -38,7 +38,7 @@ class DefaultPageContentBuilder(
contents += createText(text, kind)
}
- private fun signature(f: Function, block: PageContentBuilderFunction) {
+ protected fun signature(f: Function, block: PageContentBuilderFunction) {
contents += group(setOf(f.dri), f.platformData, ContentKind.Symbol, block)
}
@@ -163,7 +163,7 @@ class DefaultPageContentBuilder(
}
-private fun PageContentBuilder.type(t: TypeWrapper) {
+fun PageContentBuilder.type(t: TypeWrapper) {
if (t.constructorNamePathSegments.isNotEmpty() && t.dri != null)
link(t.constructorNamePathSegments.last(), t.dri!!)
else if (t.constructorNamePathSegments.isNotEmpty() && t.dri == null)
diff --git a/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt
index 651bd223..dd2d1681 100644
--- a/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt
+++ b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt
@@ -5,10 +5,10 @@ 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.ClassKind
import org.jetbrains.dokka.model.Enum
import org.jetbrains.dokka.model.Function
import org.jetbrains.dokka.model.Property
-import org.jetbrains.dokka.model.ClassKind
import org.jetbrains.dokka.model.doc.*
import org.jetbrains.dokka.pages.PlatformData
import org.jetbrains.dokka.parsers.MarkdownParser
@@ -31,21 +31,26 @@ object DefaultDescriptorToDocumentationTranslator : DescriptorToDocumentationTra
platformData: PlatformData,
context: DokkaContext
) = DokkaDescriptorVisitor(platformData, context.platforms[platformData]?.facade!!).run {
- packageFragments.map { visitPackageFragmentDescriptor(it, DRIWithPlatformInfo(DRI.topLevel, null, emptyList())) }
+ packageFragments.map {
+ visitPackageFragmentDescriptor(
+ it,
+ DRIWithPlatformInfo(DRI.topLevel, null, emptyList())
+ )
+ }
}.let { Module(moduleName, it) }
}
-internal data class DRIWithPlatformInfo(
+data class DRIWithPlatformInfo(
val dri: DRI,
val expected: PlatformInfo?,
val actual: List<PlatformInfo>
)
-private fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, null, emptyList())
+fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, null, emptyList())
-internal class DokkaDescriptorVisitor(
+open class DokkaDescriptorVisitor(
private val platformData: PlatformData,
private val resolutionFacade: DokkaResolutionFacade
) : DeclarationDescriptorVisitorEmptyBodies<Documentable, DRIWithPlatformInfo>() {
@@ -59,6 +64,7 @@ internal class DokkaDescriptorVisitor(
): Package {
val driWithPlatform = DRI(packageName = descriptor.fqName.asString()).withEmptyInfo()
val scope = descriptor.getMemberScope()
+
return Package(
dri = driWithPlatform.dri,
functions = scope.functions(driWithPlatform),
@@ -67,10 +73,11 @@ internal class DokkaDescriptorVisitor(
)
}
- override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Classlike = when (descriptor.kind) {
- org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent)
- else -> classDescriptor(descriptor, parent)
- }
+ override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Classlike =
+ when (descriptor.kind) {
+ org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent)
+ else -> classDescriptor(descriptor, parent)
+ }
fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Enum {
val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo()
@@ -80,14 +87,19 @@ internal class DokkaDescriptorVisitor(
return Enum(
dri = driWithPlatform.dri,
name = descriptor.name.asString(),
- entries = scope.classlikes(driWithPlatform).filter { it.kind == KotlinClassKindTypes.ENUM_ENTRY }.map { EnumEntry(it) },
+ entries = scope.classlikes(driWithPlatform).filter { it.kind == KotlinClassKindTypes.ENUM_ENTRY }.map {
+ EnumEntry(
+ it
+ )
+ },
constructors = descriptor.constructors.map { visitConstructorDescriptor(it, driWithPlatform) },
functions = scope.functions(driWithPlatform),
properties = scope.properties(driWithPlatform),
classlikes = scope.classlikes(driWithPlatform),
expected = descriptor.takeIf { it.isExpect }?.resolveClassDescriptionData(),
actual = listOfNotNull(descriptorData),
- extra = mutableSetOf() // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet()
+ extra = mutableSetOf(), // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet()
+ visibility = mapOf(platformData to descriptor.visibility)
)
}
@@ -101,23 +113,26 @@ internal class DokkaDescriptorVisitor(
dri = driWithPlatform.dri,
name = descriptor.name.asString(),
kind = KotlinClassKindTypes.valueOf(descriptor.kind.toString()),
- constructors = descriptor.constructors.map { visitConstructorDescriptor(
- it,
- if(it.isPrimary)
- DRIWithPlatformInfo(
- driWithPlatform.dri,
- expected?.info.filterTagWrappers(listOf(Constructor::class)),
- actual.filterTagWrappers(listOf(Constructor::class))
- )
- else
- DRIWithPlatformInfo(driWithPlatform.dri, null, emptyList())
- ) },
+ constructors = descriptor.constructors.map {
+ visitConstructorDescriptor(
+ it,
+ if (it.isPrimary)
+ DRIWithPlatformInfo(
+ driWithPlatform.dri,
+ expected?.info.filterTagWrappers(listOf(Constructor::class)),
+ actual.filterTagWrappers(listOf(Constructor::class))
+ )
+ else
+ DRIWithPlatformInfo(driWithPlatform.dri, null, emptyList())
+ )
+ },
functions = scope.functions(driWithPlatform),
properties = scope.properties(driWithPlatform),
classlikes = scope.classlikes(driWithPlatform),
expected = expected,
actual = actual,
- extra = mutableSetOf() // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet()
+ extra = mutableSetOf(), // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet()
+ visibility = mapOf(platformData to descriptor.visibility)
)
}
@@ -125,19 +140,24 @@ internal class DokkaDescriptorVisitor(
val expected = descriptor.takeIf { it.isExpect }?.resolveDescriptorData()
val actual = listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData())
val dri = parent.dri.copy(callable = Callable.from(descriptor))
+
return Property(
dri = dri,
name = descriptor.name.asString(),
- receiver = descriptor.extensionReceiverParameter?.let { visitReceiverParameterDescriptor(
- it,
- DRIWithPlatformInfo(
- dri,
- expected?.filterTagWrappers(listOf(Receiver::class)),
- actual.filterTagWrappers(listOf(Receiver::class))
+ receiver = descriptor.extensionReceiverParameter?.let {
+ visitReceiverParameterDescriptor(
+ it,
+ DRIWithPlatformInfo(
+ dri,
+ expected?.filterTagWrappers(listOf(Receiver::class)),
+ actual.filterTagWrappers(listOf(Receiver::class))
+ )
)
- ) },
+ },
expected = expected,
- actual = actual
+ actual = actual,
+ accessors = descriptor.accessors.map { visitPropertyAccessorDescriptor(it, descriptor, dri) },
+ visibility = mapOf(platformData to descriptor.visibility)
)
}
@@ -145,28 +165,35 @@ internal class DokkaDescriptorVisitor(
val expected = descriptor.takeIf { it.isExpect }?.resolveDescriptorData()
val actual = listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData())
val dri = parent.dri.copy(callable = Callable.from(descriptor))
+
return Function(
dri = dri,
name = descriptor.name.asString(),
returnType = descriptor.returnType?.let { KotlinTypeWrapper(it) },
isConstructor = false,
- receiver = descriptor.extensionReceiverParameter?.let { visitReceiverParameterDescriptor(
- it,
- DRIWithPlatformInfo(
- dri,
- expected?.filterTagWrappers(listOf(Receiver::class)),
- actual.filterTagWrappers(listOf(Receiver::class))
+ receiver = descriptor.extensionReceiverParameter?.let {
+ visitReceiverParameterDescriptor(
+ it,
+ DRIWithPlatformInfo(
+ dri,
+ expected?.filterTagWrappers(listOf(Receiver::class)),
+ actual.filterTagWrappers(listOf(Receiver::class))
+ )
)
- ) },
- parameters = descriptor.valueParameters.mapIndexed { index, desc -> parameter(index, desc,
- DRIWithPlatformInfo(
- dri,
- expected.filterTagWrappers(listOf(Param::class), desc.name.asString()),
- actual.filterTagWrappers(listOf(Param::class), desc.name.asString())
+ },
+ parameters = descriptor.valueParameters.mapIndexed { index, desc ->
+ parameter(
+ index, desc,
+ DRIWithPlatformInfo(
+ dri,
+ expected.filterTagWrappers(listOf(Param::class), desc.name.asString()),
+ actual.filterTagWrappers(listOf(Param::class), desc.name.asString())
+ )
)
- ) },
+ },
expected = expected,
- actual = actual
+ actual = actual,
+ visibility = mapOf(platformData to descriptor.visibility)
)
}
@@ -178,15 +205,19 @@ internal class DokkaDescriptorVisitor(
returnType = KotlinTypeWrapper(descriptor.returnType),
isConstructor = true,
receiver = null,
- parameters = descriptor.valueParameters.mapIndexed { index, desc -> parameter(index, desc,
- DRIWithPlatformInfo(
- dri,
- parent.expected.filterTagWrappers(listOf(Param::class)),
- parent.actual.filterTagWrappers(listOf(Param::class))
+ parameters = descriptor.valueParameters.mapIndexed { index, desc ->
+ parameter(
+ index, desc,
+ DRIWithPlatformInfo(
+ dri,
+ parent.expected.filterTagWrappers(listOf(Param::class)),
+ parent.actual.filterTagWrappers(listOf(Param::class))
+ )
)
- ) },
+ },
expected = parent.expected ?: descriptor.takeIf { it.isExpect }?.resolveDescriptorData(),
- actual = parent.actual
+ actual = parent.actual,
+ visibility = mapOf(platformData to descriptor.visibility)
)
}
@@ -201,6 +232,50 @@ internal class DokkaDescriptorVisitor(
actual = parent.actual
)
+ open fun visitPropertyAccessorDescriptor(
+ descriptor: PropertyAccessorDescriptor,
+ propertyDescriptor: PropertyDescriptor,
+ parent: DRI
+ ): Function {
+ val dri = parent.copy(callable = Callable.from(descriptor))
+ val isGetter = descriptor is PropertyGetterDescriptor
+
+ fun PropertyDescriptor.asParameter(parent: DRI) =
+ Parameter(
+ parent.copy(target = 1),
+ this.name.asString(),
+ KotlinTypeWrapper(this.type),
+ descriptor.takeIf { it.isExpect }?.resolveDescriptorData(),
+ listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData())
+ )
+
+ val name = run {
+ val modifier = if (isGetter) "get" else "set"
+ val rawName = propertyDescriptor.name.asString()
+ "$modifier${rawName[0].toUpperCase()}${rawName.drop(1)}"
+ }
+
+ descriptor.visibility
+ val parameters =
+ if (isGetter) {
+ emptyList()
+ } else {
+ listOf(propertyDescriptor.asParameter(dri))
+ }
+
+ return Function(
+ dri,
+ name,
+ descriptor.returnType?.let { KotlinTypeWrapper(it) },
+ false,
+ null,
+ parameters,
+ descriptor.takeIf { it.isExpect }?.resolveDescriptorData(),
+ listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData()),
+ visibility = mapOf(platformData to descriptor.visibility)
+ )
+ }
+
private fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) =
Parameter(
dri = parent.dri.copy(target = index + 1),
@@ -229,6 +304,7 @@ internal class DokkaDescriptorVisitor(
val doc = findKDoc()
val parser: MarkdownParser = MarkdownParser(resolutionFacade, this)
val docHeader = parser.parseFromKDocTag(doc)
+
return BasePlatformInfo(docHeader, listOf(platformData))
}
@@ -237,8 +313,11 @@ internal class DokkaDescriptorVisitor(
(getSuperInterfaces() + getAllSuperclassesWithoutAny()).map { DRI.from(it) })
}
- private fun PlatformInfo?.filterTagWrappers(types: List<KClass<out TagWrapper>>, name: String? = null): PlatformInfo? {
- if(this == null)
+ private fun PlatformInfo?.filterTagWrappers(
+ types: List<KClass<out TagWrapper>>,
+ name: String? = null
+ ): PlatformInfo? {
+ if (this == null)
return null
return BasePlatformInfo(
DocumentationNode(
@@ -248,7 +327,10 @@ internal class DokkaDescriptorVisitor(
)
}
- private fun List<PlatformInfo>.filterTagWrappers(types: List<KClass<out TagWrapper>>, name: String? = null): List<PlatformInfo> =
+ private fun List<PlatformInfo>.filterTagWrappers(
+ types: List<KClass<out TagWrapper>>,
+ name: String? = null
+ ): List<PlatformInfo> =
this.map { it.filterTagWrappers(types, name)!! }
}
diff --git a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt
index ec67ea88..0d7fa249 100644
--- a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt
+++ b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt
@@ -52,7 +52,8 @@ fun Function.mergeWith(other: Function): Function = Function(
if (receiver != null && other.receiver != null) receiver.mergeWith(other.receiver) else null,
merge(parameters + other.parameters, Parameter::mergeWith),
expected?.mergeWith(other.expected),
- (actual + other.actual).merge()
+ (actual + other.actual).merge(),
+ visibility = (visibility + other.visibility)
)
fun Property.mergeWith(other: Property) = Property(
@@ -60,7 +61,9 @@ fun Property.mergeWith(other: Property) = Property(
name,
if (receiver != null && other.receiver != null) receiver.mergeWith(other.receiver) else null,
expected?.mergeWith(other.expected),
- (actual + other.actual).merge()
+ (actual + other.actual).merge(),
+ accessors = (this.accessors + other.accessors).distinct(),
+ visibility = (visibility + other.visibility)
)
fun Classlike.mergeWith(other: Classlike): Classlike = when {
@@ -78,7 +81,8 @@ fun Class.mergeWith(other: Class) = Class(
properties = merge(properties + other.properties, Property::mergeWith),
classlikes = merge(classlikes + other.classlikes, Classlike::mergeWith),
expected = expected?.mergeWith(other.expected),
- actual = (actual + other.actual).mergeClassPlatformInfo()
+ actual = (actual + other.actual).mergeClassPlatformInfo(),
+ visibility = (visibility + other.visibility)
)
fun Enum.mergeWith(other: Enum) = Enum(
@@ -90,7 +94,8 @@ fun Enum.mergeWith(other: Enum) = Enum(
expected = expected?.mergeWith(other.expected),
actual = (actual + other.actual).mergeClassPlatformInfo(),
entries = (this.entries + other.entries.distinctBy { it.dri }.toList()),
- constructors = merge(constructors + other.constructors, Function::mergeWith)
+ constructors = merge(constructors + other.constructors, Function::mergeWith),
+ visibility = visibility
)
fun Parameter.mergeWith(other: Parameter) = Parameter(
diff --git a/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt
index 05c07070..2078faa7 100644
--- a/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt
+++ b/core/src/main/kotlin/transformers/psi/DefaultPsiToDocumentationTranslator.kt
@@ -12,6 +12,7 @@ import org.jetbrains.dokka.model.Function
import org.jetbrains.dokka.pages.PlatformData
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.utilities.DokkaLogger
+import org.jetbrains.kotlin.descriptors.Visibilities
object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator {
@@ -47,6 +48,14 @@ object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator {
return listOf(BasePlatformInfo(comment, listOf(platformData)))
}
+ private fun PsiModifierListOwner.getVisibility() = modifierList?.children?.toList()?.let { ml ->
+ when {
+ ml.any { it.text == PsiKeyword.PUBLIC } -> Visibilities.PUBLIC
+ ml.any { it.text == PsiKeyword.PROTECTED } -> Visibilities.PROTECTED
+ else -> Visibilities.PRIVATE
+ }
+ } ?: Visibilities.PRIVATE
+
fun parseClass(psi: PsiClass, parent: DRI): Class = with(psi) {
val kind = when {
isAnnotationType -> JavaClassKindTypes.ANNOTATION_CLASS
@@ -62,6 +71,7 @@ object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator {
link(superClass, node, RefKind.Inheritor)
}
}*/
+
return Class(
dri,
name.orEmpty(),
@@ -72,7 +82,8 @@ object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator {
innerClasses.map { parseClass(it, dri) },
null,
emptyList(),
- mutableSetOf()
+ mutableSetOf(),
+ visibility = mapOf(platformData to psi.getVisibility())
)
}
@@ -101,7 +112,8 @@ object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator {
)
},
null,
- getComment(psi)
+ getComment(psi),
+ visibility = mapOf(platformData to psi.getVisibility())
)
}
@@ -118,7 +130,9 @@ object DefaultPsiToDocumentationTranslator : PsiToDocumentationTranslator {
psi.name,
null,
null,
- getComment(psi)
+ getComment(psi),
+ accessors = emptyList(),
+ visibility = mapOf(platformData to psi.getVisibility())
)
}
}
@@ -132,16 +146,28 @@ enum class JavaClassKindTypes : ClassKind {
ANNOTATION_CLASS;
}
-class JavaTypeWrapper(
- type: PsiType
-) : TypeWrapper {
+class JavaTypeWrapper : TypeWrapper {
override val constructorFqName: String?
override val constructorNamePathSegments: List<String>
- override val arguments: List<JavaTypeWrapper>
+ override val arguments: List<TypeWrapper>
override val dri: DRI?
+ val isPrimitive: Boolean
+
+ constructor(
+ constructorNamePathSegments: List<String>,
+ arguments: List<TypeWrapper>,
+ dri: DRI?,
+ isPrimitiveType: Boolean
+ ) {
+ this.constructorFqName = constructorNamePathSegments.joinToString(".")
+ this.constructorNamePathSegments = constructorNamePathSegments
+ this.arguments = arguments
+ this.dri = dri
+ this.isPrimitive = isPrimitiveType
+ }
- init {
+ constructor(type: PsiType) {
if (type is PsiClassReferenceType) {
val resolved = type.resolve()
constructorFqName = resolved?.qualifiedName
@@ -150,22 +176,26 @@ class JavaTypeWrapper(
if (it is PsiClassReferenceType) JavaTypeWrapper(it) else null
}
dri = fromPsi(type)
+ this.isPrimitive = false
} else if (type is PsiEllipsisType) {
constructorFqName = type.canonicalText
constructorNamePathSegments = listOf(type.canonicalText) // TODO
arguments = emptyList()
dri = DRI("java.lang", "Object") // TODO
+ this.isPrimitive = false
} else if (type is PsiArrayType) {
constructorFqName = type.canonicalText
constructorNamePathSegments = listOf(type.canonicalText)
arguments = emptyList()
dri = (type as? PsiClassReferenceType)?.let { fromPsi(it) } // TODO
+ this.isPrimitive = false
} else {
type as PsiPrimitiveType
constructorFqName = type.name
constructorNamePathSegments = type.name.split('.')
arguments = emptyList()
dri = null
+ this.isPrimitive = true
}
}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index a869af2d..1b16c34a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Wed Jan 29 14:26:26 CET 2020
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
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<MavenPublication>("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<PackageFragmentDescriptor>,
+ 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 <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 }
+
+class KotlinAsJavaPageBuilder(rootContentGroup: RootContentBuilder) : DefaultPageBuilder(rootContentGroup) {
+
+ 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)
+ 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<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)
+ }
+ }
+
+ 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<DRI>,
+ private val platformData: Set<PlatformData>,
+ private val kind: Kind,
+ private val commentsConverter: CommentsToContentConverter,
+ override val logger: DokkaLogger,
+ private val styles: Set<Style> = emptySet(),
+ private val extras: Set<Extra> = emptySet()
+) : DefaultPageContentBuilder(dri, platformData, kind, commentsConverter, logger, styles, extras) {
+ private val contents = mutableListOf<ContentNode>()
+
+ override fun signature(f: Function) = signature(f) {
+
+ 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(")")
+ }
+
+ 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
new file mode 100644
index 00000000..345dc9be
--- /dev/null
+++ b/plugins/kotlin-as-java/src/main/kotlin/KotlinAsJavaPlugin.kt
@@ -0,0 +1,39 @@
+package org.jetbrains.dokka.kotlinAsJava
+
+
+import org.jetbrains.dokka.CoreExtensions
+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.plugability.DokkaPlugin
+import org.jetbrains.dokka.plugability.single
+import org.jetbrains.dokka.transformers.documentation.DocumentationToPageTranslator
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+
+class KotlinAsJavaPlugin : DokkaPlugin() {
+ val kotlinAsJavaDescriptorToDocumentableTranslator by extending { CoreExtensions.descriptorToDocumentationTranslator with KotlinAsJavaDescriptorToDocumentationTranslator }
+ val kotlinAsJavaDocumentableToPageTranslator by extending { CoreExtensions.documentationToPageTranslator with KotlinAsJavaDocumentationToPageTranslator }
+}
+
+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]
+}
+
+object KotlinAsJavaDocumentationToPageTranslator : DocumentationToPageTranslator {
+ override fun invoke(module: Module, context: DokkaContext): ModulePageNode =
+ KotlinAsJavaPageBuilder { node, kind, operation ->
+ KotlinAsJavaPageContentBuilder.group(
+ setOf(node.dri),
+ node.platformData,
+ kind,
+ context.single(CoreExtensions.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
new file mode 100644
index 00000000..87a173f3
--- /dev/null
+++ b/plugins/kotlin-as-java/src/main/kotlin/KotlinToJVMResolver.kt
@@ -0,0 +1,151 @@
+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.dokka.transformers.psi.JavaTypeWrapper
+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/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/plugins/kotlin-as-java/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
new file mode 100644
index 00000000..8ff3df82
--- /dev/null
+++ b/plugins/kotlin-as-java/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin
@@ -0,0 +1 @@
+org.jetbrains.dokka.kotlinAsJava.KotlinAsJavaPlugin
diff --git a/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt
new file mode 100644
index 00000000..c0833293
--- /dev/null
+++ b/plugins/kotlin-as-java/src/test/kotlin/KotlinAsJavaPluginTest.kt
@@ -0,0 +1,98 @@
+package kotlinAsJavaPlugin
+
+import junit.framework.Assert.fail
+import org.jetbrains.dokka.pages.ContentGroup
+import org.jetbrains.dokka.pages.ContentPage
+import org.jetbrains.dokka.pages.ContentTable
+import org.jetbrains.dokka.pages.children
+import org.junit.Test
+import testApi.testRunner.AbstractCoreTest
+
+class KotlinAsJavaPluginTest : AbstractCoreTest() {
+
+ @Test
+ fun topLevelTest() {
+ val configuration = dokkaConfiguration {
+ passes {
+ pass {
+ sourceRoots = listOf("src/")
+ }
+ }
+ }
+ testInline(
+ """
+ |/src/main/kotlin/kotlinAsJavaPlugin/Test.kt
+ |package kotlinAsJavaPlugin
+ |
+ |object TestObj {}
+ |
+ |fun testFL(l: List<String>) = l
+ |fun testF() {}
+ |fun testF2(i: Int) = i
+ |fun testF3(to: TestObj) = to
+ |fun <T : Char> testF4(t: T) = listOf(t)
+ |val testV = 1
+ """,
+ configuration,
+ cleanupOutput = true
+ ) {
+ pagesGenerationStage = { root ->
+ val content = (root.children.firstOrNull()?.children?.firstOrNull() as? ContentPage )?.content ?: run {
+ fail("Either children or content is null")
+ }
+
+ val children =
+ if (content is ContentGroup)
+ content.children.filterIsInstance<ContentTable>().filter { it.children.isNotEmpty() }
+ else emptyList()
+
+ children.assertCount(2)
+ }
+ }
+ }
+
+ @Test
+ fun topLevelWithClassTest() {
+ val configuration = dokkaConfiguration {
+ passes {
+ pass {
+ sourceRoots = listOf("src/")
+ }
+ }
+ }
+ testInline(
+ """
+ |/src/main/kotlin/kotlinAsJavaPlugin/Test.kt
+ |package kotlinAsJavaPlugin
+ |
+ |class Test {
+ | fun testFC() {}
+ | val testVC = 1
+ |}
+ |
+ |fun testF(i: Int) = i
+ |val testV = 1
+ """,
+ configuration,
+ cleanupOutput = true
+ ) {
+ pagesGenerationStage = { root ->
+ val contentList = root.children
+ .flatMap { it.children<ContentPage>() }
+ .map { it.content }
+
+ val children = contentList.flatMap { content ->
+ if (content is ContentGroup)
+ content.children.filterIsInstance<ContentTable>().filter { it.children.isNotEmpty() }
+ else emptyList()
+ }.filterNot { it.toString().contains("<init>") }
+
+ children.assertCount(4)
+ }
+ }
+ }
+
+ private fun <T> Collection<T>.assertCount(n: Int) =
+ assert(count() == n) { "Expected $n, got ${count()}" }
+
+} \ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 295c484b..8efca079 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -8,9 +8,9 @@ include("runners:cli")
include("runners:maven-plugin")
include("plugins:xml")
include("plugins:mathjax")
+include("plugins:kotlin-as-java")
include("integration-tests:gradle-integration-tests")
-
pluginManagement {
val kotlin_version: String by settings
plugins {