aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/Languages/JavaLanguageService.kt
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/kotlin/Languages/JavaLanguageService.kt')
-rw-r--r--core/src/main/kotlin/Languages/JavaLanguageService.kt179
1 files changed, 179 insertions, 0 deletions
diff --git a/core/src/main/kotlin/Languages/JavaLanguageService.kt b/core/src/main/kotlin/Languages/JavaLanguageService.kt
new file mode 100644
index 000000000..4b3979b54
--- /dev/null
+++ b/core/src/main/kotlin/Languages/JavaLanguageService.kt
@@ -0,0 +1,179 @@
+package org.jetbrains.dokka
+
+import org.jetbrains.dokka.Formats.nameWithOuterClass
+import org.jetbrains.dokka.LanguageService.RenderMode
+
+/**
+ * Implements [LanguageService] and provides rendering of symbols in Java language
+ */
+class JavaLanguageService : LanguageService {
+ override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
+ return ContentText(when (node.kind) {
+ NodeKind.Package -> renderPackage(node)
+ in NodeKind.classLike -> renderClass(node)
+
+ NodeKind.TypeParameter -> renderTypeParameter(node)
+ NodeKind.Type,
+ NodeKind.UpperBound -> renderType(node)
+
+ NodeKind.Constructor,
+ NodeKind.Function -> renderFunction(node)
+ NodeKind.Property -> renderProperty(node)
+ else -> "${node.kind}: ${node.name}"
+ })
+ }
+
+ override fun renderName(node: DocumentationNode): String {
+ return when (node.kind) {
+ NodeKind.Constructor -> node.owner!!.name
+ else -> node.name
+ }
+ }
+
+ override fun renderNameWithOuterClass(node: DocumentationNode): String {
+ return when (node.kind) {
+ NodeKind.Constructor -> node.owner!!.nameWithOuterClass()
+ else -> node.nameWithOuterClass()
+ }
+ }
+
+ override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
+
+ private fun renderPackage(node: DocumentationNode): String {
+ return "package ${node.name}"
+ }
+
+ private fun renderModifier(node: DocumentationNode): String {
+ return when (node.name) {
+ "open" -> ""
+ "internal" -> ""
+ else -> node.name
+ }
+ }
+
+ fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.qualifiedName()) {
+ "kotlin.Array" ->
+ node.details(NodeKind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et } ?:
+ DocumentationNode("Object", node.content, NodeKind.ExternalClass)
+
+ "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
+ "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
+ DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, NodeKind.Type)
+
+ else -> null
+ }
+
+ fun getArrayDimension(node: DocumentationNode): Int = when (node.qualifiedName()) {
+ "kotlin.Array" ->
+ 1 + (node.details(NodeKind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0)
+
+ "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
+ "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
+ 1
+ else -> 0
+ }
+
+ fun renderType(node: DocumentationNode): String {
+ return when (node.name) {
+ "Unit" -> "void"
+ "Int" -> "int"
+ "Long" -> "long"
+ "Double" -> "double"
+ "Float" -> "float"
+ "Char" -> "char"
+ "Boolean" -> "bool"
+ // TODO: render arrays
+ else -> node.name
+ }
+ }
+
+ private fun renderTypeParameter(node: DocumentationNode): String {
+ val constraints = node.details(NodeKind.UpperBound)
+ return if (constraints.none())
+ node.name
+ else {
+ node.name + " extends " + constraints.map { renderType(node) }.joinToString()
+ }
+ }
+
+ private fun renderParameter(node: DocumentationNode): String {
+ return "${renderType(node.detail(NodeKind.Type))} ${node.name}"
+ }
+
+ private fun renderTypeParametersForNode(node: DocumentationNode): String {
+ return StringBuilder().apply {
+ val typeParameters = node.details(NodeKind.TypeParameter)
+ if (typeParameters.any()) {
+ append("<")
+ append(typeParameters.map { renderTypeParameter(it) }.joinToString())
+ append("> ")
+ }
+ }.toString()
+ }
+
+ private fun renderModifiersForNode(node: DocumentationNode): String {
+ val modifiers = node.details(NodeKind.Modifier).map { renderModifier(it) }.filter { it != "" }
+ if (modifiers.none())
+ return ""
+ return modifiers.joinToString(" ", postfix = " ")
+ }
+
+ private fun renderClass(node: DocumentationNode): String {
+ return StringBuilder().apply {
+ when (node.kind) {
+ NodeKind.Class -> append("class ")
+ NodeKind.Interface -> append("interface ")
+ NodeKind.Enum -> append("enum ")
+ NodeKind.EnumItem -> append("enum value ")
+ NodeKind.Object -> append("class ")
+ else -> throw IllegalArgumentException("Node $node is not a class-like object")
+ }
+
+ append(node.name)
+ append(renderTypeParametersForNode(node))
+ }.toString()
+ }
+
+ private fun renderFunction(node: DocumentationNode): String {
+ return StringBuilder().apply {
+ when (node.kind) {
+ NodeKind.Constructor -> append(node.owner?.name)
+ NodeKind.Function -> {
+ append(renderTypeParametersForNode(node))
+ append(renderType(node.detail(NodeKind.Type)))
+ append(" ")
+ append(node.name)
+ }
+ else -> throw IllegalArgumentException("Node $node is not a function-like object")
+ }
+
+ val receiver = node.details(NodeKind.Receiver).singleOrNull()
+ append("(")
+ if (receiver != null)
+ (listOf(receiver) + node.details(NodeKind.Parameter)).map { renderParameter(it) }.joinTo(this)
+ else
+ node.details(NodeKind.Parameter).map { renderParameter(it) }.joinTo(this)
+
+ append(")")
+ }.toString()
+ }
+
+ private fun renderProperty(node: DocumentationNode): String {
+ return StringBuilder().apply {
+ when (node.kind) {
+ NodeKind.Property -> append("val ")
+ else -> throw IllegalArgumentException("Node $node is not a property")
+ }
+ append(renderTypeParametersForNode(node))
+ val receiver = node.details(NodeKind.Receiver).singleOrNull()
+ if (receiver != null) {
+ append(renderType(receiver.detail(NodeKind.Type)))
+ append(".")
+ }
+
+ append(node.name)
+ append(": ")
+ append(renderType(node.detail(NodeKind.Type)))
+ }.toString()
+ }
+} \ No newline at end of file