blob: a4b3de578a20283fde2036606034b8f2b8c93bd4 [file] [log] [blame]
package org.jetbrains.dokka
import org.jetbrains.dokka.Formats.classNodeNameWithOuterClass
import org.jetbrains.dokka.LanguageService.RenderMode
/**
* Implements [LanguageService] and provides rendering of symbols in Java language
*/
class NewJavaLanguageService : CommonLanguageService() {
override fun showModifierInSummary(node: DocumentationNode): Boolean {
return true
}
override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
return content {
(when (node.kind) {
NodeKind.Package -> renderPackage(node)
in NodeKind.classLike -> renderClass(node, renderMode)
NodeKind.Modifier -> renderModifier(this, node, renderMode)
NodeKind.TypeParameter -> renderTypeParameter(node)
NodeKind.Type,
NodeKind.UpperBound -> renderType(node)
NodeKind.Parameter -> renderParameter(node)
NodeKind.Constructor,
NodeKind.Function -> renderFunction(node)
NodeKind.Property -> renderProperty(node)
NodeKind.Field -> renderField(node, renderMode)
NodeKind.EnumItem -> renderClass(node, renderMode)
else -> "${node.kind}: ${node.name}"
})
}
}
override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
override fun renderModifier(block: ContentBlock, node: DocumentationNode, renderMode: RenderMode, nowrap: Boolean) {
when (node.name) {
"open", "internal" -> {
}
else -> super.renderModifier(block, node, renderMode, nowrap)
}
}
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 ContentBlock.renderType(node: DocumentationNode) {
when (node.name) {
"Unit" -> identifier("void")
"Int" -> identifier("int")
"Long" -> identifier("long")
"Double" -> identifier("double")
"Float" -> identifier("float")
"Char" -> identifier("char")
"Boolean" -> identifier("bool")
// TODO: render arrays
else -> {
renderLinked(this, node) {
identifier(
it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name,
IdentifierKind.TypeName
)
}
renderTypeArgumentsForType(node)
}
}
}
private fun ContentBlock.renderTypeParameter(node: DocumentationNode) {
val constraints = node.details(NodeKind.UpperBound)
if (constraints.none())
identifier(node.name)
else {
identifier(node.name)
text(" ")
keyword("extends")
text(" ")
constraints.forEach { renderType(node) }
}
}
private fun ContentBlock.renderParameter(node: DocumentationNode) {
renderType(node.detail(NodeKind.Type))
text(" ")
identifier(node.name)
}
private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode) {
val typeParameters = node.details(NodeKind.TypeParameter)
if (typeParameters.any()) {
symbol("<")
renderList(typeParameters, noWrap = true) {
renderTypeParameter(it)
}
symbol(">")
text(" ")
}
}
private fun ContentBlock.renderTypeArgumentsForType(node: DocumentationNode) {
val typeArguments = node.details(NodeKind.Type)
if (typeArguments.any()) {
symbol("<")
renderList(typeArguments, noWrap = true) {
renderType(it)
}
symbol(">")
}
}
// 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 ContentBlock.renderClassKind(node: DocumentationNode) {
when (node.kind) {
NodeKind.Interface -> {
keyword("interface")
}
NodeKind.EnumItem -> {
keyword("enum value")
}
NodeKind.Enum -> {
keyword("enum")
}
NodeKind.Class, NodeKind.Exception, NodeKind.Object -> {
keyword("class")
}
else -> throw IllegalArgumentException("Node $node is not a class-like object")
}
text(" ")
}
private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
renderModifiersForNode(node, renderMode)
renderClassKind(node)
identifier(node.name)
renderTypeParametersForNode(node)
val superClassType = node.superclassType
val interfaces = node.supertypes - superClassType
if (superClassType != null) {
text(" ")
keyword("extends")
text(" ")
renderType(superClassType)
}
if (interfaces.isNotEmpty()) {
text(" ")
keyword("implements")
text(" ")
renderList(interfaces.filterNotNull()) {
renderType(it)
}
}
}
private fun ContentBlock.renderParameters(nodes: List<DocumentationNode>) {
renderList(nodes) {
renderParameter(it)
}
}
private fun ContentBlock.renderFunction(node: DocumentationNode) {
when (node.kind) {
NodeKind.Constructor -> identifier(node.owner?.name ?: "")
NodeKind.Function -> {
renderTypeParametersForNode(node)
renderType(node.detail(NodeKind.Type))
text(" ")
identifier(node.name)
}
else -> throw IllegalArgumentException("Node $node is not a function-like object")
}
val receiver = node.details(NodeKind.Receiver).singleOrNull()
symbol("(")
if (receiver != null)
renderParameters(listOf(receiver) + node.details(NodeKind.Parameter))
else
renderParameters(node.details(NodeKind.Parameter))
symbol(")")
}
private fun ContentBlock.renderProperty(node: DocumentationNode) {
when (node.kind) {
NodeKind.Property -> {
keyword("val")
text(" ")
}
else -> throw IllegalArgumentException("Node $node is not a property")
}
renderTypeParametersForNode(node)
val receiver = node.details(NodeKind.Receiver).singleOrNull()
if (receiver != null) {
renderType(receiver.detail(NodeKind.Type))
symbol(".")
}
identifier(node.name)
symbol(":")
text(" ")
renderType(node.detail(NodeKind.Type))
}
private fun ContentBlock.renderField(node: DocumentationNode, renderMode: RenderMode) {
renderModifiersForNode(node, renderMode)
renderType(node.detail(NodeKind.Type))
text(" ")
identifier(node.name)
}
}