<lambda>null1 package org.jetbrains.dokka
2
3 import com.google.inject.Inject
4 import com.intellij.openapi.util.text.StringUtil
5 import com.intellij.psi.PsiField
6 import com.intellij.psi.PsiJavaFile
7 import org.jetbrains.dokka.DokkaConfiguration.*
8 import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser
9 import org.jetbrains.kotlin.builtins.KotlinBuiltIns
10 import org.jetbrains.kotlin.descriptors.*
11 import org.jetbrains.kotlin.descriptors.annotations.Annotated
12 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
13 import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor
14 import org.jetbrains.kotlin.idea.kdoc.findKDoc
15 import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType
16 import org.jetbrains.kotlin.idea.util.makeNotNullable
17 import org.jetbrains.kotlin.idea.util.toFuzzyType
18 import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
19 import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
20 import org.jetbrains.kotlin.lexer.KtTokens
21 import org.jetbrains.kotlin.name.ClassId
22 import org.jetbrains.kotlin.name.FqName
23 import org.jetbrains.kotlin.name.Name
24 import org.jetbrains.kotlin.psi.KtModifierListOwner
25 import org.jetbrains.kotlin.psi.KtParameter
26 import org.jetbrains.kotlin.psi.KtVariableDeclaration
27 import org.jetbrains.kotlin.resolve.DescriptorUtils
28 import org.jetbrains.kotlin.resolve.constants.ConstantValue
29 import org.jetbrains.kotlin.resolve.descriptorUtil.*
30 import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors
31 import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
32 import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
33 import org.jetbrains.kotlin.resolve.source.PsiSourceElement
34 import org.jetbrains.kotlin.resolve.source.getPsi
35 import org.jetbrains.kotlin.types.*
36 import org.jetbrains.kotlin.types.typeUtil.supertypes
37 import org.jetbrains.kotlin.util.supertypesWithAny
38 import java.io.File
39 import java.nio.file.Path
40 import java.nio.file.Paths
41 import com.google.inject.name.Named as GuiceNamed
42
43 class DocumentationOptions(val outputDir: String,
44 val outputFormat: String,
45 includeNonPublic: Boolean = false,
46 val includeRootPackage: Boolean = false,
47 reportUndocumented: Boolean = true,
48 val skipEmptyPackages: Boolean = true,
49 skipDeprecated: Boolean = false,
50 jdkVersion: Int = 6,
51 val generateClassIndexPage: Boolean = true,
52 val generatePackageIndexPage: Boolean = true,
53 val sourceLinks: List<SourceLinkDefinition> = emptyList(),
54 val impliedPlatforms: List<String> = emptyList(),
55 // Sorted by pattern length
56 perPackageOptions: List<PackageOptions> = emptyList(),
57 externalDocumentationLinks: List<ExternalDocumentationLink> = emptyList(),
58 noStdlibLink: Boolean,
59 noJdkLink: Boolean = false,
60 val languageVersion: String?,
61 val apiVersion: String?,
62 cacheRoot: String? = null,
63 val suppressedFiles: Set<File> = emptySet(),
64 val collectInheritedExtensionsFromLibraries: Boolean = false,
65 val outlineRoot: String = "",
66 val dacRoot: String = "") {
67 init {
68 if (perPackageOptions.any { it.prefix == "" })
69 throw IllegalArgumentException("Please do not register packageOptions with all match pattern, use global settings instead")
70 }
71
72 val perPackageOptions = perPackageOptions.sortedByDescending { it.prefix.length }
73 val rootPackageOptions = PackageOptionsImpl("", includeNonPublic, reportUndocumented, skipDeprecated)
74
75 fun effectivePackageOptions(pack: String): PackageOptions = perPackageOptions.firstOrNull { pack == it.prefix || pack.startsWith(it.prefix + ".") } ?: rootPackageOptions
76 fun effectivePackageOptions(pack: FqName): PackageOptions = effectivePackageOptions(pack.asString())
77
78 val defaultLinks = run {
79 val links = mutableListOf<ExternalDocumentationLink>()
80 //links += ExternalDocumentationLink.Builder("https://developer.android.com/reference/").build()
81 if (!noJdkLink)
82 links += ExternalDocumentationLink.Builder("http://docs.oracle.com/javase/$jdkVersion/docs/api/").build()
83
84 if (!noStdlibLink)
85 links += ExternalDocumentationLink.Builder("https://kotlinlang.org/api/latest/jvm/stdlib/").build()
86 links
87 }
88
89 val externalDocumentationLinks = defaultLinks + externalDocumentationLinks
90
91 val cacheRoot: Path? = when {
92 cacheRoot == "default" -> Paths.get(System.getProperty("user.home"), ".cache", "dokka")
93 cacheRoot != null -> Paths.get(cacheRoot)
94 else -> null
95 }
96 }
97
isExtensionForExternalClassnull98 private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor,
99 extensionReceiverDescriptor: DeclarationDescriptor,
100 allFqNames: Collection<FqName>): Boolean {
101 val extensionFunctionPackage = DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java)
102 val extensionReceiverPackage = DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java)
103 return extensionFunctionPackage != null && extensionReceiverPackage != null &&
104 extensionFunctionPackage.fqName != extensionReceiverPackage.fqName &&
105 extensionReceiverPackage.fqName !in allFqNames
106 }
107
108 interface PackageDocumentationBuilder {
buildPackageDocumentationnull109 fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
110 packageName: FqName,
111 packageNode: DocumentationNode,
112 declarations: List<DeclarationDescriptor>,
113 allFqNames: Collection<FqName>)
114 }
115
116 interface DefaultPlatformsProvider {
117 fun getDefaultPlatforms(descriptor: DeclarationDescriptor): List<String>
118 }
119
120 val ignoredSupertypes = setOf(
121 "kotlin.Annotation", "kotlin.Enum", "kotlin.Any"
122 )
123
124 class DocumentationBuilder
125 @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
126 val descriptorDocumentationParser: DescriptorDocumentationParser,
127 val options: DocumentationOptions,
128 val refGraph: NodeReferenceGraph,
129 val platformNodeRegistry: PlatformNodeRegistry,
130 val logger: DokkaLogger,
131 val linkResolver: DeclarationLinkResolver,
132 val defaultPlatformsProvider: DefaultPlatformsProvider) {
133 val boringBuiltinClasses = setOf(
134 "kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean",
135 "kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any")
136 val knownModifiers = setOf(
137 KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PRIVATE_KEYWORD,
138 KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD,
139 KtTokens.OVERRIDE_KEYWORD)
140
linknull141 fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: RefKind) {
142 refGraph.link(node, descriptor.signature(), kind)
143 }
144
linknull145 fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: RefKind) {
146 if (fromDescriptor != null && toDescriptor != null) {
147 refGraph.link(fromDescriptor.signature(), toDescriptor.signature(), kind)
148 }
149 }
150
registernull151 fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) {
152 refGraph.register(descriptor.signature(), node)
153 }
154
nodeForDescriptornull155 fun <T> nodeForDescriptor(
156 descriptor: T,
157 kind: NodeKind,
158 external: Boolean = false
159 ): DocumentationNode where T : DeclarationDescriptor, T : Named {
160 val (doc, callback) =
161 if (external) {
162 Content.Empty to { node -> }
163 } else {
164 descriptorDocumentationParser.parseDocumentationAndDetails(
165 descriptor,
166 kind == NodeKind.Parameter
167 )
168 }
169 val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor)
170 node.appendSignature(descriptor)
171 callback(node)
172 return node
173 }
174
withModifiersnull175 private fun DocumentationNode.withModifiers(descriptor: DeclarationDescriptor): DocumentationNode {
176 if (descriptor is MemberDescriptor) {
177 appendVisibility(descriptor)
178 if (descriptor !is ConstructorDescriptor) {
179 appendModality(descriptor)
180 }
181 }
182 return this
183 }
184
appendModalitynull185 fun DocumentationNode.appendModality(descriptor: MemberDescriptor) {
186 var modality = descriptor.modality
187 if (modality == Modality.OPEN) {
188 val containingClass = descriptor.containingDeclaration as? ClassDescriptor
189 if (containingClass?.modality == Modality.FINAL) {
190 modality = Modality.FINAL
191 }
192 }
193 val modifier = modality.name.toLowerCase()
194 appendTextNode(modifier, NodeKind.Modifier)
195 }
196
appendVisibilitynull197 fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) {
198 val modifier = descriptor.visibility.normalize().displayName
199 appendTextNode(modifier, NodeKind.Modifier)
200 }
201
appendSupertypenull202 fun DocumentationNode.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) {
203 val unwrappedType = superType.unwrap()
204 if (unwrappedType is AbbreviatedType) {
205 appendSupertype(descriptor, unwrappedType.abbreviation, backref)
206 } else {
207 appendType(unwrappedType, NodeKind.Supertype)
208 val superclass = unwrappedType.constructor.declarationDescriptor
209 if (backref) {
210 link(superclass, descriptor, RefKind.Inheritor)
211 }
212 link(descriptor, superclass, RefKind.Superclass)
213 }
214 }
215
appendProjectionnull216 fun DocumentationNode.appendProjection(projection: TypeProjection, kind: NodeKind = NodeKind.Type) {
217 if (projection.isStarProjection) {
218 appendTextNode("*", NodeKind.Type)
219 } else {
220 appendType(projection.type, kind, projection.projectionKind.label)
221 }
222 }
223
DocumentationNodenull224 fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: NodeKind = NodeKind.Type, prefix: String = "") {
225 if (kotlinType == null)
226 return
227 (kotlinType.unwrap() as? AbbreviatedType)?.let {
228 return appendType(it.abbreviation)
229 }
230
231 if (kotlinType.isDynamic()) {
232 append(DocumentationNode("dynamic", Content.Empty, kind), RefKind.Detail)
233 return
234 }
235
236 val classifierDescriptor = kotlinType.constructor.declarationDescriptor
237 val name = when (classifierDescriptor) {
238 is ClassDescriptor -> {
239 if (classifierDescriptor.isCompanionObject) {
240 classifierDescriptor.containingDeclaration.name.asString() +
241 "." + classifierDescriptor.name.asString()
242 } else {
243 classifierDescriptor.name.asString()
244 }
245 }
246 is Named -> classifierDescriptor.name.asString()
247 else -> "<anonymous>"
248 }
249 val node = DocumentationNode(name, Content.Empty, kind)
250 if (prefix != "") {
251 node.appendTextNode(prefix, NodeKind.Modifier)
252 }
253 if (kotlinType.isNullabilityFlexible()) {
254 node.appendTextNode("!", NodeKind.NullabilityModifier)
255 } else if (kotlinType.isMarkedNullable) {
256 node.appendTextNode("?", NodeKind.NullabilityModifier)
257 }
258 if (classifierDescriptor != null) {
259 val externalLink =
260 linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor)
261 if (externalLink != null) {
262 if (classifierDescriptor !is TypeParameterDescriptor) {
263 val targetNode =
264 refGraph.lookup(classifierDescriptor.signature()) ?: classifierDescriptor.build(true)
265 node.append(targetNode, RefKind.ExternalType)
266 node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
267 }
268 }
269 link(
270 node, classifierDescriptor,
271 if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link
272 )
273 if (classifierDescriptor !is TypeParameterDescriptor) {
274 node.append(
275 DocumentationNode(
276 classifierDescriptor.fqNameUnsafe.asString(),
277 Content.Empty,
278 NodeKind.QualifiedName
279 ), RefKind.Detail
280 )
281 }
282 }
283
284
285 append(node, RefKind.Detail)
286 node.appendAnnotations(kotlinType)
287 for (typeArgument in kotlinType.arguments) {
288 node.appendProjection(typeArgument)
289 }
290 }
291
ClassifierDescriptornull292 fun ClassifierDescriptor.isBoringBuiltinClass(): Boolean =
293 DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses
294
295 fun DocumentationNode.appendAnnotations(annotated: Annotated) {
296 annotated.annotations.forEach {
297 it.build()?.let { annotationNode ->
298 if (annotationNode.isSinceKotlin()) {
299 appendSinceKotlin(annotationNode)
300 }
301 else {
302 val refKind = when {
303 it.isDocumented() ->
304 when {
305 annotationNode.isDeprecation() -> RefKind.Deprecation
306 else -> RefKind.Annotation
307 }
308 it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation
309 else -> return@forEach
310 }
311 append(annotationNode, refKind)
312 }
313
314 }
315 }
316 }
317
DocumentationNodenull318 fun DocumentationNode.appendExternalLink(externalLink: String) {
319 append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
320 }
321
DocumentationNodenull322 fun DocumentationNode.appendExternalLink(descriptor: DeclarationDescriptor) {
323 val target = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(descriptor)
324 if (target != null) {
325 appendExternalLink(target)
326 }
327 }
328
appendSinceKotlinnull329 fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) {
330 val kotlinVersion = annotation
331 .detail(NodeKind.Parameter)
332 .detail(NodeKind.Value)
333 .name.removeSurrounding("\"")
334
335 append(platformNodeRegistry["Kotlin " + kotlinVersion], RefKind.Platform)
336 }
337
appendModifiersnull338 fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) {
339 val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return
340 KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { it !in knownModifiers }.forEach {
341 if (psi.hasModifier(it)) {
342 appendTextNode(it.value, NodeKind.Modifier)
343 }
344 }
345 }
346
appendDefaultPlatformsnull347 fun DocumentationNode.appendDefaultPlatforms(descriptor: DeclarationDescriptor) {
348 for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor)) {
349 append(platformNodeRegistry[platform], RefKind.Platform)
350 }
351 }
352
isDeprecationnull353 fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated"
354
355 fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation
356
357 fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) {
358 appendSourceLink(sourceElement.getPsi(), options.sourceLinks)
359 }
360
appendSignaturenull361 fun DocumentationNode.appendSignature(descriptor: DeclarationDescriptor) {
362 appendTextNode(descriptor.signature(), NodeKind.Signature, RefKind.Detail)
363 }
364
appendChildnull365 fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? {
366 if (!descriptor.isGenerated() && descriptor.isDocumented(options)) {
367 val node = descriptor.build()
368 append(node, kind)
369 return node
370 }
371 return null
372 }
373
<lambda>null374 fun createGroupNode(signature: String, nodes: List<DocumentationNode>) = (nodes.find { it.kind == NodeKind.GroupNode } ?:
<lambda>null375 DocumentationNode(nodes.first().name, Content.Empty, NodeKind.GroupNode).apply {
376 appendTextNode(signature, NodeKind.Signature, RefKind.Detail)
377 })
groupNodenull378 .also { groupNode ->
379 nodes.forEach { node ->
380 if (node != groupNode) {
381 node.owner?.let { owner ->
382 node.dropReferences { it.to == owner && it.kind == RefKind.Owner }
383 owner.dropReferences { it.to == node && it.kind == RefKind.Member }
384 owner.append(groupNode, RefKind.Member)
385 }
386 groupNode.append(node, RefKind.Member)
387 }
388 }
389 }
390
391
DocumentationNodenull392 fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) {
393 if (descriptor.isGenerated() || !descriptor.isDocumented(options)) return
394
395 val existingNode = refGraph.lookup(descriptor.signature())
396 if (existingNode != null) {
397 if (existingNode.kind == NodeKind.TypeAlias && descriptor is ClassDescriptor
398 || existingNode.kind == NodeKind.Class && descriptor is TypeAliasDescriptor) {
399 val node = createGroupNode(descriptor.signature(), listOf(existingNode, descriptor.build()))
400 register(descriptor, node)
401 return
402 }
403
404 existingNode.updatePlatforms(descriptor)
405
406 if (descriptor is ClassDescriptor) {
407 val membersToDocument = descriptor.collectMembersToDocument()
408 for ((memberDescriptor, inheritedLinkKind, extraModifier) in membersToDocument) {
409 if (memberDescriptor is ClassDescriptor) {
410 existingNode.appendOrUpdateMember(memberDescriptor) // recurse into nested classes
411 }
412 else {
413 val existingMemberNode = refGraph.lookup(memberDescriptor.signature())
414 if (existingMemberNode != null) {
415 existingMemberNode.updatePlatforms(memberDescriptor)
416 }
417 else {
418 existingNode.appendClassMember(memberDescriptor, inheritedLinkKind, extraModifier)
419 }
420 }
421 }
422 }
423 }
424 else {
425 appendChild(descriptor, RefKind.Member)
426 }
427 }
428
updatePlatformsnull429 private fun DocumentationNode.updatePlatforms(descriptor: DeclarationDescriptor) {
430 for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor) - platforms) {
431 append(platformNodeRegistry[platform], RefKind.Platform)
432 }
433 }
434
appendClassMembernull435 fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor,
436 inheritedLinkKind: RefKind = RefKind.InheritedMember,
437 extraModifier: String?) {
438 if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
439 val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull()
440 if (baseDescriptor != null) {
441 link(this, baseDescriptor, inheritedLinkKind)
442 }
443 } else {
444 val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original
445 val child = appendChild(descriptorToUse, RefKind.Member)
446 if (extraModifier != null) {
447 child?.appendTextNode("static", NodeKind.Modifier)
448 }
449 }
450 }
451
appendInPageChildrennull452 fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) {
453 descriptors.forEach { descriptor ->
454 val node = appendChild(descriptor, kind)
455 node?.addReferenceTo(this, RefKind.TopLevelPage)
456 }
457 }
458
DocumentationModulenull459 fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>,
460 packageContent: Map<String, Content>,
461 packageDocumentationBuilder: PackageDocumentationBuilder) {
462 val allFqNames = fragments.map { it.fqName }.distinct()
463
464 for (packageName in allFqNames) {
465 if (packageName.isRoot && !options.includeRootPackage) continue
466 val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() }
467
468 if (options.skipEmptyPackages && declarations.none { it.isDocumented(options) }) continue
469 logger.info(" package $packageName: ${declarations.count()} declarations")
470 val packageNode = findOrCreatePackageNode(this, packageName.asString(), packageContent, this@DocumentationBuilder.refGraph)
471 packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode,
472 declarations, allFqNames)
473 }
474
475 }
476
propagateExtensionFunctionsToSubclassesnull477 fun propagateExtensionFunctionsToSubclasses(
478 fragments: Collection<PackageFragmentDescriptor>,
479 resolutionFacade: DokkaResolutionFacade
480 ) {
481
482 val moduleDescriptor = resolutionFacade.moduleDescriptor
483
484 // Wide-collect all view descriptors
485 val allPackageViewDescriptors = generateSequence(listOf(moduleDescriptor.getPackage(FqName.ROOT))) { packages ->
486 packages
487 .flatMap { pkg ->
488 moduleDescriptor.getSubPackagesOf(pkg.fqName) { true }
489 }.map { fqName ->
490 moduleDescriptor.getPackage(fqName)
491 }.takeUnless { it.isEmpty() }
492 }.flatten()
493
494 val allDescriptors =
495 if (options.collectInheritedExtensionsFromLibraries) {
496 allPackageViewDescriptors.map { it.memberScope }
497 } else {
498 fragments.asSequence().map { it.getMemberScope() }
499 }.flatMap {
500 it.getDescriptorsFiltered(
501 DescriptorKindFilter.CALLABLES
502 ).asSequence()
503 }
504
505
506 val documentingDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() }
507 val documentingClasses = documentingDescriptors.filterIsInstance<ClassDescriptor>()
508
509 val classHierarchy = buildClassHierarchy(documentingClasses)
510
511 val allExtensionFunctions =
512 allDescriptors
513 .filterIsInstance<CallableMemberDescriptor>()
514 .filter { it.extensionReceiverParameter != null }
515 val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name }
516
517 for (extensionFunction in allExtensionFunctions) {
518 if (extensionFunction.dispatchReceiverParameter != null) continue
519 val possiblyShadowingFunctions = extensionFunctionsByName[extensionFunction.name]
520 ?.filter { fn -> fn.canShadow(extensionFunction) }
521 ?: emptyList()
522
523 if (extensionFunction.extensionReceiverParameter?.type?.isDynamic() == true) continue
524 val subclasses =
525 classHierarchy.filter { (key) -> key.isExtensionApplicable(extensionFunction) }
526 if (subclasses.isEmpty()) continue
527 subclasses.values.flatten().forEach { subclass ->
528 if (subclass.isExtensionApplicable(extensionFunction) &&
529 possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) {
530
531 val hasExternalLink =
532 linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(
533 extensionFunction
534 ) != null
535 if (hasExternalLink) {
536 val containerDesc =
537 extensionFunction.containingDeclaration as? PackageFragmentDescriptor
538 if (containerDesc != null) {
539 val container = refGraph.lookup(containerDesc.signature())
540 ?: containerDesc.buildExternal()
541 container.append(extensionFunction.buildExternal(), RefKind.Member)
542 }
543 }
544
545 refGraph.link(subclass.signature(), extensionFunction.signature(), RefKind.Extension)
546 }
547 }
548 }
549 }
550
ClassDescriptornull551 private fun ClassDescriptor.isExtensionApplicable(extensionFunction: CallableMemberDescriptor): Boolean {
552 val receiverType = extensionFunction.fuzzyExtensionReceiverType()?.makeNotNullable()
553 val classType = defaultType.toFuzzyType(declaredTypeParameters)
554 return receiverType != null && classType.checkIsSubtypeOf(receiverType) != null
555 }
556
buildClassHierarchynull557 private fun buildClassHierarchy(classes: List<ClassDescriptor>): Map<ClassDescriptor, List<ClassDescriptor>> {
558 val result = hashMapOf<ClassDescriptor, MutableList<ClassDescriptor>>()
559 classes.forEach { cls ->
560 TypeUtils.getAllSupertypes(cls.defaultType).forEach { supertype ->
561 val classDescriptor = supertype.constructor.declarationDescriptor as? ClassDescriptor
562 if (classDescriptor != null) {
563 val subtypesList = result.getOrPut(classDescriptor) { arrayListOf() }
564 subtypesList.add(cls)
565 }
566 }
567 }
568 return result
569 }
570
CallableMemberDescriptornull571 private fun CallableMemberDescriptor.canShadow(other: CallableMemberDescriptor): Boolean {
572 if (this == other) return false
573 if (this is PropertyDescriptor && other is PropertyDescriptor) {
574 return true
575 }
576 if (this is FunctionDescriptor && other is FunctionDescriptor) {
577 val parameters1 = valueParameters
578 val parameters2 = other.valueParameters
579 if (parameters1.size != parameters2.size) {
580 return false
581 }
582 for ((p1, p2) in parameters1 zip parameters2) {
583 if (p1.type != p2.type) {
584 return false
585 }
586 }
587 return true
588 }
589 return false
590 }
591
buildnull592 fun DeclarationDescriptor.build(): DocumentationNode = when (this) {
593 is ClassifierDescriptor -> build()
594 is ConstructorDescriptor -> build()
595 is PropertyDescriptor -> build()
596 is FunctionDescriptor -> build()
597 is ValueParameterDescriptor -> build()
598 is ReceiverParameterDescriptor -> build()
599 else -> throw IllegalStateException("Descriptor $this is not known")
600 }
601
buildExternalnull602 fun PackageFragmentDescriptor.buildExternal(): DocumentationNode {
603 val node = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.Package)
604
605 val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(this)
606 if (externalLink != null) {
607 node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
608 }
609 register(this, node)
610 return node
611 }
612
buildExternalnull613 fun CallableDescriptor.buildExternal(): DocumentationNode = when(this) {
614 is FunctionDescriptor -> build(true)
615 is PropertyDescriptor -> build(true)
616 else -> throw IllegalStateException("Descriptor $this is not known")
617 }
618
619
buildnull620 fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) {
621 is ClassDescriptor -> build(external)
622 is TypeAliasDescriptor -> build(external)
623 is TypeParameterDescriptor -> build()
624 else -> throw IllegalStateException("Descriptor $this is not known")
625 }
626
TypeAliasDescriptornull627 fun TypeAliasDescriptor.build(external: Boolean = false): DocumentationNode {
628 val node = nodeForDescriptor(this, NodeKind.TypeAlias)
629
630 if (!external) {
631 node.appendAnnotations(this)
632 }
633 node.appendModifiers(this)
634 node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
635
636 node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType)
637
638 if (!external) {
639 node.appendSourceLink(source)
640 node.appendDefaultPlatforms(this)
641 }
642 register(this, node)
643 return node
644 }
645
ClassDescriptornull646 fun ClassDescriptor.build(external: Boolean = false): DocumentationNode {
647 val kind = when {
648 kind == ClassKind.OBJECT -> NodeKind.Object
649 kind == ClassKind.INTERFACE -> NodeKind.Interface
650 kind == ClassKind.ENUM_CLASS -> NodeKind.Enum
651 kind == ClassKind.ANNOTATION_CLASS -> NodeKind.AnnotationClass
652 kind == ClassKind.ENUM_ENTRY -> NodeKind.EnumItem
653 isSubclassOfThrowable() -> NodeKind.Exception
654 else -> NodeKind.Class
655 }
656 val node = nodeForDescriptor(this, kind, external)
657 register(this, node)
658 supertypesWithAnyPrecise().forEach {
659 node.appendSupertype(this, it, !external)
660 }
661 if (getKind() != ClassKind.OBJECT && getKind() != ClassKind.ENUM_ENTRY) {
662 node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail)
663 }
664 if (!external) {
665 for ((descriptor, inheritedLinkKind, extraModifier) in collectMembersToDocument()) {
666 node.appendClassMember(descriptor, inheritedLinkKind, extraModifier)
667 }
668 node.appendAnnotations(this)
669 }
670 node.appendModifiers(this)
671 if (!external) {
672 node.appendSourceLink(source)
673 node.appendDefaultPlatforms(this)
674 }
675 return node
676 }
677
678 data class ClassMember(val descriptor: DeclarationDescriptor,
679 val inheritedLinkKind: RefKind = RefKind.InheritedMember,
680 val extraModifier: String? = null)
681
ClassDescriptornull682 fun ClassDescriptor.collectMembersToDocument(): List<ClassMember> {
683 val result = arrayListOf<ClassMember>()
684 if (kind != ClassKind.OBJECT && kind != ClassKind.ENUM_ENTRY) {
685 val constructorsToDocument = if (kind == ClassKind.ENUM_CLASS)
686 constructors.filter { it.valueParameters.size > 0 }
687 else
688 constructors
689 constructorsToDocument.mapTo(result) { ClassMember(it) }
690 }
691
692 defaultType.memberScope.getContributedDescriptors()
693 .filter { it != companionObjectDescriptor }
694 .mapTo(result) { ClassMember(it) }
695
696 staticScope.getContributedDescriptors()
697 .mapTo(result) { ClassMember(it, extraModifier = "static") }
698
699 val companionObjectDescriptor = companionObjectDescriptor
700 if (companionObjectDescriptor != null && companionObjectDescriptor.isDocumented(options)) {
701 val descriptors = companionObjectDescriptor.defaultType.memberScope.getContributedDescriptors()
702 val descriptorsToDocument = descriptors.filter { it !is CallableDescriptor || !it.isInheritedFromAny() }
703 descriptorsToDocument.mapTo(result) {
704 ClassMember(it, inheritedLinkKind = RefKind.InheritedCompanionObjectMember)
705 }
706
707 if (companionObjectDescriptor.getAllSuperclassesWithoutAny().isNotEmpty()
708 || companionObjectDescriptor.getSuperInterfaces().isNotEmpty()) {
709 result += ClassMember(companionObjectDescriptor)
710 }
711 }
712 return result
713 }
714
isInheritedFromAnynull715 fun CallableDescriptor.isInheritedFromAny(): Boolean {
716 return findTopMostOverriddenDescriptors().any {
717 DescriptorUtils.getFqNameSafe(it.containingDeclaration).asString() == "kotlin.Any"
718 }
719 }
720
ClassDescriptornull721 fun ClassDescriptor.isSubclassOfThrowable(): Boolean =
722 defaultType.supertypes().any { it.constructor.declarationDescriptor == builtIns.throwable }
723
buildnull724 fun ConstructorDescriptor.build(): DocumentationNode {
725 val node = nodeForDescriptor(this, NodeKind.Constructor)
726 node.appendInPageChildren(valueParameters, RefKind.Detail)
727 node.appendDefaultPlatforms(this)
728 register(this, node)
729 return node
730 }
731
inCompanionObjectnull732 private fun CallableMemberDescriptor.inCompanionObject(): Boolean {
733 val containingDeclaration = containingDeclaration
734 if ((containingDeclaration as? ClassDescriptor)?.isCompanionObject ?: false) {
735 return true
736 }
737 val receiver = extensionReceiverParameter
738 return (receiver?.type?.constructor?.declarationDescriptor as? ClassDescriptor)?.isCompanionObject ?: false
739 }
740
buildnull741 fun FunctionDescriptor.build(external: Boolean = false): DocumentationNode {
742 if (ErrorUtils.containsErrorType(this)) {
743 logger.warn("Found an unresolved type in ${signatureWithSourceLocation()}")
744 }
745
746 val node = nodeForDescriptor(this, if (inCompanionObject()) NodeKind.CompanionObjectFunction else NodeKind.Function, external)
747
748 node.appendInPageChildren(typeParameters, RefKind.Detail)
749 extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) }
750 node.appendInPageChildren(valueParameters, RefKind.Detail)
751 node.appendType(returnType)
752 node.appendAnnotations(this)
753 node.appendModifiers(this)
754 if (!external) {
755 node.appendSourceLink(source)
756 node.appendDefaultPlatforms(this)
757 } else {
758 node.appendExternalLink(this)
759 }
760
761 overriddenDescriptors.forEach {
762 addOverrideLink(it, this)
763 }
764
765 register(this, node)
766 return node
767 }
768
addOverrideLinknull769 fun addOverrideLink(baseClassFunction: CallableMemberDescriptor, overridingFunction: CallableMemberDescriptor) {
770 val source = baseClassFunction.original.source.getPsi()
771 if (source != null) {
772 link(overridingFunction, baseClassFunction, RefKind.Override)
773 } else {
774 baseClassFunction.overriddenDescriptors.forEach {
775 addOverrideLink(it, overridingFunction)
776 }
777 }
778 }
779
PropertyDescriptornull780 fun PropertyDescriptor.build(external: Boolean = false): DocumentationNode {
781 val node = nodeForDescriptor(
782 this,
783 if (inCompanionObject()) NodeKind.CompanionObjectProperty else NodeKind.Property,
784 external
785 )
786 node.appendInPageChildren(typeParameters, RefKind.Detail)
787 extensionReceiverParameter?.let { node.appendChild(it, RefKind.Detail) }
788 node.appendType(returnType)
789 node.appendAnnotations(this)
790 node.appendModifiers(this)
791 if (!external) {
792 node.appendSourceLink(source)
793 if (isVar) {
794 node.appendTextNode("var", NodeKind.Modifier)
795 }
796
797 if (isConst) {
798 val psi = sourcePsi()
799 val valueText = when (psi) {
800 is KtVariableDeclaration -> psi.initializer?.text
801 is PsiField -> psi.initializer?.text
802 else -> null
803 }
804 valueText?.let { node.appendTextNode(it, NodeKind.Value) }
805 }
806
807
808 getter?.let {
809 if (!it.isDefault) {
810 node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Getter")
811 }
812 }
813 setter?.let {
814 if (!it.isDefault) {
815 node.addAccessorDocumentation(descriptorDocumentationParser.parseDocumentation(it), "Setter")
816 }
817 }
818 node.appendDefaultPlatforms(this)
819 }
820 if (external) {
821 node.appendExternalLink(this)
822 }
823
824 overriddenDescriptors.forEach {
825 addOverrideLink(it, this)
826 }
827
828 register(this, node)
829 return node
830 }
831
addAccessorDocumentationnull832 fun DocumentationNode.addAccessorDocumentation(documentation: Content, prefix: String) {
833 if (documentation == Content.Empty) return
834 updateContent {
835 if (!documentation.children.isEmpty()) {
836 val section = addSection(prefix, null)
837 documentation.children.forEach { section.append(it) }
838 }
839 documentation.sections.forEach {
840 val section = addSection("$prefix ${it.tag}", it.subjectName)
841 it.children.forEach { section.append(it) }
842 }
843 }
844 }
845
buildnull846 fun ValueParameterDescriptor.build(): DocumentationNode {
847 val node = nodeForDescriptor(this, NodeKind.Parameter)
848 node.appendType(varargElementType ?: type)
849 if (declaresDefaultValue()) {
850 val psi = source.getPsi() as? KtParameter
851 if (psi != null) {
852 val defaultValueText = psi.defaultValue?.text
853 if (defaultValueText != null) {
854 node.appendTextNode(defaultValueText, NodeKind.Value)
855 }
856 }
857 }
858 node.appendAnnotations(this)
859 node.appendModifiers(this)
860 if (varargElementType != null && node.details(NodeKind.Modifier).none { it.name == "vararg" }) {
861 node.appendTextNode("vararg", NodeKind.Modifier)
862 }
863 register(this, node)
864 return node
865 }
866
TypeParameterDescriptornull867 fun TypeParameterDescriptor.build(): DocumentationNode {
868 val doc = descriptorDocumentationParser.parseDocumentation(this)
869 val name = name.asString()
870 val prefix = variance.label
871
872 val node = DocumentationNode(name, doc, NodeKind.TypeParameter)
873 if (prefix != "") {
874 node.appendTextNode(prefix, NodeKind.Modifier)
875 }
876 if (isReified) {
877 node.appendTextNode("reified", NodeKind.Modifier)
878 }
879
880 for (constraint in upperBounds) {
881 if (KotlinBuiltIns.isDefaultBound(constraint)) {
882 continue
883 }
884 node.appendType(constraint, NodeKind.UpperBound)
885 }
886 register(this, node)
887 return node
888 }
889
buildnull890 fun ReceiverParameterDescriptor.build(): DocumentationNode {
891 var receiverClass: DeclarationDescriptor = type.constructor.declarationDescriptor!!
892 if ((receiverClass as? ClassDescriptor)?.isCompanionObject ?: false) {
893 receiverClass = receiverClass.containingDeclaration!!
894 } else if (receiverClass is TypeParameterDescriptor) {
895 val upperBoundClass = receiverClass.upperBounds.singleOrNull()?.constructor?.declarationDescriptor
896 if (upperBoundClass != null) {
897 receiverClass = upperBoundClass
898 }
899 }
900
901 if ((containingDeclaration as? FunctionDescriptor)?.dispatchReceiverParameter == null) {
902 link(receiverClass, containingDeclaration, RefKind.Extension)
903 }
904
905 val node = DocumentationNode(name.asString(), Content.Empty, NodeKind.Receiver)
906 node.appendType(type)
907 register(this, node)
908 return node
909 }
910
AnnotationDescriptornull911 fun AnnotationDescriptor.build(): DocumentationNode? {
912 val annotationClass = type.constructor.declarationDescriptor
913 if (annotationClass == null || ErrorUtils.isError(annotationClass)) {
914 return null
915 }
916 val node = DocumentationNode(annotationClass.name.asString(), Content.Empty, NodeKind.Annotation)
917 allValueArguments.forEach { (name, value) ->
918 val valueNode = value.toDocumentationNode()
919 if (valueNode != null) {
920 val paramNode = DocumentationNode(name.asString(), Content.Empty, NodeKind.Parameter)
921 paramNode.append(valueNode, RefKind.Detail)
922 node.append(paramNode, RefKind.Detail)
923 }
924 }
925 return node
926 }
927
toDocumentationNodenull928 fun ConstantValue<*>.toDocumentationNode(): DocumentationNode? = value?.let { value ->
929 when (value) {
930 is String ->
931 "\"" + StringUtil.escapeStringCharacters(value) + "\""
932 is EnumEntrySyntheticClassDescriptor ->
933 value.containingDeclaration.name.asString() + "." + value.name.asString()
934 is Pair<*, *> -> {
935 val (classId, name) = value
936 if (classId is ClassId && name is Name) {
937 classId.shortClassName.asString() + "." + name.asString()
938 } else {
939 value.toString()
940 }
941 }
942 else -> value.toString()
943 }.let { valueString ->
944 DocumentationNode(valueString, Content.Empty, NodeKind.Value)
945 }
946 }
947
948
getParentForPackageMembernull949 fun DocumentationNode.getParentForPackageMember(descriptor: DeclarationDescriptor,
950 externalClassNodes: MutableMap<FqName, DocumentationNode>,
951 allFqNames: Collection<FqName>): DocumentationNode {
952 if (descriptor is CallableMemberDescriptor) {
953 val extensionClassDescriptor = descriptor.getExtensionClassDescriptor()
954 if (extensionClassDescriptor != null && isExtensionForExternalClass(descriptor, extensionClassDescriptor, allFqNames) &&
955 !ErrorUtils.isError(extensionClassDescriptor)) {
956 val fqName = DescriptorUtils.getFqNameSafe(extensionClassDescriptor)
957 return externalClassNodes.getOrPut(fqName, {
958 val newNode = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.ExternalClass)
959 val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(extensionClassDescriptor)
960 if (externalLink != null) {
961 newNode.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link)
962 }
963 append(newNode, RefKind.Member)
964 newNode
965 })
966 }
967 }
968 return this
969 }
970
971 }
972
isDocumentednull973 fun DeclarationDescriptor.isDocumented(options: DocumentationOptions): Boolean {
974 return (options.effectivePackageOptions(fqNameSafe).includeNonPublic
975 || this !is MemberDescriptor
976 || this.visibility.isPublicAPI)
977 && !isDocumentationSuppressed(options)
978 && (!options.effectivePackageOptions(fqNameSafe).skipDeprecated || !isDeprecated())
979 }
980
isGeneratednull981 private fun DeclarationDescriptor.isGenerated() = this is CallableMemberDescriptor && kind != CallableMemberDescriptor.Kind.DECLARATION
982
983 class KotlinPackageDocumentationBuilder : PackageDocumentationBuilder {
984 override fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder,
985 packageName: FqName,
986 packageNode: DocumentationNode,
987 declarations: List<DeclarationDescriptor>,
988 allFqNames: Collection<FqName>) {
989 val externalClassNodes = hashMapOf<FqName, DocumentationNode>()
990 declarations.forEach { descriptor ->
991 with(documentationBuilder) {
992 if (descriptor.isDocumented(options)) {
993 val parent = packageNode.getParentForPackageMember(descriptor, externalClassNodes, allFqNames)
994 parent.appendOrUpdateMember(descriptor)
995 }
996 }
997 }
998 }
999 }
1000
1001 class KotlinJavaDocumentationBuilder
1002 @Inject constructor(val resolutionFacade: DokkaResolutionFacade,
1003 val documentationBuilder: DocumentationBuilder,
1004 val options: DocumentationOptions,
1005 val logger: DokkaLogger) : JavaDocumentationBuilder {
appendFilenull1006 override fun appendFile(file: PsiJavaFile, module: DocumentationModule, packageContent: Map<String, Content>) {
1007 val classDescriptors = file.classes.map {
1008 it.getJavaClassDescriptor(resolutionFacade)
1009 }
1010
1011 if (classDescriptors.any { it != null && it.isDocumented(options) }) {
1012 val packageNode = findOrCreatePackageNode(module, file.packageName, packageContent, documentationBuilder.refGraph)
1013
1014 for (descriptor in classDescriptors.filterNotNull()) {
1015 with(documentationBuilder) {
1016 packageNode.appendChild(descriptor, RefKind.Member)
1017 }
1018 }
1019 }
1020 }
1021 }
1022
1023 private val hiddenAnnotations = setOf(
1024 KotlinBuiltIns.FQ_NAMES.parameterName.asString()
1025 )
1026
AnnotationDescriptornull1027 private fun AnnotationDescriptor.isHiddenInDocumentation() =
1028 type.constructor.declarationDescriptor?.fqNameSafe?.asString() in hiddenAnnotations
1029
1030 private fun AnnotationDescriptor.isDocumented(): Boolean {
1031 if (source.getPsi() != null && mustBeDocumented()) return true
1032 val annotationClassName = type.constructor.declarationDescriptor?.fqNameSafe?.asString()
1033 return annotationClassName == KotlinBuiltIns.FQ_NAMES.extensionFunctionType.asString()
1034 }
1035
AnnotationDescriptornull1036 fun AnnotationDescriptor.mustBeDocumented(): Boolean {
1037 val annotationClass = type.constructor.declarationDescriptor as? Annotated ?: return false
1038 return annotationClass.isDocumentedAnnotation()
1039 }
1040
isDocumentationSuppressednull1041 fun DeclarationDescriptor.isDocumentationSuppressed(options: DocumentationOptions): Boolean {
1042
1043 if (options.effectivePackageOptions(fqNameSafe).suppress) return true
1044
1045 val path = this.findPsi()?.containingFile?.virtualFile?.path
1046 if (path != null) {
1047 if (File(path).absoluteFile in options.suppressedFiles) return true
1048 }
1049
1050 val doc = findKDoc()
1051 if (doc is KDocSection && doc.findTagByName("suppress") != null) return true
1052
1053 return hasSuppressDocTag(sourcePsi()) || hasHideAnnotation(sourcePsi())
1054 }
1055
DeclarationDescriptornull1056 fun DeclarationDescriptor.sourcePsi() =
1057 ((original as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi
1058
1059 fun DeclarationDescriptor.isDeprecated(): Boolean = annotations.any {
1060 DescriptorUtils.getFqName(it.type.constructor.declarationDescriptor!!).asString() == "kotlin.Deprecated"
1061 } || (this is ConstructorDescriptor && containingDeclaration.isDeprecated())
1062
getExtensionClassDescriptornull1063 fun CallableMemberDescriptor.getExtensionClassDescriptor(): ClassifierDescriptor? {
1064 val extensionReceiver = extensionReceiverParameter
1065 if (extensionReceiver != null) {
1066 val type = extensionReceiver.type
1067 val receiverClass = type.constructor.declarationDescriptor as? ClassDescriptor
1068 if (receiverClass?.isCompanionObject ?: false) {
1069 return receiverClass?.containingDeclaration as? ClassifierDescriptor
1070 }
1071 return receiverClass
1072 }
1073 return null
1074 }
1075
signaturenull1076 fun DeclarationDescriptor.signature(): String {
1077 if (this != original) return original.signature()
1078 return when (this) {
1079 is ClassDescriptor,
1080 is PackageFragmentDescriptor,
1081 is PackageViewDescriptor,
1082 is TypeAliasDescriptor -> DescriptorUtils.getFqName(this).asString()
1083
1084 is PropertyDescriptor -> containingDeclaration.signature() + "$" + name + receiverSignature()
1085 is FunctionDescriptor -> containingDeclaration.signature() + "$" + name + parameterSignature()
1086 is ValueParameterDescriptor -> containingDeclaration.signature() + "/" + name
1087 is TypeParameterDescriptor -> containingDeclaration.signature() + "*" + name
1088 is ReceiverParameterDescriptor -> containingDeclaration.signature() + "/" + name
1089 else -> throw UnsupportedOperationException("Don't know how to calculate signature for $this")
1090 }
1091 }
1092
receiverSignaturenull1093 fun PropertyDescriptor.receiverSignature(): String {
1094 val receiver = extensionReceiverParameter
1095 if (receiver != null) {
1096 return "#" + receiver.type.signature()
1097 }
1098 return ""
1099 }
1100
parameterSignaturenull1101 fun CallableMemberDescriptor.parameterSignature(): String {
1102 val params = valueParameters.map { it.type }.toMutableList()
1103 val extensionReceiver = extensionReceiverParameter
1104 if (extensionReceiver != null) {
1105 params.add(0, extensionReceiver.type)
1106 }
1107 return params.joinToString(prefix = "(", postfix = ")") { it.signature() }
1108 }
1109
signaturenull1110 fun KotlinType.signature(): String {
1111 val visited = hashSetOf<KotlinType>()
1112
1113 fun KotlinType.signatureRecursive(): String {
1114 if (this in visited) {
1115 return ""
1116 }
1117 visited.add(this)
1118
1119 val declarationDescriptor = constructor.declarationDescriptor ?: return "<null>"
1120 val typeName = DescriptorUtils.getFqName(declarationDescriptor).asString()
1121 if (arguments.isEmpty()) {
1122 return typeName
1123 }
1124 return typeName + arguments.joinToString(prefix = "((", postfix = "))") { it.type.signatureRecursive() }
1125 }
1126
1127 return signatureRecursive()
1128 }
1129
signatureWithSourceLocationnull1130 fun DeclarationDescriptor.signatureWithSourceLocation(): String {
1131 val signature = signature()
1132 val sourceLocation = sourceLocation()
1133 return if (sourceLocation != null) "$signature ($sourceLocation)" else signature
1134 }
1135
DeclarationDescriptornull1136 fun DeclarationDescriptor.sourceLocation(): String? {
1137 val psi = sourcePsi()
1138 if (psi != null) {
1139 val fileName = psi.containingFile.name
1140 val lineNumber = psi.lineNumber()
1141 return if (lineNumber != null) "$fileName:$lineNumber" else fileName
1142 }
1143 return null
1144 }
1145
DocumentationModulenull1146 fun DocumentationModule.prepareForGeneration(options: DocumentationOptions) {
1147 if (options.generateClassIndexPage) {
1148 generateAllTypesNode()
1149 }
1150 nodeRefGraph.resolveReferences()
1151 }
1152
generateAllTypesNodenull1153 fun DocumentationNode.generateAllTypesNode() {
1154 val allTypes = members(NodeKind.Package)
1155 .flatMap { it.members.filter { it.kind in NodeKind.classLike || it.kind == NodeKind.ExternalClass } }
1156 .sortedBy { if (it.kind == NodeKind.ExternalClass) it.name.substringAfterLast('.').toLowerCase() else it.name.toLowerCase() }
1157
1158 val allTypesNode = DocumentationNode("alltypes", Content.Empty, NodeKind.AllTypes)
1159 for (typeNode in allTypes) {
1160 allTypesNode.addReferenceTo(typeNode, RefKind.Member)
1161 }
1162
1163 append(allTypesNode, RefKind.Member)
1164 }
1165
ClassDescriptornull1166 fun ClassDescriptor.supertypesWithAnyPrecise(): Collection<KotlinType> {
1167 if (KotlinBuiltIns.isAny(this)) {
1168 return emptyList()
1169 }
1170 return typeConstructor.supertypesWithAny()
1171 }