diff options
| author | Błażej Kardyś <bkardys@virtuslab.com> | 2019-10-31 11:44:03 +0100 |
|---|---|---|
| committer | Błażej Kardyś <bkardys@virtuslab.com> | 2019-10-31 11:44:03 +0100 |
| commit | c33e8e16a0e446b78496cbcd878ba76ea51c0940 (patch) | |
| tree | 7362b668c5ee48255e46a7efcb8db3f2525d1e8f /core/src/main/kotlin/Kotlin | |
| parent | 14a290009098b777521b1dedb551047fb66ba73b (diff) | |
| download | dokka-c33e8e16a0e446b78496cbcd878ba76ea51c0940.tar.gz dokka-c33e8e16a0e446b78496cbcd878ba76ea51c0940.tar.bz2 dokka-c33e8e16a0e446b78496cbcd878ba76ea51c0940.zip | |
Temp changes
Diffstat (limited to 'core/src/main/kotlin/Kotlin')
3 files changed, 186 insertions, 806 deletions
diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt index ce20aeec..7c9f2d15 100644 --- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt +++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt @@ -30,20 +30,28 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.source.PsiSourceElement class DescriptorDocumentationParser - @Inject constructor(val options: DokkaConfiguration.PassConfiguration, - val logger: DokkaLogger, - val linkResolver: DeclarationLinkResolver, - val resolutionFacade: DokkaResolutionFacade, - val refGraph: NodeReferenceGraph, - val sampleService: SampleProcessingService, - val signatureProvider: KotlinElementSignatureProvider, - val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver -) -{ - fun parseDocumentation(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Content = - parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first +@Inject constructor( + val options: DokkaConfiguration.PassConfiguration, + val logger: DokkaLogger, + val linkResolver: DeclarationLinkResolver, + val resolutionFacade: DokkaResolutionFacade, + val refGraph: NodeReferenceGraph, + val sampleService: SampleProcessingService, + val signatureProvider: KotlinElementSignatureProvider, + val externalDocumentationLinkResolver: ExternalDocumentationLinkResolver +) { + fun parseDocumentation( + descriptor: DeclarationDescriptor, + inline: Boolean = false, + isDefaultNoArgConstructor: Boolean = false + ): Content = + parseDocumentationAndDetails(descriptor, inline, isDefaultNoArgConstructor).first - fun parseDocumentationAndDetails(descriptor: DeclarationDescriptor, inline: Boolean = false, isDefaultNoArgConstructor: Boolean = false): Pair<Content, (DocumentationNode) -> Unit> { + fun parseDocumentationAndDetails( + descriptor: DeclarationDescriptor, + inline: Boolean = false, + isDefaultNoArgConstructor: Boolean = false + ): Pair<Content, (DocumentationNode) -> Unit> { if (descriptor is JavaClassDescriptor || descriptor is JavaCallableMemberDescriptor) { return parseJavadoc(descriptor) } @@ -51,8 +59,8 @@ class DescriptorDocumentationParser val kdoc = descriptor.findKDoc() ?: findStdlibKDoc(descriptor) if (kdoc == null) { if (options.effectivePackageOptions(descriptor.fqNameSafe).reportUndocumented && !descriptor.isDeprecated() && - descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor && - descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) { + descriptor !is ValueParameterDescriptor && descriptor !is TypeParameterDescriptor && + descriptor !is PropertyAccessorDescriptor && !descriptor.isSuppressWarning()) { logger.warn("No documentation for ${descriptor.signatureWithSourceLocation()}") } return Content.Empty to { node -> } @@ -62,7 +70,7 @@ class DescriptorDocumentationParser (PsiTreeUtil.getParentOfType(kdoc, KDoc::class.java)?.context as? KtDeclaration) ?.takeIf { it != descriptor.original.sourcePsi() } ?.resolveToDescriptorIfAny() - ?: descriptor + ?: descriptor var kdocText = if (isDefaultNoArgConstructor) { getConstructorTagContent(descriptor) ?: kdoc.getContent() @@ -74,7 +82,11 @@ class DescriptorDocumentationParser } val tree = parseMarkdown(kdocText) val linkMap = LinkMap.buildLinkMap(tree.node, kdocText) - val content = buildContent(tree, LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }, inline) + val content = buildContent( + tree, + LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }, + inline + ) if (kdoc is KDocSection) { val tags = kdoc.getTags() tags.forEach { @@ -87,7 +99,10 @@ class DescriptorDocumentationParser val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName()) val sectionContent = it.getContent() val markdownNode = parseMarkdown(sectionContent) - buildInlineContentTo(markdownNode, section, LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }) + buildInlineContentTo( + markdownNode, + section, + LinkResolver(linkMap) { href -> linkResolver.resolveContentLink(contextDescriptor, href) }) } } } @@ -102,7 +117,7 @@ class DescriptorDocumentationParser } - private fun DeclarationDescriptor.isSuppressWarning() : Boolean { + private fun DeclarationDescriptor.isSuppressWarning(): Boolean { val suppressAnnotation = annotations.findAnnotation(FqName(Suppress::class.qualifiedName!!)) return if (suppressAnnotation != null) { @Suppress("UNCHECKED_CAST") @@ -126,11 +141,12 @@ class DescriptorDocumentationParser } if (DescriptorUtils.getFqName(deepestDescriptor.containingDeclaration).asString() == "kotlin.Any") { val anyClassDescriptors = resolutionFacade.resolveSession.getTopLevelClassifierDescriptors( - FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE) + FqName.fromSegments(listOf("kotlin", "Any")), NoLookupLocation.FROM_IDE + ) anyClassDescriptors.forEach { val anyMethod = (it as ClassDescriptor).getMemberScope(listOf()) - .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name } - .single() + .getDescriptorsFiltered(DescriptorKindFilter.FUNCTIONS) { it == descriptor.name } + .single() val kdoc = anyMethod.findKDoc() if (kdoc != null) { return kdoc @@ -145,17 +161,12 @@ class DescriptorDocumentationParser val psi = ((descriptor as? DeclarationDescriptorWithSource)?.source as? PsiSourceElement)?.psi if (psi is PsiDocCommentOwner) { val parseResult = JavadocParser( - refGraph, - logger, - signatureProvider, - externalDocumentationLinkResolver + refGraph, + logger, + signatureProvider, + externalDocumentationLinkResolver ).parseDocumentation(psi as PsiNamedElement) - return parseResult.content to { node -> - parseResult.deprecatedContent?.let { - val deprecationNode = DocumentationNode("", it, NodeKind.Modifier) - node.append(deprecationNode, RefKind.Deprecation) - } - } + return parseResult.content to { node -> } } return Content.Empty to { node -> } } diff --git a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt index 3168e033..6d258564 100644 --- a/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt +++ b/core/src/main/kotlin/Kotlin/DocumentationBuilder.kt @@ -1,61 +1,51 @@ package org.jetbrains.dokka import com.google.inject.Inject -import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiJavaFile import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration -import org.jetbrains.dokka.Kotlin.DescriptorDocumentationParser import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.coroutines.hasFunctionOrSuspendFunctionType import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotated -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor -import org.jetbrains.kotlin.descriptors.impl.EnumEntrySyntheticClassDescriptor import org.jetbrains.kotlin.idea.kdoc.findKDoc -import org.jetbrains.kotlin.idea.util.fuzzyExtensionReceiverType -import org.jetbrains.kotlin.idea.util.makeNotNullable -import org.jetbrains.kotlin.idea.util.toFuzzyType import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtModifierListOwner -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.descriptorUtil.* import org.jetbrains.kotlin.resolve.findTopMostOverriddenDescriptors import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.source.PsiSourceElement -import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.util.supertypesWithAny +import kotlin.reflect.KClass import com.google.inject.name.Named as GuiceNamed -private fun isExtensionForExternalClass(extensionFunctionDescriptor: DeclarationDescriptor, - extensionReceiverDescriptor: DeclarationDescriptor, - allFqNames: Collection<FqName>): Boolean { - val extensionFunctionPackage = DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java) - val extensionReceiverPackage = DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java) +private fun isExtensionForExternalClass( + extensionFunctionDescriptor: DeclarationDescriptor, + extensionReceiverDescriptor: DeclarationDescriptor, + allFqNames: Collection<FqName> +): Boolean { + val extensionFunctionPackage = + DescriptorUtils.getParentOfType(extensionFunctionDescriptor, PackageFragmentDescriptor::class.java) + val extensionReceiverPackage = + DescriptorUtils.getParentOfType(extensionReceiverDescriptor, PackageFragmentDescriptor::class.java) return extensionFunctionPackage != null && extensionReceiverPackage != null && extensionFunctionPackage.fqName != extensionReceiverPackage.fqName && extensionReceiverPackage.fqName !in allFqNames } interface PackageDocumentationBuilder { - fun buildPackageDocumentation(documentationBuilder: DocumentationBuilder, - packageName: FqName, - packageNode: DocumentationNode, - declarations: List<DeclarationDescriptor>, - allFqNames: Collection<FqName>) + fun buildPackageDocumentation( + documentationBuilder: DocumentationBuilder, + packageName: FqName, + packageNode: DocumentationNodes.Package, + declarations: List<DeclarationDescriptor>, + allFqNames: Collection<FqName> + ) } interface DefaultPlatformsProvider { @@ -67,121 +57,33 @@ val ignoredSupertypes = setOf( ) class DocumentationBuilder -@Inject constructor(val resolutionFacade: DokkaResolutionFacade, - val descriptorDocumentationParser: DescriptorDocumentationParser, - val passConfiguration: DokkaConfiguration.PassConfiguration, - val refGraph: NodeReferenceGraph, - val platformNodeRegistry: PlatformNodeRegistry, - val logger: DokkaLogger, - val linkResolver: DeclarationLinkResolver, - val defaultPlatformsProvider: DefaultPlatformsProvider) { - val boringBuiltinClasses = setOf( - "kotlin.Unit", "kotlin.Byte", "kotlin.Short", "kotlin.Int", "kotlin.Long", "kotlin.Char", "kotlin.Boolean", - "kotlin.Float", "kotlin.Double", "kotlin.String", "kotlin.Array", "kotlin.Any") - val knownModifiers = setOf( - KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.INTERNAL_KEYWORD, KtTokens.PRIVATE_KEYWORD, - KtTokens.OPEN_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.ABSTRACT_KEYWORD, KtTokens.SEALED_KEYWORD, - KtTokens.OVERRIDE_KEYWORD, KtTokens.INLINE_KEYWORD) - - fun link(node: DocumentationNode, descriptor: DeclarationDescriptor, kind: RefKind) { - refGraph.link(node, descriptor.signature(), kind) - } - - fun link(fromDescriptor: DeclarationDescriptor?, toDescriptor: DeclarationDescriptor?, kind: RefKind) { - if (fromDescriptor != null && toDescriptor != null) { - refGraph.link(fromDescriptor.signature(), toDescriptor.signature(), kind) - } - } - - fun register(descriptor: DeclarationDescriptor, node: DocumentationNode) { - refGraph.register(descriptor.signature(), node) - } - - fun <T> nodeForDescriptor( - descriptor: T, - kind: NodeKind, - external: Boolean = false - ): DocumentationNode where T : DeclarationDescriptor, T : Named { - val (doc, callback) = - if (external) { - Content.Empty to { node -> } - } else { - descriptorDocumentationParser.parseDocumentationAndDetails( - descriptor, - kind == NodeKind.Parameter - ) - } - val node = DocumentationNode(descriptor.name.asString(), doc, kind).withModifiers(descriptor) - node.appendSignature(descriptor) - callback(node) - return node - } - - private fun DocumentationNode.withModifiers(descriptor: DeclarationDescriptor): DocumentationNode { - if (descriptor is MemberDescriptor) { - appendVisibility(descriptor) - if (descriptor !is ConstructorDescriptor) { - appendModality(descriptor) - } - } - return this - } +@Inject constructor( + val resolutionFacade: DokkaResolutionFacade, + val passConfiguration: DokkaConfiguration.PassConfiguration, + val logger: DokkaLogger +) { - fun DocumentationNode.appendModality(descriptor: MemberDescriptor) { - var modality = descriptor.modality - if (modality == Modality.OPEN) { - val containingClass = descriptor.containingDeclaration as? ClassDescriptor - if (containingClass?.modality == Modality.FINAL) { - modality = Modality.FINAL - } - } - val modifier = modality.name.toLowerCase() - appendTextNode(modifier, NodeKind.Modifier) - } - - fun DocumentationNode.appendInline(descriptor: DeclarationDescriptor, psi: KtModifierListOwner) { - if (!psi.hasModifier(KtTokens.INLINE_KEYWORD)) return - if (descriptor is FunctionDescriptor - && descriptor.valueParameters.none { it.hasFunctionOrSuspendFunctionType }) return - appendTextNode(KtTokens.INLINE_KEYWORD.value, NodeKind.Modifier) - } - - fun DocumentationNode.appendVisibility(descriptor: DeclarationDescriptorWithVisibility) { - val modifier = descriptor.visibility.normalize().displayName - appendTextNode(modifier, NodeKind.Modifier) - } - - fun DocumentationNode.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) { + private fun DocumentationNodes.Class.appendSupertype(descriptor: ClassDescriptor, superType: KotlinType, backref: Boolean) { val unwrappedType = superType.unwrap() if (unwrappedType is AbbreviatedType) { appendSupertype(descriptor, unwrappedType.abbreviation, backref) } else { - appendType(unwrappedType, NodeKind.Supertype) - val superclass = unwrappedType.constructor.declarationDescriptor - if (backref) { - link(superclass, descriptor, RefKind.Inheritor) - } - link(descriptor, superclass, RefKind.Superclass) + appendType(unwrappedType, descriptor) } } - fun DocumentationNode.appendProjection(projection: TypeProjection, kind: NodeKind = NodeKind.Type) { - if (projection.isStarProjection) { - appendTextNode("*", NodeKind.Type) - } else { - appendType(projection.type, kind, projection.projectionKind.label) - } - } - - fun DocumentationNode.appendType(kotlinType: KotlinType?, kind: NodeKind = NodeKind.Type, prefix: String = "") { + private fun DocumentationNodes.Class.appendType( + kotlinType: KotlinType?, + descriptor: ClassDescriptor? + ) { if (kotlinType == null) return (kotlinType.unwrap() as? AbbreviatedType)?.let { - return appendType(it.abbreviation) + return appendType(it.abbreviation, descriptor) } if (kotlinType.isDynamic()) { - append(DocumentationNode("dynamic", Content.Empty, kind), RefKind.Detail) + append(kind.createNode("dynamic", descriptor), RefKind.Detail) return } @@ -198,244 +100,80 @@ class DocumentationBuilder is Named -> classifierDescriptor.name.asString() else -> "<anonymous>" } - val node = DocumentationNode(name, Content.Empty, kind) - if (prefix != "") { - node.appendTextNode(prefix, NodeKind.Modifier) - } - if (kotlinType.isNullabilityFlexible()) { - node.appendTextNode("!", NodeKind.NullabilityModifier) - } else if (kotlinType.isMarkedNullable) { - node.appendTextNode("?", NodeKind.NullabilityModifier) - } - if (classifierDescriptor != null) { - val externalLink = - linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(classifierDescriptor) - if (externalLink != null) { - if (classifierDescriptor !is TypeParameterDescriptor) { - val targetNode = - refGraph.lookup(classifierDescriptor.signature()) ?: classifierDescriptor.build(true) - node.append(targetNode, RefKind.ExternalType) - node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - } else { - link( - node, classifierDescriptor, - if (classifierDescriptor.isBoringBuiltinClass()) RefKind.HiddenLink else RefKind.Link - ) - } - if (classifierDescriptor !is TypeParameterDescriptor) { - node.append( - DocumentationNode( - classifierDescriptor.fqNameUnsafe.asString(), - Content.Empty, - NodeKind.QualifiedName - ), RefKind.Detail - ) - } - } - + val node = kind.createNode(name, descriptor) append(node, RefKind.Detail) - node.appendAnnotations(kotlinType) for (typeArgument in kotlinType.arguments) { - node.appendProjection(typeArgument) - } - } - - fun ClassifierDescriptor.isBoringBuiltinClass(): Boolean = - DescriptorUtils.getFqName(this).asString() in boringBuiltinClasses - - fun DocumentationNode.appendAnnotations(annotated: Annotated) { - annotated.annotations.forEach { - it.build()?.let { annotationNode -> - if (annotationNode.isSinceKotlin()) { - appendSinceKotlin(annotationNode) - } - else { - val refKind = when { - it.isDocumented() -> - when { - annotationNode.isDeprecation() -> RefKind.Deprecation - else -> RefKind.Annotation - } - it.isHiddenInDocumentation() -> RefKind.HiddenAnnotation - else -> return@forEach - } - append(annotationNode, refKind) - } - - } - } - } - - fun DocumentationNode.appendExternalLink(externalLink: String) { - append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - - fun DocumentationNode.appendExternalLink(descriptor: DeclarationDescriptor) { - val target = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(descriptor) - if (target != null) { - appendExternalLink(target) - } - } - - fun DocumentationNode.appendSinceKotlin(annotation: DocumentationNode) { - val kotlinVersion = annotation - .detail(NodeKind.Parameter) - .detail(NodeKind.Value) - .name.removeSurrounding("\"") - - sinceKotlin = kotlinVersion - } - - fun DocumentationNode.appendDefaultSinceKotlin() { - if (sinceKotlin == null) { - sinceKotlin = passConfiguration.sinceKotlin - } - } - - fun DocumentationNode.appendModifiers(descriptor: DeclarationDescriptor) { - val psi = (descriptor as DeclarationDescriptorWithSource).source.getPsi() as? KtModifierListOwner ?: return - KtTokens.MODIFIER_KEYWORDS_ARRAY.filter { - it !in knownModifiers - }.sortedBy { - MODIFIERS_ORDER.indexOf(it) - }.forEach { - if (psi.hasModifier(it)) { - appendTextNode(it.value, NodeKind.Modifier) - } + node.appendProjection(typeArgument, null) } - appendInline(descriptor, psi) } - fun DocumentationNode.appendDefaultPlatforms(descriptor: DeclarationDescriptor) { - for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor)) { - append(platformNodeRegistry[platform], RefKind.Platform) - } - } - - fun DocumentationNode.isDeprecation() = name == "Deprecated" || name == "deprecated" - - fun DocumentationNode.isSinceKotlin() = name == "SinceKotlin" && kind == NodeKind.Annotation - - fun DocumentationNode.appendSourceLink(sourceElement: SourceElement) { - appendSourceLink(sourceElement.getPsi(), passConfiguration.sourceLinks) - } - - fun DocumentationNode.appendSignature(descriptor: DeclarationDescriptor) { - appendTextNode(descriptor.signature(), NodeKind.Signature, RefKind.Detail) - } - - fun DocumentationNode.appendChild(descriptor: DeclarationDescriptor, kind: RefKind): DocumentationNode? { + fun DocumentationNode<*>.appendChild(descriptor: DeclarationDescriptor) { if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) { val node = descriptor.build() append(node, kind) - return node } - return null } - fun createGroupNode(signature: String, nodes: List<DocumentationNode>) = (nodes.find { it.kind == NodeKind.GroupNode } ?: - DocumentationNode(nodes.first().name, Content.Empty, NodeKind.GroupNode).apply { - appendTextNode(signature, NodeKind.Signature, RefKind.Detail) - }) - .also { groupNode -> - nodes.forEach { node -> - if (node != groupNode) { - node.owner?.let { owner -> - node.dropReferences { it.to == owner && it.kind == RefKind.Owner } - owner.dropReferences { it.to == node && it.kind == RefKind.Member } - owner.append(groupNode, RefKind.Member) - } - groupNode.append(node, RefKind.Member) - } - } - } - - - fun DocumentationNode.appendOrUpdateMember(descriptor: DeclarationDescriptor) { - if (descriptor.isGenerated() || !descriptor.isDocumented(passConfiguration)) return - - val existingNode = refGraph.lookup(descriptor.signature()) - if (existingNode != null) { - if (existingNode.kind == NodeKind.TypeAlias && descriptor is ClassDescriptor - || existingNode.kind == NodeKind.Class && descriptor is TypeAliasDescriptor) { - val node = createGroupNode(descriptor.signature(), listOf(existingNode, descriptor.build())) - register(descriptor, node) - return - } - - existingNode.updatePlatforms(descriptor) - - if (descriptor is ClassDescriptor) { - val membersToDocument = descriptor.collectMembersToDocument() - for ((memberDescriptor, inheritedLinkKind, extraModifier) in membersToDocument) { - if (memberDescriptor is ClassDescriptor) { - existingNode.appendOrUpdateMember(memberDescriptor) // recurse into nested classes - } - else { - val existingMemberNode = refGraph.lookup(memberDescriptor.signature()) - if (existingMemberNode != null) { - existingMemberNode.updatePlatforms(memberDescriptor) - } - else { - existingNode.appendClassMember(memberDescriptor, inheritedLinkKind, extraModifier) + fun DocumentationNode.appendMember(descriptor: DeclarationDescriptor) { + if (!descriptor.isGenerated() && descriptor.isDocumented(passConfiguration)) { + val existingNode = members.firstOrNull { it.descriptor?.fqNameSafe == descriptor.fqNameSafe } + if (existingNode != null) { + if (descriptor is ClassDescriptor) { + val membersToDocument = descriptor.collectMembersToDocument() + for ((memberDescriptor, _, _) in membersToDocument) { + if (memberDescriptor is ClassDescriptor) { + existingNode.appendMember(memberDescriptor) // recurse into nested classes + } else { + if (members.any { it.descriptor?.fqNameSafe == memberDescriptor.fqNameSafe }) { + existingNode.appendClassMember(memberDescriptor) + } } } } + } else { + appendChild(descriptor, RefKind.Member) } } - else { - appendChild(descriptor, RefKind.Member) - } - } - - private fun DocumentationNode.updatePlatforms(descriptor: DeclarationDescriptor) { - for (platform in defaultPlatformsProvider.getDefaultPlatforms(descriptor) - platforms) { - append(platformNodeRegistry[platform], RefKind.Platform) - } } - fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor, - inheritedLinkKind: RefKind = RefKind.InheritedMember, - extraModifier: String?) { - if (descriptor is CallableMemberDescriptor && descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { - val baseDescriptor = descriptor.overriddenDescriptors.firstOrNull() - if (baseDescriptor != null) { - link(this, baseDescriptor, inheritedLinkKind) - } - } else { + private fun DocumentationNode.appendClassMember(descriptor: DeclarationDescriptor) { + if (descriptor !is CallableMemberDescriptor || descriptor.kind != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { val descriptorToUse = if (descriptor is ConstructorDescriptor) descriptor else descriptor.original - val child = appendChild(descriptorToUse, RefKind.Member) - if (extraModifier != null) { - child?.appendTextNode("static", NodeKind.Modifier) - } + appendChild(descriptorToUse, RefKind.Member) } } - fun DocumentationNode.appendInPageChildren(descriptors: Iterable<DeclarationDescriptor>, kind: RefKind) { - descriptors.forEach { descriptor -> - val node = appendChild(descriptor, kind) - node?.addReferenceTo(this, RefKind.TopLevelPage) - } - } - - fun DocumentationModule.appendFragments(fragments: Collection<PackageFragmentDescriptor>, - packageContent: Map<String, Content>, - packageDocumentationBuilder: PackageDocumentationBuilder) { - val allFqNames = fragments.filter{ it.isDocumented(passConfiguration) }.map { it.fqName }.distinct() + fun DocumentationNodes.Module.appendFragments( + fragments: Collection<PackageFragmentDescriptor>, + packageDocumentationBuilder: PackageDocumentationBuilder + ) { + val allFqNames = fragments.filter { it.isDocumented(passConfiguration) }.map { it.fqName }.distinct() for (packageName in allFqNames) { if (packageName.isRoot && !passConfiguration.includeRootPackage) continue - val declarations = fragments.filter { it.fqName == packageName }.flatMap { it.getMemberScope().getContributedDescriptors() } + val declarations = fragments.filter { it.fqName == packageName } + .flatMap { it.getMemberScope().getContributedDescriptors() } if (passConfiguration.skipEmptyPackages && declarations.none { it.isDocumented(passConfiguration) }) continue logger.info(" package $packageName: ${declarations.count()} declarations") - val packageNode = findOrCreatePackageNode(this, packageName.asString(), packageContent, this@DocumentationBuilder.refGraph) - packageDocumentationBuilder.buildPackageDocumentation(this@DocumentationBuilder, packageName, packageNode, - declarations, allFqNames) + val packageNode = findOrCreatePackageNode(this, packageName.asString()) + packageDocumentationBuilder.buildPackageDocumentation( + this@DocumentationBuilder, packageName, packageNode, + declarations, allFqNames + ) } + } + fun findOrCreatePackageNode( + module: DocumentationNodes.Module, + packageName: String + ): DocumentationNode<*> { + val node = module?.member(DocumentationNodes.Package::class) ?: DocumentationNodes.Package(packageName) + if (module != null && node !in module.members) { + module.append(node, RefKind.Member) + } + return node } fun propagateExtensionFunctionsToSubclasses( @@ -466,12 +204,6 @@ class DocumentationBuilder ).asSequence() } - - val documentingDescriptors = fragments.flatMap { it.getMemberScope().getContributedDescriptors() } - val documentingClasses = documentingDescriptors.filterIsInstance<ClassDescriptor>() - - val classHierarchy = buildClassHierarchy(documentingClasses) - val allExtensionFunctions = allDescriptors .filterIsInstance<CallableMemberDescriptor>() @@ -479,9 +211,9 @@ class DocumentationBuilder val extensionFunctionsByName = allExtensionFunctions.groupBy { it.name } fun isIgnoredReceiverType(type: KotlinType) = - type.isDynamic() || - type.isAnyOrNullableAny() || - (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() }) + type.isDynamic() || + type.isAnyOrNullableAny() || + (type.isTypeParameter() && type.immediateSupertypes().all { it.isAnyOrNullableAny() }) for (extensionFunction in allExtensionFunctions) { @@ -492,53 +224,9 @@ class DocumentationBuilder ?: emptyList() if (isIgnoredReceiverType(extensionReceiverParameter.type)) continue - val subclasses = - classHierarchy.filter { (key) -> key.isExtensionApplicable(extensionFunction) } - if (subclasses.isEmpty()) continue - subclasses.values.flatten().forEach { subclass -> - if (subclass.isExtensionApplicable(extensionFunction) && - possiblyShadowingFunctions.none { subclass.isExtensionApplicable(it) }) { - - val hasExternalLink = - linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink( - extensionFunction - ) != null - if (hasExternalLink) { - val containerDesc = - extensionFunction.containingDeclaration as? PackageFragmentDescriptor - if (containerDesc != null) { - val container = refGraph.lookup(containerDesc.signature()) - ?: containerDesc.buildExternal() - container.append(extensionFunction.buildExternal(), RefKind.Member) - } - } - - refGraph.link(subclass.signature(), extensionFunction.signature(), RefKind.Extension) - } - } } } - private fun ClassDescriptor.isExtensionApplicable(extensionFunction: CallableMemberDescriptor): Boolean { - val receiverType = extensionFunction.fuzzyExtensionReceiverType()?.makeNotNullable() - val classType = defaultType.toFuzzyType(declaredTypeParameters) - return receiverType != null && classType.checkIsSubtypeOf(receiverType) != null - } - - private fun buildClassHierarchy(classes: List<ClassDescriptor>): Map<ClassDescriptor, List<ClassDescriptor>> { - val result = hashMapOf<ClassDescriptor, MutableList<ClassDescriptor>>() - classes.forEach { cls -> - TypeUtils.getAllSupertypes(cls.defaultType).forEach { supertype -> - val classDescriptor = supertype.constructor.declarationDescriptor as? ClassDescriptor - if (classDescriptor != null) { - val subtypesList = result.getOrPut(classDescriptor) { arrayListOf() } - subtypesList.add(cls) - } - } - } - return result - } - private fun CallableMemberDescriptor.canShadow(other: CallableMemberDescriptor): Boolean { if (this == other) return false if (this is PropertyDescriptor && other is PropertyDescriptor) { @@ -570,89 +258,47 @@ class DocumentationBuilder else -> throw IllegalStateException("Descriptor $this is not known") } - fun PackageFragmentDescriptor.buildExternal(): DocumentationNode { - val node = DocumentationNode(fqName.asString(), Content.Empty, NodeKind.Package) - - val externalLink = linkResolver.externalDocumentationLinkResolver.buildExternalDocumentationLink(this) - if (externalLink != null) { - node.append(DocumentationNode(externalLink, Content.Empty, NodeKind.ExternalLink), RefKind.Link) - } - register(this, node) - return node - } - - fun CallableDescriptor.buildExternal(): DocumentationNode = when(this) { - is FunctionDescriptor -> build(true) - is PropertyDescriptor -> build(true) - else -> throw IllegalStateException("Descriptor $this is not known") - } - - fun ClassifierDescriptor.build(external: Boolean = false): DocumentationNode = when (this) { - is ClassDescriptor -> build(external) - is TypeAliasDescriptor -> build(external) + is ClassDescriptor -> build(this, external) + is TypeAliasDescriptor -> build() is TypeParameterDescriptor -> build() else -> throw IllegalStateException("Descriptor $this is not known") } - fun TypeAliasDescriptor.build(external: Boolean = false): DocumentationNode { - val node = nodeForDescriptor(this, NodeKind.TypeAlias) - - if (!external) { - node.appendDefaultSinceKotlin() - node.appendAnnotations(this) - } - node.appendModifiers(this) - node.appendInPageChildren(typeConstructor.parameters, RefKind.Detail) - - node.appendType(underlyingType, NodeKind.TypeAliasUnderlyingType) - - if (!external) { - node.appendSourceLink(source) - node.appendDefaultPlatforms(this) - } - register(this, node) + fun TypeAliasDescriptor.build(): DocumentationNode { + val node = DocumentationNodes.TypeAlias(name.asString(), this) + node.appendType(underlyingType, this, DocumentationNodes.TypeAliasUnderlyingType::class) return node } - fun ClassDescriptor.build(external: Boolean = false): DocumentationNode { - val kind = when { - kind == ClassKind.OBJECT -> NodeKind.Object - kind == ClassKind.INTERFACE -> NodeKind.Interface - kind == ClassKind.ENUM_CLASS -> NodeKind.Enum - kind == ClassKind.ANNOTATION_CLASS -> NodeKind.AnnotationClass - kind == ClassKind.ENUM_ENTRY -> NodeKind.EnumItem - isSubclassOfThrowable() -> NodeKind.Exception - else -> NodeKind.Class + fun ClassDescriptor.build(descriptor: DeclarationDescriptor, external: Boolean = false): DocumentationNode { + val node = when { + kind == ClassKind.OBJECT |
