<lambda>null1 package org.jetbrains.dokka
2
3 import org.jetbrains.dokka.classNodeNameWithOuterClass
4 import org.jetbrains.dokka.LanguageService.RenderMode
5
6 /**
7 * Implements [LanguageService] and provides rendering of symbols in Java language
8 */
9 class NewJavaLanguageService : CommonLanguageService() {
10 override fun showModifierInSummary(node: DocumentationNode): Boolean {
11 return node.name !in fullOnlyModifiers
12 }
13
14 private val fullOnlyModifiers = setOf("public", "protected", "private")
15
16 override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
17 return content {
18 (when (node.kind) {
19 NodeKind.Package -> renderPackage(node)
20 in NodeKind.classLike -> renderClass(node, renderMode)
21
22 NodeKind.Modifier -> renderModifier(this, node, renderMode)
23 NodeKind.TypeParameter -> renderTypeParameter(node)
24 NodeKind.Type,
25 NodeKind.UpperBound -> renderType(node)
26 NodeKind.Parameter -> renderParameter(node)
27 NodeKind.Constructor,
28 NodeKind.Function -> renderFunction(node, renderMode)
29 NodeKind.Property -> renderProperty(node)
30 NodeKind.Field -> renderField(node, renderMode)
31 NodeKind.EnumItem -> renderClass(node, renderMode)
32 else -> "${node.kind}: ${node.name}"
33 })
34 }
35 }
36
37 override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? = null
38
39
40 override fun renderModifier(block: ContentBlock, node: DocumentationNode, renderMode: RenderMode, nowrap: Boolean) {
41 when (node.name) {
42 "open", "internal" -> {
43 }
44 else -> {
45 if (node.name !in fullOnlyModifiers || renderMode == RenderMode.FULL) {
46 super.renderModifier(block, node, renderMode, nowrap)
47 }
48 }
49 }
50 }
51
52 fun getArrayElementType(node: DocumentationNode): DocumentationNode? = when (node.qualifiedName()) {
53 "kotlin.Array" ->
54 node.details(NodeKind.Type).singleOrNull()?.let { et -> getArrayElementType(et) ?: et }
55 ?: DocumentationNode("Object", node.content, NodeKind.ExternalClass)
56
57 "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
58 "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
59 DocumentationNode(node.name.removeSuffix("Array").toLowerCase(), node.content, NodeKind.Type)
60
61 else -> null
62 }
63
64 fun getArrayDimension(node: DocumentationNode): Int = when (node.qualifiedName()) {
65 "kotlin.Array" ->
66 1 + (node.details(NodeKind.Type).singleOrNull()?.let { getArrayDimension(it) } ?: 0)
67
68 "kotlin.IntArray", "kotlin.LongArray", "kotlin.ShortArray", "kotlin.ByteArray",
69 "kotlin.CharArray", "kotlin.DoubleArray", "kotlin.FloatArray", "kotlin.BooleanArray" ->
70 1
71 else -> 0
72 }
73
74 fun ContentBlock.renderType(node: DocumentationNode) {
75 when (node.name) {
76 "Unit" -> identifier("void")
77 "Int" -> identifier("int")
78 "Long" -> identifier("long")
79 "Double" -> identifier("double")
80 "Float" -> identifier("float")
81 "Char" -> identifier("char")
82 "Boolean" -> identifier("bool")
83 // TODO: render arrays
84 else -> {
85 renderLinked(this, node) {
86 identifier(
87 it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name,
88 IdentifierKind.TypeName
89 )
90 }
91 renderTypeArgumentsForType(node)
92 }
93 }
94 }
95
96 private fun ContentBlock.renderTypeParameter(node: DocumentationNode) {
97 val constraints = node.details(NodeKind.UpperBound)
98 if (constraints.none())
99 identifier(node.name)
100 else {
101 identifier(node.name)
102 text(" ")
103 keyword("extends")
104 text(" ")
105 constraints.forEach { renderType(node) }
106 }
107 }
108
109 private fun ContentBlock.renderParameter(node: DocumentationNode) {
110 renderType(node.detail(NodeKind.Type))
111 text(" ")
112 identifier(node.name)
113 }
114
115 private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode) {
116 val typeParameters = node.details(NodeKind.TypeParameter)
117 if (typeParameters.any()) {
118 symbol("<")
119 renderList(typeParameters, noWrap = true) {
120 renderTypeParameter(it)
121 }
122 symbol(">")
123 text(" ")
124 }
125 }
126
127 private fun ContentBlock.renderTypeArgumentsForType(node: DocumentationNode) {
128 val typeArguments = node.details(NodeKind.Type)
129 if (typeArguments.any()) {
130 symbol("<")
131 renderList(typeArguments, noWrap = true) {
132 renderType(it)
133 }
134 symbol(">")
135 }
136 }
137
138 // private fun renderModifiersForNode(node: DocumentationNode): String {
139 // val modifiers = node.details(NodeKind.Modifier).map { renderModifier(it) }.filter { it != "" }
140 // if (modifiers.none())
141 // return ""
142 // return modifiers.joinToString(" ", postfix = " ")
143 // }
144
145 private fun ContentBlock.renderClassKind(node: DocumentationNode) {
146 when (node.kind) {
147 NodeKind.Interface -> {
148 keyword("interface")
149 }
150 NodeKind.EnumItem -> {
151 keyword("enum value")
152 }
153 NodeKind.Enum -> {
154 keyword("enum")
155 }
156 NodeKind.Class, NodeKind.Exception, NodeKind.Object -> {
157 keyword("class")
158 }
159 else -> throw IllegalArgumentException("Node $node is not a class-like object")
160 }
161 text(" ")
162 }
163
164 private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
165 renderModifiersForNode(node, renderMode)
166 renderClassKind(node)
167
168 identifier(node.name)
169 renderTypeParametersForNode(node)
170 val superClassType = node.superclassType
171 val interfaces = node.supertypes - superClassType
172 if (superClassType != null) {
173 text(" ")
174 keyword("extends")
175 text(" ")
176 renderType(superClassType)
177 }
178 if (interfaces.isNotEmpty()) {
179 text(" ")
180 keyword("implements")
181 text(" ")
182 renderList(interfaces.filterNotNull()) {
183 renderType(it)
184 }
185 }
186 }
187
188 private fun ContentBlock.renderParameters(nodes: List<DocumentationNode>) {
189 renderList(nodes) {
190 renderParameter(it)
191 }
192 }
193
194 private fun ContentBlock.renderFunction(
195 node: DocumentationNode,
196 renderMode: RenderMode
197 ) {
198 renderModifiersForNode(node, renderMode)
199 when (node.kind) {
200 NodeKind.Constructor -> identifier(node.owner?.name ?: "")
201 NodeKind.Function -> {
202 renderTypeParametersForNode(node)
203 renderType(node.detail(NodeKind.Type))
204 text(" ")
205 identifier(node.name)
206
207 }
208 else -> throw IllegalArgumentException("Node $node is not a function-like object")
209 }
210
211 val receiver = node.details(NodeKind.Receiver).singleOrNull()
212 symbol("(")
213 if (receiver != null)
214 renderParameters(listOf(receiver) + node.details(NodeKind.Parameter))
215 else
216 renderParameters(node.details(NodeKind.Parameter))
217
218 symbol(")")
219 }
220
221 private fun ContentBlock.renderProperty(node: DocumentationNode) {
222
223 when (node.kind) {
224 NodeKind.Property -> {
225 keyword("val")
226 text(" ")
227 }
228 else -> throw IllegalArgumentException("Node $node is not a property")
229 }
230 renderTypeParametersForNode(node)
231 val receiver = node.details(NodeKind.Receiver).singleOrNull()
232 if (receiver != null) {
233 renderType(receiver.detail(NodeKind.Type))
234 symbol(".")
235 }
236
237 identifier(node.name)
238 symbol(":")
239 text(" ")
240 renderType(node.detail(NodeKind.Type))
241
242 }
243
244 private fun ContentBlock.renderField(node: DocumentationNode, renderMode: RenderMode) {
245 renderModifiersForNode(node, renderMode)
246 renderType(node.detail(NodeKind.Type))
247 text(" ")
248 identifier(node.name)
249 }
250 }
251