• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<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 Kotlin language
8  */
9 class KotlinLanguageService : CommonLanguageService() {
10     override fun showModifierInSummary(node: DocumentationNode): Boolean {
11         return node.name !in fullOnlyModifiers
12     }
13 
14     private val fullOnlyModifiers =
15         setOf("public", "protected", "private", "inline", "noinline", "crossinline", "reified")
16 
17     override fun render(node: DocumentationNode, renderMode: RenderMode): ContentNode {
18         return content {
19             when (node.kind) {
20                 NodeKind.Package -> if (renderMode == RenderMode.FULL) renderPackage(node)
21                 in NodeKind.classLike -> renderClass(node, renderMode)
22 
23                 NodeKind.EnumItem -> renderClass(node, renderMode)
24                 NodeKind.ExternalClass -> if (renderMode == RenderMode.FULL) identifier(node.name)
25 
26                 NodeKind.Parameter -> renderParameter(node, renderMode)
27                 NodeKind.TypeParameter -> renderTypeParameter(node, renderMode)
28                 NodeKind.Type,
29                 NodeKind.UpperBound -> renderType(node, renderMode)
30 
31                 NodeKind.Modifier -> renderModifier(this, node, renderMode)
32                 NodeKind.Constructor,
33                 NodeKind.Function,
34                 NodeKind.CompanionObjectFunction -> renderFunction(node, renderMode)
35                 NodeKind.Property,
36                 NodeKind.CompanionObjectProperty -> renderProperty(node, renderMode)
37                 else -> identifier(node.name)
38             }
39         }
40     }
41 
42 
43     override fun summarizeSignatures(nodes: List<DocumentationNode>): ContentNode? {
44         if (nodes.size < 2) return null
45         val receiverKind = nodes.getReceiverKind() ?: return null
46         val functionWithTypeParameter = nodes.firstOrNull { it.details(NodeKind.TypeParameter).any() } ?: return null
47         return content {
48             val typeParameter = functionWithTypeParameter.details(NodeKind.TypeParameter).first()
49             if (functionWithTypeParameter.kind == NodeKind.Function) {
50                 renderFunction(
51                     functionWithTypeParameter,
52                     RenderMode.SUMMARY,
53                     SummarizingMapper(receiverKind, typeParameter.name)
54                 )
55             } else {
56                 renderProperty(
57                     functionWithTypeParameter,
58                     RenderMode.SUMMARY,
59                     SummarizingMapper(receiverKind, typeParameter.name)
60                 )
61             }
62         }
63     }
64 
65     private fun List<DocumentationNode>.getReceiverKind(): ReceiverKind? {
66         val qNames = map { it.getReceiverQName() }.filterNotNull()
67         if (qNames.size != size)
68             return null
69 
70         return ReceiverKind.values().firstOrNull { kind -> qNames.all { it in kind.classes } }
71     }
72 
73     private fun DocumentationNode.getReceiverQName(): String? {
74         if (kind != NodeKind.Function && kind != NodeKind.Property) return null
75         val receiver = details(NodeKind.Receiver).singleOrNull() ?: return null
76         return receiver.detail(NodeKind.Type).qualifiedNameFromType()
77     }
78 
79     companion object {
80         private val arrayClasses = setOf(
81             "kotlin.Array",
82             "kotlin.BooleanArray",
83             "kotlin.ByteArray",
84             "kotlin.CharArray",
85             "kotlin.ShortArray",
86             "kotlin.IntArray",
87             "kotlin.LongArray",
88             "kotlin.FloatArray",
89             "kotlin.DoubleArray"
90         )
91 
92         private val arrayOrListClasses = setOf("kotlin.List") + arrayClasses
93 
94         private val iterableClasses = setOf(
95             "kotlin.Collection",
96             "kotlin.Sequence",
97             "kotlin.Iterable",
98             "kotlin.Map",
99             "kotlin.String",
100             "kotlin.CharSequence"
101         ) + arrayOrListClasses
102     }
103 
104     private enum class ReceiverKind(val receiverName: String, val classes: Collection<String>) {
105         ARRAY("any_array", arrayClasses),
106         ARRAY_OR_LIST("any_array_or_list", arrayOrListClasses),
107         ITERABLE("any_iterable", iterableClasses),
108     }
109 
110     interface SignatureMapper {
111         fun renderReceiver(receiver: DocumentationNode, to: ContentBlock)
112     }
113 
114     private class SummarizingMapper(val kind: ReceiverKind, val typeParameterName: String) : SignatureMapper {
115         override fun renderReceiver(receiver: DocumentationNode, to: ContentBlock) {
116             to.append(ContentIdentifier(kind.receiverName, IdentifierKind.SummarizedTypeName))
117             to.text("<$typeParameterName>")
118         }
119     }
120 
121     private fun ContentBlock.renderFunctionalTypeParameterName(node: DocumentationNode, renderMode: RenderMode) {
122         node.references(RefKind.HiddenAnnotation).map { it.to }
123             .find { it.name == "ParameterName" }?.let {
124                 val parameterNameValue = it.detail(NodeKind.Parameter).detail(NodeKind.Value)
125                 identifier(parameterNameValue.name.removeSurrounding("\""), IdentifierKind.ParameterName)
126                 symbol(":")
127                 nbsp()
128             }
129     }
130 
131     private fun ContentBlock.renderFunctionalType(node: DocumentationNode, renderMode: RenderMode) {
132         var typeArguments = node.details(NodeKind.Type)
133 
134         if (node.name.startsWith("Suspend")) {
135             keyword("suspend ")
136         }
137 
138         // lambda
139         val isExtension = node.annotations.any { it.name == "ExtensionFunctionType" }
140         if (isExtension) {
141             renderType(typeArguments.first(), renderMode)
142             symbol(".")
143             typeArguments = typeArguments.drop(1)
144         }
145         symbol("(")
146         renderList(typeArguments.take(typeArguments.size - 1), noWrap = true) {
147             renderFunctionalTypeParameterName(it, renderMode)
148             renderType(it, renderMode)
149         }
150         symbol(")")
151         nbsp()
152         symbol("->")
153         nbsp()
154         renderType(typeArguments.last(), renderMode)
155 
156     }
157 
158     private fun DocumentationNode.isFunctionalType(): Boolean {
159         val typeArguments = details(NodeKind.Type)
160         val functionalTypeName = "Function${typeArguments.count() - 1}"
161         val suspendFunctionalTypeName = "Suspend$functionalTypeName"
162         return name == functionalTypeName || name == suspendFunctionalTypeName
163     }
164 
165     private fun ContentBlock.renderType(node: DocumentationNode, renderMode: RenderMode) {
166         if (node.name == "dynamic") {
167             keyword("dynamic")
168             return
169         }
170         if (node.isFunctionalType()) {
171             renderFunctionalType(node, renderMode)
172             return
173         }
174         if (renderMode == RenderMode.FULL) {
175             renderAnnotationsForNode(node)
176         }
177         renderModifiersForNode(node, renderMode, true)
178         renderLinked(this, node) {
179             identifier(it.typeDeclarationClass?.classNodeNameWithOuterClass() ?: it.name, IdentifierKind.TypeName)
180         }
181         val typeArguments = node.details(NodeKind.Type)
182         if (typeArguments.isNotEmpty()) {
183             symbol("<")
184             renderList(typeArguments, noWrap = true) {
185                 renderType(it, renderMode)
186             }
187             symbol(">")
188         }
189         val nullabilityModifier = node.details(NodeKind.NullabilityModifier).singleOrNull()
190         if (nullabilityModifier != null) {
191             symbol(nullabilityModifier.name)
192         }
193     }
194 
195     override fun renderModifier(
196         block: ContentBlock,
197         node: DocumentationNode,
198         renderMode: RenderMode,
199         nowrap: Boolean
200     ) {
201         when (node.name) {
202             "final", "public", "var" -> {
203             }
204             else -> {
205                 if (node.name !in fullOnlyModifiers || renderMode == RenderMode.FULL) {
206                     super.renderModifier(block, node, renderMode, nowrap)
207                 }
208             }
209         }
210     }
211 
212     private fun ContentBlock.renderTypeParameter(node: DocumentationNode, renderMode: RenderMode) {
213         renderModifiersForNode(node, renderMode, true)
214 
215         identifier(node.name)
216 
217         val constraints = node.details(NodeKind.UpperBound)
218         if (constraints.size == 1) {
219             nbsp()
220             symbol(":")
221             nbsp()
222             renderList(constraints, noWrap = true) {
223                 renderType(it, renderMode)
224             }
225         }
226     }
227 
228     private fun ContentBlock.renderParameter(node: DocumentationNode, renderMode: RenderMode) {
229         if (renderMode == RenderMode.FULL) {
230             renderAnnotationsForNode(node)
231         }
232         renderModifiersForNode(node, renderMode)
233         identifier(node.name, IdentifierKind.ParameterName, node.detailOrNull(NodeKind.Signature)?.name)
234         symbol(":")
235         nbsp()
236         val parameterType = node.detail(NodeKind.Type)
237         renderType(parameterType, renderMode)
238         val valueNode = node.details(NodeKind.Value).firstOrNull()
239         if (valueNode != null) {
240             nbsp()
241             symbol("=")
242             nbsp()
243             text(valueNode.name)
244         }
245     }
246 
247     private fun ContentBlock.renderTypeParametersForNode(node: DocumentationNode, renderMode: RenderMode) {
248         val typeParameters = node.details(NodeKind.TypeParameter)
249         if (typeParameters.any()) {
250             symbol("<")
251             renderList(typeParameters) {
252                 renderTypeParameter(it, renderMode)
253             }
254             symbol(">")
255         }
256     }
257 
258     private fun ContentBlock.renderExtraTypeParameterConstraints(node: DocumentationNode, renderMode: RenderMode) {
259         val parametersWithMultipleConstraints =
260             node.details(NodeKind.TypeParameter).filter { it.details(NodeKind.UpperBound).size > 1 }
261         val parametersWithConstraints = parametersWithMultipleConstraints
262             .flatMap { parameter ->
263                 parameter.details(NodeKind.UpperBound).map { constraint -> parameter to constraint }
264             }
265         if (parametersWithMultipleConstraints.isNotEmpty()) {
266             keyword(" where ")
267             renderList(parametersWithConstraints) {
268                 identifier(it.first.name)
269                 nbsp()
270                 symbol(":")
271                 nbsp()
272                 renderType(it.second, renderMode)
273             }
274         }
275     }
276 
277     private fun ContentBlock.renderSupertypesForNode(node: DocumentationNode, renderMode: RenderMode) {
278         val supertypes = node.details(NodeKind.Supertype).filterNot { it.qualifiedNameFromType() in ignoredSupertypes }
279         if (supertypes.any()) {
280             nbsp()
281             symbol(":")
282             nbsp()
283             renderList(supertypes) {
284                 indentedSoftLineBreak()
285                 renderType(it, renderMode)
286             }
287         }
288     }
289 
290     private fun ContentBlock.renderAnnotationsForNode(node: DocumentationNode) {
291         node.annotations.forEach {
292             renderAnnotation(it)
293         }
294     }
295 
296     private fun ContentBlock.renderAnnotation(node: DocumentationNode) {
297         identifier("@" + node.name, IdentifierKind.AnnotationName)
298         val parameters = node.details(NodeKind.Parameter)
299         if (!parameters.isEmpty()) {
300             symbol("(")
301             renderList(parameters) {
302                 text(it.detail(NodeKind.Value).name)
303             }
304             symbol(")")
305         }
306         text(" ")
307     }
308 
309     private fun ContentBlock.renderClass(node: DocumentationNode, renderMode: RenderMode) {
310         if (renderMode == RenderMode.FULL) {
311             renderAnnotationsForNode(node)
312         }
313         renderModifiersForNode(node, renderMode)
314         when (node.kind) {
315             NodeKind.Class,
316             NodeKind.AnnotationClass,
317             NodeKind.Exception,
318             NodeKind.Enum -> keyword("class ")
319             NodeKind.Interface -> keyword("interface ")
320             NodeKind.EnumItem -> keyword("enum val ")
321             NodeKind.Object -> keyword("object ")
322             NodeKind.TypeAlias -> keyword("typealias ")
323             else -> throw IllegalArgumentException("Node $node is not a class-like object")
324         }
325 
326         identifierOrDeprecated(node)
327         renderTypeParametersForNode(node, renderMode)
328         renderSupertypesForNode(node, renderMode)
329         renderExtraTypeParameterConstraints(node, renderMode)
330 
331         if (node.kind == NodeKind.TypeAlias) {
332             nbsp()
333             symbol("=")
334             nbsp()
335             renderType(node.detail(NodeKind.TypeAliasUnderlyingType), renderMode)
336         }
337     }
338 
339     private fun ContentBlock.renderFunction(
340         node: DocumentationNode,
341         renderMode: RenderMode,
342         signatureMapper: SignatureMapper? = null
343     ) {
344         if (renderMode == RenderMode.FULL) {
345             renderAnnotationsForNode(node)
346         }
347         renderModifiersForNode(node, renderMode)
348         when (node.kind) {
349             NodeKind.Constructor -> identifier(node.owner!!.name)
350             NodeKind.Function,
351             NodeKind.CompanionObjectFunction -> keyword("fun ")
352             else -> throw IllegalArgumentException("Node $node is not a function-like object")
353         }
354         renderTypeParametersForNode(node, renderMode)
355         if (node.details(NodeKind.TypeParameter).any()) {
356             text(" ")
357         }
358 
359         renderReceiver(node, renderMode, signatureMapper)
360 
361         if (node.kind != NodeKind.Constructor)
362             identifierOrDeprecated(node)
363 
364         symbol("(")
365         val parameters = node.details(NodeKind.Parameter)
366         renderHardWrappingList(parameters) {
367             renderParameter(it, renderMode)
368         }
369         if (needReturnType(node)) {
370             if (parameters.size > 1) {
371                 hardLineBreak()
372             }
373             symbol(")")
374             symbol(": ")
375             renderType(node.detail(NodeKind.Type), renderMode)
376         } else {
377             symbol(")")
378         }
379         renderExtraTypeParameterConstraints(node, renderMode)
380     }
381 
382     private fun ContentBlock.renderReceiver(
383         node: DocumentationNode,
384         renderMode: RenderMode,
385         signatureMapper: SignatureMapper?
386     ) {
387         val receiver = node.details(NodeKind.Receiver).singleOrNull()
388         if (receiver != null) {
389             if (signatureMapper != null) {
390                 signatureMapper.renderReceiver(receiver, this)
391             } else {
392                 val type = receiver.detail(NodeKind.Type)
393 
394                 if (type.isFunctionalType()) {
395                     symbol("(")
396                     renderFunctionalType(type, renderMode)
397                     symbol(")")
398                 } else {
399                     renderType(type, renderMode)
400                 }
401             }
402             symbol(".")
403         }
404     }
405 
406     private fun needReturnType(node: DocumentationNode) = when (node.kind) {
407         NodeKind.Constructor -> false
408         else -> !node.isUnitReturnType()
409     }
410 
411     fun DocumentationNode.isUnitReturnType(): Boolean =
412         detail(NodeKind.Type).hiddenLinks.firstOrNull()?.qualifiedName() == "kotlin.Unit"
413 
414     private fun ContentBlock.renderProperty(
415         node: DocumentationNode,
416         renderMode: RenderMode,
417         signatureMapper: SignatureMapper? = null
418     ) {
419         if (renderMode == RenderMode.FULL) {
420             renderAnnotationsForNode(node)
421         }
422         renderModifiersForNode(node, renderMode)
423         when (node.kind) {
424             NodeKind.Property,
425             NodeKind.CompanionObjectProperty -> keyword("${node.getPropertyKeyword()} ")
426             else -> throw IllegalArgumentException("Node $node is not a property")
427         }
428         renderTypeParametersForNode(node, renderMode)
429         if (node.details(NodeKind.TypeParameter).any()) {
430             text(" ")
431         }
432 
433         renderReceiver(node, renderMode, signatureMapper)
434 
435         identifierOrDeprecated(node)
436         symbol(": ")
437         renderType(node.detail(NodeKind.Type), renderMode)
438         renderExtraTypeParameterConstraints(node, renderMode)
439     }
440 
441     fun DocumentationNode.getPropertyKeyword() =
442         if (details(NodeKind.Modifier).any { it.name == "var" }) "var" else "val"
443 
444     fun ContentBlock.identifierOrDeprecated(node: DocumentationNode) {
445         if (node.deprecation != null) {
446             val strike = ContentStrikethrough()
447             strike.identifier(node.name)
448             append(strike)
449         } else {
450             identifier(node.name)
451         }
452     }
453 }
454 
qualifiedNameFromTypenull455 fun DocumentationNode.qualifiedNameFromType(): String {
456     return details.firstOrNull { it.kind == NodeKind.QualifiedName }?.name
457             ?: (links.firstOrNull { it.kind != NodeKind.ExternalLink } ?: hiddenLinks.firstOrNull())?.qualifiedName()
458             ?: name
459 }
460 
461 
462 val DocumentationNode.typeDeclarationClass
<lambda>null463     get() = (links.firstOrNull { it.kind in NodeKind.classLike } ?: externalType)
464