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