<lambda>null1 package org.jetbrains.dokka
2
3 import org.jetbrains.dokka.Formats.nameWithOuterClass
4 import org.jetbrains.dokka.LanguageService.RenderMode
5
6 /**
7 * Implements [LanguageService] and provides rendering of symbols in Java language
8 */
9 class JavaLanguageService : LanguageService {
10 override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
11 return ContentText(when (node.kind) {
12 NodeKind.Package -> renderPackage(node)
13 in NodeKind.classLike -> renderClass(node)
14
15 NodeKind.TypeParameter -> renderTypeParameter(node)
16 NodeKind.Type,
17 NodeKind.UpperBound -> renderType(node)
18
19 NodeKind.Constructor,
20 NodeKind.Function -> renderFunction(node)
21 NodeKind.Property -> renderProperty(node)
22 else -> "${node.kind}: ${node.name}"
23 })
24 }
25
26 override fun renderName(node: DocumentationNode): String {
27 return when (node.kind) {
28 NodeKind.Constructor -> node.owner!!.name
29 else -> node.name
30 }
31 }
32
33 override fun renderNameWithOuterClass(node: DocumentationNode): String {
34 return when (node.kind) {
35 NodeKind.Constructor -> node.owner!!.nameWithOuterClass()
36 else -> node.nameWithOuterClass()
37 }
38 }
39
40 override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
41
42 private fun renderPackage(node: DocumentationNode): String {
43 return "package ${node.name}"
44 }
45
46 private fun renderModifier(node: DocumentationNode): String {
47 return when (node.name) {
48 "open" -> ""
49 "internal" -> ""
50 else -> node.name
51 }
52 }
53
54 fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.qualifiedName()) {
55 "kotlin.Array" ->
56 node.details(NodeKind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et } ?:
57 DocumentationNode("Object", node.content, NodeKind.ExternalClass)
58
59 "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
60 "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
61 DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, NodeKind.Type)
62
63 else -> null
64 }
65
66 fun getArrayDimension(node: DocumentationNode): Int = when (node.qualifiedName()) {
67 "kotlin.Array" ->
68 1 + (node.details(NodeKind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0)
69
70 "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
71 "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
72 1
73 else -> 0
74 }
75
76 fun renderType(node: DocumentationNode): String {
77 return when (node.name) {
78 "Unit" -> "void"
79 "Int" -> "int"
80 "Long" -> "long"
81 "Double" -> "double"
82 "Float" -> "float"
83 "Char" -> "char"
84 "Boolean" -> "bool"
85 // TODO: render arrays
86 else -> node.name
87 }
88 }
89
90 private fun renderTypeParameter(node: DocumentationNode): String {
91 val constraints = node.details(NodeKind.UpperBound)
92 return if (constraints.none())
93 node.name
94 else {
95 node.name + " extends " + constraints.map { renderType(node) }.joinToString()
96 }
97 }
98
99 private fun renderParameter(node: DocumentationNode): String {
100 return "${renderType(node.detail(NodeKind.Type))} ${node.name}"
101 }
102
103 private fun renderTypeParametersForNode(node: DocumentationNode): String {
104 return StringBuilder().apply {
105 val typeParameters = node.details(NodeKind.TypeParameter)
106 if (typeParameters.any()) {
107 append("<")
108 append(typeParameters.map { renderTypeParameter(it) }.joinToString())
109 append("> ")
110 }
111 }.toString()
112 }
113
114 private fun renderModifiersForNode(node: DocumentationNode): String {
115 val modifiers = node.details(NodeKind.Modifier).map { renderModifier(it) }.filter { it != "" }
116 if (modifiers.none())
117 return ""
118 return modifiers.joinToString(" ", postfix = " ")
119 }
120
121 private fun renderClass(node: DocumentationNode): String {
122 return StringBuilder().apply {
123 when (node.kind) {
124 NodeKind.Class -> append("class ")
125 NodeKind.Interface -> append("interface ")
126 NodeKind.Enum -> append("enum ")
127 NodeKind.EnumItem -> append("enum value ")
128 NodeKind.Object -> append("class ")
129 else -> throw IllegalArgumentException("Node $node is not a class-like object")
130 }
131
132 append(node.name)
133 append(renderTypeParametersForNode(node))
134 }.toString()
135 }
136
137 private fun renderFunction(node: DocumentationNode): String {
138 return StringBuilder().apply {
139 when (node.kind) {
140 NodeKind.Constructor -> append(node.owner?.name)
141 NodeKind.Function -> {
142 append(renderTypeParametersForNode(node))
143 append(renderType(node.detail(NodeKind.Type)))
144 append(" ")
145 append(node.name)
146 }
147 else -> throw IllegalArgumentException("Node $node is not a function-like object")
148 }
149
150 val receiver = node.details(NodeKind.Receiver).singleOrNull()
151 append("(")
152 if (receiver != null)
153 (listOf(receiver) + node.details(NodeKind.Parameter)).map { renderParameter(it) }.joinTo(this)
154 else
155 node.details(NodeKind.Parameter).map { renderParameter(it) }.joinTo(this)
156
157 append(")")
158 }.toString()
159 }
160
161 private fun renderProperty(node: DocumentationNode): String {
162 return StringBuilder().apply {
163 when (node.kind) {
164 NodeKind.Property -> append("val ")
165 else -> throw IllegalArgumentException("Node $node is not a property")
166 }
167 append(renderTypeParametersForNode(node))
168 val receiver = node.details(NodeKind.Receiver).singleOrNull()
169 if (receiver != null) {
170 append(renderType(receiver.detail(NodeKind.Type)))
171 append(".")
172 }
173
174 append(node.name)
175 append(": ")
176 append(renderType(node.detail(NodeKind.Type)))
177 }.toString()
178 }
179 }